Forum: Compiler & IDEs Ist mein Mega 128 Kaputt


von Martin (Gast)


Lesenswert?

Hi

Habe seit neusten Probleme mit meinen 128iger.


Wenn ich einen Funktion Aufrufe die mir aus dem Flash was ließt und in 
eine Strucktur schreibt und diese dann abfrage und dann ein array 
abfrage dann enthält mein array nur wirres zeug.

wenn ich die struct nicht abfrage dann ist alles io.

auch auf meinen lcd display kommt manchmal wirres zeug.

Ist der Speicher defket des AVRS????

mir sieht es so aus als ob er irgendwo reinschreibt und mir meine Arrays 
und structuren überschreibt.

Ich habe alle Variablen als volatile deklariert muß ich das überhaupt.
Wann sollte ich und warum???



habe ein Interrupt der auf UART0 hört und daten davon sammelt und einen 
Timer der alle 1 sec zuschlägt. sonst keine weiteren interrupts.


Mein Project ist ein Barometer und Windmesser. Baro über SPI und 
Windmesser über UART0 Daten werden in einen Atmel Flash 16MB abgelegt.



Danke

von Gast (Gast)


Lesenswert?

>mir sieht es so aus als ob er irgendwo reinschreibt und mir meine Arrays
>und structuren überschreibt.

Ohne Quelltext kann dir nur der heilige Geist helfen.

Frohe Ostern!

von Martin (Gast)


Lesenswert?

Hallo

Also ich habe noch folgendes Problem.

im Flash speichere ich Ortsdaten folgendermaßen


$kennung;testort;plz;latitude;lontitude§kennung;testort;plz;latitude;lon 
titude#


$=Startzeichen
§=endezeichen für einzelnen Ort
#=terminierung Datensatz im Flash

hier lese ich aus

ortschaft enthält $kennung;testort;plz;latitude;lontitude§


//Inhalt meiner ort.c

typedef struct{
char kennung[10];
char testort[60];
char plz[7];
char latitude[18];
char lontitude[18];
}datensatz;

datensatz ort;


void read_ort(char *ortschaft)
{
short int zaehler;
char *pch1;
pch1=strtok_r(ortschaft,";","§");
while (pch1 != NULL)
  {
switch(zaehler)
{
case 0:
memcpy(ort.kennung,pch1+1,strlen(pch1)-1);
break;

case 1:
memcpy(ort.testort,pch1,strlen(pch1));
}
break;


case 2:
memcpy(ort.plz,pch1,strlen(pch1));
break;

case 3:
memcpy(ort.latitude,pch1,strlen(pch1));
break;

case 4:

memcpy(ort.lontitude,pch1,strlen(pch1));
}
break;

}
zaehler++;
pch1=strtok_r(NULL,";","§");
}
}


wenn ich nun die daten über die UART sende mache ich es so



char uartbuffer[528];

