Programm: J_Tools und Threading

Veröffentlicht von Joe-C (jch) am Oct 23 2011
Software >>

Diese Webseite ist gerade in Überarbeitung.

Bis zum Abschluss der Arbeiten, ist auf den Unterseiten mit Darstellungsfehlern und Unvollständigkeiten zu rechnen.

Index

Zurück zur Übersicht

Beschreibung

zurück zum Index


Hier ein weiteres Programm zur Verwendung auf dem Pocket PC. Schönerweise hat .net die nette Eigenschaft , dass ich die Datei auf dem Pocket PC genauso wie auf dem PC einfach starten kann. Das Framework ist ja sowieso schon drauf.

Es gibt derzeit 3 Funktionsblöcke:

  • 16 Bit Konverter
    Konvertiert von und zu Hexadezimal, Dezimal und Binär. Für mich recht hilfreich bei der Verwendung von Mikrocontrollern, z.B. wenn man die Pinbelegung als Zahl übergeben möchte.
  • Stringkonverter
    Zerlegt einen String in eine Abfolge von Dezimal oder Hexadezimal Zahlen, oder umgekehrt. Hilfreich u.a. bei der Verwendung der seriellen Schnittstelle.
  • RS 232 Terminal
    Das umfangreichste der Tools. Es beinhaltet eine Sende und Empfangsmöglichkeit (in Dezimal oder Text) sowie die Nutzung der Steuerleitungen. Die Steuerleitungen können auch als Signalgeber verwendet werden, allerdings nur im Sekundenbereich.

Damit auf der recht kleinen Oberfläche mehr untergebracht werden konnte, hab ich vom TabControl Gebrauch gemacht... es wurde ja schließlich auch dafür erzeugt. Das erste Tab zeigt eine Art Auswahl. Alle anderen sind für die entsprechenden Funktionen.
Es gibt auch an mehreren Stellen die Möglichkeit, Ergebnisse als TXT zu speichern, falls man sie extern auswerten möchte.

  • Bild 1
    Hier ein Testaufbau für die Steuerleitungen. Obwohl die serielle Schnittstelle 2 Ausgänge und 3 Eingänge hat (Rx und Tx nicht mitgezählt), sind beim Ipaq nur die 2 Ausgänge und 1 Eingang verwendbar. CD und DSR sind gebrückt und CTS ist permanent High. Ein Ausgang hat ca. -5.4V wenn er auf Low ist und +6V bei High. Zum Testen hab ich einfach 2 Duo-LEDs (eine rote und eine grüne LED, antiparallel in einem Gehäuse mit 2 Pins) in Reihe geschaltet.
  • Bild 2
    Bei meinem Ipaq ist an DTR der eine Eingang angeschlossen. Das Einschalten vom DTR führt so zu einem aktiven CD und DSR. Außerdem schalten die 2 LEDs von grün nach rot, was bei dem Bild leider nicht ganz so gut zu sehen ist.
  • Bild 3
    Diverse Screenshots. Hier sind die Hauptfunktionen zu sehen und unten rechts ein Vergleich zum PC. Das linke ist das normale Bild, das rechte zeigt das Programm in einem Simulator. Man sieht aber auch, dass der Simulator die kleine Schrift schlechter darstellt, als der PDA.

Bild1
Auflösung: 1200x900

Bild 2
Auflösung: 1200x900

Bild 3
Auflösung: 1200x900

 
  •  
  •  
  •  

Threading

Die tiefere Verwendung der seriellen Schnittstelle führte dazu, dass ich mich mit dem Threading (using System.Threading;) in Kontakt kam. Beim PICAXE Testprogramm wurde die Schnittstelle geöffnet, etwas gesendet, ein bisschen gewartet und geschaut, ob was zurück gekommen ist.
Diesmal sollte die Schnittstelle offen bleiben und automatisch bei Datenempfang reagieren. Dafür gibt es beim Objekt SerialPort den Event DataReceived. Dieser wird immer dann ausgelöst, wenn sich was tut... es läuft aber parallel zum Hauptprogramm in einem eigenen Thread. Dadurch können die empfangenen Daten verarbeitet werden, während der Haupthread sich um andere Sachen kümmert. Wenn man etwas Empfangenes über die Messagebox darstellen lässt, funktioniert das auch ohne Probleme, da die Box innerhalb des Threads neu erstellt wird. Wenn man aber eine Textbox von der Anwendung damit füllen will...
bekommt man gleich einen Laufzeitfehler: Ungültiger threadübergreifender Vorgang.

