Hallo Leute,
ich wollte ein paar 16bit Sensorwerte auf dem PC darstellen. Der Sensor
ist an einem Atmega324p (16MHz) angeschlossen.
Für die Kommunikation nutze ich einen Ft232r und einen virtuellen
COM-Port. Es klappt alles wunderbar, allerdings ist die Kommunikation
recht langsam. Ich betreibe es momentan bei 38400 Baud. Da wäre sicher
noch mehr drin, allerdings soll erst mein eigenes
Kommunikationsprotokoll optimiert werden.
Zur Kommunikation:
Ich muss jeden Wert einzeln erfragen, was auch so bleiben soll. Dazu
schicke ich vom PC Programm einen String "b1" (für Sensor b und Channel
1).Der Atmega bekommt einen Interrupt, wertet den String aus und liefert
den geforderten Sensorwert zurück. Dafür wandelt der Atmega den 16bit
Integer in einen String und schickt diesen. Der String wird vom PC
empfangen und wieder in einen Integer umgerechnet.Klappt wunderbar,
allerdings wird jede Zahl einzeln als String geschickt, das ist nicht
besonders effizient.
Gibt es da eine bessere Variante oder kann ich auch irgendwie direkt
Integer über den COM-Port schicken?
Vielen Dank
Peter schrieb:> Klappt wunderbar,> allerdings wird jede Zahl einzeln als String geschickt, das ist nicht> besonders effizient.
das würde aber kaum etwas ändern. Deine Übertragung ist so langsam, weil
du jeden Wert einzeln abfragst. Damit bringt es fast nichts, ob man nun
2 oder 5byte für eine Zahl überträgt.
Aber du kannst es gerne versuchen, einfach den 16bit wert in 2bytes
zerlegen und diese direkt übertragen. Nur hast du damit ein Problem, das
dann auch Sonderzeichen entstehen können, ob du damit klar kommt hängt
daovn ab wie du den Protokoll umgesetzt hast.
Peter schrieb:> Da wäre sicher> noch mehr drin
Mit einem 14,7456MHz Quarz.
Peter schrieb:> kann ich auch irgendwie direkt> Integer über den COM-Port schicken?
Dann mußt Du Dir erstmal ein Protokoll ausdenken, was die Paketerkennung
gewährleistet.
Beim String hast Du das durch das "\n" am Ende gewährleistet.
Du kannst beliebige Daten verschicken, dazu musst Du sie nur in einzelne
Bytes zerstückeln.
Allerdings solltest Du ein Protokoll verwenden, bei dem Du (resp. Dein
Programm) erkennen kann, wo ein Datensatz beginnt und wo er endet.
Daher ist es nicht ausreichend, Deinen "int" als zwei bzw. vier einzelne
Bytes zu senden -- wenn Dein sendendes und Dein empfangendes Programm
"aus dem Takt" geraten, was z.B. beim Stecken/Trennen der Verbindung
leicht passieren kann, dann kommt nicht das an, was Du erwartest,
sondern Quark.
Daher ist die Übertragung als Text, auch wenn sie ineffizient erscheinen
mag, gar nicht so schlecht.
Das simpelste Protokoll ist bei der Textübertragung die Zeile, d.h.
ein Datensatz wird mit \n abgeschlossen.
Wenn Du tausende von Werten übertragen willst, ist eine
Effizienzbetrachtung angebracht, aber wenn Du nur gelegentlich mal einen
Sollwert vorgeben willst, ist das eher irrelevant.
Rufus Τ. Firefly schrieb:> Wenn Du tausende von Werten übertragen willst, ist eine> Effizienzbetrachtung angebracht, aber wenn Du nur gelegentlich mal einen> Sollwert vorgeben willst, ist das eher irrelevant.
Mhm, ich würde meine Daten ja gerne als Graph anzeigen. Nun komme ich
vielleicht auf eine max. Abtastrate von 1kHz. Falls ich dann noch 2
Sensoren abfrage sinkt die Rate leider deutlich.
Ich dachte das Problem hätte bestimmt schon jemand gelöst und ich könnte
einen "offenen" Code verweden. Aber dann werde ich wohl erst einmal die
Baudrate erhöhen
Peter schrieb:> Ich dachte das Problem hätte bestimmt schon jemand gelöst
Im Normalfall löst man dieses Problem, indem man die Telegramme
vergrößert - also nicht jeden Wert einzeln abfragt, sondern
Wertegruppen, z.B. eine Sensorgruppe oder einen gepufferten Werteverlauf
eines einzelnen Sensors.
Und wenn das dann immer noch zu langsam ist, gibt es noch mehr
Standardmethoden, z.B. Komprimierungsverfahren.
Aber um das zu beschreiben, müßte man mehr über Deine Anforderungen an
Latenz und Bandbreite wissen.
"Als Graph darstellen" klingt zum Beispiel nach sehr geringen
Anforderungen in der Latenz.
Peter schrieb:> Mhm, ich würde meine Daten ja gerne als Graph anzeigen. Nun komme ich> vielleicht auf eine max. Abtastrate von 1kHz. Falls ich dann noch 2> Sensoren abfrage sinkt die Rate leider deutlich.
ja, aber das liegt ja nur ein deinem Protokoll.
Ich würde es so machen:
PC sagt welchen Sensor wie oft abgefragt werden soll.
µC sendet selbstständig alle werte ohne das der PC dafür etwas machen
muss. Vor jeden wert kommt einfach die Kennung vom welchen Sensor.
Damit kannst du die Leitung fast 100% auslasten und du hast kein
Zeitproblem mehr.
Peter schrieb:> Ich betreibe es momentan bei 38400 Baud.Peter schrieb:> Nun komme ich> vielleicht auf eine max. Abtastrate von 1kHz.
Das kann man doch einfach ausrechnen.
Nehmen wir mal an, der String hat 5 Byte (4 Hex-Digits + \n):
38400 / 10 / 5 = 768 Hz
Walter Tarpan schrieb:> "Als Graph darstellen" klingt zum Beispiel nach sehr geringen> Anforderungen in der Latenz.
Ja, das ist nur ein Hobbyprojekt. Ich will ein bisschen mit
verschiedenen Sensoren spielen und vielleicht eine kleine Regelung
aufbauen.
Peter II schrieb:> Ich würde es so machen:>> PC sagt welchen Sensor wie oft abgefragt werden soll.> µC sendet selbstständig alle werte ohne das der PC dafür etwas machen> muss. Vor jeden wert kommt einfach die Kennung vom welchen Sensor.
Das klingt schon sehr gut... Momentan möchte ich die Einzelwertabfrage
behalten, weil ich auch eine kleine Regelung am PC (nicht auf dem
Atmega) realisieren will. Je nach Abtastwert soll dann zwischendurch
noch ein Wert an ein Stellglied geschickt werden.
Wahrscheinlich bieten sich dann zwei Modi an. Zusätzlich zur
Einzelwertabfrage realisiere ich auch deine Paketabfrage.
Peter Dannegger schrieb:> Nehmen wir mal an, der String hat 5 Byte (4 Hex-Digits + \n):> 38400 / 10 / 5 = 768 Hz
Das passt schon ganz gut, dann reicht mir die Erhöhung der Abtastrate
eigentlich.
Peter Dannegger schrieb:> Das kann man doch einfach ausrechnen.> Nehmen wir mal an, der String hat 5 Byte (4 Hex-Digits + \n):> 38400 / 10 / 5 = 768 Hz
nein kann man nicht. Es kommt ja noch die zeit für die Abfrage dazu.
Dann kommt auch noch die Verbartungszeit auf beiden Seiten dazu weil es
scheinbar ein synchrones Protokoll ist.
PC -> µC "b1\n" 3byte
µC verarbeitet ? ms
µC -> PC 1234\n 5byte
USB Latenz ? ms
PC verarbeitet ? ms
dann geht es wieder von vorne los. Damit wird mal nie sinnvoll schnell
werden.
Joachim B. schrieb:> leider erlaubt Hyperterminal nur 921600 Bd> und Hterm nur 256000 Bd (Achtung 256kBd != 250kBd)
glaubst du, das er die Daten Hyperterminal abruft?
Hab mir den Beitrag nicht komplett durchgelesen, aber noch ein kleiner
Hinweis:
Nur die Baudrate hochschrauben bringt allein nix, richtig Speed bekommt
das wegen dem USB-Serial-Converter erst wenn das größere Pakete sind.
Das liegt daran dass USB-Pakete immer gleich lang sind - und X Bytes in
ein Byte beinhaltenden Paketen zu senden dauert länger als X Bytes am
Stück zu verschicken.
Ralf
Vielleicht nicht exakt die Antwort, aber ein paar Anregungen...
Ich habe mal eine Messverbindung zwischen Arduino (ATMega256) und PC
aufgebaut. Dabei sollten je bis zu ca. 120Bytes ca. 50Mal pro Sekunde
übertragen werden (48kBaud netto). Der Controller sendet:
- 2 Byte Startkennung (bei mir $0D0A = Zeilenumbruch)
- feste Anzahl Datenbytes
- 2 Byte Prüfsumme
Der PC synchroniert bei der ersten Messung:
- lese bis $0D0A gefunden wird
- lese feste Anzahl Datenbytes
- lese Prüfsumme und vergleiche mit Selbstberechneter
- wenn die Prüfsumme stimmt: Synch hergestellt
- wenn nicht: war $0D0A wohl zufällig in den Nutzdaten -> nochmal
Bei "lebenden" Messdaten, die sich ständig etwas ändern, ist es damit
recht unwahrscheinlich, dass die Startsequenz permanent falsch erkannt
wird.
Zu erwähnen ist, dass der PC über USB verbunden die RS232-Schnittstelle
auf PC-Seite per Treiber emuliert (soweit ich verstanden habe) und das
die CPU-Last erstaunlich erhöht. Ich bin bei 65kBaud gebleiben, bei 115
gab es Probleme. Da kam der PC nicht mehr hinterher, die Daten wurden
gepuffert und die Messung war dann nicht mehr Echtzeit sondern ein paar
Sekunden verzögert.
-------
Zum Rückkanal (Befehle PC and µC): Wenn keine Daten, sondern nur reine
eindeutige 8Bit "Befehle", z.B. $01="Sensor1Aus" gesendet werden,
braucht man dafür ggf. kein extra Protokoll.
-------
Auch wenn die Daten nur auf Anforderung und nicht kontinuierlich
gesendet werden, sollte man irgendwie markieren, um welches Datum es
sich jeweils handelt. Ansonsten ist die zeitlich Zuordnung schwer, falls
sich etwas verzögert oder außer Takt gerät.
CaptainAlbern schrieb:> Ich bin bei 65kBaud gebleiben, bei 115> gab es Probleme. Da kam der PC nicht mehr hinterher, die Daten wurden> gepuffert und die Messung war dann nicht mehr Echtzeit sondern ein paar> Sekunden verzögert.
dann war es ein Programmfehler. PC habe auch mit weit über 1Mbaud keine
Problem wenn man es richtig macht.
Peter II schrieb:> nein kann man nicht. Es kommt ja noch die zeit für die Abfrage dazu.
Die UART ist Full-Duplex, man kann also die nächsten Daten schon
anfordern, bevor die vorherigen Daten eingetroffen sind.
Sinvoller Weise spendiert man der UART auf dem MC eine FIFO und liest
ständig den ADC (ADC-Interrupt), so daß man die Daten sofort losschicken
kann.
Als Flaschenhals bleibt dann wirklich nur die reine Senderate übrig.
Ich mach das oft so, daß der Master die FIFO-Größe abfragen kann. D.h.
er weiß also, wieviel Anfragen er auf einen Rutsch losschicken kann.
Peter Dannegger schrieb:> Peter II schrieb:>> nein kann man nicht. Es kommt ja noch die zeit für die Abfrage dazu.>> Die UART ist Full-Duplex, man kann also die nächsten Daten schon> anfordern, bevor die vorherigen Daten eingetroffen sind.
deswegen habe ich geschrieben, das er vermutlich ein Synchrones
Protokoll verwendet. Sonst könnte er ja gar nicht mehr erkennen, welchen
zahl zu welcher Anfrage gehört.
Und da hilft es nicht wenn Full-Duplex ist, wenn er es nicht nutzt.
Peter II schrieb:> glaubst du, das er die Daten Hyperterminal abruft?
ich bin vor 47 Jahren ausgetreten, glauben ist nicht so mein Ding.
Weisst du mit was er die Daten abruft und welche Baudraten er einstellen
kann?
Peter schrieb:> Für die Kommunikation nutze ich einen Ft232r und einen virtuellen> COM-Port. Es klappt alles wunderbar, allerdings ist die Kommunikation> recht langsam.
Wenn es dir auf Geschwindigkeit ankommt, dann machst du das Ganze in
zweifacher Hinsicht grundfalsch.
1. Nimm anstelle des seriellen Chips von FTDI einen mit 8 Bit
Parallelschnittstelle, denn da bist du frei von allen
Baudraten-Beschränkungen. Kannst also mit größter Speed, was dein Atmel
so hergibt, senden.
2. Versuche bloß nicht irgend ein Ping-pong-Protokoll. Also PC sendet
"haben wollen", µC ermittelt und sendet "da isses" zurück. Sowas ist
IMMER grottenlangsam.
Laß den µC stattdessen lustig vor sich hinsenden, also Daten sammeln, in
eine ausgemachte Protokollform bringen und dann raus damit. Das Programm
auf dem PC muß aus dem sprudelnden Stream dann bloß noch sich das
heraussuchen, was es haben will. So geht es am schnellsten.
W.S.
Ein USB 2.0 time slot dauert immer 1ms egal ob du 1000 Byte oder 1 Byte
sendest. Dann kommt noch die Antwort, die auch immer 1ms dauert egal ob
1 Byte oder 1000. Das ist halt so bei USB.
uwe schrieb:> Ein USB 2.0 time slot dauert immer 1ms egal ob du 1000 Byte oder 1 Byte> sendest. Dann kommt noch die Antwort, die auch immer 1ms dauert egal ob> 1 Byte oder 1000. Das ist halt so bei USB.
Nö, in deinen Angaben stimmt fast garnix.
Erstens hängt die Sache natürlich nicht direkt von der USB-Version ab,
sondern vom "Speed-Grade". Von der USB-Version hängt nur ab, welche
Speed-Grades überhaupt verfügbar sind.
Bei USB2.0 gibt es LowSpeed(1,5MBit/s), FullSpeed(12MBit/s) und
HighSpeed(480MBit/s).
Bei LowSpeed und FullSpeed dauert ein "time slot" (richtiger: ein Frame)
tatsächlich genau 1ms, bei HighSpeed hingegen nur 125µs.
Da für ein "Ping-Pong-Protokoll" mindestens zwei Frames erforderlich
sind, ist also die kürzestmögliche Latenz für Low/FullSpeed 2ms, für
HighSpeed hingegen nur 250µs. Dazu kommen aber natürlich die Latenzen
des OS und sofern es sich nicht um ein Echtzeit-OS handelt, können die
die durch USB vorgegebene Mindestgröße der Latenz nochmal locker um ein
bis zwei Größenordnungen "nach oben korrigieren", wenn im System gerade
viel los ist.