Forum: Mikrocontroller und Digitale Elektronik Serieller Eingangspuffer zu klein Arduino UNO


von D. C. (joker89)


Lesenswert?

Wie oben schon geschrieben der Eingangspuffer ist mir zu klein mit 64 
Byte, die Nachricht ist 107 Byte groß.
Gibt es dafür Abhilfe ?
Leider finde ich dazu keine Blogs Einträge ect.

Gruß

von Max H. (hartl192)


Lesenswert?

D. Chung schrieb:
> Gibt es dafür Abhilfe ?
Man könnte eine Funktion mit größerem Buffer schreiben.

von Peter D. (peda)


Lesenswert?

Vermutlich reicht es, die Hilfe oder das Manual zu lesen, wie man die 
Größe einstellt.
Es würde mich wundern, wenn die Arduion-Lib völlig ohne Doku daherkommt.

von Mr. Wu (Gast)


Lesenswert?

D. Chung schrieb:
> Wie oben schon geschrieben der Eingangspuffer ist mir zu klein mit 64
> Byte, die Nachricht ist 107 Byte groß.

Warum änderst du nicht SERIAL_BUFFER_SIZE?

von Kaj (Gast)


Lesenswert?

D. Chung schrieb:
> Leider finde ich dazu keine Blogs Einträge ect.
Alleine auf's Klo gehen kannst du aber schon, oder musst du dafür auch 
vorher erst einen Blog lesen?

D. Chung schrieb:
> Gibt es dafür Abhilfe ?
Ja: C-Buch lesen, verstehen und das Datenblatt zum Controller suchen, 
lesen, verstehen und verstehen wie der UART funktioniert und dann ganz 
easy den Controller so programmieren wie du es brauchst.

Alternativ:
Arduino-Dokumentation lesen? (http://arduino.cc/en/Reference/Serial)
Das Puffer-Array größer machen?

Oder aber, einfach hinnehmen, weiterhin das selbstständige denken 
verweigern und dumm und vermeindlich glücklich sterben.

Troll dich!

von Coder (Gast)


Lesenswert?

Die Daten in kleineren Stücken lesen und/oder schreiben.

von Arduinchen (Gast)


Lesenswert?


von meckerziege (Gast)


Lesenswert?

Das ist ja geil. Jetzt brauchen die Arduino-User schon ein Video damit 
sie verstehen wie sie ein Define ändern können um den Puffer größer zu 
machen.
Dokumentation lesen is wohl "zu 80's".


Aber dennoch ein Tipp an dich: Die Lösung für dein Problem ist NICHT, 
den Buffer größer zu machen, sondern anständigen Code zu schreiben. Du 
kannst die Daten auch in kleineren Blöcken empfangen. Es muss nicht 
alles in den Puffern der Library Platz haben.
Man versucht allgemein die Libraries so wenig wie möglich zu verändern, 
sofern es geht überhaupt nicht! Denn wenn du deinen Code weitergibst 
müsstest du auch die Lib mitgeben.
Was passiert in ein paar Monaten wenn es ein Update gibt? Dann musst du 
diese Änderungen wieder ausführen.

von Leonhard K. (leonhard_k)


Lesenswert?

meckerziege schrieb:
> Das ist ja geil. Jetzt brauchen die Arduino-User schon ein Video damit
> sie verstehen wie sie ein Define ändern können um den Puffer größer zu
> machen.
> Dokumentation lesen is wohl "zu 80's".

Bald gibt es Videos, die erklären, wie Videos geschaut werden.

von steffen (Gast)


Lesenswert?

Hallo Zusammen,
hier ein kleine Umfrage, bitte zutreffendes ankreuzen:

[ ] 80% der geposteten Anworten eines Threads im Mikrocontrollernetz 
helfen dem Fragenden freundlich und zielgerichtet weiter
[ ] nur 1% der Antworten stammen von besserwisserischen Nörglern
[ ] es gibt immer mal wieder eine Perle unter den Antworten, die dem 
Fragenden weiterhilft.
[ ] Ich würde weiterhin im Mikrocontrollernetz posten

von D. C. (joker89)


Lesenswert?

Wahnsinn ^^, hätte ich eine Lösung dafür hätte ich sicher nichts hier 
rein geschrieben .

Beim MAC OS kann ich die lib nicht bearbeiten die schon Standard dabei 
sind. Zumindestens finde ich bisher keinen Speichertort dafür ;-).
Zweite Möglichkeit wäre ein Ringpuffer, nur ich bekomme es nicht hin 
;-)...

