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
>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!
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
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
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
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 | }
|
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.
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
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
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;
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
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????
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.
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
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.
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
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); }
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.