Beispielquellcode für einen Thread (C#):

//Hauptthread der Anwendung ###############################
void Button1Click(object sender, EventArgs e)
{
     //Threadobjekt erstellen und starten
     Thread T = new Thread(Funktion);
     T.Name = DateTime.Now.ToLongTimeString(); //Format ist HH:MM:SS
     T.Start();
}

//Zusatzthread #########################################

void Funktion()
{
     MessageBox.Show("Startzeit: " + Thread.CurrentThread.Name); //Funktioniert
     //textBox1.Text = "test"; //Funktioniert so nicht
}

Man muss sich Threads wie 2 Autos vorstellen. Hat man einen Rechner mit Hyperthreading oder Multicore, ist es sowas wie mehrere Fahrspuren nebeneinander. Die Autos können parallel zueinander fahren. Das Fahren der Autos ist in diesem Fall die Datenverarbeitung.
Ist nur ein Rechnerkern vorhanden, wird nur ein Thread gleichzeitig bearbeitet. Bei mehreren, wird zwischen ihnen je nach Priorität hin und her geschaltet. Im Bezug auf die Autos ist es wie eine einspurige Fahrbahn, bei denen die Autos hintereinander Fahren (wobei das nicht genau passt, da sie nicht den gleichen Raum einnehmen können und gleichzeitig fahren könnten, aber das ist erst mal nicht weiter relevant).

Wenn jetzt beispielsweise das eine Auto die Lichter anschalten soll, während vom anderen Auto die Anweisung dazu kommt, dann klappt es natürlich nicht. In diesem Fall kann jeder nur seinen eigenen Lichtschalter betätigen und ob der andere es will, ist unbekannt. Man könnte aber mit einem Handy von einem zu anderen Auto die Anweisung weitergeben. Im Bezug auf mein Programm ist das Kommunikationsmittel ein delegate.
Er wird wie eine Datenstruktur (z.B. int oder byte) deklariert, damit er verwendet werden kann. Mit "byte Test;" wird beispielsweise eine Datenstruktur mit dem Namen "Test" erstellt, die den Dezimalwert 0 bis 255 annehmen kann... ein Byte eben. Delegaten erstellt man z.B. mit: "delegate void Test();", sie verweisen nicht auf Datenstrukturen, sondern auf Funktionen (oder Methoden). Mit dem Delegaten deklariert man auch gleich, was dieser zurück gibt (void = nix) und was ihm übergeben werden muss.
Wenn nun ein Zugriff erfolgen soll (weil beispielsweise gerade was Empfangen wurde), dann wird dieser so erzeugt: "BeginInvoke(new Test(Data_recived)); ". Man braucht dann noch eine Funktion Namens "void Data_recived()" die damit aufgerufen wird. Mit "BeginInvoke" wird ein neuer Zugriff (deshalb new vor dem delegate) aus dem Thread erzeugt, in dem der Code ausgeführt wird. Ist die Aufgerufene Funktion durchlaufen, verfällt der Zugriff.

Beispielquellcode 2 für einen Thread (C#):

//Delegate zur interaktion zwischen
//verschiedenen Threads

delegate void delegatonaut();

//Hauptthread der Anwendung ###############################
void Button1Click(object sender, EventArgs e)
{
     //Threadobjekt erstellen und starten
     Thread T = new Thread(Funktion);
     T.Name = DateTime.Now.ToLongTimeString(); //Format ist "HH:MM:SS"
     T.Start();
}
void Update_TXT()
{
     textBox1.Text = "test";
}

//Zusatzthread #########################################

void Funktion()
{
     MessageBox.Show("Startzeit: " + Thread.CurrentThread.Name); //Funktioniert
     //textBox1.Text = "test"; //Funktioniert so nicht

     //Erstellt einen neuen Zugriff auf eine Funktion aus
     //einem anderen Thread. In diesem Fall, erstellt der
     //Zusatzthread einen Zugriff auf die Hauptanwendung.

     BeginInvoke(new delegatonaut(Update_TXT));
}

Bilder eines Threading Beispiels

  • Bild 1
    Hier die Anwendung, nachdem 2x auf die Schaltfläche geklickt und dann bei einer der entstandenen Messageboxen auf OK geklickt wurde. Wäre die Messagebox im Hauptthread entstanden, hätte die Form keinen Focus haben können, da die Box im Vordergrund bleibt.
    (Man sollte übrigens keine Messagebox bei einer Form benutzen, die "topmost = true" ist. Dann führt ein Klick auf die Form nur dazu, dass die Messagebox den Focus bekommt, diese kann aber nicht angeklickt werden, da sie von der Form verdeckt wird.)
  • Bild 2
    Die Hauptform wurde mit dem üblichen Klick auf das rote Kreuz beendet. Der Hauptthread ist damit geschlossen, der Zusatzthread hingegen nicht. Das kann man bei #Develop gut sehen, da trotzt geschlossener Form der Debugger immer noch auf run steht.
    Sowas führt übrigens auch dazu, dass eine Anwendung geschlossen wird, im Hintergrund aber weiter läuft und die Datei blockiert. Wenn man so eine Anwendung erstellt und nach dem Testen erneut erstellen will, heißt es dann: "auf xxx.exe kann nicht zugegriffen werden".
  • Bild 3
    Das Passiert, wenn man auf die Messagebox klickt, während der Hauptthread geschlossen ist...
    ein Laufzeitfehler:
    Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.
    Das Fensterhandle war erstellt, ist mit dem Schließen der Form nun aber nicht mehr registriert. Jetzt versucht der andere Thread auf etwas zuzugreifen, was nicht mehr da ist.

Bild1
Auflösung: 977x589

Bild 2
Auflösung: 977x589

Bild 3
Auflösung: 977x589

 
  •  
  •  
  •  

Jetzt habe ich mich mehr zum Threading ausgelassen, als zu meinem eigentlichen Programm... was solls.
Weitere Infos auf msdn (Gewusst wie: Erstellen und Beenden von Threads) und an genügend anderen Stellen im Netz.

Download

zurück zum Index


Die Datei unten enthält den Soucecode und die Anwendung, welches direkt zum PDA kopiert werden kann.

Version auf 1.1 geändert. Hab noch eine Stoppuhr und einen Countdowntimer mit eingebaut.

zurück zum Index




 

Zuletzt geändert am: Feb 05 2014 um 11:24 AM

Zurück