Forum: Mikrocontroller und Digitale Elektronik Arrays weden überschrieben ATMega1280


von Jürgen P. (juergenp)


Lesenswert?

Hallo,
Ich habe einen ATMega1280 auf einem Arduino Mega Board, und programmiere 
ihn auch mit der Arduino IDE.
Bislang hat alles super geklappt, aber jetzt bin ich an einem Punkt 
angekommen, wo eine zusätzliche Lib plötzlich Arrays überschreibt. Ich 
nehme an, dass ich da irgendeine Grenze überschritten habe.
Als Info: Ich lese seriell diverse Sensoren aus, und packe alle zu einem 
großen String zusammen, den ich dann seriell im ganzen ausgebe.
Der Ausgangsstring ist dabei jetzt schon auf 902 Bytes angestiegen, 
daher die frage, ob es überhaupt sinvoll ist, die Daten erst in einem 
Ausgangsstring zusammenzufassen, und als Paket zu übertragen, oder 
einfach alle Werte einzeln zu übertragen.
Und dann die Frage, ob das überhaupt mein Problem ist.
Ich hatte auch eine Funktion zum hinzufügen einer Checksumme eingebaut, 
aber bei der war das das selbe: Wenn ich nur einen Sensor auslese, kein 
Problem. Setze ich aber alles zusammen, gehts durcheinander.
Ich hoffe, Ihr versteht mein Problem.

Danke schonmal für Anregungen!

von Karl H. (kbuchegg)


Lesenswert?

Jürgen Papadopolis schrieb:

> Als Info: Ich lese seriell diverse Sensoren aus, und packe alle zu einem
> großen String zusammen, den ich dann seriell im ganzen ausgebe.

Das kann bis zu einem gewissen Grad Sinn machen.

> Der Ausgangsstring ist dabei jetzt schon auf 902 Bytes angestiegen,

902 Bytes macht allerdings keinen Sinn mehr.

> daher die frage, ob es überhaupt sinvoll ist, die Daten erst in einem
> Ausgangsstring zusammenzufassen, und als Paket zu übertragen, oder
> einfach alle Werte einzeln zu übertragen.

Wenn du es richtig machst, kann dein Empfänger sowieso keinen 
Unterschied feststellen. Ich weiß nicht, wie die Arduino eigenen 
Übertragungsfunktionen arbeiten, aber wenn die halbwegs was taugen (und 
davon gehe ich aus), dann arbeiten die Interrupt gesteuert im 
Hintergrund, d.h. während dein Hauptprogramm den nächsten Sensor abfrägt 
und den Teilstring zusammensetzt, findet im Hintergrund die Übertragung 
des zuletzt abgefragten Sensors statt. Und ehe die fertig ist, hat dein 
Hauptprogramm schon wieder den nächsten Teil fertig, so dass es zu 
keiner Unterbrechung im Datenstrom nach aussen kommt.

> Und dann die Frage, ob das überhaupt mein Problem ist.

Das kannst nur du beantworten. Du hast 8K SRAM zur Verfügung. Wieviel 
davon vom Arduino System selbst belegt wird, kann ich nicht sagen.

> aber bei der war das das selbe: Wenn ich nur einen Sensor auslese, kein
> Problem. Setze ich aber alles zusammen, gehts durcheinander.

Kann aber auch genausogut ein Fehler in deinem Programm sein

von Volker Z. (vza)


Lesenswert?

Anregung 1 : Zeige dein Quelltext. Wir können nicht hell sehen.
Anregung 2 : Schaue in dein Map-File. Dort steht drin ob du Grenzen 
überschritten hast.
Anregung 3 : Beschreibe deinen Fehler genauer. Wo (Anfang Ende) wird was 
uberschrieben.
Anregung 4 : Gebe nur immer kleine Teile aus. z.B. jeden Sensor für 
sich.
Ergiebt einen kleinen Buffer.

von Jürgen P. (juergenp)


Lesenswert?

