-
der "Data: 1366 bytes (66.7% Full) " bereich wird vom flash gleich zu beginn des Programms in der RAM geladen (soweit ich weiß).
Wenn der Stack nun zu groß wird (was leicht vorkommen kann, vor allem bei verschachtelten Funktionen) dann kann es leicht sein, dass der Daten-Teil und der Stack sich treffen, und dann werden die Rücksprungadressen der Funktionen möglicherweise mit Daten überschrieben, und dann kommt der Controller in Teufels Küche.
Versuch einen pin-kompatiblem Controller mit mehr Ram zu verwenden (z.B. ATmega64 oder 644) und du solltest keine Probleme mehr damit haben.
Gruß, Yaro
-
Das mit dem Stack ist in der Tat eine Möglichkeit. Allerdings sind ja noch ~400 Byte im RAM frei. Gehen wir mal davon aus, das bei jedem Funktionsaufruf alle 32 Register auf den Stack geschaufelt werden (was nicht der Fall sein dürfte, aber egal). Zusätzlich noch durchschnittlich 4 Byte Funkionsparameter. Macht 36 Byte pro Verschachtelungsebene. 400/36 ~ 11. Ob eine Software tatsächlich so oft eine Unterfunktion aufrufen kann, sollte man schon abschätzen können als Programmierer. Für einen Controller wäre das durch einiges.
Verwendest du malloc oder ähnliches?
Wenn ich mit solchen Problemen konfrontiert bin, sind sämtliche verwendeten Pointer das erste was ich prüfe. Dabei gibt es ein paar Möglichkeiten:
- Array Zugriffe über die Array Grenzen hinaus?
- Pointer versehentlich zu weit erhöht?
- Bei String bearbeitenden Funktionen den Buffer evtl. doch nicht ausreichend dimensioniert?
Auch beliebt: Über/Unterläufe irgendwelcher Variablen, die dann zu den genannten Fehlern führen können.
Was ich auch schon hatte: Versehentlich einen externen Interrupt aktiviert, obwohl der zugehörige Pin nicht beschalten war. Das ging - zumindest fast immer. So lange bis die Spannung durch irgendwelchen eingefangenen Müll mal wieder einen Interrupt ausgelöst hat und der Controller ins Nirvana gesprungen ist. Da stand ich kurz vor einem Nervenzusammenbruch ;)
-
Ich hab das Program etwas optimiert, braucht jetzt "nur" mehr 1350 Bytes Daten.
Zusätzlich habe ich mir im laufenden Betrieb den freien Speicher anzeigen lassen, es waren immer mehr als 500 Bytes frei. Ist auch realistisch, da der Großteil schon in den 1350 Bytes enthalten ist, und in den Funktionen je 3-15 Byte dazukommen.
Die Funktionen sind nicht extrem verschachtelt, ich komme auf 5 Ebenen. Davon einige inline, also 4 Ebenen?
malloc wird nicht verwendet.
Array passt, ich verwende ja ein sehr großes für die Navigation und das wurde ausreichend überprüft.
Buffer für Stringfunktionen werde ich überprüfen.
Momentan hab ich den Fehler ja nicht, aber ich will das Program noch erweitern, und bisher hatte ich für solche Fehler noch keine nachvollziehbare Ursache gefunden, deshalb danke für alle Ideen die mir in Zukunft weiterhelfen.
Ich werde auch versuchen ob ich den Fehler von vorgestern mit der Drehzahlregelung reproduzieren kann.
LG!
-
Hallo,
ich hatte auch mal so ein Phänomen. Aber mein Programm war komplett in Assembler. Und die Lösung war, dass ich einen PUSH/POP des Statusregisters in einer Interrupt-Routine vergessen habe.
Viele Grüße
Andreas
-
So, konnte den Fehler wieder hervorufen:
Das ist der normale Code der Wartefunktion
Code:
void Warten()
{
timecount=0;
while (1) { if (timecount>=50) break;}
}
und hier ist die Drehzahlüberprüfung eingebaut:
Code:
void Warten()
{
char x;
timecount=0;
x=0;
while (x<2)
{ if (timecount>=25)
{Messercheck();x++;}
}
}
(immer alle 0.25s, wie auch sonst im Programm)
Der Robi führt die ersten 5 Sekunden richtig aus = blinken einer Led nach dem einschalten mit dieser Wartefunktion.
Danach soll er auf GPS Empfang warten und zeigt dabei GPS Status, Uhrzeit und Datum an, erst wenn ein guter Empfang da ist werden die Motoren gestartet.
Dabei hängt er sich auf, mal kommt er noch dazu Uhrzeit und Datum anzuzeigen, meistens kommt aber nur die Überschrift "Warten auf GPS" und es wird kein GPS Signal ausgewertet oder angezeigt. Oder die Uhrzeit udn Status ändern sich nicht mehr, daher sicher keine richtige Ausführung des Programmes mehr.
In dieser Phase wird weder die Wartefunktion noch der Messercheck verwendet, die Wartefunktion wie gesagt nur vorher fürs blinken der LED.
Messercheck ist als static inline definiert, wird schon oft im Programm verwendet, und ich hab es gerade an noch einer anderen Stelle im Programm eingefügt ohne dass es den normalen Ablauf stört.
Warum stört es also ausgerechnet hier den kompletten Programmablauf und an anderer Stelle nicht?
LG!
-
1) wo wird timecount erhöht? In einem Interrupt? Poste diesen mal.
2) Er hängt sich also auf, wenn die Motoren gestartet werden, richtig? versuch mal die motoren von der Versorgungsspannuung wegzunehmen. Es könnte sein, dass sie einen zu hohen Stromstoß verursachen, der den Controller kurzzeitig den Saft wegnimmt.
3) überprüfe nochmal alle Pointer und Arrays... Ich hatte auch schonmal ähnlich mystische Probleme, die durch einen Array-Überlauf verursacht wurden.
Gruß, Yaro
-
Das riecht alles wahnsinnig nach Zeiger. Du glaubst gar nicht wie oft ich schon festgestellt habe, das meine Programme bisher mehr durch Zufall als durch durchdachten Code funktioniert haben ;)
Kannst du evtl. doch mal den gesamten Code (als Anhang) posten? Vielleicht fällt jemandem etwas auf. Mit der Zeit wird man ja für seine eigenen Fehler absolut blind. Und ich fürchte nur anhand einiger Codeschnipsel wird den Fehler niemand finden. Der sitzt wo anders.
-
Hier der Code für den Interrupt:
Code:
volatile unsigned char timecount;
ISR(TIMER2_COMP_vect)
{timecount++;}
/*+++++++Timer2++++++++++++++++*/
TCCR2 = (1<<WGM21) | (1<<CS20) | (1<<CS21) | (1<<CS22); // CTC Mode, Prescaler 1024
TIMSK = (1<<OCIE2);
OCR2=154;
Er hängt schon lange bevor die Motoren gestartet werden, da er es nicht mal schafft den GPS Empfang abzuwarten, bzw man merkt das er hier hängt da oft nicht mal die Uhrzeit akutalisiert oder gar angezeigt wird (aus Funktion Datum).
Das "Warte GPS" kommt immer.
Es ist diese Schleife:
Code:
//***********************GPS Kalibrierung ****************************
void GPS_kalib()
{
char x;
char buffer[10];
lcd_clrscr();
lcd_gotoxy(0,0);lcd_puts_p(PSTR(" Warte GPS"));
timecount=0;x=0;
while (gps<5) // auf Empfang warten
{
GPS();
rand(); // damit Zufall zufälliger wird, unbestimmt oft aufrufen
if (timecount >=25)
{timecount=0;
Zeitnehmung();
itoa(gps,buffer,10);lcd_gotoxy(11,0);lcd_puts(buffer); // Anzeige GPS Daten nach Bedarf
lcd_gotoxy(13,0);lcd_puts(gpsstatus);
itoa(hd,buffer,10);lcd_gotoxy(15,0);lcd_puts(buffer);
itoa(satcount,buffer,10);lcd_gotoxy(19,0);lcd_puts(buffer);
Datum();
}
}
}
Die restlichen Funktionen dazu:
Variablen die hier nicht deklariert sind, sind global.
Code:
static inline void Zeitnehmung()
{
static char zeit_alt,zaehler;
short temp;
char zeit_t;
temp=atoi(zeit);
zeit_t=(char)(temp-(temp/100)*100);// Stunden rauswerfen
if ((zeit_t>zeit_alt)) {zaehler++; zeit_alt=zeit_t;} // Änderung bei Minuten erkennen
if ((zeit_t==0)&&(zeit_alt!=1)) {zaehler++;zaehler++; zeit_alt=1;}
if (zaehler>=5) {zaehler=0;arbeitsstunden++;}//zaehler_x++;}
}
/************************* GPS++++++++++++++++++++++++++++++++++++++*/
static inline void GPS()
{
char x_gps;
x_gps=0;
x_gps=USART_Receive();
if (x_gps=='$')
{
Getgps(',');
if(strcmp(line,"GPGGA")==0) Gps_gga();
if(strcmp(line,"GPGLL")==0) Gps_gll();
if(strcmp(line,"GPZDA")==0) Gps_zda();
}
}
/***************Position vom GPS***********************/
static inline unsigned char Getgps(unsigned char end)
{
unsigned char c,i;
char komma, stern;
komma = ',';
stern = '*';
line[0]=0;
i=0;
c=0;
do
{
c=USART_Receive();
if(c==stern) return 0;
if(c==komma) return i;
if(c!=end) //Buchstaben sammeln
{
line[i]=(char)c;
i++;
line[i]=0; //End of String updaten
}
}while(c!=end);
return i;
}
void Gps_gga() //$GPGGA Meldung -----------------------------------------
{
char num, hdop;
char komma;
short x,y;
komma = ',';
x=0;y=0;hdop=9;
satcount=0; //Anzahl benutzter Satelliten
num=0;
// Uhrzeit
Getgps('.'); strcpy(zeit,line); zeit[4]=0;// Sekunden raus
Getgps(komma);
Getgps('.');
num=Getgps(komma);
if(num!=0) {line[4]=0;y=atoi(line);}
Getgps(komma);
Getgps('.');
num=Getgps(komma);
if(num!=0) {line[4]=0;x=atoi(line);}
Getgps(komma);
// //0=kein Empfang, 1=GPS, 2=DGPS
num=Getgps(komma);
//Anzahl benutzter Satelliten
num=Getgps(komma);
if(num!=0) { satcount=(unsigned char)atoi(line); }
Getgps('.');
hdop=(char)atoi(line);
hd= hdop; // für LCD
// nur wenn Empfang gut ist die aktuellen Koordinaten verwenden
if (satcount>=4)
{
gps=1; // globale Anzeige
x=(x-8534);
y=(y-3388);
x=(x*13);// Auflösung auf 1cm hochrechnen
y=(y*19)-250;
if (hdop<=1) gps=5;
if (hdop>=4) gps=0;
if (x<0) x=0;
if (x>2300) x=2300;
if (y<0) y=0;
if (y>4200) y=4200;
pos_x_gps_akt=x;
pos_y_gps_akt=y;
}
else gps=0; // zurücksetzen
}
void Gps_gll() //$GLL Meldung -----------------------------------------
{
char num,komma;
komma = ',';
Getgps(komma);
Getgps(komma);
Getgps(komma);
Getgps(komma);
Getgps(komma);
num=Getgps(komma);
if (num!=0)
{strcpy(gpsstatus,line);
}
}
void Gps_zda() //$zda Meldung +Wochentagberechnung -----------------------------------------
{
char num,komma, tag, monat, jahr;
short jahrx,xx;
komma = ',';
tag=0;monat=0;jahr=0;jahrx=0;
Getgps(komma); //zeit
num=Getgps(komma);
if(num!=0) { tag=(char)atoi(line); }
num=Getgps(komma);
if(num!=0) { monat=(char)atoi(line); }
num=Getgps(komma);
if(num!=0) { jahrx=(short)atoi(line); jahr=(char)(jahrx-2000);}
if (monat<3) {monat=monat+12;jahr--;}
xx=(tag+((monat+1)*26)/10+jahr+jahr/4-35);// http://de.wikipedia.org/wiki/Zellers_Kongruenz
num=xx/7;
wochentag=xx-num*7;
}
void Datum() //-------------------------------------------------------------------
{
char buffer[10];
short temp;
lcd_gotoxy(0,1);
switch (wochentag) // http://de.wikipedia.org/wiki/Zellers_Kongruenz
{ case 0: lcd_puts_p(PSTR("Samstag"));break;
case 1: lcd_puts_p(PSTR("Sonntag"));break;
case 2: lcd_puts_p(PSTR("Montag"));break;
case 3: lcd_puts_p(PSTR("Dienstag"));break;
case 4: lcd_puts_p(PSTR("Mittwoch"));break;
case 5: lcd_puts_p(PSTR("Donnerstag "));break;
case 6: lcd_puts_p(PSTR("Freitag"));break;
}
strcpy(buffer,zeit);
buffer[2]=0;
stunden=atoi(buffer);
temp=atoi(zeit)-stunden*100;
minuten=(char)temp;
stunden++;stunden++;// Sommerzeit
if (stunden>=24) stunden=stunden-24;
itoa(stunden,buffer,10);lcd_gotoxy(11,1);lcd_puts(buffer);lcd_gotoxy(13,1);lcd_putc('h');
itoa(minuten,buffer,10);lcd_gotoxy(14,1);lcd_puts(buffer);
}
LCD Bibliothek ist von Fleury.
Ich hatte schon mal so eine ähnliche Situation wo eine If Abfrage alles zum Absturz brachte und das konnte ich umgehen, aber die fehlende Drehzahlregelung in der Wartefunktion ist ein echter Nachteil.
LG!
-
Ohne vollständigen Code kann man ja nur Raten, aber beim Überfliegen ist mir gleich folgendes aufgefallen:
Code:
do
{
c=USART_Receive();
if(c==stern) return 0;
if(c==komma) return i;
if(c!=end) //Buchstaben sammeln
{
line[i]=(char)c;
i++;
line[i]=0; //End of String updaten
}
}while(c!=end);
i wird nicht überwacht. Fehler auf der UART Seite -> Array kann Überlaufen. Sowas kann dir schon passieren wenn der Controller mal zu lange in einem Interrupt braucht und das entscheidente UART Zeichen verpasst wird!
-
Danke! Habs sofort eingebaut.
LG!