Pages: [1]   Go Down
Author Topic: Serielle Schnittstelle: Daten >128Bytes  (Read 1384 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich versuche gerade einem Mega2560 beizubringen mehr als 128 Byte von der seriellen Schnittstelle zu lesen.
Als Grundlage habe ich das SerialEvent aus den Beispielen genommen. Ich sende eine Datei mit 256 Byte an den Arduino. Die 256 Byte sind mit 00...FF gefüllt. Also jedes Byte eine andere Zahl.
Code:
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(2000);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == 127) {
      stringComplete = true;
    }
  }
}

Der Code oben läuft. Da schreibt er 128 Byte über die Schnittstelle zurück. (Ich frage ab, wann der Wert 127 über die serielle Schnittstelle kommt.
Und das ist ja bei dem Aufbau der Datei das 128. Byte.
Aber sobald ich einen größeren Wert eingebe, kommt nichts mehr zurück. Das heisst für mnich, daß er da nichts mehr empfängt.
Hole ich die Daten nicht schnell genug ab? oder wo liegt da mein (Denk-)Fehler?

Gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Offline Offline
Full Member
***
Karma: 2
Posts: 137
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

eventuell ein Problem des Datentyps. Char hat einen Bereich von -128 bis +127. Du kannst da keine grösseren Zahlen als 127 speichern.

http://arduino.cc/en/Reference/Char

byte (bzw uint8_t) hat einen Bereich von 0 .. 255
Logged

duemilanove / OSX & WIN
Arduino & Teensy: http://bit.ly/13rbdtQ

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh oh.
Da könntest du Recht haben.

Stellt sich jetzt die Frage, wie ein "FF" als Char gelesen wird. Als "-1" oder es wird ignoriert. Werd das mal am Abend testen.

Den Typ Byte hatte ich mir zwischenzeitlich auch schon mal überlegt. Aber da ist mir zum Einlesen nur das Mittel eines Arrays eingefallen und da war dann für mich ein String einfacher. Vor allem, wollte ich dann in den 256 Bytes bestimmte Zeichenketten erkennen können und das ist in einem Array m.E. aufwändiger als in einem String.

Gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2983
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

machs doch einfach ohne
   inputString += inChar;
String mag ja ganz nett sein, ist aber nicht für Zeichen > 127 gedacht. ( Und ich hab noch keine Arduino-Anwendung gesehen, wo String geholfen hätte. )

Was du willst, ist ein
  byte array[200]; // falls FF als 255 interpretiert werden soll, oder ein
  char array [200] ; // für -128 .. 127 , und FF = -1


Quote
Code:
   // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == 127) {
      stringComplete = true;
    }


Der Kommentar passt nicht so ganz...  Ich verstehe das so , dass du Bytes binär überträgst ? newline ( 0x0A ) ist dann ein ganz normales Zeichen ?

String.reserve() ist übrigens in der Arduino Referenz nicht erwähnt...

SerialEvent ist eine Interrupt-Routine, die asynchron zu loop() läuft, denke ich.
Ich würde
volatile boolean stringComplete;   definieren.
Und nur while (stringComplete == false &&  Serial.available() ) { /* das byte array füllen */ }
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi michael_x,

richtig, der Kommentar passt nicht. Der ist noch aus dem SerialEvent-beispiel von den Arduino Examples. Und da haben sie als Ende-Kennung der seriellen Sequenz das "NL" genommen.
Ich glaube String kann ich wirklich vergessen.

Vllt. sollte ich mal kurz schildern, was ich vorhabe:
Ich will einen Zähler seriell an meinen Arduino koppeln. Da kommen dann als "Telegramm" so ca. 1500 Byte an den Arduino.
Das Ende des Telegrammes wird durch eine spezielle Sequenz aus 4 byte angezeigt.
Also ist es Ziel meines Projektes, die 1500 Byte beim Empfang in einen Puffer (am besten wohl "byte array[1500]") zu schreiben, das Ende des Telegrammes zu erkennen und das Array dann nach dem Senden auf bestimmte Werten zu durchforsten.

