Arduino: Arduino startet mitten im Code neu

#3790930
Lesenswert?

Hallo zusammen,

ich habe folgendes Problem und weiß leider nicht mehr weiter:
Ich habe einen Code für ein Meldersystem geschreiben, welches serielle 
Daten im Format ID;Typ;Text~ bekommt also z.B. 1;A;Text!~
Wenn ich diesen Befehl an den Arduino schicke, startet dieser jedoch 
beim Befehl atoi() neu.
Hier der Code:
1
//Libraries
2
#include <RFM12B.h>
3

4
//-----------------------
5

6
//Variables
7
uint8_t   key[] =           "1234567890123456";
8
int      serialSpeed =   19200;
9
int      ownId =         1;
10
int      group =         86;
11
char     destination[3];
12
char     type[1];
13
char     text[128];
14
char     sendText[128];
15
int      ackTime=        25;
16
bool     requestAck=     true;
17
int      dest=           0;
18
//-------------------------------
19

20
//Instances
21
RFM12B radio;
22

23
//------------------------------
24

25

26
void setup()
27
{
28
  Serial.begin(serialSpeed);
29
  Serial.println("0x00");
30
  radio.Initialize(ownId, RF12_433MHZ, group);
31
  radio.Encrypt(key);
32
}
33

34
void incoming()
35
{
36
  if (Serial.available())
37
  {
38
    delay(10);
39
    Serial.readBytesUntil(';',destination,3);
40
    Serial.println((String)destination);
41
    Serial.readBytesUntil(';',type,1);
42
    Serial.println((String)type);
43
    Serial.readBytesUntil('~',text,128);
44
    Serial.println((String)text);
45
    dest = atoi(destination);              //Hier steigt der Arduino aus
46
    Serial.println(dest);
47
    String stext = (String)type[0]+";"+text;
48
    stext.toCharArray(sendText, 128);
49
    Serial.println((String)sendText);
50
    radio.Send((uint8_t)dest, sendText, (uint8_t)sizeof(sendText), requestAck);
51
    if(waitForAck(dest))
52
    {
53
       Serial.println("Nachricht erfolgreich an Melder: "+(String)dest+" gesendet!");
54
    }
55
  }
56
}
57

58
static boolean waitForAck(int dest)
59
{
60
  long now = millis();
61
  while(millis() < (now+ackTime))
62
  {
63
    if(radio.ACKReceived(dest))
64
      return true;
65
  }
66
  return false;
67
}
68

69
void loop()
70
{
71
  incoming();
72
}

Es wäre super, wenn jemand einen Tipp hätte warum das nicht 
funktoniert...
Die Serielle ausgabe des Arduino sieht wie folgt aus:

0x00
1
A
;Te0x00


Ich freue mich auf ein paar Tipps.

Nette Grüße
Jan-Niklas
#3790933
Lesenswert?

Hi,

nur eine Vermutung evtl. stört die unter Umständen fehlende 
Nullterminierung von destination. Alternativ sieh dir die Funktion 
strtol mal an, hier gibt es bei Fehlern bessere Möglichkeiten der 
Diagnose.
Als erster Test könntest du

char destination[4];

wählen und in der loop() alle Einträge von destination auf '\0' setzen.
Gast #3791185
Lesenswert?

Jan-Niklas B. schrieb:
> char     destination[3];
> char     type[1];
> char     text[128];
> char     sendText[128];

Alle Arrays möchten nullterminiert sein, deswegen um eins vergrößern:
1
char     destination[4];
2
char     type[2];
3
char     text[129];
4
char     sendText[129];

Die Arrays werden eigentlich alle mit \0 initialisiert. Wenn man sich 
nicht darauf verlassen will, schreibt man:
1
char     destination[4] = { 0 };
2
char     type[2] = { 0 };
3
char     text[129] = { 0 };
4
char     sendText[129] = { 0 };
Gast #3791260
Lesenswert?