Also, den kompleten Code will ich euch nicht um die Ohren hauen, ist 
mittlerweile sehr umfangreich. Aber hier mal die Funktion, mit der ich 4 
Zeilen aus einem GPS auslese:
1
/*****************************************************************
2
 **                   GPS                                       **
3
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
4
 ** angeschlossenes GPS-Gerät                                   **
5
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
6
 ** Datensätzen                                                 **
7
 ****************************************************************/
8
9
char* GPS(void){                                                  
10
  // Umschalten der YB auf GPS
11
  digitalWrite(swPinS0, HIGH);
12
  digitalWrite(swPinS1, LOW);
13
GPSstart:
14
  i=0;                                                            
15
  int Zeile=0;
16
17
  while(1) {                                                      
18
    GPSin[i]=Serial.read();
19
    // Wenn Datensatz nich am Anfang eingelesen wurde nochmal 
20
    // GPS versuchen
21
    if(GPSin[0] != 36){                                           
22
      goto GPSstart;
23
    }
24
    // Wenn LF gelesen wurde, Zeile erhöhen
25
    if(GPSin[i]==10) {
26
      Zeile++;                    
27
      // Per 'GPS_Zeilen' festgelegte Anzahl von NMEA-Datensätzen auslesen      
28
      if(Zeile==GPS_Zeilen) break;
29
    }
30
    // Wenn kein Byte gelesen wird, Zähler nicht erhöhen
31
    if(GPSin[i]!=-1) i++;                                         
32
  }
33
  GPSin[i+1] = 0;
34
  //Ausgabe print hier nur zum debuggen
35
  Serial2.print(GPSin);
36
  return GPSin;
37
}

Ein Datensatz mit eingebundenen lib sieht so aus:
$GPHDT,,T*1B
$GPGGA,,,,,M,,,6
GPG,,,,NK,2C$GSA,1,,,,,,,*
$GHDT,,T*1B
$GPGGA,,,,,,0,,,,M,,M,,*66

korrekt wäre aber
$GPHDT,,T*1B
$GPGGA,,,,,,0,,,,M,,M,,*66
$GPVTG,,T,,M,,N,,K,N*2C
$GPGSA,M,1,,,,,,,,,,,,,,,*12
So kommt es auch an, wenn ich die Library rausschmeiße.
GPSin ist ein Array mit 330 Bytes. Das GPS liefert NMEA-Daten. Pro 
Datensatz kommen 82 Bytes enthalten sein, daher so groß.
Es wird auch bisher nur in der Funktion für das GPS überschriebeb, und 
nicht bei jedem Durchlauf. Jeder zweite oder dritte Datensatz kommt 
korrekt.

von Peter (Gast)


Lesenswert?

wie gross ist denn GPSin? du prüfst in der schleife nicht die länge ab, 
wenn du zu viele zeichen bekommst dann überschreibst du dir alles was 
nach GPSin im Ram liegt.

von Jürgen P. (juergenp)


Lesenswert?

Also wie gesagt, GPSin ist deklariert als
1
char GPSin[330];
Größer kann der Datensatz nicht werden, der übertragen wird.

Ich hab grade nochmal alle anderen Funktionen rausgeschmissen, und lasse 
nur das GPS auslesen. Soabal ich die Library drin habe, kommt der selbe 
Quatsch raus. Ohne ist alles super.

von Peter (Gast)


Lesenswert?

Jürgen Papadopolis schrieb:
> Größer kann der Datensatz nicht werden, der übertragen wird.

das sagst du, denn mach aber auch eine Prüfung in die schleife damit du 
bei 330 auch schluss machst.

von Jürgen P. (juergenp)


Lesenswert?

Ok, ich unterbreche die While-Schleife nun, wenn i > 330 ist. Aber das 
Problem ist damit nicht behoben.

von Karl H. (kbuchegg)


Lesenswert?

Jürgen Papadopolis schrieb:
> Also, den kompleten Code will ich euch nicht um die Ohren hauen, ist
> mittlerweile sehr umfangreich. Aber hier mal die Funktion, mit der ich 4
> Zeilen aus einem GPS auslese:

Was mit an deinem Code nicht gefällt, ist zb. dass i offenbar ein 
gloable Variablen ist. Speziell bei dem Namen i (der gerne mal für 
Schleifenzähler u. dgl. verwendet wird) steht hier Tür und Tor offen, 
dass es irgendwo anders verändert wird. Solche Variablen solltest du 
immer funktionslokal definieren um eben genau das zu verhindern. 
Grundsätzlich möchtest du die Sichtbarkeit einer Variablen soweit wie 
möglich einschränken, genau aus dem Grund um nicht den Überblick zu 
verlieren, welcher Code sich an welcher Variablen zu schaffen macht. 
Speziell wenn Interrupts ins Spiel kommen, bzw. Funktionsaufrufe über 
mehrere Hierarchiebenen gehen, dann wird das ziemlich rasch unnötig 
komplex zu durchschauen.

Auch solltest du goto vermeiden, wenn es Alternativen gibt, die 
einfacher zu durchschauen sind.
1
/*****************************************************************
2
 **                   GPS                                       **
3
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
4
 ** angeschlossenes GPS-Gerät                                   **
5
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
6
 ** Datensätzen                                                 **
7
 ****************************************************************/
8
 
9
char* GPS(void){
10
  int i = 0;
11
  int Zeile = 0;
12
13
  int Zeichen;
14
15
  // Umschalten der YB auf GPS
16
  digitalWrite(swPinS0, HIGH);
17
  digitalWrite(swPinS1, LOW);
18
19
  //
20
  // alles bis zum nächsten '$' einfach überlesen
21
  //
22
  do {
23
    Zeichen = Serial.read();
24
  } while ( Zeichen != '$' );
25
26
  //
27
  // der Anfang des nächsten NMEA Satzes wurde gefunden
28
  // ab hier Zeichensammeln, bis eine entsprechende Anzahl an Zeilen
29
  // zusammengekommen ist
30
  //
31
  GPSin[0] = Zeichen;
32
33
  while( Zeile < GPS_Zeilen && i <  sizeof(GPSin) - 1 ) {
34
    Zeichen = Serial.read();
35
    
36
    if( Zeichen != -1 ) {
37
      GPSin[i++] = Zeichen;
38
      if( Zeichen == '\n' )
39
        Zeile++;
40
    }
41
  }
42
43
  //
44
  // die Zeilen sind soweit vollständig. Den String noch abschliessen
45
  //
46
  GPSin[i] = '\0';
47
48
  Serial2.print(GPSin);
49
50
  return GPSin;
51
}

Beachte auch:

    if(GPSin[0] != 36
    if(GPSin[i]==10)

Benutze keine direkten ASCII Codes wie 36 oder 10, wenn es nicht 
notwendig ist! Du gewinnst nichts dadurch.

Bei
    if(GPSin[0] != '$'
    if(GPSin[i] == '\n')
ist es um einiges leichter zu durchschauen, was hier die Absicht ist.

von Peter (Gast)


Lesenswert?

wo kommt i überhaupt her? Ist i etwa Global? kann es sein das jemand 
anderes i noch ändert?

von Jürgen P. (juergenp)


Lesenswert?

i ist eigentlich global, wird aber in den Funktionen immer auf 0 
gesetzt. Da sollte doch nichts dazwischenfunken können innerhalb einer 
Funktion, oder? Hab jetzt mal alles ausgeschlossen, indem ich das 
Programm komplett eingedampft habe nur auf die GPS Funktion. Also wird 
auch i von sonst niemandem benutzt. Der Fehler ist trotzdem da.
Der momentan komplette Code ist:
1
#include <NewSoftSerial.h>
2
3
#define GPS_Zeilen 4                // Anzahl zu lesender GPS NMEA-Datensätze
4
5
char GPSin[330];
6
int i;
7
8
int swPinS0 = 26;
9
int swPinS1 = 27;
10
int WLANreset = 48;
11
int SerialCommandMode = 49;
12
int SerialACT = 51;
13
14
15
NewSoftSerial Wind(50,60);
16
17
void setup() { 
18
  
19
  Serial.begin(19200);                 // INC / GPS
20
  Serial2.begin(19200);                // RS232 OUT
21
  Wind.begin(4800);                    // Windmuehle über SoftSerial
22
  
23
  pinMode(swPinS0, OUTPUT);            // SchaltPins fuer Umschaltung INC/GPS ueber HTC4052
24
  pinMode(swPinS1, OUTPUT);            // "
25
  pinMode(SerialCommandMode, OUTPUT);  // SchaltPin fuer WLAN-Modul CommandMode
26
  pinMode(SerialACT, OUTPUT);          // LED Ansteuerung SerialAct
27
  pinMode(WLANreset, OUTPUT);          // WLAN-Modul Reset-Pin
28
}
29
30
/*****************************************************************
31
 **                   GPS                                       **
32
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
33
 ** angeschlossenes GPS-Gerät                                   **
34
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
35
 ** Datensätzen                                                 **
36
 ****************************************************************/
37
38
char* GPS(void){                                                  
39
  // Umschalten der YB auf GPS
40
  digitalWrite(swPinS0, HIGH);
41
  digitalWrite(swPinS1, LOW);
42
GPSstart:
43
  i=0;                                                            
44
  int Zeile=0;
45
46
  while(1) {                                                      
47
    GPSin[i]=Serial.read();
48
    // Wenn Datensatz nich am Anfang eingelesen wurde nochmal 
49
    // GPS versuchen
50
    if(GPSin[0] != 36){                                           
51
      goto GPSstart;
52
    }
53
    // Wenn LF gelesen wurde, Zeile erhöhen
54
    if(GPSin[i]==10) {
55
      Zeile++;                    
56
      // Per 'GPS_Zeilen' festgelegte Anzahl von NMEA-Datensätzen auslesen      
57
      if(Zeile==GPS_Zeilen) break;
58
    }
59
    // Wenn kein Byte gelesen wird, Zähler nicht erhöhen
60
    if(GPSin[i]!=-1){
61
    i++;
62
    if (i >330) break;}   
63
  }
64
  GPSin[i+1] = 0;
65
  //Ausgabe print hier nur zum debuggen
66
  Serial2.print(GPSin);
67
  return GPSin;
68
}
69
70
/****************************************************************
71
 *                             MAIN                             *
72
 ***************************************************************/
73
74
void loop(){
75
  
76
    digitalWrite(SerialCommandMode, HIGH);
77
    digitalWrite(WLANreset, LOW);
78
    GPS();
79
}

von Karl H. (kbuchegg)


Lesenswert?

Jürgen Papadopolis schrieb:
> i ist eigentlich global, wird aber in den Funktionen immer auf 0
> gesetzt. Da sollte doch nichts dazwischenfunken können innerhalb einer
> Funktion, oder?

Tus trotzdem nicht.
Eine Variable mit dem Namen i macht man nicht global. Das schreit 
förmlich nach schwer zu findenden Fehlern. Und geh besser nicht davon 
aus, dass du nie Fehler machst.

von Peter (Gast)


Lesenswert?

Jürgen Papadopolis schrieb:
> ist eigentlich global, wird aber in den Funktionen immer auf 0
> gesetzt. Da sollte doch nichts dazwischenfunken können innerhalb einer
> Funktion, oder?

doch, wir wissen ja nicht was in Serial.read() passiert, vielleicht 
verwendest du dort auch i.

von Jürgen P. (juergenp)


Lesenswert?

Ja, hab ich auch grade drüber nachgedacht, und alle i durch GPS_i 
ersetzt...Leider ohne Erfolg.
Ich tippe langsam darauf, dass die Lib NewSoftSerial irgendwie 
fehlerhaft ist.
Ich weiß nicht, wie weit Ihr Euch mit der Arduino-Umgebung und den Libs 
auskennt. Hatte vorher die SoftwareSerial drin, die über einen Digital 
i/o Pin einen UART simuliert. Das ging auch ganz gut, bis ich den Sensor 
daran ersetzen musste, und die Funktion nur Müll lieferte. Ich schätze, 
dass framing stimmte damit nich mehr. Die NewSoftSerial funktioniert für 
sich alleine eigentlich super, aber scheinbar macht sie doch irgendwie 
ärger... Son mist!

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.