Geht das Einlesen irgendwie eleganter als so?
Code:
Byte[i] = Serial.read();
i = i+1;
.....


Quote
SerialEvent ist eine Interrupt-Routine, die asynchron zu loop() läuft, denke ich.
Ja, immer wenn was im Empfangspuffer ist, dann wird dahin verzweigt.
Erscheint mir aber irgendwie eleganter, als das im Hauptprogramm abzuarbeiten.

Quote
String.reserve() ist übrigens in der Arduino Referenz nicht erwähnt...
Kommt auch aus dem Beispiel ;-)

Gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2983
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Geht das Einlesen irgendwie eleganter als so?
Code:
Byte[i] = Serial.read();
i = i+1;
.....


So hätte ich es auch gedacht. ( Vielleicht ein schönerer Name für den Puffer ; )
Wenn nur i nicht zu groß werden kann...

Quote
Ich will einen Zähler seriell an meinen Arduino koppeln. Da kommen dann als "Telegramm" so ca. 1500 Byte an den Arduino.
Das Ende des Telegrammes wird durch eine spezielle Sequenz aus 4 byte angezeigt.
? Ein Zählwert-Telegramm mit 1500 Byte ?
1500 byte wären für einen UNO eine ganze Menge, da bliebe nicht viel übrig für anderes/weiter bearbeiten.
Ein Mega2560 ist nicht ganz so knapp.

Aber bei 1500 byte ist doch viel Overhead im Telegramm, der evtl. schon weggeschmissen werden kann, während es kommt, und der Rest wird während des Lesens schon ausgewertet. ?

SerialEvent() könnte schon noch mehr als Speichern und Ende Erkennen.

CheckSumme auswerten kann schon beim Lesen vorbereitet werden...
 

Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So: mit Byte-Array klappts prima. Kann alle 1524 Bytes sauber in das Array einlesen. smiley-grin

Quote
Aber bei 1500 byte ist doch viel Overhead im Telegramm, der evtl. schon weggeschmissen werden kann, während es kommt, und der Rest wird während des Lesens schon ausgewertet. ?
SerialEvent() könnte schon noch mehr als Speichern und Ende Erkennen.
CheckSumme auswerten kann schon beim Lesen vorbereitet werden...

Ja du hast recht. Ich werde so ca. 20 Werte aus dem Telegramm lesen. Das sind dann max. 100 Byte. Da die Werte im Telegramm immer an der selben Stelle stehen, wäre das auch kein Problem.
Aber ich müsste dann im serialEvent nach dem Lesen immer abfragen, ob die Nummer des gelesene Bytes (also die Stelle im Telegramm) eine der 100 relevanten Bytes ist und dann wegspeichern. Also nach jedem Serial.read() 100 If-Abfragen. Das finde ich nicht elegant, und treibt die CPU-Last wohl stark in die Höhe. Im schlimmsten Fall krieg ich dann nicht mehr alles von der seriellen Schnittstelle mit.
Die serielle hat ja nur 128 Byte Puffer. Was passiert, wenn der voll ist? Glaube nicht, daß ich die andere Seite dann anhalten kann, damit die wartet bis ich meinen Puffer ausgelesen habe. Nicht mit (TX,RX und GND).

Oder weiss jemand zum "Maskieren" der 100Byte eine schönere Lösung?

Gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn es nur 20 Werte sind, brauchst Du auch nur 20 if-Abfragen, Du mußt ja nur den Anfang erwischen. Ich würde das aber eleganter lösen.

Die 20 "Start"-Stellen der Werte kommen in ein Array (position) . Der Zählindex für das Array zeigt auf den ersten Eintrag (current).

