Laden...

Serielle Schnittstelle auslesen... Ende erkennen??

Erstellt von oli001 vor 14 Jahren Letzter Beitrag vor 14 Jahren 14.502 Views
O
oli001 Themenstarter:in
449 Beiträge seit 2005
vor 14 Jahren
Serielle Schnittstelle auslesen... Ende erkennen??

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

A
254 Beiträge seit 2007
vor 14 Jahren

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

3.430 Beiträge seit 2007
vor 14 Jahren

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

O
oli001 Themenstarter:in
449 Beiträge seit 2005
vor 14 Jahren

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

F
155 Beiträge seit 2009
vor 14 Jahren

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."

O
oli001 Themenstarter:in
449 Beiträge seit 2005
vor 14 Jahren

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

A
254 Beiträge seit 2007
vor 14 Jahren

Wie stellst Du eigentlich sicher, dass zwei Bytes m PC angekommen sind ?

Über die Eigenschaft ReceivedBytesThreshold ?

3.430 Beiträge seit 2007
vor 14 Jahren

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

O
oli001 Themenstarter:in
449 Beiträge seit 2005
vor 14 Jahren

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

888 Beiträge seit 2007
vor 14 Jahren

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:

Template SerialPort

O
oli001 Themenstarter:in
449 Beiträge seit 2005
vor 14 Jahren

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