Beispiele dazu sind auch raarr und wenn für mich unverständlich.

von Peter D. (peda)


Lesenswert?

D. Chung schrieb:
> Zumindestens finde ich bisher keinen Speichertort dafür ;-).

Hat das MAC OS denn keine Suchfunktion?

In der Regel kriegt man passendere Antworten, wenn man gleich angibt, 
daß man kein Windows benutzt. Die Leute können ja nicht in Deinen Kopf 
schauen.

von Jürgen S. (jurs)


Lesenswert?

D. Chung schrieb:
> Beim MAC OS kann ich die lib nicht bearbeiten die schon Standard dabei
> sind.

Das dürftest Du frei erfunden haben, eine solche 
Bearbeitungsverhinderung für die Arduino Core-Library gibt es sicher 
auch beim MAC OS nicht.

> Zumindestens finde ich bisher keinen Speichertort dafür ;-).

Damit dürftest Du dem Problem schon näher kommen.
Bei Deinem geringen Kenntnisstand ist es allerdings fraglich, ob Dein 
Problem wirklich in den Arduino-Core Libraries liegt oder nicht eher 
Deinen mangelhaften Programmierkenntnissen zuzuschreiben ist. Und ob es 
wirklich angebracht ist, mit so geringen Kenntnissen in den 
Core-Libraries herumzufuhrwerken.

> Zweite Möglichkeit wäre ein Ringpuffer, nur ich bekomme es nicht hin

Ein einfaches Array mit Zählindex reicht nicht?

Wie wird denn Deine Nachricht gesendet, kann man irgendwie feststellen, 
wo sie zuende ist? Ist das letzte Zeichen der 107 Byte irgendwie ein 
spezielles Stopzeichen und kennzeichnet das Ende der Nachricht? Oder ist 
das erste Zeichen der Nachricht ein spezielles Startzeichen? Oder gibt 
es immer eine kleine Sendepause zwischen zwei Nachrichten?

von D. C. (joker89)


Lesenswert?

Ja du kannst mir ja gerne mitteilen wo ich diese finden sollte, es gibt 
eine Ordner dazu aber darin befinden sich nur die lib die ich selbst 
hinzugefügt habe. Ich hab auch nie behauptet das meine 
Programmierkenntnisse sehr gut wären , dann würde ich mich wohl hier 
nicht austoben....

> Wie wird denn Deine Nachricht gesendet, kann man irgendwie feststellen,
> wo sie zuende ist? Ist das letzte Zeichen der 107 Byte irgendwie ein
> spezielles Stopzeichen und kennzeichnet das Ende der Nachricht? Oder ist
> das erste Zeichen der Nachricht ein spezielles Startzeichen? Oder gibt
> es immer eine kleine Sendepause zwischen zwei Nachrichten?

--> http://www.ecmspy.com/cgi-bin/runtime.cgi

Was ich nur darüber weiß ist das was man hier findet .

Ich stelle eine Anfrage und gleich im Anschluss antwortet mir das ECM 
mit 107 Byte . Die letzten zwei Byte sind einmal für End of text und 
Checksum.
Ich wüsste nicht das es eine Sendepause gäbe.
Plausibel würde mir ein Ringpuffer erscheinen aber ich weiß nicht wie 
ich das am besten angehe .

Ein kleiner Ausschnitt ->
1
  ByteNumber = 0;
2
  inArray[0] = 0x01; //SOH
3
  inArray[1] = 0x00; //Emittend
4
  inArray[2] = 0x42; //Recipient
5
  inArray[3] = 0x02; //Data Size
6
  inArray[4] = 0xFF; //EOH
7
  inArray[5] = 0x02; //SOT
8
  inArray[6] = 0x43; //Data 1 //0x56 = Get version, 0x43 = Get runttime data
9
  inArray[7] = 0x03; //EOT
10
  inArray[8] = 0xFD; //Checksum
11
  requestData();
