Eine Sammlung von meinen Projekten aus den Bereichen Physik, Elektronik, Informatik und sogar ein bisschen Botanik. Dieser Blog soll einerseits Hilfestellung bei Problemen geben aber andererseits auch als Anregung für weitere Projekte dienen. Falls es zu einem Thema Fragen oder Anregungen gibt: Einfach schnell einen Kommentar schreiben oder das Kontaktformular rechts unten benutzen, ich beantworte das normalerweise innerhalb von einem Tag.
AdSense
Freitag, 31. Oktober 2014
Arduino Nano V3.0 Klon mit CH340G in Betrieb nehmen
Bei Ebay gibt es einen Klon des Arduino Nano schon für unter 3 Euro zu kaufen. Meist unter dem Namen "Nano V3.0 ATmega328 CH340G" mit dem Zusatz "for Arduino" oder "Arduino compatible", wie zum Beispiel hier. Bei diesen Klonen kommt als USB-Seriell-Wandler nicht wie beim Original ein FT232R sondern (wie der Name schon erkennen lässt) ein CH340G zum Einsatz. Daher sind auch die Treiber der Arduino IDE ungeeignet, stattdessen muss ein extra Treiber von Hand installiert werden. Dieser kann hier beim Hersteller herunter geladen werden. Sollte der Link direkte nicht mehr funktionieren, einfach nach "ch341ser.zip" suchen. Es sind auch Treiber für MAC oder Linux erhältlich. Ich werde hier nur auf die Installation unter Windows eingehen. Zuerst muss das ZIP-Archiv entpackt werden. Falls die Version für 64bit-Windows benötigt wird, muss dann die Datei "DRVSETUP64.exe" aus dem Ordner "DRVSETUP64" in den darüberliegenden Ordner (der unter anderem die Datei "CH341SER.INF" enthält) kopiert werden. Je nach System muss dann die "SETUP.EXE" (32bit) oder die "DRVSETUP64.exe" (64bit) ausgeführt werden. Dann wird auf "INSTALL" geklickt und der Treiber damit installiert. Damit die Installation des Treibers reibungslos abläuft, darf das Board dabei NICHT eingesteckt sein. Erst NACH der Installation wird der Arduino Nano eingestöpselt. Er sollte dann von Windows erkannt werden.
Kategorien:
Arduino
Sonntag, 5. Oktober 2014
C# - Programm zum Lösen von Sudokus
(English version) Ein Sudoku von Hand lösen ist nicht weiter schwer, irgendwann überkommt einen Programmierer aber dann die Lust, ein Programm zu schreiben, was Sudokus selber löst. Die Grundidee ist einfach. Das erste freie Kästchen wird ausgefüllt (mit einer 1). Dann wird geprüft ob das Sudoku noch korrekt ist. Falls ja, wird das nächste Kästchen ausgefüllt, falls nicht wird das vorige Kästchen eins hochgezählt. Das wird wiederholt, bis das Sudoku komplett ausgefüllt ist.
Zuallererst habe ich ein Fenster erstellt, welches das Sudoku anzeigt:
Und der dazugehörige Code:
Dies wird nun benutzt um das Sudoku anzuzeigen. Das Löseprogramm zeigt das aktuelle Sudoku und öffnet für jede gefundene Lösung ein neues Fenster. MainWindow ist leer, wird lediglich zum Starten des Programmes benötigt.
Zuallererst habe ich ein Fenster erstellt, welches das Sudoku anzeigt:
<Window x:Class="SudokuSolver.SudokuShowWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SudokuShowWindow" Height="550" Width="550">
<Grid Name="Grid1" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
</Grid>
</Window>
Und der dazugehörige Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SudokuSolver
{
/// <summary>
/// Interaktionslogik für SudokuShowWindow.xaml
/// </summary>
public partial class SudokuShowWindow : Window
{
public SudokuShowWindow()
{
InitializeComponent();
}
public int[] numbers;
public TextBlock[] TextBlocks;
public void refreshValues(int[] _numbers)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (_numbers[i * 9 + j] != numbers[i * 9 + j])
{
TextBlocks[i * 9 + j].Text = _numbers[i * 9 + j].ToString();
}
}
}
}
public static SudokuShowWindow newSudokuShowWindow(int[] numbers)
{
SudokuShowWindow window = new SudokuShowWindow();
window.numbers = new int[81];
window.TextBlocks = new TextBlock[81];
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
window.numbers[i * 9 + j] = numbers[i * 9 + j];
TextBlock tb = new TextBlock();
tb.Text = numbers[i * 9 + j].ToString();
tb.HorizontalAlignment = HorizontalAlignment.Center;
tb.VerticalAlignment = VerticalAlignment.Center;
Grid.SetRow(tb, i);
Grid.SetColumn(tb, j);
Thickness thk = new Thickness(0, 0, 0, 0);
if (i == 2 || i == 5)
{
thk.Bottom = 1;
}
if (i == 3 || i == 6)
{
thk.Top = 1;
}
if (j == 2 || j == 5)
{
thk.Right = 1;
}
if (j == 3 || j == 6)
{
thk.Left = 1;
}
Border border = new Border();
border.BorderThickness = thk;
border.BorderBrush = Brushes.Black;
Grid.SetRow(border, i);
Grid.SetColumn(border, j);
window.Grid1.Children.Add(border);
window.Grid1.Children.Add(tb);
window.TextBlocks[i * 9 + j] = tb;
}
}
window.Show();
return window;
}
}
}
Dies wird nun benutzt um das Sudoku anzuzeigen. Das Löseprogramm zeigt das aktuelle Sudoku und öffnet für jede gefundene Lösung ein neues Fenster. MainWindow ist leer, wird lediglich zum Starten des Programmes benötigt.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SudokuSolver
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread = new Thread(workLoop);
thread.Start();
}
private SudokuShowWindow window;
private int numberCounter;
private int[] initialNumbers;
private int[] numbers;
List<int[]> Solutions = new List<int[]>();
private void workLoop()
{
//The initial Sudoku which should be solved
initialNumbers = new int[81]
{
5,3,0, 0,7,0, 0,0,0,
6,0,0, 1,9,5, 0,0,0,
0,9,8, 0,0,0, 0,6,0,
8,0,0, 0,6,0, 0,0,3,
4,0,0, 8,0,3, 0,0,1,
7,0,0, 0,2,0, 0,0,6,
0,6,0, 0,0,0, 2,8,0,
0,0,0, 4,1,9, 0,0,5,
0,0,0, 0,8,0, 0,7,9
};
numbers = new int[81];
for (int i = 0; i < 81; i++)
{
numbers[i] = 0;
}
//Invoke window actions because we are not in the main thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = SudokuShowWindow.newSudokuShowWindow(initialNumbers);
}));
//Position of the "cursor" in the sudoku
numberCounter = 0;
int ctr = 0;
bool noi = false;
while (true)
{
if (isItValid())
{
noi = false;
//A valid solution!
if (numberCounter > 80)
{
int[] totalNumbers = new int[81];
for (int i = 0; i < 81; i++)
{
totalNumbers[i] = initialNumbers[i];
if (totalNumbers[i] == 0)
{
totalNumbers[i] = numbers[i];
}
}
bool eq = false;
foreach (int[] solution in Solutions)
{
bool leq = true;
for (int i = 0; i < 81; i++)
{
if (solution[i] != totalNumbers[i])
{
leq = false;
}
}
if (leq)
{
eq = true;
}
}
if (!eq)
{
int[] tmp = new int[81];
for (int i = 0; i < 81; i++)
{
tmp[i] = totalNumbers[i];
}
Solutions.Add(tmp);
}
else
{
System.Console.WriteLine("Done!");
break;
}
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SudokuShowWindow.newSudokuShowWindow(totalNumbers);
}));
//Check for other solutions?
noi = true;
while (true)
{
numberCounter--;
if (initialNumbers[numberCounter] == 0)
{
if (numbers[numberCounter] >= 9)
{
numbers[numberCounter] = 0;
}
else
{
numbers[numberCounter]++;
break;
}
}
}
}
if (numberCounter > 80)
{
break;
}
if (numbers[numberCounter] == 0 && initialNumbers[numberCounter] == 0)
{
iterateOne();
}
else
{
if (!noi)
{
increaseNumberCounter();
}
}
}
else
{
if (numberCounter > 80 || numberCounter < 0)
{
break;
}
if (numbers[numberCounter] >= 9)
{
decreaseOne();
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
int[] totalNumbers = new int[81];
for (int i = 0; i < 81; i++)
{
totalNumbers[i] = initialNumbers[i];
if (totalNumbers[i] == 0)
{
totalNumbers[i] = numbers[i];
}
}
window.refreshValues(totalNumbers);
}));
}
else
{
iterateOne();
}
}
ctr++;
if (ctr > 1000)
{
ctr = 0;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
int[] totalNumbers = new int[81];
for (int i = 0; i < 81; i++)
{
totalNumbers[i] = initialNumbers[i];
if (totalNumbers[i] == 0)
{
totalNumbers[i] = numbers[i];
}
}
window.refreshValues(totalNumbers);
}));
Thread.Sleep(1);
}
}
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
}
void increaseNumberCounter()
{
numberCounter++;
while (numberCounter <= 80 && initialNumbers[numberCounter] != 0)
{
numberCounter++;
}
}
void iterateOne()
{
if (numberCounter > 80)
{
return;
}
while (initialNumbers[numberCounter] != 0)
{
numberCounter++;
}
numbers[numberCounter]++;
}
void decreaseOne()
{
if (numberCounter > 80)
{
numberCounter = 80;
}
numbers[numberCounter] = 0;
if (numberCounter == 0)
{
return;
}
while (numberCounter >= 0)
{
numberCounter--;
while (numberCounter > 0 && initialNumbers[numberCounter] != 0)
{
numberCounter--;
}
if (numberCounter < 0)
{
return;
}
if (numbers[numberCounter] < 9)
{
numbers[numberCounter]++;
return;
}
else
{
numbers[numberCounter] = 0;
}
}
}
bool isItValid()
{
int[] totalNumbers = new int[81];
for (int i = 0; i < 81; i++)
{
totalNumbers[i] = initialNumbers[i];
if (totalNumbers[i] == 0)
{
totalNumbers[i] = numbers[i];
}
}
//Check Horizontal
List<int> testList;
for (int i = 0; i < 9; i++)
{
testList = new List<int>();
for (int j = 0; j < 9; j++)
{
if (testList.Contains(totalNumbers[i * 9 + j]))
{
//Invalid
return false;
}
if (totalNumbers[i * 9 + j] != 0)
{
testList.Add(totalNumbers[i * 9 + j]);
}
}
}
//Check Vertical
for (int j = 0; j < 9; j++)
{
testList = new List<int>();
for (int i = 0; i < 9; i++)
{
if (testList.Contains(totalNumbers[i * 9 + j]))
{
//Invalid
return false;
}
if (totalNumbers[i * 9 + j] != 0)
{
testList.Add(totalNumbers[i * 9 + j]);
}
}
}
//Check squares
for (int ii = 0; ii < 3; ii++)
{
for (int jj = 0; jj < 3; jj++)
{
testList = new List<int>();
for (int i = ii * 3; i < ii * 3 + 3; i++)
{
for (int j = jj * 3; j < jj * 3 + 3; j++)
{
if (testList.Contains(totalNumbers[i * 9 + j]))
{
//Invalid
return false;
}
if (totalNumbers[i * 9 + j] != 0)
{
testList.Add(totalNumbers[i * 9 + j]);
}
}
}
}
}
//Valid
return true;
}
}
}
Kategorien:
C#
Visual Studio - Anwendung mit automatischen Updates benötigt lange zum Starten
(English version) Wenn man in Visual Studio ein Projekt veröffentlicht und dann die Anwendung startet wird normalerweise zuerst nach Updates gesucht. Dies kann einige Zeit in Anspruch nehmen und ist nervig wenn man die Anwendung möglichst schnell haben will. Glücklicherweise kann man den Zeitpunkt der Updates umstellen, sodass erst nach Updates geprüft wird, wenn die Anwendung schon gestartet ist. Die Updates kann man dann beim nächsten Start installieren ohne lange Wartezeiten zu haben.
Um dies einzustellen muss man in die Projekteigenschaften gehen. Hier gibt es dann den Unterpunkt "Veröffentlichen", wo es dann die Schaltfläche "Updates" gibt. Hier ist man dann auch bei der gewünschten Einstellung: "Zeitpunkt für Updateüberprüfungen auswählen". Hier ist standartmäßig "Vor Start der Anwendung" ausgewählt, um die Startzeit zu verkürzen muss man nun "Nach dem Starten der Anwendung" auswählen.
Um dies einzustellen muss man in die Projekteigenschaften gehen. Hier gibt es dann den Unterpunkt "Veröffentlichen", wo es dann die Schaltfläche "Updates" gibt. Hier ist man dann auch bei der gewünschten Einstellung: "Zeitpunkt für Updateüberprüfungen auswählen". Hier ist standartmäßig "Vor Start der Anwendung" ausgewählt, um die Startzeit zu verkürzen muss man nun "Nach dem Starten der Anwendung" auswählen.
Speichernutzung übersichtlich anzeigen - WinDirStat
(English version) Bei zunehmender Datenmenge wird es immer schwieriger, die Datenmengen zu kontrollieren und so passiert es immer öfter dass die Festplatte voll ist und man eigentlich keine Ahnung hat was die Speicherfresser sind. Um dieses Problem anzugehen gibt es ein sehr nützlichen Programm: WinDirStat.
Dieses Programm zeigt die Speichernutzung einer Partition sehr übersichtlich an, wie man im folgenden Bild sehen kan:
Man kann Ordner auswählen und sieht sofort einen weißen Rahmen der den Speicherplatz des gesamten Ordners anzeigt. Jede Datei entspricht einem Rechteck, sodass man einzelne große Dateien sofort ausmachen kann. Ich persönlich habe mit diesem Programm bereits einige viele Gigabyte an unnötigen Daten gelöscht und kann es nur jedem weiterempfehlen.
Dieses Programm zeigt die Speichernutzung einer Partition sehr übersichtlich an, wie man im folgenden Bild sehen kan:
Abonnieren
Posts (Atom)