DirkZ schrieb:
> Die Arrays werden eigentlich alle mit \0 initialisiert. Wenn man sich
> nicht darauf verlassen will, schreibt man:char     destination[4] = { 0
> };
> char     type[2] = { 0 };
> char     text[129] = { 0 };
> char     sendText[129] = { 0 };

Damit setzt du aber nur das erste Array-Element auf 0!?
Gast #3791328
Lesenswert?

Kirkenes schrieb:
> DirkZ schrieb:
>> Die Arrays werden eigentlich alle mit \0 initialisiert. Wenn man sich
>> nicht darauf verlassen will, schreibt man:char     destination[4] = { 0
>> };
>> char     type[2] = { 0 };
>> char     text[129] = { 0 };
>> char     sendText[129] = { 0 };
>
> Damit setzt du aber nur das erste Array-Element auf 0!?

Ja, das stimmt. Und nach C89 (3.5.7) oder C99 (6.7.8/21) auch den Rest 
des Arrays.
#3791556
Lesenswert?

Danke erstmal für die ganzen Rückmeldungen :)
Leider hat das noch nicht viel gebracht...
Ich hab den Code nun wie folgt abgeändert:
1
//Libraries
2
#include <RFM12B.h>
3

4
//-----------------------
5

6
//Variables
7
char     serialdata;
8
uint8_t   key[] =           "1234567890123456";
9
int      serialSpeed =   19200;
10
int      ownId =         1;
11
int      group =         86;
12
char     destination[4]= {0};
13
char     type[2]=        {0};
14
char     text[128]=      {0};
15
byte     sendType;
16
char     sendText[128]=  {0};
17
int      ackTime=        25;
18
bool     requestAck=     true;
19
int      dest=           0;
20
//-------------------------------
21

22
//Instances
23
RFM12B radio;
24

25
//------------------------------
26

27

28
void setup()
29
{
30
  Serial.begin(serialSpeed);
31
  Serial.println("0x00");
32
  radio.Initialize(ownId, RF12_433MHZ, group);
33
  radio.Encrypt(key);
34
}
35

36
void incoming()
37
{
38
  if (Serial.available())
39
  {
40
    delay(10);
41
    Serial.readBytesUntil(';',destination,3);
42
    Serial.readBytesUntil(';',type,1);
43
    Serial.readBytesUntil('~',text,128);
44
    destination[4]='\0';
45
    type[2]='\0';
46
    text[128]='\0';
47
    dest = atoi(destination);
48
    Serial.println(dest);
49
    String stext = (String)type[0]+";"+text;
50
    stext.toCharArray(sendText, 128);
51
    sendText[128]='\0';
52
    Serial.println("sendText nullterminiert");
53
    Serial.println((String)sendText);
54
    radio.Send((uint8_t)dest, sendText, (uint8_t)sizeof(sendText), requestAck);
55
    if(waitForAck(dest))
56
    {
57
       Serial.println("Nachricht erfolgreich an Melder: "+(String)destination+" gesendet!");
58
    }
59
  }
60
}
61

62
static boolean waitForAck(int dest)
63
{
64
  long now = millis();
65
  while(millis() < (now+ackTime))
66
  {
67
    if(radio.ACKReceived(dest))
68
      return true;
69
  }
70
  return false;
71
}
72

73
void loop()
74
{
75
  incoming();
76
}

Nun sieht die Ausgabe so aus:
0x00
1
sendTå0x00


Sonst irgendwelche ideen woran das liegen könnte?
Gast #3791571
Lesenswert?

Jan-Niklas B. schrieb:

>     text[128]='\0';

>     sendText[128]='\0';

1
char     text[128]=      {0};

legt die Variable text mit 128 Feldern an, die - in C nullindiziert - 
von 0 bis 127 angesprochen werden. Oder hast Du vergessen, die Variablen 
text und sentText auf 129 zu erweitern?

Denn die Zuweisung
1
text[128]='\0';
schreibt irgendwo im Speicher rum. Mit bekanntem Resultat.
Gast #3791610
Lesenswert?

Jan-Niklas B. schrieb:
> Gut aufgepasst, aber das ist gewollt ;)

Das das Programm abstürzt? Tut es doch!


Jan-Niklas B. schrieb:
> Das Funkmodul kann nur einen Datensatz von 128 Byte pro Sendung

Und? Die Variable könnte auch 1000 Byte groß sein. Solange Du beim 
Senden nicht mehr als 128 Byte angibts, ist alles gut.
Entweder definierst Du
1
char     text[128];
und schreibst dazu passend
1
text[127]='\0';
#3791652
Lesenswert?

Exakt was DirkZ gesagt hat.
Und gleiches für folgendes:
1
destination[4]='\0';
2
type[2]='\0'

Du vereinbarst mit
1
char     type[2]=        {0};
eine Array aus 2 Chars.

Auf das erste Element greifst du mit dem Index 0 zu auf das zweite mit 1

Der Ausdruck
1
type[2]='\0'
würde auf ein drittes Element zugreifen. Das gibt es aber nicht... Der 
Speicher an dieser Stelle gehört nunmal zu jemand anderem. Dem Compiler 
ist das aber egal ... der meint du weißt was du tust, und lässt dich das 
da hinschreiben ... Resultat? undefiniertes Verhalten ...

Ich unterstell dir jetzt einfach mal, dass das nen Flüchtigkeitsfehler 
war. Ansonsten kann ich dir nur noch mal Grundlagenliteratur zum Thema 
Arrays empfehlen.
#3791924
Lesenswert?

Das mag sein, ich weiß nur leider nicht wo...ich hab inzwischen überall 
die null-terminierung eingebaut, und komischer weise stürzt er immer 
während des sendens eines Strings via Serial.println("xyz") ab... ein 
gedanke den ich momentan habe ist das ich entweder das RAM aufgebraucht 
habe oder ein Memmory-leak / segfault hab ...
Gast #3791943
Lesenswert?

Hallo Jan-Nicklas,

ich hatte auf meinem Arduino UNO unlängst möglicherweise das gleiche 
Problem. Mein Programm wurde (bei knappem SRAM Speicherplatz) durch 
Serial-Print()Befehle in einen unbeabsichtigten Reset-Zustand gebracht.

Nach längerem Studium der Beschreibungen im Internet kam ich zur 
Konklusion, dass diese Verhalten mit der Größe des Puffers im ARDUINO 
RAM zusammenhängt. Offensichtlich ist hier die Länge auf etwa 32 Zeichen 
limitiert.

Abhilfe brachte bei mir nur das "Verkürzen" der Ausgaben bzw. die 
Auslagerung einiger Texte in den Programm-Speicher.

Ich hoffe, dass dir dieser Hinweis bei Lösung deines Problems hilft.
Gast #3792343
Lesenswert?

STS schrieb:
> Hallo Jan-Nicklas,
>
> ich hatte auf meinem Arduino UNO unlängst möglicherweise das gleiche
> Problem. Mein Programm wurde (bei knappem SRAM Speicherplatz) durch
> Serial-Print()Befehle in einen unbeabsichtigten Reset-Zustand gebracht.
>
> Nach längerem Studium der Beschreibungen im Internet kam ich zur
> Konklusion, dass diese Verhalten mit der Größe des Puffers im ARDUINO
> RAM zusammenhängt. Offensichtlich ist hier die Länge auf etwa 32 Zeichen
> limitiert.
>
> Abhilfe brachte bei mir nur das "Verkürzen" der Ausgaben bzw. die
> Auslagerung einiger Texte in den Programm-Speicher.
>
> Ich hoffe, dass dir dieser Hinweis bei Lösung deines Problems hilft.

Hallo,

kann ich so bestätigen, wie geschrieben. Grudsätzlich sollten Text mit 
dem
F(...) eingebunden werden damit sie ins Flash kommen.

Aus

Serial.println("Nachricht erfolgreich an Melder: "+(String)destination+" 
gesendet!");

wird

Serial.println(F("Nachricht erfolgreich an Melder: 
")+(String)destination+ F("gesendet!"));

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren