Hallo,
ich habe eine elektronische Waage an einer RS232. Wenn ich der Waage ein Telegramm schicke, sendet diese das Gewicht zurück. Dafür habe ich folgenden Code:
class GewichtFromRs232
{
public SerialPort comport = new SerialPort();
public String gewicht = null;
public bool dataReceived = false;
public String gew1=null;
public String gew2=null;
private String[] hexArray = new String[13];
public GewichtFromRs232()
{
comport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
if (comport.IsOpen) comport.Close();
else
{
comport.BaudRate = int.Parse("9600");
comport.DataBits = int.Parse("8");
comport.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "1");
comport.Parity = (Parity)Enum.Parse(typeof(Parity), "Odd");
comport.PortName = "COM1";
comport.Open();
}
}
public void SendData(String text)
{
byte[] data = hexToByte(text);
comport.Write(data, 0, data.Length);
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int byteCount = comport.BytesToRead;
byte[] dataBuffer = new byte[byteCount];
comport.Read(dataBuffer, 0, byteCount);
encode(dataBuffer);
}
private byte[] hexToByte(string data)
{
data = data.Replace(" ", "");
byte[] buffer = new byte[data.Length / 2];
for (int i = 0; i < data.Length; i += 2)
buffer[i / 2] = (byte)Convert.ToByte(data.Substring(i, 2), 16);
return buffer;
}
private void encode(byte[] data)
{
gewicht += Encoding.ASCII.GetString(data);
if (comport.BytesToRead == 0) dataReceived = true;
}
}
Aufgrufen wird so:
GewichtFromRs232 gewicht = new GewichtFromRs232();
gewicht.SendData("71250D0A");
while (!gewicht.dataReceived) ;
//Thread.Sleep(2000);
MessageBox.Show(gewicht.gewicht);
Die Waage sendet zwei Bytes der Länge 8 und 7. Wenn ich in encode die Daten zum gewicht adde, funktioniert alles prima. Aber nur wenn ich Thread.sleep(2000); aufrufe (oben auskommentiert). Wenn ich mit dataReceived arbeite, bekomme ich nur die ersten 8 Bytes zurück. Warum ist das so? Dauert das schreiben des Strings so lange?
Ich hoffe mir kann jemand helfen, bin hier am veerzweifeln...
Grüße Oli
Viele Grüße, Oli
Hallo,
erstma ne Frage, die Waage sendet zwei Bytes der Länge 7 und 8 ? Die Waage sendet unterschiedlich viele Datenbits oder wie ?
Generell hat die SerialPort ja einen Empfangspuffer, deshalb kann ja eigentlich keine Daten verloren gehen. Ich würde mal kontrollieren, wieivel Bytes wirklich ankommen.
Tschüss
Hallo oli001,
das hier
while (!gewicht.dataReceived) ;
Solle man auf keinen Fall machen.
Weil damit blockierst du das ganze Programm solange du nix empfangen hast.
D.h. die CPU - Auslastung geht auf 100% und dein Programm hängt sich auch (wenn nix empfangen wird).
Da ist es viel besser wenn du in deiner GewichtFromRs232 Klasse aus ein Event schmeisst.
Siehe dazu: [FAQ] Eigenen Event definieren / Information zu Events
Die Waage sendet zwei Bytes der Länge 8 und 7. Wenn ich in encode die Daten zum gewicht adde, funktioniert alles prima. Aber nur wenn ich Thread.sleep(2000); aufrufe (oben auskommentiert). Wenn ich mit dataReceived arbeite, bekomme ich nur die ersten 8 Bytes zurück. Warum ist das so? Dauert das schreiben des Strings so lange?
Nein. Sobald du die ersten 8 Bits empfängst setzt du das dataReceived Property auf true weshalb er dir aus der While-Endlosschleife springt und die bestehenden 8 Bits ausliest.
Also deshalb musst du das mit der WhileSchleife unbedingt lassen, ist eh ein Wunder dass es so überhaupt läuft. Verwende stattdessen ein Event in der Klasse das du schmeisst wenn die Daten erfolgreich ausgelesen wurden
Gruss
Michael
Hallo michlG,
naja ich dachte eigentlich, dass dataReceived erst dann true wird, wenn keine Daten mehr im Buffer stehen. bytesToRead == 0 ??
Das mit dem Event sollte kein Problem sein, aber auch da habe ich dann das Problem, dass ich den Event erst dann werfen kann, wenn die Daten vollständig eingelesen sind. Und das zu erkennen ist eben mein Problem...
Wenn ich übrigens vor receivedDate ein Threaf.sleep(100); setze, dann funktioniert es. Also dauert es zu lange, bis die Daten in den String geschrieben werden. Oder sehe ich das falsch?
Grüße Oli
Viele Grüße, Oli
Hallo oli001,
warum schreibst du das so umständlich
comport.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "1");
comport.Parity = (Parity)Enum.Parse(typeof(Parity), "Odd");
wenn es auch so geht?
comport.StopBits = StopBits.One;
comport.Parity = Parity.Odd;
Grüße FZ
edit: ein = zuviel
"We better hurry up and start coding, there are going to be a lot of bugs to fix."
Wahrscheinlixh liegt das an zuviel von deinem Logo. Das ist aber auch net wirklich kriegsentscheidend für die Lösung meines Problems...
Viele Grüße, Oli
Wie stellst Du eigentlich sicher, dass zwei Bytes m PC angekommen sind ?
Über die Eigenschaft ReceivedBytesThreshold ?
Hallo,
naja ich dachte eigentlich, dass dataReceived erst dann true wird, wenn keine Daten mehr im Buffer stehen. bytesToRead == 0 ??
Ja so sollte es auch sein.
Jedoch hast du gesagt dass die Waage zwei byte-Arrays sendet.
D.h. sie sendet das erste du empfängst die 8 Bytes und dann hast du keine Bytes mehr zum lesen (bytestoread ist 0).
Die Waage sendet dann das zweite Byte Array und du hast erneut daten zu lesen...
Das mit dem Event sollte kein Problem sein, aber auch da habe ich dann das Problem, dass ich den Event erst dann werfen kann, wenn die Daten vollständig eingelesen sind. Und das zu erkennen ist eben mein Problem...
Du kannst nach dem senden so lange mit dem lesen warten bis du 15 bytes im Buffer hast.
Oder du liest sie immer aus und merkst dir in einer Membervariable wieviele bytes du schon hast und löst das event erst dann aus wenn du alle hast.
Sry, aber ich bin jetzt nicht so genau informiert über der SerialPort Klasse um sagen zu können wie genau die reagiert.
Aber normalerweise müsste er dir das Event bei jedem empfangenen Byte-Array auslösen...
Wenn ich übrigens vor receivedDate ein Threaf.sleep(100); setze, dann funktioniert es. Also dauert es zu lange, bis die Daten in den String geschrieben werden. Oder sehe ich das falsch?
ich weiss jetzt zwar nicht genau wo du das Thread.Sleep nun gesetzt hast aber das ist sicherlich nicht eine gute Lösung.
Denn damit wird es momentan zwar vielleicht funktionieren das ist aber sehr fehleranfällig....
Also lass es lieber sein.
PS: Du solltest dir wirklich mal den Ratschlag von fz7090 zu Herzen nehmen weil viel umständlicher kann man das ganze Zeug echt nicht mehr machen 😃
Das selbe hier
comport.BaudRate = int.Parse("9600");
comport.DataBits = int.Parse("8");
kannste auch einfach
comport.BaudRate = 9600;
comport.DataBits = 8;
schreiben
Gruss
Michael
Halo michlG,
Wegen dem "umständlichen" Schreibweisen. Das ganze soll später so dynamisiert werden, dass der Port, die Paritärt usw. aus einer DB kommen. Es gibt verschiedene Waagentypen, die Antwort auf eine Gewichtsabfrage ist herstellerseitig genormt. Das ist also immer das gleiche, nicht aber die Parität usw. Auch kann es sein das an manchen Arbeitsplätzen unterschiedliche Com - Ports hängen.
Also deswegen etwas umständlicher...
So nun zum eigentlichen Thema:
Wie kann ich denn warten bis 15 Bytes im Buffer sind?
Viele Grüße, Oli
Hallo oli001,
das Ganze sollte sich eigentlich ziemlich einfach, da standartisiert, gestallten.
Das Problem bei der seriellen SS ist, das man nie genau weis, wann, welche Daten über die Leitung kommen. Deshalb benötigst Du ein definiertes Ende. Ich habe schon mehrere digitale Waagen über die serielle SS angesprochen und überall konnte man die Endekennung einstellen. Mein Favoriet ist immer CRLF (\r\n).
Du lauscht also auf der seriellen SS und wartest bist die Kennung kommt. Wie CRLF in Byte aussieht findest du bei Google.
Eine Beispielimplementierung findest du hier:
Hi
danke, genau so hab ich es jetzt gelöst. In der genialen Schnittstellenbeschreibung des HErstellers stand natürlich nicht davon, dass man das an der Waage einstellten kann. Ich hab´s eher durch zufall gefunden.
Besten Dank an alle,
Grüße Oli
Viele Grüße, Oli