12
"
13
"
14
//Send data request to ECM
15
void requestData(void) {
16
  WaitTimer = millis();
17
  Serial.println("Request to ECM");
18
  
19
  for (int i = 0; i < 9; i += 1){
20
    mySerial.write(inArray[i]);
21
  }
1
void loop() {
2
  
3
   if (mySerial.available()) {
4
                  //fill the data array
5
                  outArray[ByteNumber ++] = mySerial.read();
6
                  
7
                  Serial.print("ByteNumber");
8
                  Serial.print(ByteNumber);
9
                  Serial.print(" ,");
10
                  Serial.println(outArray[ByteNumber]);
11
                 
12
                     
13
                 
14
           }
15
      
16
            else {
17
                      ByteNumber = 0;
18
                      if ((millis() - WaitTimer) > 2000) {
19
20
                        mySerial.flush();
21
                        ByteNumber = 0;
22
                        Serial.println("Reset");
23
                       // Serial.println(millis() - WaitTimer);
24
                        mySerial.flush();
25
                        WaitTimer = millis();
26
                        requestData();
27
                        delay(2000);
28
29
                      }
30
            }
31
              
32
             
33
              
34
              if (ByteNumber > 107) { // process it
35
                ByteNumber = 0;  // ready for next time
36
            
37
                callTPS();
38
                callATemp();
39
                callSpeed();
40
                callRPM();
41
                callPulsewidth();
42
                callLogger();
43
                WaitTimer = millis();
44
                requestData();  //restart data
45
                delay(1000);
46
47
     } 
48
}

: Bearbeitet durch User
von Jürgen S. (jurs)


Lesenswert?

D. Chung schrieb:
> Was ich nur darüber weiß ist das was man hier findet .
>
> Ich stelle eine Anfrage und gleich im Anschluss antwortet mir das ECM
> mit 107 Byte . Die letzten zwei Byte sind einmal für End of text und
> Checksum.

OK, mal abgesehen davon, dass man "gleich" nochmal genauer definieren 
müßte, ob damit 100 Mikrosekunden, 5 Millisekunden oder 1 Sekunde 
gemeint ist, reicht zum Empfangen natürlich der Standardmäßige serielle 
Eingangspuffer voll aus.

> Ich wüsste nicht das es eine Sendepause gäbe.

Aber in dem Fall, dass Du eine "Anforderung" sendest, weißt Du, wann die 
Sendung eintrifft, nämlich nach dem Absenden der Anforderung.

Das Vorgehen zum Empfangen ist also:
- Du definierst einen Byte-Puffer von 107 Bytes Größe
- Du definierst einen Byte-Zähler

Erste mögliche Programmlogik:
Sobald Du Deine Anforderung gesendet hast, setzt Du den Byte Zähler auf 
0 und wartest auf die 107 eintreffenden Zeichen.

Zweite mögliche Programmlogik:
Sobald das Startzeichen SOH empfangen wird, setzt Du den Byte Zähler auf 
0 und wartest auf die 107 eintreffenden Zeichen.

Such Dir was aus!

> Plausibel würde mir ein Ringpuffer erscheinen aber ich weiß nicht wie
> ich das am besten angehe .

Du hast von keinem Ringpuffer irgendeine Ahnung.
Und Du brauchst dafür auch keinen Ringpuffer, nur ein einfaches Array.

von D. C. (joker89)


Lesenswert?

Kannst du das zur Nr eins nochmals genauer erläutern ?
Du meinst ich sollte eine Klasse definieren ?
Wie gesagt ich bin hier eher ein Anfänger und beiß mich gerne durch 
aber, dafür braucht es meist konkrete Ansätze.

von Karl H. (kbuchegg)


Lesenswert?

D. Chung schrieb:
> Kannst du das zur Nr eins nochmals genauer erläutern ?
> Du meinst ich sollte eine Klasse definieren ?

Nein.
Ein ganz stink normales Array, das gross genug ist.
Und dazu einen Zähler, der einfach nur mitzählt, wieviele Bytes schon in 
diesem Buffer sind und wo daher das nächste zu empfangene Zeichen 
abgelegt werden muss.

Mit einem Array wirst du ja doch wenigstens umgehen können!
Wenn nicht, dann lerne es
1
unsigned char Data[200];  // Platz genug
2
unsigned char nextByte;
3
4
void loop()
5
{
6
  if( Serial.available() ) {
7
    data[nextByte] = Serial.read();
8
    nextByte++;
9
  }
10
11
  .... wenn genug Bytes beisammen sind, dann werte sie aus
12
  .... und/oder setze nextByte wieder auf 0, damit die nächsten Bytes
13
  .... wieder vom Begin des Arrays an abgelegt werden
14
}

Wo genau ist da jetzt das Problem mit dem 64 Byte Buffer der Serial 
Klasse?

> Wie gesagt ich bin hier eher ein Anfänger und beiß
mich gerne durch
> aber, dafür braucht es meist konkrete Ansätze.

Dann wird es Zeit, dass du ein paar absolute Basic Standardverfahren dir 
zur Gemüte führst. Bytes der Reihe nach in ein Array schreiben ist 
wahrlich keine Hexerei.

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Kaj schrieb:
> D. Chung schrieb:
>> Leider finde ich dazu keine Blogs Einträge ect.
> Alleine auf's Klo gehen kannst du aber schon, oder musst du dafür auch
> vorher erst einen Blog lesen?
>
> Oder aber, einfach hinnehmen, weiterhin das selbstständige denken
> verweigern und dumm und vermeindlich glücklich sterben.
>
> Troll dich!

Beirag finde ich nicht gut.

von Karl H. (kbuchegg)


Lesenswert?

und wenn du mutwillig ...
1
...
2
                delay(1000);
3
...
dein Programm ausbremst, darfst du dich nicht wundern, wenn dir die 
Puffer hinten und vorne zu klein werden.
Ich kann ja verstehen, dass jeder mal angefangen hat. Aber wer seinem µC 
absichtlich Prügel zwischen die Beinchen wirft und die Handbremse 
anzieht, sollte sich erst mal überlegen, was er da eigentlich tut.

Wie die Sache mit der Funktion millis() funktioniert und wie man sich 
damit Aktionen so kapselt, dass sie in regelmässigen Zeitintervallen 
ausgeführt werden, hast du nicht wirklich verstanden bzw. mal darüber 
nachgedacht. Code einfach abschreiben ist dann doch ganz einfach zu 
wenig.

Da, in diesen delays liegt dein Problem und nicht in zu kleinen Buffern. 
Denn pikanterweise scheint der Rest des Codes bereits so geschrieben zu 
sein, dass es genau das von dir geschriebene Problem nicht gibt. D.h. 
der, von dem du abgeschrieben hast, hat das schon alles bedacht. Mit dem 
ergänzen der delays und noch einer weiteren Änderungen hast du 
allerdings alles wieder zerstört.

: Bearbeitet durch User
von Jürgen S. (jurs)


Lesenswert?

D. Chung schrieb:
> Kannst du das zur Nr eins nochmals genauer erläutern ?
> Du meinst ich sollte eine Klasse definieren ?
> Wie gesagt ich bin hier eher ein Anfänger und beiß mich gerne durch
> aber, dafür braucht es meist konkrete Ansätze.

Anbei ein sehr konkreter Ansatz.

Mit einer receiveData() Funktion, die verschiedene Statuscodes 
zurückliefert und sogar schon eine rudimentäre Fehlerüberprüfung 
enthält.
1
#include <SoftwareSerial.h>
2
SoftwareSerial mySerial(8, 9); // RX, TX
3
// Besser: SoftwareSerial Library durch AltSoftSerial ersetzen!
4
5
#define REQUESTINTERVALL 5000
6
#define MESSAGETIMEOUT 3000
7
#define SOH 0x01
8
#define EOT 0x03
9
10
#define MSGBYTES 107
11
byte inArray[MSGBYTES]; // Platz zum Speichern von 107 Bytes
12
byte ByteNumber = 0;
13
unsigned long lastRequestTime;
14
boolean requestPending=false;
15
  
16
void request()
17
{
18
  // hier die Anforderung senden
19
  inArray[0] = 0x01; //SOH
20
  inArray[1] = 0x00; //Emittend
21
  inArray[2] = 0x42; //Recipient
22
  inArray[3] = 0x02; //Data Size
23
  inArray[4] = 0xFF; //EOH
24
  inArray[5] = 0x02; //SOT
25
  inArray[6] = 0x43; //Data 1 //0x56 = Get version, 0x43 = Get runttime data
26
  inArray[7] = 0x03; //EOT
27
  inArray[8] = 0xFD; //Checksum
28
  for (int i = 0; i < 9; i += 1) mySerial.write(inArray[i]);
29
  lastRequestTime=millis(); // Zeit der letzten Datenanforderung merken
30
  Serial.println("Request pending...");
31
  ByteNumber=0; // Zähler zurücksetzen
32
  requestPending=true;
33
}
34
35
// Einige Ergebniscodes für den Datenempfang
36
enum {PENDING, NOTPENDING, TIMEOUT, DATAERROR, OK};
37
  
38
byte receiveData()
39
{
40
  if (!requestPending) // kein Request anhängig
41
  {
42
    while (mySerial.available()) mySerial.read(); // Eingangspuffer leeren
43
    return NOTPENDING; // Kein Request anhängig
44
  }
45
  if (millis()-lastRequestTime>MESSAGETIMEOUT) // Timeout, keine vollständige Antwort
46
  {
47
    requestPending=false;
48
    return TIMEOUT;
49
  }
50
  if (mySerial.available()==0) return PENDING; // Es wird auf weitere Zeichen gewartet
51
  char c=mySerial.read();
52
  inArray[ByteNumber]=c;
53
  ByteNumber++;
54
  if (ByteNumber<MSGBYTES) return PENDING; // Es wird auf weitere Zeichen gewartet
55
  // Der folgende Code wird ausgeführt, wenn alle Zeichen empfangen wurden
56
  requestPending=false;
57
  ByteNumber=0;
58
  // Fehlerüberorprüfung
59
  if (inArray[0]!=SOH || inArray[105]!=EOT) return DATAERROR;
60
  // Wenn keine Fehler, dann Daten OK
61
  return OK;
62
}
63
64
void printData()
65
{
66
  // Empfangene Codes numerisch dezimal ausgeben
67
  for (int i=0;i<MSGBYTES;i++)
68
  {
69
    Serial.print(inArray[i]);
70
    Serial.print('\t');
71
    if ((i+1)%10==0) Serial.println();
72
  }
73
  Serial.println();
74
}
75
76
void setup() {
77
  Serial.begin(9600);
78
  Serial.println("Good night and good luck!");
79
}
80
81
void loop() {
82
  unsigned long now=millis();
83
  if (now-lastRequestTime>=REQUESTINTERVALL) request();
84
  switch (receiveData())
85
  {
86
    case TIMEOUT: Serial.println("REQUEST TIMEOUT");break;
87
    case DATAERROR: Serial.println("DATA ERROR");break;
88
    case OK: printData();break;
89
  }
90
}

Wie hier im Thread schon erwähnt: Für Programme, die schnell reagieren 
sollen, sind Blockierungen der Programmausführung mit der "delay" 
Funktion absolut tabu.

Wenn Du mit Arduino irgendwelche Aktionen zu timen hast, wie zum 
Beispiel Anforderungsintervalle oder Timeoutintervalle, dann immer nur 
über den Stand des millis() Timers durch Zeitpunktvergleich, aber nie 
durch "blockierendes Warten" ("busy waiting").

Schau's Dir an!

Falls Dein Controller nicht genügend HardwareSerial-Schnittstellen hat, 
sollte für die Softwaremulation besser nicht die zur Arduino-Software 
gehörende SoftwareSerial Library verwendet werden, sondern praktisch 
immer viel besser geeignete Drittanbieter-Library "AltSoftSerial".

von D. C. (joker89)


Lesenswert?

Danke Dir für deine Antwort.

Zu einem Abschnitt hätte ich eine Frage

byte receiveData()
.........
  char c=mySerial.read();
  inArray[ByteNumber]=c;
  ByteNumber++;
....


Er liest jetzt zu jedem Durchlauf in das Array ein und erhöht ByteNumber 
um 1 und das auch wenn nichts im Puffer steht kann das richtig sein ?

Oder liege ich falsch ?
Gruß

von PittyJ (Gast)


Lesenswert?

Schau einfach auf die Zeile davor. Das beantwortet die Frage.

von Karl H. (kbuchegg)


Lesenswert?

D. Chung schrieb:

> Er liest jetzt zu jedem Durchlauf in das Array ein und erhöht ByteNumber
> um 1 und das auch wenn nichts im Puffer steht kann das richtig sein ?

Was denkst du, welchen Zweck das unmittelbar vorhergehende
1
  if (mySerial.available()==0) return PENDING;

hat?

von Jürgen S. (jurs)


Lesenswert?

D. Chung schrieb:
> Er liest jetzt zu jedem Durchlauf in das Array ein und erhöht ByteNumber
> um 1 und das auch wenn nichts im Puffer steht kann das richtig sein ?
>
> Oder liege ich falsch ?

Ja.

Eine Funktion kann mit "return" vorzeitig verlassen werden und davon 
mache ich reichlich Gebrauch.
1
if (mySerial.available()==0) return PENDING; // Es wird auf weitere Zeichen gewartet

Wenn keine Zeichen im Eingangspuffer sind, wird die Funktion vorzeitig 
mit dem Returncode "PENDING" verlassen. Der Nachfolgende Code mit dem 
Auslesen des seriellen Eingangspuffers wird also nur dann ausgeführt, 
wenn sich mindestens ein Zeichen im Eingangspuffer befindet.

von Karl H. (kbuchegg)


Lesenswert?

Da
1
  if (millis()-lastRequestTime>MESSAGETIMEOUT) // Timeout, keine vollständige Antwort
2
  {
3
    requestPending=false;
4
    return TIMEOUT;
5
  }
sollte sicherheitshalber noch ein
1
  if (millis()-lastRequestTime>MESSAGETIMEOUT) // Timeout, keine vollständige Antwort
2
  {
3
    requestPending=false;
4
    ByteNumber=0;                // <-------
5
    return TIMEOUT;
6
  }
rein.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?


von D. C. (joker89)


Lesenswert?

Ohje sry ja , sollte ich eigentlich wissen.
Habs irgendwie übersehen oder nicht mehr daran gedacht ....
Danke

von Nosnibor (Gast)


Lesenswert?

D. Chung schrieb:
> Beim MAC OS kann ich die lib nicht bearbeiten die schon Standard dabei
> sind. Zumindestens finde ich bisher keinen Speichertort dafür ;-).

 - Arduino-Applikation im Finder-Fenster finden.
 - Kontextmenü aufrufen (d.h. bei gedrückter ctrl-Taste draufklicken. 
Entspricht dem "Rechtsklick" bei Windows).
 - Da sollte es den Punkt "Paketinhalt zeigen" geben.
 - Dann sieht man das "Innere" der Applikation, d.h. das ist eigentlich 
