Guten Abend,
ich hab folgendes Problem, mit einem AVR-Controller schicke ich alle
paar sekunden 127 Bytes an PC COM-Port, die Daten habe ich schon öfter
kontrolliert, die werden richtig von AVR verschickt, auf der Pc-Seite
speichere ich die Daten in einem Array. Leider werden die Daten aber
flasch angezeigt. unten ist der code den ich zum lesen des seriellen
Ports geschrieben hab.
die WErte werden zum Teil falsch angezeigt, Baudrate ist beidseitig auf
115200 eingestellt. liegt es eventuell an der Encoding-Funktion!! kann
ich den ENcoding komplett ausschalten, denn ich brauc die Rohwerte des
UCs. die werde ich dann später weiter filtern usw.
vielen Dank vorasu!
Gruss
Ps.: für alle die erst mit google-suchen-rat anfangen wollen hab genug
gelesen und ausprobiert keinen erfolg!!!!!
marti harti schrieb:> kann> ich den ENcoding komplett ausschalten, denn ich brauc die Rohwerte des> UCs. die werde ich dann später weiter filtern usw.
wenn du readbyte verwendest, dann wird kein coding angewendet.
> (byte)serialPort.ReadByte()
was soll hier der cast? willst du von byte auf byte?
welchen datentype hat arra?
Hast du schon mal ein anders Programm als Refenzen verwendet, um zu
testen ob es überhaupt ein softwarefehler bei dir ist?
Peter II schrieb:> marti harti schrieb:>> kann>> ich den ENcoding komplett ausschalten, denn ich brauc die Rohwerte des>> UCs. die werde ich dann später weiter filtern usw.>> wenn du readbyte verwendest, dann wird kein coding angewendet.>>> (byte)serialPort.ReadByte()> was soll hier der cast? willst du von byte auf byte?>> welchen datentype hat arra?>> Hast du schon mal ein anders Programm als Refenzen verwendet, um zu> testen ob es überhaupt ein softwarefehler bei dir ist?
@Peter danke erst mal für die ANtwort,
Muss schon sagen ... du traust dich was.
Wer oder was garantiert dir, dass du in der while Schleife auch
tatsächlich alle 127 Bytes bekommst? Übertragung auf der Seriellen
dauert viel länger als dein PC rechnen kann. D.h. dein serialPort wird
relativ schnell mitteilen, dass keine Bytes mehr vorliegen. Aber nicht,
weil bereits alle 127 Bytes bereits abgeholt wurden sondern weil sie
noch gar nicht übertragen wurden!
1
....
2
serialPort.DiscardInBuffer();
3
....
und spätestens danach hast du ein gewaltiges Problem. Du weißt nicht
wieviele Zeichen du hier verwirfst. D.h. ab hier hast du keinen blassen
Schimmer mehr, was das nächste eintreffende Byte aussagt. Ist das ein
Byte, welche noch zu den Daten gehört? Ist es der Beginn der nächsten
127 Byte Nachricht?
Protokolle, die einzig und alleine auf dem Wissen aufbauen, dass eine
Nachricht aus genau so und so vielen Bytes besteht und ansonsten
keinerlei Rahmenbedingungen definieren (wie zb das erste Byte ist
eindeutig immer 0xFE weil 0xFE in den Daten nicht vorkommen kann) haben
ein enormes Problem: Wenn die Synchronisierung erst mal verloren
gegangen ist, dann ist es praktisch unmöglich sie wieder herzustellen.
Mit dem DiscardInBuffer wirfst du die Synchronisierung aber mutwillig
weg.
Der cast wird benötigt da readByte einen int zurückliefert. Warum ist
mir nicht ganz klar, denn anders als im klassischen C hibt es meines
Wissens keine -1 als Fehlerrückgabe. Bei fehlern wird eine Exception
geworfen.
Wie wird der AVR betrieben? mit dem internen Oszillator, mit einem
Quarz?
Karl Heinz Buchegger schrieb:> Protokolle, die einzig und alleine auf dem Wissen aufbauen, dass eine> Nachricht aus genau so und so vielen Bytes besteht und ansonsten> keinerlei Rahmenbedingungen definieren (wie zb das erste Byte ist> eindeutig immer 0xFE weil 0xFE in den Daten nicht vorkommen kann) haben> ein enormes Problem: Wenn die Synchronisierung erst mal verloren> gegangen ist, dann ist es praktisch unmöglich sie wieder herzustellen.> Mit dem DiscardInBuffer wirfst du die Synchronisierung aber mutwillig> weg.
Soweit war ich noch nicht. Das Zusammenspiel aus
while (serialPort.BytesToRead > 0)
und
serialPort.DiscardInBuffer();
dürften des Rätsels Lösung sein.
Die Schleife kann ein paar Bytes lesen bis sie schneller ist als die
UART Übertragung, die werden ausgewertet und dann kommt ein
discardBuffer, dann werden wieder mal ein paar Bytes mitten aus dem
Datenblock ausgewertet, ...
Kann niemals funktionieren.
Sychronisieren wie Karl Heinz gesagt hat über ein Start Byte oder eine
Folge von Bytes die so nie vorkommen kann, oder wenn das nicht geht über
einen Timeout-read der die Lücke zwischen 2 Datenpaketen erkennen kann.
Das ist aber nicht schön.
Wenn genügend Zeit vorhanden ist könnte man auch die Binärdaten in Hex
wandeln und übertragen. Dann kann man ein Sonderzeichen als Start/Stopp
etc nehmen und es hat den Charme daß es direkt lesbar ist.
Nachtrag: Ein Protokoll, das am Anfang die Länge das Datenpakets und am
Ende noch eine Prüfsumme sendet würde das Leben dqann nochmal einfacher
und sicherer machen.
oder einfach erstmal über ReadsByte ohne event funktion arbeiten und die
Daten einlesen.
while( true ) {
this.arra.Add((byte)serialPort.ReadByte());
//auswerten und break wenn das richtig oder genug in arra drin steht
}
Udo Schmitt schrieb:> Der cast wird benötigt da readByte einen int zurückliefert. Warum ist> mir nicht ganz klar, denn anders als im klassischen C hibt es meines> Wissens keine -1 als Fehlerrückgabe. Bei fehlern wird eine Exception> geworfen.>> Wie wird der AVR betrieben? mit dem internen Oszillator, mit einem> Quarz?
ja, mit interen RC-Osci. an uc liegt es nicht ich kann die Daten durch
printf und tera term ausgeben und die stimmen auch alle. es muss irgend
etwas mit meinem c# programm zu tun haben.
ich habe es mit serial port monitor ausprobiert, der zeigt auch genau
die selben werte wie mein eigenes programm ??????
sobald ich die Daten durch pintf bzw. acii codes ausgebe stimmen die!!!
Udo Schmitt schrieb:> Die Schleife kann ein paar Bytes lesen bis sie schneller ist als die> UART Übertragung,
Ich würd sogar sagen:
Da das ganze auf einen Event triggert, wird genau 1 einziges Byte von
der UART geholt ehe die while Schleife abbricht.
Läubi .. schrieb:> Warum steht doch in der API:Rückgabewert> Typ: System.Int32> Das Byte, das in Int32 umgewandelt wurde, oder -1,> wenn das Ende des Streams gelesen wurde.
Superklasse. Ich hatte gegoogelt und den ersten Treffer in der MSDN
gefunden:
http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.readbyte%28v=vs.80%29.aspx
Da steht:
"Rückgabewert
Das Byte, das gelesen wurde. "
und sonst NIX!
Scheiß Doku! Früher war MSDN mal klasse.
marti harti schrieb:> ja, mit interen RC-Osci.
Sehr suboptimal, das kann funktionieren, und wenn es 4 Grad wärmer ist
dann nicht mehr. Der interne Oszillator ist nicht exakt genug, da kann
es sein daß der Zeitfehler über die 10 Bit zu groß wird.
Danke erstmal an alle!
Udo Schmitt schrieb:> marti harti schrieb:>> ja, mit interen RC-Osci.>> Sehr suboptimal, das kann funktionieren, und wenn es 4 Grad wärmer ist> dann nicht mehr. Der interne Oszillator ist nicht exakt genug, da kann> es sein daß der Zeitfehler über die 10 Bit zu groß wird.
auf der Platine hab ich einen externen oszi, werde ich den Takt-Quelle
umändern.
jetzt abgesehen von den ganzen oben geschriebenen code mit
while-schleife,
welche möglichkeiten gibts in c# einen Roh-Byte aus Seriellen Ports zu
lesen.
denn der arra-array wird wirklich tatsächlich beim ersten empfang mi 127
byte gefüllt. aber nur DIE WERTE stimmen nicht.
ich werd es morgen nochmal mit paar anderen methoden probieren.
und schreib es noch mal hier.
Udo Schmitt schrieb:> Ich hatte gegoogelt und den ersten Treffer in der> MSDN gefunden:
C# SerialPort hat mir das geliefert.
http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.readbyte.aspx
ansonsten ist das Verhalten in Java ebenso, irgendwie muss man ja das
Dateiende feststellen auch wenn es sicher anders ginge als über den
Rückgabewert. Hat aber den Vorteil, dass z.B. beim lesen über
Buffer/Arrays die selbe Semantik gilt.
Hatten wir nicht letztens schonmal so einen Fall mit EventLesen +
Wegwerfen von Bytes gehabt??
Läubi .. schrieb:> ansonsten ist das Verhalten in Java ebenso,
Deshalb hab ichs ja geschrieben, weil mich das etwas verwundert hat.
Auch in K&R C wurde die -1 schon als EOF genommen.
marti harti schrieb:> jetzt abgesehen von den ganzen oben geschriebenen code mit> while-schleife,> welche möglichkeiten gibts in c# einen Roh-Byte aus Seriellen Ports zu> lesen.
Die Methode readByte() stimmt schon.
Du solltest aber wie von Karl Heinz und mir beschrieben auf jeden Fall
ein sauberes Protokoll aufbauen, sonst weisst du nie ob du sauber
synchron bist.
Udo Schmitt schrieb:> marti harti schrieb:>> jetzt abgesehen von den ganzen oben geschriebenen code mit>> while-schleife,>> welche möglichkeiten gibts in c# einen Roh-Byte aus Seriellen Ports zu>> lesen.>> Die Methode readByte() stimmt schon.> Du solltest aber wie von Karl Heinz und mir beschrieben auf jeden Fall> ein sauberes Protokoll aufbauen, sonst weisst du nie ob du sauber> synchron bist.
den Protkoll werde ich noch mal überarbeiten.
irgendwie hab ich das gefühl das konnte tatsächlich etwas mit vorzeichen
zu tun haben, leider bin ich jetzt nicht mehr am System, aber ich werd
es bis morgen noch mal ausprobieren und posten. den uc werde ich auch
noch mal genauer unter die luppe nehemn was er liefert.
marti harti schrieb:> denn der arra-array wird wirklich tatsächlich beim ersten empfang mi 127> byte gefüllt.
Mit Verlaub: Aber das glaube ich dir nicht!
Mach da mal einen Zähler rein
und wenn der hinten nach 127 ist, dann fress ich einen Besen.
Wichtig: Nicht im Debugger. IM Debugger gibst du beim Einzelschritt
genügend Zeit, dass die 127 Bytes über die Serielle flutschen. Aber wenn
dein Programm eigenständig full speed läuft nicht mehr. Da wirst du
sehen, dass der Zähler auf 1 oder 2 steht. Wie willst du daher
1
if((MsgTyp_t)this.arra[4]==MsgTyp_t.BATCHG)
hier das 5. Byte auswerten, wenn du es noch gar nicht hast?
Karl Heinz Buchegger schrieb:> marti harti schrieb:>>> denn der arra-array wird wirklich tatsächlich beim ersten empfang mi 127>> byte gefüllt.>> Mit Verlaub: Aber das glaube ich dir nicht!>> Mach da mal einen Zähler rein>>
1
>privatevoidreadDataFromSerialPort(objectsender,
2
>SerialDataReceivedEventArgse)
3
>{
4
>try
5
>{
6
>byteCount=0;
7
>while(serialPort.BytesToRead>0)
8
>{
9
>this.arra.Add((byte)serialPort.ReadByte());
10
>byteCount++;
11
>}
12
>
13
>
> und wenn der hinten nach 127 ist, dann fress ich einen Besen.>
dann werd ich mal erst mal einen halben Besen für dich suchen ;)
das mit dme zählen hab ich probiert beim ersten durchgang bekomme ich
immer 127 Bytes dann natürlich geht mit synch alles verloren.
aber mir geht es erst mal darum richtige werte zu empfangen.
byte ist im c# vorzeichnlos
http://msdn.microsoft.com/de-de/library/5bdb6693%28v=vs.80%29.aspx
deswegen wird wohl nicht an byte legen.
werd es heute abend noch mal probieren und posten.
Hallo,
also leute ich hab mein Fehler gefunden, es lag an der höhen Baudrate,
anscheinend war der interne RC-osci. ungenau für höhe Baudraten. jetzt
bekomme ich Daten mit richtigen Werten. zu dem habe ich auch den Externe
Osci aktivert.
Danke nochmal für die Anregungen und Tipps.
marti harti schrieb:> also leute ich hab mein Fehler gefunden, es lag an der höhen Baudrate,> anscheinend war der interne RC-osci. ungenau für höhe Baudraten.
Und was hatte ich gestern schon gefragt?
Aber du hast behauptet:
marti harti schrieb:> ja, mit interen RC-Osci. an uc liegt es nicht ich kann die Daten durch> printf und tera term ausgeben und die stimmen auch alle. es muss irgend> etwas mit meinem c# programm zu tun haben.>> ich habe es mit serial port monitor ausprobiert, der zeigt auch genau> die selben werte wie mein eigenes programm ??????>> sobald ich die Daten durch pintf bzw. acii codes ausgebe stimmen die!!!
Klar daran lag es nicht.
Genauso wie es jetzt keine Probleme mit dem Empfang von 127 Bytes mit
deiner Routine gibt.
Bastel mal schön so weiter dann wird dir nicht langweilig. Nächste Woche
hast du dann selbst 'entdeckt' dass deine Empfangsfunktion so nicht
funktioniert.
Udo Schmitt schrieb:> Klar daran lag es nicht.> Genauso wie es jetzt keine Probleme mit dem Empfang von 127 Bytes mit> deiner Routine gibt.> Bastel mal schön so weiter dann wird dir nicht langweilig. Nächste Woche> hast du dann selbst 'entdeckt' dass deine Empfangsfunktion so nicht> funktioniert.
Ja, mit dme Empfang hat es nicht so geklappt, wie ich es mir vorstellte.
ich habe es mit Readexisting probiert, bringt aber leider auch nicht
viel, da Daten nur im Ascii-Stringform kodiert vorliegn.
ich habe folgendes vor, aber sagt mir falls ich mich irre,
die Daten des Seriellenports werd ich event-gestuert in einem Array
mittels Readbyte() speichern und wenn die Daten in dem Array eine
gewisse Anzahl erreicht haben, kompletten Array nach besonderen
Merkmalen für Anfang eines neuen Datenpakets suchen, und dann
dementsprechend die benötigte anzahl der Daten aus dem Array entfernen
und weiterbearbeiten.
ich bin gerade dabei dies umzusetzten, aber falls ihr einen besseren
vorschlag habt oder meint es gibt eine Methode die mir das ganze
ersparrt, dann bin ich ganz ohr, herdamit.
Wie oben schon gesagt, überlege dir ein Protokoll, das das leistet.
Sind die Daten binär, können alle Werte vorkommen?
Dann ändere sie so um daß du bestimmte Zeichen als Steuerzeihen zur
verfügung hast.
Oder am einfachsten aber verschwenderischsten. Codiere jedes Byte als 2
Zeichen Hex Wert. dann hast du alle Zeichen ausser 0-9 und a-f als
Kontrollzeichen, und das Ganze ist lesbar in einem Terminal (immer gut
fürs debugging).
Man kann z.B. auch für Zeichen 00 -0f einühren, daß sie eine Meta
Zeichen als Prefix erhalten z.b. 0f. dann wäre 00 -> 0f00 01 -> 0f01,
... 0f -> 0f0f
Damit hättest du die Zeichen 00 -0e als Steuerzeichen frei.
Einfaches nicht besonders schönes Beispiel.
etc. pp.
Dann noch so Dinge wie eine Längenangabe zu Beginn jedes Datenblocks,
eine Prüfsumme (CRC oder einfach Quersumme) am Ende ....
so wird ein richtiges fehlertolerantes Protokoll draus
Udo Schmitt schrieb:> Dann noch so Dinge wie eine Längenangabe zu Beginn jedes Datenblocks,> eine Prüfsumme (CRC oder einfach Quersumme) am Ende ....> so wird ein richtiges fehlertolerantes Protokoll draus
ja genau das hab ich auch vor. mein protokoll hat folgender aufbau:
dabei sind network-id, massege-id. und host-adresse immer konstant.
werde es mal nach networkid suchen dann die anderen beiden wenn alle
drei bedingungen erfüllt sind dann soviel wie paketlänge vom array
entfernen und bearbeiten.
marti harti schrieb:> CRC oder einfach Quersumme
naja da gibts schon Unterschiede, ich sage nur:
Aliasing-Wahrscheinlichkeit.
Irgendwie erkenne ich die Prüfsumme in marihari's Paketstruktur nicht.
Wenn wirklich alle werte vorkommen, dann gibt es immer noch die
Möglichkeit einen Wert zu "Quoten". Wenn du z.b. die 0x00 als start
haben willst, und in den daten aber eine 0x00 vorkommen dann muss im µC
bei senden einer 0 eine 2.0 vorrangestellt werden. Beim empfänger gilt
dann eine einzelnen 0 als start und eine eine doppelete 0 als daten.
Das wird bei hdlc auch so gemacht, ist also gar nicht so unüblich.
Kan asta schrieb:> naja da gibts schon Unterschiede, ich sage nur:> Aliasing-Wahrscheinlichkeit.
Klar.
Wenn du sicher gehen willst packst du einen MD5 hash dahinter :-)
mata hari, was dir fehlt ist die eindeutige Startsequenz, damit du
weisst wann genau ein Datenblock beginnt.
marti harti schrieb:> am ende des Paketts
sorry, habe nicht den ganzen Thread mitgelesen, aber am Anfang beim Rest
des Headers würds ja auch nicht schlecht positioniert sein, oder? Warum
als einzigstes Meta-Feld am Ende?
Kan asta schrieb:> marti harti schrieb:>> am ende des Paketts>> sorry, habe nicht den ganzen Thread mitgelesen, aber am Anfang beim Rest> des Headers würds ja auch nicht schlecht positioniert sein, oder? Warum> als einzigstes Meta-Feld am Ende?
nein, position ist bliebig, aber ich habes halt so aufgebaut. eskonnte
genau sogut nach vorne geschoben werden.
ok leute, ich habe mit nach drei bit muster suchen auspobiert es funkt,
aber es ist mir sehr unsicher, dann die wahrscheinlichkeit, dass auch im
Daten Bereich auch diese Drei Byte-Muster vorkommen ist sehr gross.
>@Peter II>Wenn wirklich alle werte vorkommen, dann gibt es immer noch die>Möglichkeit einen Wert zu "Quoten". Wenn du z.b. die 0x00 als start>haben willst, und in den daten aber eine 0x00 vorkommen dann muss im µC>bei senden einer 0 eine 2.0 vorrangestellt werden. Beim empfänger gilt>dann eine einzelnen 0 als start und eine eine doppelete 0 als daten.
hdlc gefällt mir ganz gut werde versuchen etwas ähnliches umzusetzten.
bluppdidupp schrieb:> Naja, selbst wenn das Synchronisations-Muster mal im Paket vorkommt muss> dann ja auch noch zufällig der CRC stimmen
man konnte natürlich das ganze noch mit einem FEC erweitern um auf die
nummer sicher zu gehen aber für meine Anwendung reicht erstmal CRC und
noch ein Synchron.-Verfahren.
Peter II schrieb:> Wenn wirklich alle werte vorkommen, dann gibt es immer noch die> Möglichkeit einen Wert zu "Quoten". Wenn du z.b. die 0x00 als start> haben willst, und in den daten aber eine 0x00 vorkommen dann muss im µC> bei senden einer 0 eine 2.0 vorrangestellt werden. Beim empfänger gilt> dann eine einzelnen 0 als start und eine eine doppelete 0 als daten.>> Das wird bei hdlc auch so gemacht, ist also gar nicht so unüblich.
Danke erst mal an alle Beteiligen.
hier noch mal darstellung der aktuellen Situation:
- es werden Sensor Daten vom uC zum Pc übertragen und visualisiert.
- es können alle Werte vorkommen.
- Die übertragung sollte schnll gehen--> also wenn möglich mit wenig
overhead und extra Bytes.
- Die Daten sin im uC in einem uint8-Bereiten Buffer gespeichert und
werden genau so durch URAT übertragen --> 8N1 .
- auf dr Pc-Seite werden die Daten wieder in einem 8 bit Array
gespeichert und weiter bearbeitet.
Lösungswege:
1) jedes Byte in 2 Teilen splitten --> zu viel extraBytes.
2) als HEX übertragen auch ziemlich lang.
3) Bitsopfen, gefällt mir am besten da ich kein etra bytes übertragen
muss.
aber nehmen wir mal an mein Flag würde 01111110 lauten und ich die Daten
des Array die Reihe nach übertragen will.
in Array werd ich erstmal nach allen vorkommenden 5er 1-Folgen suchen
und dann ein 0 dazwischen stopfen.
1
----------
2
Flag|01111110|
3
Daten|00111111|nachBitStuffing00111110(1)
4
|.|------------------->
5
.
6
.
ich hoffe ich konnte es oben einigermassen klar beschreiben.
wenn ich die bitfolge 00111110 senden will, wird durch die bitstuffing
nach der fünften 1 ein 0 hinzugefügt. Somit geht ja die letzte 1
verloren, oder? Denn 9 bits sende ich ja nicht.
marti harti schrieb:> . Somit geht ja die letzte 1> verloren, oder? Denn 9 bits sende ich ja nicht.
aus den grund solltest du das ja auch nichts mit bits machen sonder mit
bytes. HDLC ist eine "bit" übertragung. Bei dir würde sich alles bits
und damit die zusammenstellung der bytes verschieben. Was für die µC
viel zu aufwendig ist.
Wähle einfach ein byte-wert aus der sehr selten übertragen wird, diesen
wählst du als SYN wert aus. Wenn er jetzt in den Daten vorkommen dann
sendest du ihn 2 mal.