www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Arrays weden überschrieben ATMega1280


Autor: Jürgen Papadopolis (juergenp)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Volker Zabe (vza)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen Papadopolis (juergenp)
Datum:

Bewertung
0 lesenswert
nicht 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:
/*****************************************************************
 **                   GPS                                       **
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
 ** angeschlossenes GPS-Gerät                                   **
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
 ** Datensätzen                                                 **
 ****************************************************************/

char* GPS(void){                                                  
  // Umschalten der YB auf GPS
  digitalWrite(swPinS0, HIGH);
  digitalWrite(swPinS1, LOW);
GPSstart:
  i=0;                                                            
  int Zeile=0;

  while(1) {                                                      
    GPSin[i]=Serial.read();
    // Wenn Datensatz nich am Anfang eingelesen wurde nochmal 
    // GPS versuchen
    if(GPSin[0] != 36){                                           
      goto GPSstart;
    }
    // Wenn LF gelesen wurde, Zeile erhöhen
    if(GPSin[i]==10) {
      Zeile++;                    
      // Per 'GPS_Zeilen' festgelegte Anzahl von NMEA-Datensätzen auslesen      
      if(Zeile==GPS_Zeilen) break;
    }
    // Wenn kein Byte gelesen wird, Zähler nicht erhöhen
    if(GPSin[i]!=-1) i++;                                         
  }
  GPSin[i+1] = 0;
  //Ausgabe print hier nur zum debuggen
  Serial2.print(GPSin);
  return GPSin;
}

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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen Papadopolis (juergenp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wie gesagt, GPSin ist deklariert als
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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen Papadopolis (juergenp)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
/*****************************************************************
 **                   GPS                                       **
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
 ** angeschlossenes GPS-Gerät                                   **
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
 ** Datensätzen                                                 **
 ****************************************************************/
 
char* GPS(void){
  int i = 0;
  int Zeile = 0;

  int Zeichen;

  // Umschalten der YB auf GPS
  digitalWrite(swPinS0, HIGH);
  digitalWrite(swPinS1, LOW);

  //
  // alles bis zum nächsten '$' einfach überlesen
  //
  do {
    Zeichen = Serial.read();
  } while ( Zeichen != '$' );

  //
  // der Anfang des nächsten NMEA Satzes wurde gefunden
  // ab hier Zeichensammeln, bis eine entsprechende Anzahl an Zeilen
  // zusammengekommen ist
  //
  GPSin[0] = Zeichen;

  while( Zeile < GPS_Zeilen && i <  sizeof(GPSin) - 1 ) {
    Zeichen = Serial.read();
    
    if( Zeichen != -1 ) {
      GPSin[i++] = Zeichen;
      if( Zeichen == '\n' )
        Zeile++;
    }
  }

  //
  // die Zeilen sind soweit vollständig. Den String noch abschliessen
  //
  GPSin[i] = '\0';

  Serial2.print(GPSin);

  return GPSin;
}

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.

Autor: Peter (Gast)
Datum:

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

Autor: Jürgen Papadopolis (juergenp)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <NewSoftSerial.h>

#define GPS_Zeilen 4                // Anzahl zu lesender GPS NMEA-Datensätze

char GPSin[330];
int i;

int swPinS0 = 26;
int swPinS1 = 27;
int WLANreset = 48;
int SerialCommandMode = 49;
int SerialACT = 51;


NewSoftSerial Wind(50,60);

void setup() { 
  
  Serial.begin(19200);                 // INC / GPS
  Serial2.begin(19200);                // RS232 OUT
  Wind.begin(4800);                    // Windmuehle über SoftSerial
  
  pinMode(swPinS0, OUTPUT);            // SchaltPins fuer Umschaltung INC/GPS ueber HTC4052
  pinMode(swPinS1, OUTPUT);            // "
  pinMode(SerialCommandMode, OUTPUT);  // SchaltPin fuer WLAN-Modul CommandMode
  pinMode(SerialACT, OUTPUT);          // LED Ansteuerung SerialAct
  pinMode(WLANreset, OUTPUT);          // WLAN-Modul Reset-Pin
}

/*****************************************************************
 **                   GPS                                       **
 ** Umschalten eines UART-Kanals über HCT4052 auf ein           **
 ** angeschlossenes GPS-Gerät                                   **
 ** Auslesen der über GPS_Zeilen vorgegebenen Anzahl an NMEA-   **
 ** Datensätzen                                                 **
 ****************************************************************/

char* GPS(void){                                                  
  // Umschalten der YB auf GPS
  digitalWrite(swPinS0, HIGH);
  digitalWrite(swPinS1, LOW);
GPSstart:
  i=0;                                                            
  int Zeile=0;

  while(1) {                                                      
    GPSin[i]=Serial.read();
    // Wenn Datensatz nich am Anfang eingelesen wurde nochmal 
    // GPS versuchen
    if(GPSin[0] != 36){                                           
      goto GPSstart;
    }
    // Wenn LF gelesen wurde, Zeile erhöhen
    if(GPSin[i]==10) {
      Zeile++;                    
      // Per 'GPS_Zeilen' festgelegte Anzahl von NMEA-Datensätzen auslesen      
      if(Zeile==GPS_Zeilen) break;
    }
    // Wenn kein Byte gelesen wird, Zähler nicht erhöhen
    if(GPSin[i]!=-1){
    i++;
    if (i >330) break;}   
  }
  GPSin[i+1] = 0;
  //Ausgabe print hier nur zum debuggen
  Serial2.print(GPSin);
  return GPSin;
}

/****************************************************************
 *                             MAIN                             *
 ***************************************************************/

void loop(){
  
    digitalWrite(SerialCommandMode, HIGH);
    digitalWrite(WLANreset, LOW);
    GPS();
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen Papadopolis (juergenp)
Datum:

Bewertung
0 lesenswert
nicht 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!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.