sprintf(uartbuffer,"Kennung:%s \r\n Ortschaft:%s \r\n PLZ:%s \r\n 
Breitengrad: %s \r\n Längengrad:%s \r\n 
Ende!",ort.kennung,ort.testort,ort.plz,ort.latitude,ort.lontitude);
send_UART1(&uartbuffer[0]);


nun bekomme ich.


Kennung:12345
Ortschaft:Teststadt
PLZ:D-233adt
latitude:51N12,876 --> und wirre ASCII Zeichen
lontitude:011E22--> wirre ASCII Zeichen


was ist da falsch????

Danke



von Roland P. (pram)


Lesenswert?

Ich wette 100%ig dass da ein Stacküberlauf passiert.

Du kommst wahrscheinlich aus der PC-Welt und machst deshalb Sachen die 
man auf einen µC besser nicht macht.

der Mega128 hat nämlich nur 4kbyte Speicher,
davon "verplemperst" du schon 528 Bytes mit dem Uartbuffer,
(rund weitere 100 gehen mit der Struct drauf)
Weiterhin verwendest du Funktionen wie sprintf und strtok (und 
vielleicht noch andere) welche schon relativ viel Ressourcen brauchen.

mach aus:
sprintf(uartbuffer,"Kennung:%s \r\n Ortschaft:%s \r\n PLZ:%s \r\n
Breitengrad: %s \r\n Längengrad:%s \r\n
Ende!",ort.kennung,ort.testort,ort.plz,ort.latitude,ort.lontitude);
send_UART1(&uartbuffer[0]);

besser:
send_UART1_P(PSTR("Kennung"));
send_UART1(ort.kennung)
send_UART1_P(PSTR(" \r\nOrtschaft:"));
...

Die SendUART1_P musst evtl neu programmieren, damit sie Konstanten vom 
pgmspace lesen kannst.

ein send_UART1("Kennung") würde nämlich schon wieder 8 Byte Ram für die 
Konstante verbrauchen, selbiges bei deinem Sprintf-Konstrukt.

Gruß
Roland

von Martin (Gast)


Lesenswert?

Hallo

Ja das ist mir jetzt klar geworden ich gebe zu ich komme aus der C# 
Welt.


über die UART ist ok ohne sprintf.

aber wie mache ich das über das Display


ich will ja formatiert die daten ausgeben.

Koordinaten z.b.

die kommen ja vom GPS anders als ich sie sehen will.

was nutze ich da ohne sprintf????

die funktion strtok_r soll ja laut forum schnell und schonend sein.

ich kann das ganze auch mit schleifen und if then aufbauen ist das 
besser????


sollte man keine structs verwenden????

Danke

von Karl H. (kbuchegg)


Lesenswert?

Warum benutzt du memcpy() wenn du mit Strings arbeitest?

Alle String Funktionen (auch sprintf()) sind darauf angewiesen,
dass jeder String mit einem '\0' Zeichen endet. Daran erkennen
sie das Ende eines Strings. Und für Strings gibt es eigene
Funktionen die das auch berücksichtigen.

Wenn du machst:
  memcpy(ort.testort,pch1,strlen(pch1));

dann wird dieses '\0' Byte nicht mitkopiert und daher steht
auch in ort.testort kein richtiger String, weil er ja nicht
mit einem '\0' Zeichen abgeschlossen wurde. Wenn irgendeine
andere stringverarbeitende Funktion sich dann ort.testort
(oder einen anderen String aus deiner Struktur) vornimmt, dann
findet sie zwar die von dir gewünschten und dort abgelegten Zeichen
aber ob und wann sie das '\0' Byte findet, dass den String anschliesst
ist zufällig und hängt vom Speicherinhalt ab, der vor der Umkopierung
in diesem Speicher stand.

Benutzte die str...() Funktionen wenn du mit Strings arbeitest.
Dafür sind sie da!
1
void read_ort(char *ortschaft)
2
{
3
  short int zaehler;
4
  char *pch1;
5
  pch1=strtok_r(ortschaft,";","§");
6
7
  while (pch1 != NULL)
8
  {
9
    switch(zaehler)
10
    {
11
      case 0:
12
        strcpy( ort.kennung, pch1+1 );
13
        break;
14
15
      case 1:
16
        strcpy( ort.testort, pch1 );
17
        break;
18
19
      case 2:
20
        strcpy( ort.plz, pch1 )
21
        break;
22
23
      case 3:
24
        strcpy( ort.latitude, pch1 );
25
        break;
26
27
      case 4:
28
        strcpy( ort.lontitude, pch1 );
29
        break;
30
    }
31
    zaehler++;
32
    pch1 = strtok_r(NULL,";","§");
33
  }
34
}

  

von Karl H. (kbuchegg)


Lesenswert?

Martin wrote:

> die funktion strtok_r soll ja laut forum schnell und schonend sein.
>
strtok hat einen gravierenden Nachteil: Es verändert den originalen
String.

> ich kann das ganze auch mit schleifen und if then aufbauen ist das
> besser????

Probiers einfach aus.

> sollte man keine structs verwenden????
Unsinn.

Du sollst:

* die str... Funktionen (strcat, strcpy, strcmp, str... ) verwenden
  wenn du mit Strings arbeitest. Also mit Byte Strömen deren letztes
  Zeichen immer ein '\0' Byte ist.

* die mem... Funktionen benutzen, wenn du mit unstrukturierten
  Byte Strömen arbeitest.

Halte dich an diese einfache Regel und du hast weniger Probleme.

von Simon K. (simon) Benutzerseite


Lesenswert?

Btw, heißt das nicht "longitude" ?

von Roland P. (pram)


Lesenswert?

Structs darfst natürlich verwenden, aber man sollte sie mit Bedacht 
einsetzen, da man eben nur 4 kb Speicher hat.

sprintf braucht hauptsächlich Flash-Speicher (ca 2 kb) das dürfte beim 
mega128 nicht so ins Gewicht fallen, da da genug Flashspeicher da ist, 
auf nem Mega8 sind aber 2kb schon 25%
Es ist dann egal ob man sie 1x oder 10x verwendet, die 2kb sind weg.
(dann aber auch sprintf_P verwenden, da sonst der Formatstring auch 
jedes mal im Ram liegt)

bei LCD Ausgabe schreib ich mir immer die entsprechenden LCD-Funktionen, 
z.B: lcd_puti(int i) schreibt einen Integer an der aktuellen 
Cursorposition, sieht dann z.B. so aus:
lcd_puts_P(PSTR("Wert: "));
lcd_puti(wert);

Gruß
Roland

von Martin (Gast)


Lesenswert?

Hallo

Ja genau das habe ich am anfang gemacht so wars auch unter Linux C++.
String mit string funktionen.

Nur einer sagt die kosten viel Resourchen und mann sollte memcpy 
vorziehen.

nun das habe ich gemacht und meine Probleme begannen.

Nur noch eine Frage zu extern und Volatile.

brauche ich die deklaration nur wenn ich eine Variable innerhalb der 
Interrupt routine ändert oder generell??

Wann benötige ich definitiv volatile und extern.


habe immer im entsprechenden header verweis folgendes


test,c


unsigned short int flag1=0;


test.h

unigned short int flag1;


oder reiocht es nur in der header die definition???


Danke

werde jetzt erstmal alles wieder umschreiben und es mit string Variablen 
probieren.


Danke


von Karl H. (kbuchegg)


Lesenswert?

Martin wrote:
> Hallo
>
> Ja genau das habe ich am anfang gemacht so wars auch unter Linux C++.
> String mit string funktionen.
>
> Nur einer sagt die kosten viel Resourchen und mann sollte memcpy
> vorziehen.

Vergiss diesen Unsinn.

Vor allem dann, wenn deine Alternative lautet:
  memcpy(ort.testort,pch1,strlen(pch1));

Es macht keinen Sinn vorher im String abzuzählen, wieviele
Zeichen da drinnen sind um dann eine Funktion aufzurufen
die möglicherweise einen Tick schneller ist, wenn

   strcpy( ort.testort, pch1 );

das alles in einem Rutsch, über alles gesehen schneller
und vor allen Dingen richtig erledigt.

Nur als Nachsatz: Korrekt wäre im obigen
  memcpy( ort.testort, pch1, strlen(pch1) + 1 );
das heist aber nicht, das es schneller wäre.

>
> nun das habe ich gemacht und meine Probleme begannen.

Siehst du.

>
> Nur noch eine Frage zu extern und Volatile.
>
> brauche ich die deklaration nur wenn ich eine Variable innerhalb der
> Interrupt routine ändert oder generell??
>
> Wann benötige ich definitiv volatile und extern.

extern und volatile haben nichts miteinander zu tun.

extern
======

Vor allem auf Desktop Systemen besteht ein Programm nicht aus
einem *.c File, sondern aus mehreren. Nun hat man auch schon mal
den Fall, dass in einem *.c File eine Variable definiert wird
auf die man auch aus einem anderen *.c File zugreifen möchte:

a.c
===
1
int Global1;
2
3
void foo()
4
{
5
  Global1 = 2;
6
}

b.c
===
1
int Global1;
2
3
void bar()
4
{
5
  Global1 = 5;
6
}

Soweit so gut. Nur funktioniert das nicht. Man kann nicht in 2
*.c Files jeweils eine Variable mit gleichem Namen benennen und
hoffen dass der Linker schon irgendwie rauskriegt, dass du damit
meinst, dass das immer dieselbe Variable sein soll (Im WinAVR
kann man das, der hat eine Erweiterung dafür. Wir reden hier aber
von Standard-C).

Die Lösung dafür ist: "extern".

b.c
===
1
extern int Global1;
2
3
void bar()
4
{
5
  Global1 = 5;
6
}

Das extern teilt dem Compiler mit, dass es sich bei Global1 um
eine Variable handelt, die wo anders definiert wurde (in a.c), er
also für diese Variable keinen Speicherplatz reservieren muss.

volatile
========

volatile schlägt in eine komplett andere Kerbe. volatile teilt
dem Compiler mit, dass er keinerlei Optimierungen auf dieser
Variable machen darf, weil sie sich auf Wegen ändert, die der
Compiler nicht einsehen kann.

Was ist das Problem?
Nun in

   i = 3;
   while( i != 5 ) {
     mach irgendwas in dem i nicht vorkommt
   }

kann der Optimizer auf die Idee kommen:
i hat vor der Schleife den Wert 3. Innerhalb der Schleife kommt
i aber nicht vor, daher kann i niemals den Wert 5 annehmen. Ergo
kann ich die Abfrage ob i den Wert 5 hat aber auch aus dem Programm
rausnehmen und einfach nur eine Endlosschleife bauen.

Nur: Dem ist nicht immer so.
Wenn es eine Interrupt Funktion gibt, die i verändert, dann kann
i sehr wohl irgendwann einmal 5 werden und die Schleife wird beendet.
Nur: Das weis der Compiler nicht und das kann er auch aus dem
bischen Quelltext, das er analysiert, nicht ersehen. Daher muss
man ihm sagen: i kann sich auf Wegen verändern, die du nicht
kennst - spar dir Optimierungen damit, denn du wirst zu falschen
Schlüssen kommen:

  volatile unsigned char i;

von Martin (Gast)


Lesenswert?

Hallo nochmal

Also meine erkenntniss ist das der SRAM überläuft.

Habe jetzt alle konstanten Strings ins Flash Kopiert und lese diese bei 
bedarf aus.

Funktioniert jetzt.

Danke

von Martin (Gast)


Lesenswert?

Hallo Nochmal

Habe ein zweites Phänomen.

Ich will debuggen

in einer Funktion will ich einen wert ausgeben short int


ich mache es so

short int lese_wert()
{
short int wert ;
wert=1200;
char temp[13];
sprintf(temp,"Wert:%d",wert);
send_UART(&temp[0]);
return wert;
}


Als ergebniss bekomme ich èÿ08.04.2007 es sollte doch WERT:1200 
erscheinen. Wo holt er das her????

von Karl H. (kbuchegg)


Lesenswert?

Martin wrote:

> short int lese_wert()
> {
> short int wert ;
> wert=1200;
> char temp[13];
> sprintf(temp,"Wert:%d",wert);
> send_UART(&temp[0]);
> return wert;
> }
>
>
> Als ergebniss bekomme ich èÿ08.04.2007 es sollte doch WERT:1200
> erscheinen. Wo holt er das her????

Schwer zu sagen. An der Funktion an sich ist erst mal so nichts
verkehrt. Solange send_UART einen char* anzeptiert und das
auch richtig macht, ist an dieser Stelle nichts erkennbar
falsch.

von Roland P. (pram)


Lesenswert?

ich vermute mal am short int, sonst siehts eigentlich ganz OK aus

aber wie gesagt, ICH würde auf sprintf verzichten.
Alternativen stehen hier
Beitrag "char und int in string umwandeln"

Gruß
Roland

von Karl H. (kbuchegg)


Lesenswert?

Roland Praml wrote:
> ich vermute mal am short int, sonst siehts eigentlich ganz OK aus
>

In dem Fall nicht.
Solange der short int nicht größer als ein int ist, gibt das
an und für sich keine Probleme, da sprintf() sowieso eine
variadische Funktion ist und alles was kleiner als int ist,
automatisch auf int hochgewandelt wird.

Mein Tip wäre eher: entweder Stackoverflow oder sonst eine
kaputter Stack durch einen Arrayoverflow irgendwo anders
im Programm.


von Roland P. (pram)


Lesenswert?

den Short-Int wird er richtig hochcasten, das stimmt.
Ich denk mal dass Martin noch die Erfahrung fehlt auf was man alles 
aufpassen muss, ich fass mal zusammen, was mir so einfällt, bzw schon 
besprochen wurde:

- Zu viel Ram-Verbrauch durch zu großzügig dimensionierte Puffer
- ... durch Strings "foobar" welche nicht mit PSTR im Flash liegen
- ... durch zu große Structs
- durch zu viele rekursive Aufrufe

- durch nicht abgeschlossene Strings. Bsp:

char test[6]
test = "foobar" // passt nicht rein, foobar brauch 7 Byte
oder eben der memcpy-Fehler

- durch zu hohen Ressourcenverbrauch (Laufzeit)
Eine "langsame" Funktion wie z.b. sprintf oder kann in einem 
Timerinterrupt schnell die ganze Rechenzeit verbrauchen.

Der GCC gibt ja normalerweise den verbrauchten statischen Ram nach dem 
Compilieren an, oder?

@Martin, poste vielleicht noch ein paar markante Codeschnipsel 
vielleicht finden wir noch ein paar Anfängerfehler. Oder du simulierst 
das Ganze mal im Avrstudio, falls möglich.

Gruß
Roland

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Mein Problem liegt wahrscheinlich bei der berechnung des Drucks.

Habe einen INTERSEMA Drucksensor

AM ANfang lese ich die Kalibrierung die ändert sich nicht fest werte im 
Sensor (Änderung nur wenn neu kalibrierung per Hardware)

alle 2 sek lese ich den druck.

IM ANhang habe ich eine Kalkulationstabelle eingefügt die das ergebniss 
zeigt.

Nur habe ich das Problem im AVR das er den Druck nicht richtig 
berechnet.

als ergebniss bekomme ich 3371 +-4 das soll 337.10mbar darstellen aber 
es sollten ja 9929 sein also 992,9mbar.

wie gesagt manchmal stimmts und dann wieder nicht.

und es kommen sogar negativ werte raus und dann denke ich kommt alles 
dureinander.

Ich hoffe man findet iregndwas.

Danke

Hier mein Code

darstellen auf dem DISPL

char druck[25];
sprintf(druck,"Druck:%d",read_press()/10);
ergebniss mal negativ werte (Sinnlose werte -12321123)
ICh sehe auch das X falsch berechnet wird x sollte so 22773 sein.
ist aber 52332.

typedef struct
{
unsigned short int c1;
unsigned short int c2;
unsigned short int c3;
unsigned short int c4;
unsigned short int c5;
unsigned short int c6;
unsigned short int dut;
}coeffizienten;

static coeffizienten coeff;




//AUSLESEN DER KALIBRIERUNG
void calc_coeffizenten(void)
{

unsigned short int word1=read_word1();
unsigned short int word2=read_word2();
unsigned short int word3=read_word3();
unsigned short int word4=read_word4();

 coeff.c1 = word1>>1;
 coeff.c2 = word3 & 0x3f;
 coeff.c2 <<= 6;
 coeff.c2 |= (word4 & 0x3f);
 coeff.c3 = word4>>6;
 coeff.c4 = word3>>6;
 coeff.c5 = word1<<10;
 coeff.c5 &= 0x400;
 coeff.c5 += word2>>6;
 coeff.c6 = word2&0x3f;
}




//LESEN DES DRUCKS

unsigned short int read_press()
{
unsigned short int temp2=0,d1=0,d2=0,ut1=0,sens=0,p=0;
short int p2=0,dut=0,off=0,x=0,temp=0;

d1=read_D1();
d2=read_D2();

ut1  = (8*coeff.c5)+20224;
dut  = d2-ut1;
coeff.dut=dut;

off  = (coeff.c2*4)+(((coeff.c4-512)*dut)/4096);
sens = coeff.c1+(((coeff.c3*dut)/1024)+24576);
x    = ((sens*(d1-7168))/16384)-off;
p    = ((x*10)/32)+(250*10);   /* pressure in 0.01 mbar  */

temp = 200+dut*(coeff.c6+50)/1024;

  //TEMP<20GRAD
  if (temp<200)
  {
  temp2=(11*(coeff.c6+24)*(200-temp)*(200-temp))/1048576;
  p2=(3*temp2*(p-3500))/15384;
  p=p-p2;
  }

  //TEMP>45 GRAD
  if(temp>450)
  {
  temp2=(3*(coeff.c6+24)*(450-temp)*(450-temp))/1048576;
  p2=(temp2*(p-10000))/8192;
  p=p-p2;
  }
  return(p);
}

von Roland P. (pram)


Lesenswert?

Hi Martin,

ich denke mal dass da Overflows passieren:
angenommen d2 = 0, d1 = 0, alle Coeffs=2


ut1  = (8*coeff.c5)+20224; // 8*2 + 20224 = 20240
dut  = d2-ut1;  // 0 - 20240 = -20240
coeff.dut=dut;  // = -20240

off  = (coeff.c2*4)+(((coeff.c4-512)*dut)/4096);
// (2*4) + ((2-512)*-20240) / 4096 =
// 8 + (-510 * -20240) / 4096 =
// 8 + 10322400 / 4096 !!! Überlauf !!!

Befasse dich mal mit AVRstudio + Simulator.
In so einem Fall nimmst dir den problematischen Code (evtl musst dein 
Programm kurz umstricken, damit er am Besten gleich am Anfang aufgerufen 
wird, oder du packst ihn in ein neues Projekt) und simulierst ihn für 
bestimmte Werte durch, dann fallen solche Fehler relativ schnell auf.
Du wirst wohl in
ich denk mal wenn du ein paar Casts auf uint32_t einbaust, müsste es 
gehen.
Alternativ oder mal zum Testen die Variablen wie folgt deklarieren:
uint32_t temp2=0,d1=0,d2=0,ut1=0,sens=0,p=0;
int32_t p2=0,dut=0,off=0,x=0,temp=0;
Mit dem Nachteil natürlich, dass manchmal mit mehr Bit gerechnet wird 
als nötig.

Gruß
Roland

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.