Archiv verlassen und diese Seite im Standarddesign anzeigen : Beispiel Anwendung C# Zugriff auf SerialPort
Hallo.
In letzter Zeit gab es immer wieder Nachfragen wie man in C# Daten über die serielle Schnittstelle an einen Microcontroller sendet.
Deshalb habe ich mich dazu entschlossen mal als eine kleine Beispielanwendung ein kleines Terminalprogramm in C# geschrieben und kommentiert (Ok die Kommentare können noch ausgebaut werden)
Ich hoffe dass diese Beispielanwendung insbesondere Anfängern hilft den schnellen Einstieg in die Verwendung der seriellen Schnittstelle in C# ermöglicht.
Im Anhang findet ihr einmal die fertig erstellte Exe (.Net Framework 4)
und das gesamte Projekt samt Quellcode in Form einer Visualstudio Solution (Visualstudio 2010 C# Express)
liebe Grüße
shedepe
Was ich bei meinem Beitrag vor einigen Tagen vergessen habe: Anregungen und Kritik sind natürlich immer erwünscht.
Außerdem kann ich bei Bedarf auch nur den Quellcode posten
hey
das sieht echt nett aus, sowas versuche ich grad zu verstehen
nur die ganzen einstellungen mache ich im code selbst
aber könntest du hier vllt einfach mal ganz simpel erzähle wie man sendet und empfängt?
und dazu bisschen was erzählen :)
das würde mir sehr helfen
vielen dank
Hallo, zum Verständnis allgemein erstmal (sollte auch die erste Anlaufstelle bei anderen Fragen bezüglich C# sein): http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.aspx
Und nun zu deiner Frage:
Gesendet wird mit dieser Zeile: Es wird direkt der Inhalt der Textbox über die Serielleschnittstelle gesendet.
Es gibt auch die Möglichkeit mit "serialPort.Write(buffer[],int Offsize, int count);" Einzelne und mehrere Bytes zu senden, was man häufig bei einem Befehls bzw. Datenprotokoll braucht.
//Hier werden die eingebenen Daten über die serielle Schnittstelle gesendet
serialPort.WriteLine(tbDataToSend.Text);
Das Empfangen ist etwas komplizierter:
Zum einen muss man zuerst das SerialPort.DataRecieved Event abonnieren (Zur Eventbasierten Programmierung empfehle ich diesen Link hier: http://www.mycsharp.de/wbb2/thread.php?threadid=26116)
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataRece ived); //DataRecieved Event abonnieren
Zum anderen muss man die Daten dann verarbeiten wenn, das Event ausgelöst wird (also Daten angekommen sind)
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) //Methode die Aufgerufen wird, wenn das Event ausgelöst wurde. Die Methode wurde oben festgelegt beim abonnieren
{
foreach (var item in serialPort.ReadLine()) //Lese alle verfügbaren Daten. Hier gibt es auch noch andere Auslesemöglichkeiten wie z.B. Read() bzw ReadToEnd()
{
lbRecieved.Invoke(lbRecievedDelegate,new object[]{item}); //Das wird für den Zugriff auf die Gui benötigt. (Thread übergreifende Zugriffe)
}
}
das schon mal sehr nett :)
bin relativer anfänger, habe schon vieles im internet erlesen
aber dennoch echt schwer für mich
habe eben 2 usb to rs232 adapter und ein nullmodem kabel bestelle, um damit denn rumzuspielen
vllt kommen noch fragen auf und ich muss dich leider "nerven"
VIELEN DANK
Hallo, ich hab grad noch entdeckt dass ich einen kleiner Fehler bei der Verarbeitung der ankommenden Daten gemacht hab. Ich hab das jetzt korrigiert. Im Anhang befindet sich die richtige Version.
hallo...
hab nun nen problem mitn empfangen
wird gesagt das es threadübergreifend ist..
bekanntes problem ich weiß... ich habe mich damit nun über 20std! beschäftigz....es versucht im internet zu erlesen
ich packs nicht, bin grad am verzeifeln
ich brauche irgendwie diesen invoke befehl
du bist grad meine letzte hoffnung
ich hoffe du hilfst mir und erklärst mir das problem beim empfangen beim serialport...
hab hier einfach mal mein ganzen code hochgeladen, kannst dir ja mal anschauen
schon mal vielen vielen dank
Würde es dir was ausmachen den Code als Textdatei anzuhängen? Hab grad leider nichts zum .rar öffenen da.
Ganz einfach kannst du das Problem mit dem Threadübergreifenden zu Griff aber so lösen: (Ich beziehe mich bei der Namensgebung der Controls bzw. Objekte auf mein Beispielprogramm)
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Hier die Daten die du ausgelesen hast in irgendeiner globalen Variable speichern
lbRecieved.Invoke(new MethodInvoker(MethodeZumDatenInListboxSchreiben));
}
void MethodeZumDatenInListboxSchreiben()
{
lbRecieved.Items.Add(<Daten aus der globalen Variable>);
}
In meinem Programm habe ich das ganze mit einem Delegaten gelöst was den Vorteil hat dass man sich z.B. den Umweg über die globale Variable sparen kann.
Hier kannst du das auch nochmal nachlesen:
http://www.mycsharp.de/wbb2/thread.php?threadid=33113
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports; //serielleSchnittstelle
using System.Collections; //ArrayListe
using System.Threading; //Delagation invoke (Threadübergreifend)
using System.Timers; //Timer
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
SerialPort Schnittstelle = new SerialPort("COM1"); //Deklaration
byte[] daten = new byte [3];
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonConnect_Click(object sender, EventArgs e)
{ //Festlegung Parameter=
Schnittstelle.BaudRate = 9600;
Schnittstelle.Parity = Parity.None;
Schnittstelle.DataBits = 8;
Schnittstelle.StopBits = StopBits.One;
Schnittstelle.Handshake = Handshake.None;
Schnittstelle.ReadTimeout = 500;
Schnittstelle.WriteTimeout = 500;
try
{
Schnittstelle.Open(); //Serialport öffnen
if (Schnittstelle.IsOpen)
{
buttonConnect.Enabled = false; //Connect_Button blass
buttonConnect.Text = "Erfolgreich";
}
}
catch
{
MessageBox.Show("Keine Verbindung möglich", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Schnittstelle.DataReceived += new SerialDataReceivedEventHandler(Nebenthread); // Abo_Event abonnieren
}
void Nebenthread(object sender, SerialDataReceivedEventArgs e) //Diese Methode wird ausgelöst. Wurde vorher abonniert
{
//string serialIn = Schnittstelle.ReadLine();
//listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add(serialIn); }));
this.textBox1.Text = Schnittstelle.ReadExisting();
}
private void buttonDisconnect_Click(object sender, EventArgs e)
{
Schnittstelle.Close();
buttonConnect.Enabled = true;
buttonConnect.Text = "Connect";
}
private void buttonSenden_Click(object sender, EventArgs e)
{
daten[0] = 1;
daten[1] = 2;
if (Schnittstelle.IsOpen)
{
Schnittstelle.Write(daten, 0, daten.Length); //Daten senden
// oder//Schnittstelle.Write(daten, 0, 2);
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e) // Anwendungen schließen = Verbindung trennen
{
Schnittstelle.Close();
}
}
}
hoffe du blickst durch..
und wenn du mir da jetzt den passenden code schreibst, bin ich dir unendlich danklbar
versuche das jetzt natürlich noch selber und morgen auch
aber wäre dir echt dankbar wenn du was schreibst, ist ja ein leichtes für dich
DANKE :)
PS: ich möchte es auch ohne globale variabeln...hab das eben verucht, gefällt mir alles nicht so :/
Dann wirst du wohl nicht darum kommen dir anzuschaun was das mit den Delegaten auf sich hat, da du ja Daten übergeben möchtest.
Die Variante mit der globalen Variable ist allerdings wesentlich einfacher:
string Daten = "";
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Daten = serialPort.ReadLine();
lbRecieved.Invoke(new MethodInvoker(MethodeZumDatenInListboxSchreiben));
}
void MethodeZumDatenInListboxSchreiben()
{
lbRecieved.Items.Add(Daten);
}
schon mal danke dafür
würds halt gern über delegate machen... wie gesagt habe wirklich gestern 12std fast am stück versucht das zu verstehen
im internet ist jeder code anders und ich sehe nie einen zusammenhang
deswegen meine hoffung das du zu meinen code einen passenden befehl eben schnell schreiben kannst...oder ist das schon so viel
wills ja gern selber machen, aber grad komm ich einfach nicht vorran :(
Hast du auch schon in der MSDN unter delegate geschaut ? Ist zwar recht viel aber auch verständlich.
http://msdn.microsoft.com/de-de/library/ms173171(v=vs.80).aspx
Warum übernimmst für den Threadübergreifendenzugriff eigentlich nicht den Code aus meiner Beispielanwendung? Da hab ich ja auch einen Delegaten verwendet
das hat ich auch schon gelesen
ja un deinen code ausm terminal hatte ich auch versucht...
sind ja halt mehrere teile..und es passt alles irgendwie nciht zsm... habs versucht anzupassen aber klappt einfach nicht,
weil ich wohl das prinzip von dem delegate und invoke befehl nich versteh -.-
Der Delegate ist quasi ein Zeiger auf eine Methode. Und den kann man halt einer anderen Methode übergeben. Der Invoke Befehle sagt dem GUI Objekt (in dem Fall eine Listbox): He ich will auf dich aus einem anderen Thread zugreifen.
In meiner Beispielanwendung hab ich den delegaten zuerst deklariert:
delegate void InvokeLB(string Data);
Und dann ein Objekt davon deklariert
InvokeLB lbRecievedDelegate;
Und dann in der Methode bCreateSP_Click eine neue Instanz erzeugt:
lbRecievedDelegate = new InvokeLB(InvokeLBRecieved);
Die auf diese Methode hier verweist
void InvokeLBRecieved(string Data) //Parameter stimmen mit der Deklaration des Delegaten überein
{
lbRecieved.Items.Add(Data);
}
Und in der Methode die Aufgerufen wird wenn neue Daten am SerialPort verfügbar sind rufe ich dann die Invoke Methode der Listbox lbRecieved auf und übergebe ihr den davor instanzierten Delegaten und die Parameter (in dem Fall die Daten die Empfangen wurden)
lbRecieved.Invoke(lbRecievedDelegate,new object[]{RecievedLine});
ich danke dir das du mir hilfst... habs grad versucht..
lbRecieved und RecievedLine ist im aktuellen Kontex nicht vorhanden
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports; //serielleSchnittstelle
using System.Collections; //ArrayListe
using System.Threading; //Delagation invoke (Threadübergreifend)
using System.Timers; //Timer
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
delegate void InvokeLB(string Data); //Delegaten deklariert
InvokeLB lbRecievedDelegate; //Objekt deklariert
SerialPort Schnittstelle = new SerialPort("COM1"); //Deklaration
byte[] daten = new byte [3];
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonConnect_Click(object sender, EventArgs e)
{ //Festlegung Parameter=
Schnittstelle.BaudRate = 9600;
Schnittstelle.Parity = Parity.None;
Schnittstelle.DataBits = 8;
Schnittstelle.StopBits = StopBits.One;
Schnittstelle.Handshake = Handshake.None;
Schnittstelle.ReadTimeout = 500;
Schnittstelle.WriteTimeout = 500;
try
{
Schnittstelle.Open(); //Serialport öffnen
if (Schnittstelle.IsOpen)
{
buttonConnect.Enabled = false; //Connect_Button blass
buttonConnect.Text = "Erfolgreich";
}
}
catch
{
MessageBox.Show("Keine Verbindung möglich", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
lbRecievedDelegate = new InvokeLB(InvokeLBRecieved); //neue Instanz
Schnittstelle.DataReceived += new SerialDataReceivedEventHandler(Nebenthread); // Abo_Event abonnieren
}
void InvokeLBRecieved(string Data) //Parameter stimmen mit der Deklaration des Delegaten überein
{
lbRecieved.Items.Add(Data);
}
void Nebenthread(object sender, SerialDataReceivedEventArgs e) //Diese Methode wird ausgelöst. Wurde vorher abonniert
{
//string serialIn = Schnittstelle.ReadLine();
//listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add(serialIn); }));
lbRecieved.Invoke(lbRecievedDelegate,new object[]{RecievedLine});
//this.textBox1.Text = Schnittstelle.ReadExisting();
}
private void buttonDisconnect_Click(object sender, EventArgs e)
{
Schnittstelle.Close();
buttonConnect.Enabled = true;
buttonConnect.Text = "Connect";
}
private void buttonSenden_Click(object sender, EventArgs e)
{
daten[0] = 1;
daten[1] = 2;
if (Schnittstelle.IsOpen)
{
Schnittstelle.Write(daten, 0, daten.Length); //Daten senden
// oder//Schnittstelle.Write(daten, 0, 2);
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e) // Anwendungen schließen = Verbindung trennen
{
Schnittstelle.Close();
}
}
}
ich merke grad wie sehr ich anfänger bin... diese invoke und delegate..methoden..threads... überfordert mich total
dabei wollte ich heut endlich daten empfangen -.-
achso... deine lbrecieved war ja deine listbox.. SRY .. so nun noch RecievedLine zuordnen .. :)
Text = Schnittstelle.ReadLine();
listBox1.Invoke(lbRecievedDelegate,new object[]{Text});
hab ich nun so gelöst..wenn ichs programm ausführe
kam zuerst ein timeout,hab ich denn rausgenommen
nun hängt sich das programm auf und es kommt folgende meldung:
Der E/A-Vorgang wurde wegen eines Threadendes oder einer Anwendungsanforderung abgebrochen
oh man.. hab nur mit anderen terminal gesendet
kommt bei mir wieder das:
Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Form1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
-.-
Die String Variable RecievedLine deklarierst du in der SerialPortDataRecieved Methode (Bei dir Nebenthread) Die Methode würde dann so aussehen:
void Nebenthread(object sender, SerialDataReceivedEventArgs e) //Diese Methode wird ausgelöst. Wurde vorher abonniert
{
string RecievedLine = serialPort.ReadLine();
lbRecieved.Invoke(lbRecievedDelegate,new object[]{RecievedLine});
}
Bitte verwende auch absofort die Code Tags und achte ein bisschen auf die Formatierung deines Quellcodes
aaah danke! es funktioniert !!
ich habe nur das STRING vergessen ;)
DANKE
hey..
einfach mal eben kurz eine frage
was spricht gegen diesen befehel=
CheckForIllegalCrossThreadCalls = false;
?
In welchem Zusammenhang willst du den verwenden ?
um den threadübergreifenden fehler zu umgehen. würde wunderbar klappen
man benötigt kein invoke oder delegate...
denn ich will die daten die ich empfange auch weiter verarbeiten.. muss ich doch wieder alles mit delegate machen usw ?!
Die Datenverarbeitung kannst du auch ohne invoke machen. Den Invoke Befehl brauchst du nur für Zugriffe auf den GUI Thread. Es hat außerdem durchaus seinen Sinn dass man nicht ohne weiteres von einem anderen Thread auf den GUI Thread zugreifen kann, wie in dem dazu gehörigen Artikel der MSDN auch genannt wird:
http://msdn.microsoft.com/de-de/library/system.windows.forms.control.checkforillegalcrosst hreadcalls%28v=vs.80%29.aspx
Wenn ich jetzt aber eine zweite Textbox einfüge
kommen meine gesendeten ASCII Zahlen doppelt an
also wenn ich 12 sende zeigen beide textboxen 1212 an
ich will aber 12 13 senden.. und die textboxTemp soll 12 anziegen und textboxLuft soll 13 anzeigen.
und das andere ist wenn die zahlen in der textbox angezeigt sind und ich wieder zahlen sende sollen auch nur die wieder angezeigt werden, nun werden diese einfach vorne mit rangeschrieben
}
void InvokeLBRecieved(string Data) //Parameter stimmen mit der Deklaration des Delegaten überein
{
textBoxTemp.AppendText(Data);
textBoxLuft.AppendText(Data);
//listBox1.Items.Add(Data);
}
void Nebenthread(object sender, SerialDataReceivedEventArgs e) //Diese Methode wird ausgelöst. Wurde vorher abonniert
{
string Text = Schnittstelle.ReadExisting();
textBoxTemp.Invoke(Textfeld, new object[] { Text });
te
Sorry auch wenn das jetzt etwas hart klingen mag. Kauf dir ein gutes Grundlagenbuch zu C# und arbeit das durch. Wenn du dir anschaust was die Methode InvokeLBRecieved(string Data) macht, sollte dir ziemlich schnell klar werden warum beide Textboxen das gleiche anzeigen. Außerdem würde ich dir empfehlen statt einer TextBox eine Listbox zur Datendarstellung in dem Fall zu verwenden
ja.........
mit der doppelten anzeige habs ich schon hinbekommen
ich erlese mir alles aus dem internet. ist kein leichtes! .. bin seit 3 wochen dabei
Mit einem Buch das dich strukturiert heranführt machst du dir (und anderen ^^) das Leben um einiges leichter.
Es gibt sogar sehr brauchbare kostenlose Bücher zu C#:
http://openbook.galileocomputing.de/visual_csharp_2010/
kenn ich :)
also ich verstehe ja schon viel und alles
nur der delegate und invoke macht mir zu schaffen, der macht irgendwie meinen ganzen code kaputt.. und wenn ich weiter mache kommen immer fehler
Dagegen hilft nur so lange weiter lesen und üben bis man die Verwendung und das Konzept davon verstanden hat ^^
Wenn es insbesondere um die Verwendung von Delegates geht hat mir die MSDN sehr viel weitergeholfen:
http://msdn.microsoft.com/de-de/library/ms173172(v=vs.80).aspx
Aber auch in der C# Community MyCSharp.de findet man bei vielen Themen bezüglich C# hilfe (Immer zuerst in die FAQ und in die Artikel reinschaun ob das was passendens dabei is^^)
Bei delegaten findet man das hier:
http://www.mycsharp.de/wbb2/thread.php?threadid=74181&hilight=delegate
hallo ;)
läuft alles schon richtig gut!
die daten die ich empfange werden ausgelesen
so zB die temperatur ... das problem dabei... wenn 12.3 gesendet wird
zeigt meine textbox es soab
1
2
.
3
und nicht komplett in einer zeile.
ich lese mit diesem befehe aus
Schnittstelle.ReadExisting();
hast du vllt eine idee?
danke
RP6Rulez
29.01.2012, 20:36
hi :)
ich möchte mir gerne in C# ein RemoteControl-Programm schreiben, mit dem ich den RP6 vom PC aus per GUI steuern kann. Zunächst wollte ich mir hierzu Beispielcode anschauen und damit testen ob alles funktioniert. Hierzu habe ich dieses Programm verwendet. Auf dem RP6 läuft die aktuellste Version des RP6SELFTEST-Programms. Meine Vorgehensweise:
1. Ich wähle in der GUI des Programms den COM5-Port(dies ist der korrekte Port für meinen RP6) und drücke Create.
2. Ich schalte den RP6 ein.
3. Ich drücke auf dem RP6 den Programm-Start-Knopf.
4. Ich erhalte folgende Ausgabe: http://img7.imagebanana.com/img/nk0gf3qk/Screen.png
5. Ich sende ein "x" an den RP6(dies wird für den RP6SELFTEST als Bestätigung benötigt)
6. Nichts passiert.
7. Ich sende "2" an den RP6(Dies sollte das LED-Test-Programm starten).
8. Nichts passiert.
Mit dem RP6Loader hingegen funktioniert das RP6SELFTEST-Programm einwandfrei. Kann mir jemand helfen bzw. mir sagen, wo hier mein Fehler liegt? Danke :)
radbruch
29.01.2012, 21:21
Baudrate sollte 38400 sein.
artur1986
16.02.2012, 11:32
Hi@all
bin am verzweifeln!!
Hier mein Problem!!
ich habe mal ne frage wie wandel ich den Dezimal Code in ASCII Zeichen um ??
........
string start //String Variable
start = serialPort1.ReadByte().ToString() // COM Port aus lesen und Byte zu String wandel
label1.Text = start; //String Ausgabe(Dezimal) auf Label // Ich will hier ein Zeichen drin stehen haben und kein Dezimalzahl des ASCII's
.........
Das ToString wandelt bei dem Datentyp Byte nunmal leider das Byte in dessen Repräsentation als Dezialzahl um.
Versuch mal ConvertToString() zu verwenden. Wenn nicht musst du das byte erst in einen char casten und diesen dann mit ToString in einen String umwandeln.
Das casten geht so:
byte GelesenesByte = serialPort1.ReadByte();
char MeinChar = (char)GelesenesByte;
label1.Text = MeinChar.ToString();
artur1986
16.02.2012, 17:16
Das ToString wandelt bei dem Datentyp Byte nunmal leider das Byte in dessen Repräsentation als Dezialzahl um.
Versuch mal ConvertToString() zu verwenden. Wenn nicht musst du das byte erst in einen char casten und diesen dann mit ToString in einen String umwandeln.
Das casten geht so:
byte GelesenesByte = serialPort1.ReadByte();
char MeinChar = (char)GelesenesByte;
label1.Text = MeinChar.ToString();
serialPort1.ReadByte() wird rot unterstrichen und das steht in der Fehlerliste:
Fehler 1 Der Typ "int" kann nicht implizit in "byte" konvertiert werden. Es ist bereits eine explizite Konvertierung vorhanden. (Möglicherweise fehlt eine Umwandlung.) C:\Users\ArturLaptop\Desktop\Projekt\TestPort\Test Port\Form1.cs 23
artur1986
16.02.2012, 17:21
ConvertToString funzt auch nicht, habe das auch hinter ReadByte() gesetzt und klappt auch nicht
artur1986
16.02.2012, 17:45
Vielen Dank hat sich erledigt. Hat geklappt!!!
so habe ich es jetzt geschrieben
.....
char char2 = (char) serialPort1.ReadByte();
.....
richTextBox1.Text = char2.ToString() ;
Mfg
Artur1986
Bitte lerne zunächst einige C# grundlagen anhand eines Buchs. (z.B. das Galileo Open Book das sogar kostenlos im internet erhältlich ist)
Die Klasse Convert Ist eine Statische Klasse des .Net Frameworks die Convertierungen für einen erledigt.
Man wendet sie so an:
int MeineZahl = 8; //Nur als Beispiel 8
string MeineZeichenkette;
Meine Zeichenkette = Convert.ToString(MeineZahl);
Neben ToString() gibt es noch jede menge andere Methoden die in den jeweils gewünschten Datentyp konvertieren.
Bei meinem Beispiel mit dem cast habe ich tatsächlich noch ein (byte) vergessen, da SerialPort.ReadByte() einen Integer und kein Byte zurückgibt
Richtig müsste es so aussehen:
byte GelesenesByte = (byte)serialPort1.ReadByte();
char MeinChar = (char)GelesenesByte;
label1.Text = MeinChar.ToString();
Hey so gehts natürlich auch. Dass man direkt in ein char casted. Ich arbeite allerdings in meiner software meistens mit dem byte wert weiter, weshalb ich die etwas "umständliche" methode gewählt hab.
artur1986
22.02.2012, 12:34
Hi, ich bin zur Zeit in meiner Abschlussprojekt Phase. Unser Thema ist "Realisierung einer Geschwindigkeitsmessung und Rundenzeiterfassung mittels Mikrocontroller". Meine Aufgabe besteht darin die Übertragung der Werte an den PC.
Ich bin jetzt soweit kommen das ich ein AVR C Programm geschrieben habe und eine Benutzeroberfläche mittels C Sharp erstellt habe. Mein Problem liegt darin das ich die Werte die ich übertragen will nicht immer an die Benutzeroberfläche ankommen. Mal klappt es mal klappt es nicht. Im Terminal Programm kommt immer was an also am AVR C Programm liegt es nicht. Als Anhang habe ich mal das Event mit dem Datenempfang hinzugefügt. Wäre nett wenn jemand mir dabei noch Tipps geben könnte, zur Sicherer Datenübertragung.
Danke im vorauss
Meiner ansicht nach gehst du etwas falsch ran an die Sache. Du hofft dass wenn du ReadByte aufrufst das richtige Byte auch da ist. Aber wer sagt dass der Roboter zu dem Zeitpunkt zu dem du ReadByte aufrufst schon das passende Byte gesendet hat (Außerdem müsstest du auch noch einen Fehler aufgrund eines Threadübergreifenden vorgangs bekommen, da du ohne invoke aus einem anderen Thread auf die Gui zu greifs). Da du sowie so schon mit dem DataRecievedEvent arbeitest würde ich vorschlagen du schickst vom Roboter aus erst mal ein bestimmtes Byte als Startbedingung. Wenn das Empfangen wurde schreibst du jedes weitere byte, das danach kommt in eine liste bis deine Endbedingung kommt. In der Liste weist du dann dass z.B. das erste Byte für die Geschwindigkeit und das zweite Byte dann für die Rundenzeit steht.
Code mäßig könnte das ganze im RecievedEvent so aussehen:
//Globale Variable
bool PaketStart = false;
//Event
byte temp = 0;
while(temp != -1)
{
temp = (byte)serialPort1.ReadByte();
if(PaketStart)
{
if(temp == Endbedingung)
{
//Rufe eine Prozedur auf die die Daten in der Liste verarbeitet
}
Liste.Add(temp);
}
if(temp == StartBedingung)
{
PaketStart = true;
}
}
artur1986
23.02.2012, 09:03
Bin nicht frisch in dem Bereich C Sharp, wolte jetzt noch fragen was das Liste.Add(temp) bedeutet? da er mir die Liste rot unterschstreicht
artur1986
23.02.2012, 09:14
könntest du biite vielleicht paar Kommentare hinter den Befehlszeilen setzen danke
Mit List.Add(temp) meinte ich das was ich auch vorher im Text beschrieben hab, nämlich dass du dir eine Liste definierst ( List<byte> MeineList = new List<byte>()) und der dann das jeweilige Byte hinzufügst.
//Globale Variable
bool PaketStart = false;
List<byte> meineListe = new List<byte>();
//Event
byte temp = 0;
while(temp != -1) //So lange die Variable temp ungleich -1 ist, also so lange Daten vorhanden sind mache:
{
temp = (byte)serialPort1.ReadByte(); //Lese ein byte
if(PaketStart) //Sind wir bereits in einem Datenpaket drin ?
{
if(temp == Endbedingung) //Ist das byte die Endbedingung ?
{
//Rufe eine Prozedur auf die die Daten in der Liste verarbeitet (Nur eine Kopie der Datenübergeben und die ursprüngliche liste leeren), das Datenverarbeiten macht man aus Timinggründen wohl am besten aus einem anderen Thread
}
else
{
meineListe.Add(temp); //Ansonsten füge das byte der Liste hinzu
}
}
if(temp == StartBedingung) //Wir sind in keinem Datenpaket drin, ist das gerade gelesene Byte die Startbedingung ?
{
PaketStart = true; //Ja also setzten wie die Variable PaketStart auf true so dass wir bei dem nächsten Schleifendurchlauf in if-Bedingung weiter oben springen
}
}
artur1986
23.02.2012, 17:11
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) //Button zum Empfangen
{
try
{ //Globale Variable
bool PaketStart = false;
List<byte> meineListe = new List<byte>();
//Event
byte temp =0;
while (temp != -1) //So lange die Variable temp ungleich -1 ist, also so lange Daten vorhanden sind mache:
{
temp = (byte)serialPort1.ReadByte(); //Lese ein byte
if (PaketStart) //Sind wir bereits in einem Datenpaket drin ?
{
if (temp == 66) //Ist das byte die Endbedingung ?
{
//Geschwindigkeit
richTextBox1.Text = meineListe[5].ToString() + meineListe[6].ToString() + meineListe[7].ToString() + meineListe[8].ToString() + meineListe[9].ToString(); // Ausgabe Geschwindigkeit
//Rundenzeit
//richTextBox2.Text = char10.ToString() + char11.ToString() + char12.ToString() + char13.ToString() + char14.ToString(); //Ausgabe Rundenzeit
//Runde
label12.Text = meineListe[3].ToString() + meineListe[4].ToString();
//Rufe eine Prozedur auf die die Daten in der Liste verarbeitet (Nur eine Kopie der Datenübergeben und die ursprüngliche liste leeren), das Datenverarbeiten macht man aus Timinggründen wohl am besten aus einem anderen Thread
meineListe.Clear();
}
}
else
{
meineListe.Add(temp); //Ansonsten füge das byte der Liste hinzu
}
}
if (temp == 56) //Wir sind in keinem Datenpaket drin, ist das gerade gelesene Byte die Startbedingung ?
{
PaketStart = true; //Ja also setzten wie die Variable PaketStart auf true so dass wir bei dem nächsten Schleifendurchlauf in if-Bedingung weiter oben springen
}
}
catch { ;}
}
Hab das jetzt so geschrieben und unterstreicht mir while (temp != -1) grün mit der Meldung "Warnung 1 Der Vergleich mit einer ganzzahligen Konstante ist nutzlos. Die Konstante befindet sich außerhalb des Bereichs vom Typ "byte".".
kann ich dieses Temp auch direkt in Char umwandeln, da ich gerne den If(temp == startbedinung) und If(temp == Endbedinung) mit einem Char vergleich will und direk auf den rich text box als Char ausgeben will. wie sieht das dann aus ?
mfg
Ohh, ja, klar ein byte geht nur von 0 bis 255. Also deklarier die variable temp statt als byte als int und lass bei serialPort1.ReadByte() den cast nach byte weg. Dann sollte die Warnung nicht mehr da sein.
Damit das ganze allerdings halbwegs erfolg haben kann, würde ich dich bitten dir echt noch mal paar Grundlagen anzuschauen. Das Datenverarbeiten vom SerialPort (der in C# ehh etwas zickig ist) gehört nicht wirklich zu den Einstiegsprogrammen. Z.B. schau dir an was eine globale Variable ist und wie man einen typ in einen anderen Castet.
Zum Casten mit der Startbedinung wird dir das hier weiterhelfen:
Angenommen '#' ist die Startbedingung dann kannst du schreiben:
if(temp == (byte)'#')
Das direkte ausgeben auf die richTextBox1 sollte sowie so nicht funktionieren, da du einen Fehler aufgrund eines Threadübergreifendenvorgangs bekommen solltest.
So da viel Fragen kamen die sich eigentlich um die selben Kernfragen kamen wollte ich diese noch mal zusammenfassen und auch an dieser Stelle hier auf das Galileo Openbook für C# verweisen, das vollkommen kostenlos und legal im Web erhältlich ist:
http://openbook.galileocomputing.de/csharp/
Nun zu den Hauptfragen:
Wie konvertiere ich den Typ integer (int) in den Typ byte oder in den Typ char?
Entweder mit einem direkten Cast (der in diesem Fall aufjedenfall funktioniert)
oder mit der Klasse Convert
BeispielCode:
int MeinInteger = 100;
byte MeinByte;
char MeinChar;
//Den int in byte konvertieren
MeinByte = (byte)MeinInteger;
//oder
MeinByte = Convert.ToByte(MeinInteger);
//Den int in einen char konvertieren
MeinChar = (char)MeinInteger;
//oder
MeinChar = Convert.ToChar(MeinInteger);
Wenn man bei einen Integer die Methode .ToString() aufruft bekommt man die Zahl als Zeichenkette zurück
Bsp:
int EineZahl = 120;
string EineZeichenkette = EineZahl.ToString();
//In eine Zeichenkette stehen nun die drei Ziffern 1,2 und 0 drin (Das selbe wie: "120");
Was ist eine globale Variable?
In jeder Klasse haben wir verschiedene Methoden. Z.B. Methoden die aufgerufen werden wenn auf einen Button geklickt wurde.
Nun kann man in einer Methode Variablen definieren auf die man allerdings nicht aus anderen Methoden zugreifen kann.
Beispiel:
Ich habe eine Variable in der Methode die aufgerufen wird wenn auf den Button1 geklickt wird. Aus der Methode die aufgerufen wird wenn eine zweiter Button geklickt wird kann man nicht darauf zugreifen.
Nun gibt es allerdings den Fall, dass auf Variablen aus jeder Methode einer Klasse zugreifen will (Z.B. um einen Status zu speichern), dazu gibt es globale Variablen:
Beispiel Code:
//Dieser Code steht innerhalb einer Klasse
//Nun eine Globale Variable
int MeinGlobalerInt = 10;
public void Methode1()
{
//Eine lokale Variable
int MeinLokalerInt = 0;
//Auf die Globale Variable kann ich auch hier zugreifen
MeinGlobalerInt = 15;
}
public void Methode2()
{
//Auch hier kann ich auf die Globale Variable zugreifen:
MeinGlobalerInt = 99;
//Auf die Variable aus Methode1 "MeinLokalerInt" kann ich jedoch nicht zugreifen
MeinLokalerInt = 10; //Gibt Fehlermeldung
}
Ich erhalte die Fehlermeldung "Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement "..." erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."
Hierzu möchte ich nur auf den folgenden Link verweisen:
http://www.mycsharp.de/wbb2/thread.php?threadid=33113
Hallo ich hab die Komponente mal etwas erweitert mit Multithreading und Pipes and Filter Architektur bei der der Bytedatenstrom in Datenpaket Objekte zerlegt wird.
https://www.roboternetz.de/community/threads/64327-C-Serialport-Teil-2-Pipes-and-Filter
Ich habe dein Programm mal getestet. Zwischen 2 PC über Nullmodem funktioniert das Prima. Ich habe nun ein Gerät das mit RS232 funktioniert. Wenn ich nun ein Terminalprogramm in XP benutze funktioniert alles Top.
Man sendet ein Befehl und erhält als beispiel die Seriennummer. Mi ihrem Programm lassen sich zwar Befehle senden aber es erfolgt keine Antwort. Können sie mir da weiter heflen?
Was für ein End of Line Zeichen sendet dein Gerät denn ?
Wenn da nicht \n kommt, dann wird auch nichts gelesen.
Für ein anderes end of Line Zeichen musst du diese Zeile ändern:
RecievedLine = serialPort.ReadLine();
Dort musst du anstelle von ReadLine dir alle Bytes selber holen und selber nach deinem End Of Line Zeichen suchen.
Herzlichen Dank an shedepe für diesen Thread.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.