Hallo! Ich habe einen Mikrocontroller (Arduino Nano) und einen Beschleunigungssensor (LIS331), der mit einer Frequenz von 1000Hz digitale 3D-Beschleunigungsdaten zum µC sendet. Der µC ist mittels RS232 Schnittstelle mit dem PC verbunden. Dort kommen die Beschleunigungsdaten nicht mit 1000Hz an, sondern nur mit ca. 305Hz (wenn alle drei Achsen weitergeleitet werden). Wir vermuten, dass das daran liegt, weil wir die Daten nicht mittels high- und lowbytes zum PC senden, sondern in "Strings". Es liegen somit große Datenmengen vor, die auf dieser Schnittstelle nicht mit 1000Hz übertragen werden können (bei zwei Achsen beträgt die Aufnahmefrequenz 466Hz und bei einer übertragenen Achse 901Hz). Wir schaffen es leider nicht, die Daten in diese Bytes umzuwandeln. Bzw. vl. sind wir hier auf dem Holzweg und es gibt ganz andere Vorschläge, wie wir diese Aufnahmefrequenz steigern könnten? Ausschnitte aus unserem Code seht ihr unten. Habt ihr Verbesserungsvorschläge? Wir sind für alle Anregungen dankbar!! Auch Links und Literturhinweise würden uns schon sehr freuen! :) ---------------------------------------------------------------------- Unser Code (der Library in C) für das Einlesen der X-Achse sieht folgendermaßen aus: int LIS331::getXValue(){ byte high; byte low; if (!readReg(LR_OUT_X_L, &low)){ return false; } if (!readReg(LR_OUT_X_H, &high)){ return false; } return (low|(high << 8)); } Und unser Arduino Code (die relevanten Stellen) zum Einlesen der Daten besteht aus: void setup() { Serial.begin(1000000); % Baudrate = 1 000 000 LIS331 lis; % Erstellung des Objekts lis } void loop() { lis.begin(); int val = lis.getXValue(); Serial.print(val); } ------------------------------------------------------------------------ Durch den Befehl Serial.print geben wir die Daten unseres Wissens nach in Strings aus... das machst das ganze sehr langsam. Vielen Dank im Voraus und alles Gute, Lukas
Hi > byte alle; > ... >alle = (low|(high << 88)); Autsch. MfG Spess
die Baudrate muss bei Arduino nicht in Hz angegeben werden, sondern in Baud. Manual zu serial.begin nochmal lesen. Eine Übertragung mit 1 000 000 Baud schafft die Com Schnittstelle auch nicht.
spess53 schrieb: > Hi > >> byte alle; >> ... >>alle = (low|(high << 88)); > > Autsch. > > MfG Spess sorry, das war ein Tippfehler.
Dennis K. schrieb: > die Baudrate muss bei Arduino nicht in Hz angegeben werden, sondern in > Baud. > > Manual zu serial.begin nochmal lesen. > > Eine Übertragung mit 1 000 000 Baud schafft die Com Schnittstelle auch > nicht. Ich habe nicht behauptet, dass es sich bei der Baudrate um Hz handelt. Die Com Schnittstellt schafft angeblich bis zu 2Millionen Baud. Danke für den Hinweis, ich denke jedoch nicht, dass das Problem hier liegt, weil durch das Erhöhen der Baudrate die Übertragung nicht schneller wird. Habt ihr weitere Ideen?
Hi
>sorry, das war ein Tippfehler.
Auch
alle = (low|(high << 8));
passt nicht in ein Byte.
MfG Spess
Lukas Wiedemann schrieb: > Die Com Schnittstellt schafft angeblich bis zu 2Millionen Baud. Warum nutzt Du nicht die Standardbaudraten?
spess53 schrieb: > Hi > >>sorry, das war ein Tippfehler. > > Auch > > alle = (low|(high << 8)); > > passt nicht in ein Byte. > > MfG Spess mein Fehler... so solls heißen: int LIS331::getXValue(){ byte high; byte low; if (!readReg(LR_OUT_X_L, &low)){ return false; } if (!readReg(LR_OUT_X_H, &high)){ return false; } return (low|(high << 8)); }
Oliver R. schrieb: > Lukas Wiedemann schrieb: >> Die Com Schnittstellt schafft angeblich bis zu 2Millionen Baud. > > Warum nutzt Du nicht die Standardbaudraten? der Serial Monitor in Arduino schafft 115200. Doch das war zu wenig für uns... deshalb 1M
(Datensätze pro Sekunde) × (Elemente pro Datensatz) × (Elementgröße) 1000 × 3 × 2 = 6000 Bytes/s Das geht als Binärdaten locker bei 115200 Baud.
1 | Serial.write( val & 0xff ); |
2 | Serial.write( val >> 8 ); |
Als Strings geht es bei 115200 Baud nicht, das ist richtig. Aber andererseits kannst du mit dem Arduino 1 MBaud nicht bedienen, da ist der einfach zu langsam.
Konrad S. schrieb: > (Datensätze pro Sekunde) × (Elemente pro Datensatz) × (Elementgröße) > 1000 × 3 × 2 = 6000 Bytes/s > > Das geht als Binärdaten locker bei 115200 Baud. > Serial.write( val & 0xff ); > Serial.write( val >> 8 ); Da muss man sich dann nur noch ein bisschen Protokoll drum herum überlegen. Zum Beispiel einmal pro ms sechs Bytes senden, das dauert 521µs, die 479µs Pause dienen der Erkennung der Datenrahmen. Aber weil das vielleicht über ser->usb->virtuell com mit dem Timing so eine Sache sein könnte, pro ms sind das 11 Byte bei 115200 Baud, da kann man sich noch nen Header überlegen: 0xff 0xff 0x55 0xaa hX lX hY lY hZ lZ Oder so halt. :-)
Hab noch die Absicherung vergessen, eine Checksumme mitzuschicken damit der Empfänger was zum überprüfen hat schadet sicher auch nicht. 0xff 0xff hX lX hY lY hZ lZ crc8 Ein passendes Start-Token zu finden ist eventuell trickreich.
Rudolph schrieb: > 0xff 0xff hX lX hY lY hZ lZ crc8 Sowas wie 0x7f7e als Kenner dürfte ausreichend sein, da der Wert eigentlich nicht auftauchen kann (12-Bit Zweierkomplement). Der Kenner muss auch nicht in jedem Datenpaket enthalten sein, einmal pro Sekunde einstreuen sollte reichen. Irgendeine Prüfsumme kann nicht schaden. Die Werte würde ich in Little-Endian-Reihenfolge übertragen, da muss sich der PC nicht so abquälen damit.
Rudolph schrieb: > Konrad S. schrieb: >> (Datensätze pro Sekunde) × (Elemente pro Datensatz) × (Elementgröße) >> 1000 × 3 × 2 = 6000 Bytes/s >> >> Das geht als Binärdaten locker bei 115200 Baud. >> Serial.write( val & 0xff ); >> Serial.write( val >> 8 ); > > Da muss man sich dann nur noch ein bisschen Protokoll drum herum > überlegen. > Zum Beispiel einmal pro ms sechs Bytes senden, das dauert 521µs, die > 479µs Pause dienen der Erkennung der Datenrahmen. > > Aber weil das vielleicht über ser->usb->virtuell com mit dem Timing so > eine Sache sein könnte, pro ms sind das 11 Byte bei 115200 Baud, da kann > man sich noch nen Header überlegen: > > 0xff 0xff 0x55 0xaa hX lX hY lY hZ lZ > > Oder so halt. :-) Super, genau sowas in die Richtung habe ich gesucht! Danke erstmal! Kannst du mir genau diesen Punkt näher erläutern? Also wieso benötige ich diesen Header und wofür steht der? 0xff steht ja z.B. für 255 usw., aber wozu genau benötige ich das? Und mit dem Code >> Serial.write( val & 0xff ); >> Serial.write( val >> 8 ); ... kommt bei mir nun folgende Beispiels-"werte" raus, die jeweils durch Semikolons getrennt sind: ` ;P ;@ ` ; @;@ ;@ ; @ ;p ; usw. was bedeutet das dann genau, bzw. wie kann ich von diesen Zeichen wieder auf Zahlenwerte schließen? Danke für die schnellen und hilfreichen Antworten!
Bei 1kHz lohnt es sich eventuell auch einfach nur die Änderung des vorherigen Wertes zu schicken. Sollten deutlich kleinere Werte sein und entsprechend schneller zu senden sein. Das muss nur am PC Programm beachtet werden, dass man quasi die Ableitung des Signales schickt.
Lukas Wiedemann schrieb: > Super, genau sowas in die Richtung habe ich gesucht! Danke erstmal! > Kannst du mir genau diesen Punkt näher erläutern? Also wieso benötige > ich diesen Header und wofür steht der? 0xff steht ja z.B. für 255 usw., > aber wozu genau benötige ich das? > Und mit dem Code >>> Serial.write( val & 0xff ); >>> Serial.write( val >> 8 ); > > ... kommt bei mir nun folgende Beispiels-"werte" raus, die jeweils durch > Semikolons getrennt sind: > was bedeutet das dann genau, bzw. wie kann ich von diesen Zeichen wieder > auf Zahlenwerte schließen? Mit dem Serial-Monitor bekommst du nur "Text" angezeigt, damit geht es nicht. Was du überträgst sind aber Binärdaten. Dafür brauchst du ein Programm, das Bytes einliest bis der Header erkannt wird. Ab da muss es immer zwei Bytes als "short int" einlesen und irgendetwas damit machen oder, wenn es wieder ein Header ist, wegwerfen. Der Header sorgt für Synchronisation: Du musst den Anfang eines Datensatzes erkennen können.
Lukas Wiedemann schrieb: > Super, genau sowas in die Richtung habe ich gesucht! Danke erstmal! > Kannst du mir genau diesen Punkt näher erläutern? Also wieso benötige > ich diesen Header und wofür steht der? 0xff steht ja z.B. für 255 usw., > aber wozu genau benötige ich das? Setell dir einfach mal vor, auf dem PC holst du von der Seriellen Schnittstelle die Bytes ab, wobei das PC Programm gerade gestartet ist und der Arduino schon seit 2 Stunden seine Daten rausbläst die Bytes sind
1 | 0x45 0x78 0x12 0x57 0x48 0x78 ... |
welches Byte ist denn jetzt was? Wo fängt ein Datensatz an und und wo hört er auf? Wie gesagt: der Arduino soll angenommenerweise schon die längste Zeit senden. Du kannst daher nicht davon ausgehen, dass das erste Byte, das du am PC zu Gesicht bekommst auch das erste Byte aus der 3-er Sequenz von Messwerten ist. Das ganze ist ein bischen wie einer Italienerin zuzuhören, wenn er schnell spricht. Wenn der nicht an einem Satzanfang Luft holen würde, hättest du kaum eine Chance auch nur zu wissen wo ein Wort anfängt und wo es aufhört. Da prasseln einfach nur die Silben unaufhörlich auf dich ein und du kannst nichts irgendwie gesichert zuordnen. > > Und mit dem Code >>> Serial.write( val & 0xff ); >>> Serial.write( val >> 8 ); > > ... kommt bei mir nun folgende Beispiels-"werte" raus, die jeweils durch > Semikolons getrennt sind: > ` ;P ;@ > ` ; @;@ > ;@ ; > @ ;p ; Wenn du die Messwerte binär rausgibst, ist es recht sinnfrei sie sich als ASCII Repräsentierung anzusehen. Du musst deinem Anzeigeinstrument (welches auch immer du benutzt) schon auch mitteilen, dass es dir die Byte gefälligst als Hex-Werte anzeigen soll. > was bedeutet das dann genau, bzw. wie kann ich von diesen Zeichen wieder > auf Zahlenwerte schließen? Du schaust dir auf dem PC die Daten in der falschen Repräsentierung an. Die empfangenen Bytes als ASCII Zeichen anzusehen ist nicht sinnvoll.
Danke! Das ist schon mal eine riesen Hilfe. Kann die Daten mittels "hterm" einlesen (siehe Grafik im Anhang - grün = Bytes; rot = Dezimalzahlen). 1000Hz werden jedoch (nach 'Augenmaß') nicht erreicht. Der Code in Arduino sieht nun folgendermaßen aus: ---------------------------------------- // Header Serial.write(0xff); Serial.write(0xff); Serial.write(0x55); Serial.write(0xaa); // Daten einlesen int val = lis.getXValue(); Serial.write(val & 0xff ); Serial.write(val >> 8 ); //Serial.print(";"); int val = lis.getYValue(); Serial.write(val & 0xff ); Serial.write(val >> 8 ); //Serial.print(";"); int val = lis.getZValue(); Serial.write(val & 0xff ); Serial.write(val >> 8 ); ---------------------------------------- Passt das eurer Meinung nach soweit?
Lukas Wiedemann schrieb: > Danke! Das ist schon mal eine riesen Hilfe. Kann die Daten mittels > "hterm" einlesen (siehe Grafik im Anhang - grün = Bytes; rot = > Dezimalzahlen). Nur so als Tip: Das kann man doch sicher auch als Hex-Werte anzeigen lassen. Auf dieser Ebene hat man mit Dezimalzahlen eigentlich so gut wie nie auch nur irgendwas angefangen. > 1000Hz werden jedoch (nach 'Augenmaß') nicht erreicht. Tja. Komfort kostet eben. > Passt das eurer Meinung nach soweit? Was heißt unserer Meinung? Kommt am PC das richtig an oder kommt nicht das richtige an?
Lukas Wiedemann schrieb: > Passt das eurer Meinung nach soweit? Die Daten könnten korrekt sein. Der Header ist schlecht gewählt. Nimm den von mir vorgeschlagenen Wert, der sollte eindeutig sein.
Rudolph schrieb: > Konrad S. schrieb: > Da muss man sich dann nur noch ein bisschen Protokoll drum herum > überlegen. > Zum Beispiel einmal pro ms sechs Bytes senden, das dauert 521µs, die > 479µs Pause dienen der Erkennung der Datenrahmen. Wieso dauert das 512µs... wie lautet hier die Rechnung dazu? Damit ich mir das in Zukunft selbst überlegen kann. Rudolph schrieb: > Hab noch die Absicherung vergessen, eine Checksumme mitzuschicken > damit der Empfänger was zum überprüfen hat schadet sicher auch nicht. > > 0xff 0xff hX lX hY lY hZ lZ crc8 > > Ein passendes Start-Token zu finden ist eventuell trickreich. Wie wird diese Checksumme (ich schätze mal dafür steht 'crc8') erstellt? Karl Heinz schrieb: >> 1000Hz werden jedoch (nach 'Augenmaß') nicht erreicht. > > Tja. Komfort kostet eben. Wie meinst du das mit dem Komfort? Ich benötige die 1000Hz. Konrad S. schrieb: > Lukas Wiedemann schrieb: >> Passt das eurer Meinung nach soweit? > > Die Daten könnten korrekt sein. > > Der Header ist schlecht gewählt. Nimm den von mir vorgeschlagenen Wert, > der sollte eindeutig sein. Hab ich ausprobiert... die Daten sehen nun wie folgt aus (siehe Anhang, blau = hex, rot = dez, grün = bin). Mfg, Lukas
Konrad S. schrieb: > Sowas wie 0x7f7e als Kenner dürfte ausreichend sein, da der Wert > eigentlich nicht auftauchen kann (12-Bit Zweierkomplement). Du brauchst zwei Byte als Header, also nimm die Sequenz x7f 0x7e. Diese Sequenz kann in den Daten nicht auftauchen. Und ja, es macht Sinn, wenn das Fenster so breit wie ein Datensatz ist. ;-)
Lukas Wiedemann schrieb: >> Zum Beispiel einmal pro ms sechs Bytes senden, das dauert 521µs, die >> 479µs Pause dienen der Erkennung der Datenrahmen. > > Wieso dauert das 512µs... wie lautet hier die Rechnung dazu? Damit ich > mir das in Zukunft selbst überlegen kann. Wenn ich mich da nicht vertan habe (ja, seriell COM ist ne Weile her) sind es 10 Bit pro Byte Übertragung. 115200 Baud -> 8,68µs/Bit -> 86,81µs/Byte -> 520,83µs für sechs Bytes -> 868,06µs für zehn Bytes, 16-Bit Header, 3*16 Bit Daten, 16 Bit Checksumme > Rudolph schrieb: >> Hab noch die Absicherung vergessen, eine Checksumme mitzuschicken >> damit der Empfänger was zum überprüfen hat schadet sicher auch nicht. >> >> 0xff 0xff hX lX hY lY hZ lZ crc8 > > Wie wird diese Checksumme (ich schätze mal dafür steht 'crc8') erstellt? Da gibt es diverse Algorithmen zu, such Dir was aus. :-) Man könnte zum Beispiel einfach die drei Sensor-Werte addieren und als vierten 16-Bit Wert mitschicken. Wobei die Checksumme auch wieder nicht den Wert vom Header annehmen können darf. Ich bin jetzt auch nicht davon ausgegangen, dass so schnell wie möglich gesendet wird, sondern eben schon mit 1000Hz, die Übertragung also auch nur einmal pro ms gestartet wird.
Hat schon mal jemand darüber nachgedacht, dass auch das Auslesen des Sensors das bremsende Element sein könnte? Wie ist der angebunden? I²C?
Rudolph schrieb: > 115200 Baud -> 8,68µs/Bit Naja, was mir gerade durch den Kopf geht, das berücksichtigt noch nicht den Overhead durch die Software, das ist wie lange die Daten auf der Leitung brauchen. Ein "Serial.write(val >> 8 );" könnte länger benötigen, wie auch immer das implementiert ist. Und das bedeutet auch, es bleiben 132µs die Daten einzulesen, klingt erstmal viel, könnte für den Arduino aber zu knapp sein. Ich weiss auch nicht, ob die Funktion blockierend arbeitet oder per IRQ oder wie auch immer. Direkt in C würde ich einen Sende-IRQ benutzen und ein Array senden. Wie ist überhaupt der Sensor angebunden? SPI oder I2C? Wobei, warum überhaupt auf 16 Bit umrechnen und dann zurück? SPI und I2C liefern sowieso 8 Bit an, vom Sensor in ein 8-Bit Array schieben und das Array auf die Serielle werfen.
Rudolph schrieb: > Wie ist überhaupt der Sensor angebunden? SPI oder I2C? Der Sensor ist mittels I2C angebunden.
Hmm, dann müsst Ihr sicherlich noch das Auslesen des Sensors und das Übertragen zum PC gleichzeitig durchführen. Ansonsten wird das ganze zeitlich schon ziemlich knapp, da I2C einen recht hohen Overhead besitzt. Der ganze I2C-Zugriff mittel getXValue() und darin enthaltenen separaten Registerzugriffen mittels readReg() ist hochgradig ineffizient. Und dabei hat ST doch extra die entsprechenden Register sinnvoll angeordnet, so dass man alle zusammen in einem einzigen Zugriff mit Autoinkrement der Subadressierung auslesen kann. Das ganze ist im Datenblatt haarklein und sehr anschaulich beschrieben. Oder habt Ihr es nicht nötig, die Datenblätter der relevanten Bauteile intensivst zu studieren? Bei Eurem Zugriffsverfahren müssen insgesamt ca. 234 Bit übertragen werden. Bei einem I2C-Takt von 125 kHz schafft man überhaupt nicht 1000 Übertragungen pro Sekunde, sondern gerade einmal die Hälfte. Und das auch nur dann, wenn man an keiner anderen Stelle Zeit verliert. Ein optimierter Zugriff erfordert aber nur 84 Bit, d.h. damit wäre Eure Anforderung locker zu erfüllen. Dass natürlich, wie schon oben erwähnt, dass Auslesen der Sensordaten (Sample n+1) und Verschicken (Sample n) simultan geschehen muss, ist dabei auch völlig klar.
Mal prüfen, ob der nicht per SPI angebunden werden kann? Der Sensor selbst kann ja beides.
Rudolph schrieb: > Mal prüfen, ob der nicht per SPI angebunden werden kann? > Der Sensor selbst kann ja beides. Jap, funktioniert mittels SPI auch, das haben wir jedoch nicht geschafft. Ankommende Daten hatten stets den Wert "0". Wo der Fehler lag wissen wir leider nicht. Andreas Schweigstill schrieb: > Der ganze I2C-Zugriff mittel getXValue() und darin enthaltenen separaten > Registerzugriffen mittels readReg() ist hochgradig ineffizient. Und > dabei hat ST doch extra die entsprechenden Register sinnvoll angeordnet, > so dass man alle zusammen in einem einzigen Zugriff mit Autoinkrement > der Subadressierung auslesen kann. Vielen Dank für den Hinweis. Das müssen wir uns nochmal anschauen. Die Umsetzung ist denk ich mal schwieriger als sie scheint... Andreas Schweigstill schrieb: > Dass natürlich, wie schon oben erwähnt, dass Auslesen der Sensordaten > (Sample n+1) und Verschicken (Sample n) simultan geschehen muss, ist > dabei auch völlig klar. Geht das mittels Arduino-Code?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.