Während Du aus der seriellen Schnittstelle  liest, vergleichst Du den Zähler für die gelesenen Bytes (z.B. int numbytes) mit der als nächstes zu lesenden Stelle. Ist die erreicht wird der Wert gelesen, wenn nicht, wird das Byte übersprungen.

Code:
#define NUM_VALUES 20
int position[NUM_VALUES] = { 25,100,255,300 ...};
int current = 0; //index auf position des nächsten zu lesenden wertes
int numbytes = 0; //anzahl gelesene bytes

....
//hier code zum einlesen der nächsten bytes
...
//position des nächsten wertes erreicht? oder alle werte schon gelesen?
(if numbytes == position[current] && current < NUM_VALUES) {
  //code zum einlesen des Wertes
  //nicht vergessen auch hier beim einlesen "numbytes" zu erhöhen
  //wert fertig eingelesen, auf nächsten Wert umstellen
  current++;
}
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ja,
gute Idee.
So was entfernt ähnliches hab ich mir auch schon überlegt.
Allerdings hab ich noch das Problem, daß ich da ein zweidimensionales Array aufbauen muss, weil die Anzahl der Bytes bei den 20 Werten unterschiedlich ist.
Ist aber auch nicht so das Drama. Muss halt nur den Code zum Einlesen der Werte variabel auf die Bytelänge des Wertes umprogrammieren.
Momentan mach ich es mal hölzern. Alles auf einmal einlesen und dann parsen.
Aber wie ich mich kenne, werd ich die Software dann wohl in die Richtung trimmen, da ich momentan einen Mega verwende, aber evtl. doch nur einen UNO spendieren will, wenn es klappt.

Noch ne Frage:
Gibt es irgendwo eine Befehlsliste mit der Abarbeitungszeit? Ich würde gerne mal ein Gefühl dafür bekommen, wie lange die Interruptroutine läuft. Dann hab ich auch die Sicherheit, daß mir der Puffer nicht überläuft.

Gruß/hk007
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2983
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Gibt es irgendwo eine Befehlsliste mit der Abarbeitungszeit? Ich würde gerne mal ein Gefühl dafür bekommen, wie lange die Interruptroutine läuft. Dann hab ich auch die Sicherheit, daß mir der Puffer nicht überläuft.

Gibt es bestimmt, aber das willst du nicht wirklich wissen.

Soll deine ISR über 100 Zeilen Code haben? 
Willst du darin float Divisionen durchführen?
Rufst du andere Funktionen darin auf?

 3 * NEIN ? Dann wirst du die Dauer knapp in Microsekunden messen können.

Bei 115200 Bd hast du etwa 1 Zeichen in 90 Microsekunden, und der Puffer von Hardware Serial ist 64 Zeichen groß ...

Dein Arduino läuft vermutlich mit 16 MHz und es gibt Befehle, die nur einen Takt brauchen.

Quote
ein zweidimensionales

Zwei eindimensionale ... eins für die Position, eins für die Länge.
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Bei 115200 Bd hast du etwa 1 Zeichen in 90 Microsekunden, und der Puffer von Hardware Serial ist 64 Zeichen groß ...
9600Baud ist angesagt. Faktor 12 Reserve  smiley
Hmm wo hab ich nur die Info mit den 128 byte her? Hab gerade in der Reference nachgelesen. Da hast du recht mit deinen 64 byte.

Quote
Soll deine ISR über 100 Zeilen Code haben?
Willst du darin float Divisionen durchführen?
Rufst du andere Funktionen darin auf?
 3 * NEIN ? Dann wirst du die Dauer knapp in Microsekunden messen können.
OK. Das gibt mir das "Gefühl", das ich zum Programmieren brauche.


Danke @all
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Offline Offline
Full Member
***
Karma: 2
Posts: 137
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

in früheren Versionen der Arduino IDE war der Serial Buffer 128 Bytes lang
Logged

duemilanove / OSX & WIN
Arduino & Teensy: http://bit.ly/13rbdtQ

Pages: [1]   Go Up
Jump to: