Forum: Mikrocontroller und Digitale Elektronik Arduino: Arduino startet mitten im Code neu


von Jan-Niklas B. (janniklas_b)


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

von Mark B. (markbrandis)


Lesenswert?

1
char     destination[3];
2
dest = atoi(destination);              //Hier steigt der Arduino aus

destination muss nullterminiert sein. Probier mal vor dem Aufruf von 
atoi() das hier:

destination[2] = '\0';

von Gs S. (gs-scarnight)


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.

von DirkZ (Gast)


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 };

von Kirkenes (Gast)


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!?

von DirkZ (Gast)


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.

von Jan-Niklas B. (janniklas_b)


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?

von DirkZ (Gast)


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.

von Jan-Niklas B. (janniklas_b)


Lesenswert?

Gut aufgepasst, aber das ist gewollt ;)
Das Funkmodul kann nur einen Datensatz von 128 Byte pro Sendung 
übertragen, desswegen lasse ich es dabei, somal der Text von meiner 
ansteuerungssoftware eh auf 100 Zeichen begrenzt wird.

von DirkZ (Gast)


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';

von Bernhard F. (bernhard_fr)


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.

von Jan-Niklas B. (janniklas_b)


Lesenswert?

Okay,dass war wohl wirklich eigene Dummheit -.-
Das Arrays 0 indexiert sind ist mir eigentlich bekannt, aber irgendwie 
hab ich da nicht dran gedacht...ich baus mal ein und mal schauen ob es 
dann läuft...
Danke für die HInweise

von Jan-Niklas B. (janniklas_b)


Lesenswert?

Hmm... immernoch das selbe verhalten wie vorhin beschrieben...

von Jan-Niklas B. (janniklas_b)


Lesenswert?

Kann man irgendwie alle Speicher des Arduino einmal löschen?
Er hat mir grade auf den Befehl hin einen Buchstabensalat mit Fragmenten 
von alten Codes rausgegeben...

von Mark B. (markbrandis)


Lesenswert?

Du schreibst irgendwo über die Grenzen eines Arrays hinaus, jede Wette. 
Bzw. Du liest etwas was nicht (richtig) nullterminiert ist. Irgendwo im 
Speicher kommt mal wieder eine Null, und bis dahin kommt halt Grütze bei 
raus. ;-)

: Bearbeitet durch User
von Jan-Niklas B. (janniklas_b)


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 ...

von DirkZ (Gast)


Lesenswert?

Jan-Niklas B. schrieb:
> Kann man irgendwie alle Speicher des Arduino einmal löschen?
> Er hat mir grade auf den Befehl hin einen Buchstabensalat mit Fragmenten
> von alten Codes rausgegeben...

schick mal den aktuellen Programmcode

von STS (Gast)


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.

von Christian J. (Gast)


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!"));

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.