Autor Beitrag
der_max
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 01:29 
Hallo zusammen!

Ich bin C# Anfänger, ich hoffe, in diesem Forum geht man damit etwas entspannter um als in gewissen anderen... Würde mich zumindest freuen :-).

Mein Problem ist folgendes: ich lese über die serielle Schnittstelle einen String ein, den ich in ein Bytearray umwandeln möchte. Jeweils zwei Bytes des Strings entsprechen einem vorzeichenbehafteten 16 Bit Integer. Ich habe schon herausgefunden, dass die Umwandelung von zwei Bytes in einen 16 Bit Integer über BitConverter.ToInt16 läuft, der Schritt funktioniert als solcher auch. Was nicht funktioniert, ist die erforderliche Umwandelung des Strings in ein Bytearray. Ich habe das bisher mit byte[] Bytstr = Encoding.ASCII.GetBytes(serialIn) probiert. Es funktioniert, wenn jeweils zwei Byte einem *positiven* 16 bit Integer entsprechen. Wenn aber zwei Zeichen in dem String einen negavtiven Wert repräsentieren, hat das highbyte immer den (dezimal-) Wert 64. Ein Beispiel: wenn ich über die serielle Schnittstelle den Wert 256 als Integer übertragen möchte, werden zwei Bytes mit den ASCII Werten 0 (lowbyte) und 1 (higbyte) gesendet. Die kommen als String an. Wenn ich diesen String mittels Encoding.ASCII.GetBytes in ein Bytearray wandle, das dann wiederrum mittels BitConverter.ToInt16 in ein Integer gewandelt wird, funktioniert alles. Wenn ich aber nun z.B. -256 senden will, was lowbyte 0 und highbyte 255 entspricht, dann wird daraus nach der Wandelung zum Bytearray 0 und 63. Was geht da vor sich? Ist vermutlch was recht einfaches, ich komme da aber im Moment auch mit diversen Dokus und Foreneinträgen nicht weiter...

Ich wäre sehr dankbar, wenn mir jemand einen Tipp geben könnte!

Viele Grüße
Max
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 29.03.11 08:36 
Hallo und :welcome: im Forum!

Ich kann dir jetzt nicht sagen, ob es mit den anderen Encoding-Möglichkeiten besser geht, aber ich kann dir sagen warum dein Weg nur schiefgehen kann. ;-)

Und zwar benutzt du Encoding.ASCII, schau doch einmal in die Dokumentation:
msdn.microsoft.com/d....encoding.ascii.aspx hat folgendes geschrieben:
ASCII-Zeichen sind auf die 128 niedrigsten Unicode-Zeichen zwischen U+0000 und U+007F begrenzt.
Heißt: Da du den Wert hFF hast, die Codierung aber nur bis h7F geht, kann das nicht klappen.

Mit einem zeichenweisen Zugriff sollte es gehen, siehe hier:
snipplr.com/view/170...d-string-into-bytes/
Ich habe nicht die Zeit mir das genauer anzuschauen, aber es sollte sein was du suchst. ;-)
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 12:28 
Hallo und vielen Dank für deine Antwort!

Die Info, dass das ASCII Encoding nur auf sieben Bit begrenzt ist, war schonmal sehr hilfreich. Ich habe auch schon mit anderen Encodings rumgespielt (UTF8), leider ändert das nichts am Problem.

Ich muss nochmal weiterfragen: Wenn ich ein char mit BitConverter.GetBytes(char) umwandle, bekomme ich zwei bytes. Ich habe bisher nicht herausgefunden, was die Bedeutung der beiden Bytes ist. Warum sind es *zwei*? Im Grunde entspricht ein Zeichen doch so oder so 8 Bit, also einem Wert zwischen 0 und 255. Wie kann ich aus den zwei Bytes, die mir GetBytes liefert den korrespondierenden ASCII-(dezimal)-Wert (0...255) berechnen?

Ganz vielen Dank für alle Tipps und nochmals sorry wenn ich mich noch etwas blöd anstelle...
Max
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 29.03.11 12:39 
user profile iconder_max hat folgendes geschrieben Zum zitierten Posting springen:
Warum sind es *zwei*? Im Grunde entspricht ein Zeichen doch so oder so 8 Bit, also einem Wert zwischen 0 und 255.
Da ist dein Wissensstand schon einige Jahre alt. ;-)

Stichwort Unicode. Unicodezeichen bestehen in der Regel aus zwei Bytes, können aber auch mehr enthalten. Daher auch der Name "Multi Byte Character Set".

Denn in ein Byte pro Zeichen bekommst du z.B. die chinesischen Zeichen relativ schlecht alle hinein. :mrgreen:
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 12:49 
Hallo!

Hm, okay. Der Punkt ist nur, dass ich eben wirklich 8 Zeichen (die hier auch 8 Bytes entsprechen) von der seriellen Schnittstelle empfange, von denen jeweils zwei zusammen einem vorzeichenbehafteten Integer entsprechen. Die Umwandlung von jeweils zwei Bytes in einen Integer mit BitConverter.ToInt16 funktioniert auch. Die Frage ist jetzt nur noch, wie ich aus dem mit ReadLine() empfangenen String (der auch tatsächlich 8 Zeichen lang ist), ein 8 Elemente großes Bytearray machen kann, bei dem jedes Element dem Wert (0...255) des korrespondieren Zeichens des Strings entspricht. Also wie gesagt, in dem String sind tatsächlich nur 8 Zeichen, die acht Bytes entsprechen, an die Werte der Bytes möchte ich irgendwie drankommen.

Vielen Dank für die Hilfe
Max
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 29.03.11 13:04 
jaenicke hat das Stichwort schon genannt: Greife einfach zeichenweise zu und caste nach byte.

_________________
>λ=
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 14:47 
Hallo!

Also ich poste mal was ich gemacht habe - leider ohne Erfolg -, vielleicht sieht ja jemand auf einen Blick, was da faul ist. Hier ist der relevaten Code:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
            string serialIn = serialPort1.ReadLine();
            label1.Text = serialIn;
            listBox1.Items.Add(serialIn);

            char[] chars = serialIn.ToCharArray();
            int inLen = chars.Length;
            label2.Text = inLen.ToString();

            byte[] bytes = new byte[inLen];
            
            for (int i = 0; i < inLen; i++)
            {
                bytes[i] = (byte)chars[i];    
            }
           
            label3.Text = bytes[0].ToString();
            label4.Text = bytes[1].ToString();


Das ist alles in eine "auf-die-Schnelle"-GUI integriert, ich lasse mir die relevanten Werte über Labels ausgeben. Über die serielle Schnittstelle kommen nun als erstes zwei Bytes mit den Werten 12 und 254. Das ist ein von Sender zerlegter Integer mit dem Wert -500 (-500 -> lowbyte 12 und highbyte 254). Auf die ersten zwei Bytes folgen 6 weitere mit anderen Werten, betrachten wir zunächst einfach nur die ersten beiden, daran zeigt sich das Prob schon. In dem Bytearry steht nach ausführung des o.g. Codes an der ersten Stelle (bytes[0]) 12 und an der zweiten (bytes[1]) 63. Die 12 ist ja korrekt, aber wie kommt es auch in diesem Falle zur 63? Hier müsste eine 254 stehen... Nach der Conversion nach Char stimmt auch die Länge des Char-Arrays (nämlich acht).

Wäre toll, wenn jemand mal draufgucken würde. Danke!!!
Max

Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 29.03.11 14:56 
Hast du denn überhaupt einmal den Link angeschaut, den ich dir ganz am Anfang geschrieben hatte? :gruebel:
Der sollte das schließlich schon machen.
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Mit einem zeichenweisen Zugriff sollte es gehen, siehe hier:
snipplr.com/view/170...d-string-into-bytes/
Ich habe nicht die Zeit mir das genauer anzuschauen, aber es sollte sein was du suchst. ;-)
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 15:15 
Hallo jaenicke,

entschuldige dass ich nicht darauf eingegangen bin, natürlich habe ich mir den Link angesehen. Aber - wenn ich es nicht total falsch verstehe - geht es da um etwas ganz anderes, nämlich die Übersetzung eines binärcodierten Strings in eine Zahl. Eine Kette von Einsen und Nullen, die in einem String gespreichert sind, sollen also in Bytes übersetzt werden. Jedes Zeichen des Strings repräsentiert dabei ein Bit. Bitte korrigiere mich, wenn ich das falsch sehe. Aber das ist nicht das was ich will. Beispiel: ich habe einen String aus acht Zeichen, sagen wir "ABCDEFGH". Diese Zeichen entsehen nur daraus dass die Zahlenwerte als Zeichen interpretiert werden. Also eigentlich will ich an die Byte-Werte, in diesem Beispiel wären das 65 66 67 68 69 70 71 72, eben die Dezimal-Werte für diese Zeichen. Das ist etwas total simples, ich weiss, aber ich bekomme es in C# nicht hin.

Danke für die Geduld! :-)

Gruß
Max
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Di 29.03.11 15:40 
Hallo!

Du musst trotzdem Zeichen(paar)weise durchgehen:

Du gehst Deinen String durch, mit Sprüngen von zwei (weil ja je zwei Zeichen betrachtet werden sollen). In der Schleife wandelst Du das Zeichen am aktuellen Index mittels simplem Cast in ein Byte um und das Zeichen am Index+1 ebenfalls. Die beiden Bytes steckst Du dann entweder in ein Byte-Array und benutzt BitConverter.ToInt16 oder Du konvertierst selber mittels Bitshift.

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 29.03.11 15:57 
Schön, dass man mal erfährt, dass es um einen SerialPort geht ;) . Warum also nicht ReadByte? Und wenn du den BaseStream in einen BinaryReader wrappst, kannst du sogar direkt ReadInt16 benutzen.

_________________
>λ=
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Di 29.03.11 15:58 
Von der "seriellen Schnittstelle" redet er im ersten Posting schon ;-)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 29.03.11 16:10 
Tatsache. Da hat mich wohl erst der Code dazu gebracht zu hinterfragen, weshalb hier überhaupt ein String benutzt wird :) .

_________________
>λ=
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 16:10 
Hallo nochmal!

Sorry, aber ich steh aufm Schlauch. Ich habe nach Christians letztem Posting jetzt nochmal folgendes probiert - auch wenn ich der Meinung bin, dass das im Prinzip dem Code entspricht, den ich oben schon gepostet habe. Also:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
             char[] chars = serialIn.ToCharArray();
             
             int inLen = chars.Length/2;

             byte[] bytes = new byte[2];
             short[] value = new short[4];

             for (int i = 0; i < inLen; i++)
             {
                 bytes[0] = (byte)chars[i*2];
                 bytes[1] = (byte)chars[i*2+1];
                 value[i] = BitConverter.ToInt16(bytes, 0);

                 label1.Text = bytes[0].ToString();
                 label2.Text = bytes[1].ToString();
             }

             label3.Text = value[0].ToString();
             label4.Text = value[1].ToString();


War das so (oder so ähnlich) gemeint, Christian? Aber genau das geht eben nicht. Die ersten beiden Zeichen, die der Sender sendet, sind 12 und 254 (die Zerlegung von int16(-500) in low- und higbyte). Was mit der obigen Routine aber bei mir in bytes[0] und bytes[1] ankommt, ist 12 und 63 - bytes[1] ist also falsch. Aber warum?

Danke nochmals für die Geduld!
Max

Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 29.03.11 16:20 
Weil SerialPort.ReadLine standardmäßig ASCII-dekodiert und 254 eben nicht im Zeichensatz liegt - wir sind bis jetzt wohl alle davon ausgegangen, dass die Daten zumindest korrekt im String liegen :) . Also benutze bitte ReadByte oder den BinaryReader, wie es für Binärdaten vorgesehen ist.

_________________
>λ=
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Di 29.03.11 16:31 
Okay, sorry wenn ich mich nicht so recht verständlch machen konnte. Ich will nochmal eben nachtragen, warum ich diese Varainte gewählt habe. Ich dachte, ich könnte mir es dadurch einfacher machen, weil ich damit immer meine 8 Zeichen bis zum Terminator automatisch bekomme, ich also selbst nicht nach den Endzeichen (CR und LF) suchen muss. Dann als letzte Nachfrage zu dieser Variante: es gibt also keine Möglichkeit, durch eine anderes Encoding wirklich den Wertebereich 0...255 pro Zeichen auszuschöpfen? Ich bin aus Matlab und low-level Programmierung auf Mikrocontrollern gewohnt, dass das geht - das vielleicht zu meiner Verteidigung :-).

Ich danke soweit, langsam wird mir einiges klarer...

Max
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 29.03.11 17:49 
Wenn es immer 8 Zeichen sind, musst du ja so oder so nicht nach dem Terminator suchen. Allerdings gibt es wirklich einen 8-Bit-Zeichensatz, dessen Char-Werte mit den Codepoints von Unicode übereinstimmen: Latin-1 :) . Du könntest es also mal mit Encoding.GetEncoding(1252) probieren.

_________________
>λ=
der_max Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Mi 30.03.11 11:02 
Hallo,

ich bin jetzt eurem Rat gefolgt und habe Read verwendet, auf die Art lese ich die Daten direkt als Bytes ein. Ist zwar alles noch nicht sonderlich elegent gelöst, funktioniert aber - ich lerne ja noch ;-). Mit einem Terminator wollte ich arbeiten, weil das sicherstellt, dass ich im "Leseraster" bleibe. Man kann sich ja nicht 100%ig sicher sein, dass nicht doch Übertragungsfehler auftreten, u.ä. Das habe ich auch beibehalten.

Ich danke nochmal für die geduldige Hilfe, werde mich bestimmt nochmal wegen anderer Probleme hier melden :-).

Gruß
Max