ein Verzeichnis mit allerlei Unterverzeichnissen. Contents -> Ressources 
-> Java, und dann wird's interessant.

Aber auch ich bin der Meinung, daß der Empfangspuffer einer allgemeinen 
serial-Lib nicht der richtige Ort ist, komplette Protokoll-Messages 
zwischenzulagern.

von D. C. (joker89)


Lesenswert?

Danke, nach 5 Jahren MAC mal wieder was neues gelernt.

Ich teste den Code jetzt demnächst mal und berichte ob er funktioniert 
oder auch nicht. Ich hatte irgendwann mal C++ gelernt, mit MC hatten wir 
aber dann recht wenig bis gar nichts am Hut das kam nur durch meine 
Interesse... die einzige Schnittstelle die ich schon mal benutzt hab und 
das erfolgreich war der I2C Port.

Man vergisst doch relativ schnell einiges, und verliert das Gefühl oder 
den Blick für die kleinen wichtigen Dinge....

Auch unter den blöden Antworten waren, waren mal nützliche infos 
beigemischt also einen Dank an die Rund ;-).

Gruß

Beitrag #7090390 wurde von einem Moderator gelöscht.
Beitrag #7090396 wurde von einem Moderator gelöscht.
von PittyJ (Gast)


Lesenswert?

Cool, das Programmier-Buch gibt es immer noch bei Amazon.
Das kann ich also immer noch empfehlen.

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
Noch kein Account? Hier anmelden.