# Ansi C auf Mirkocontroller Variable zickt rum.



## Krumnix (3 Juli 2008)

Hallo.
Ich habe da ein sehr sehr komisches Problem.
Paar Daten:
Programmiersprache: ANSI C (NC308 (Mitsubishi)
Prozessor: M32C/83 M30833FJFP 

Problem:
Eine Variable ändert ihren Wert ohne das dazu irgendwo
eine Freigabe dazu herrscht, oder das sie sonstwo zugewiesen wird!

Hier mal die Bereiche, wo die Variable bearbeitet wird (def. nirgends wo 
anders)


```
if((Funk_Buffer[7]==32)&&(DATEN_LAENGE>18)&&(SUMME_VERSION_EMPFANGEN<2))
  {
   Befehlsname[0] = Funk_Buffer[8];
   Befehlsname[1] = Funk_Buffer[9];
   Befehlsname[2] = Funk_Buffer[10];
   Befehlsname[3] = Funk_Buffer[11];
   Befehlsname[4] = '\0';
   PROGRAMM_VERSION_BPG = atoi(Befehlsname);
   Befehlsname[0] = Funk_Buffer[13];
   Befehlsname[1] = Funk_Buffer[14];
   Befehlsname[2] = Funk_Buffer[15];
   Befehlsname[3] = Funk_Buffer[16];
   Befehlsname[4] = Funk_Buffer[17];
   Befehlsname[5] = '\0';
   //PRUEFSUMME_BPG_AKTUELL = atoi(Befehlsname);
   PRUEFSUMME_BPG_AKTUELL = 918;
   SUMME_VERSION_EMPFANGEN = 2;
  }
```
 

```
void Funk_Managment(void)
{
 unsigned char ausgabe[8];
 if(NEUES_FUNK_BPG == 1)
  {
   Funk_Daten_Senden(2);
  }
 if((NEUE_SCANNUNG_1_TYP==1)&&(NEUE_SCANNUNG_1_BPG==1))
  {
   TIMER_START[0] = 0;  // Timer zurücksetzen
   if(SUMME_VERSION_EMPFANGEN==0)
    {
     Funk_Daten_Senden(3);
     SUMME_VERSION_EMPFANGEN=1;
    }
   if(SUMME_VERSION_EMPFANGEN>=2)
    {
     if((PRUEFSUMME_BPG_AKTUELL!=Pruefnummer_Programm[Programm_Nr_Pruefung-1])||(PROGRAMM_VERSION_BPG!=Pruefversion_Programm[Programm_Nr_Pruefung-1]))
      {
       FUNKAUFTRAG_STEH_AN = 1;
       SUMME_VERSION_EMPFANGEN = 0;
      }
     if((PRUEFSUMME_BPG_AKTUELL==Pruefnummer_Programm[Programm_Nr_Pruefung-1])&&(PROGRAMM_VERSION_BPG==Pruefversion_Programm[Programm_Nr_Pruefung-1])) 
      {
       if(SUMME_VERSION_EMPFANGEN<4)
        Funk_Daten_Senden(4);
       SUMME_VERSION_EMPFANGEN = 4;
      }
     if(SUMME_VERSION_EMPFANGEN>=5)
      {
       Funk_Daten_Senden(5);
       SUMME_VERSION_EMPFANGEN = 6;
      }
     if(SUMME_VERSION_EMPFANGEN==7) 
      {
       SUMME_VERSION_EMPFANGEN=0;
       PROGRAMM_VERSION_BPG = 0;
       PRUEFSUMME_BPG_AKTUELL = 0;
      }
     if((DRUCK_STEH_AN==0)&&(FUNKAUFTRAG_STEH_AN==0))
      {
       NEUE_SCANNUNG_1_TYP=0;
       NEUE_SCANNUNG_1_BPG=0;
      }
    }
  }
  
 inttostr(AUSGABE_TEXT_1,Pruefversion_Programm[Programm_Nr_Pruefung-1]);
 inttostr(AUSGABE_TEXT_2,PROGRAMM_VERSION_BPG);
 inttostr(AUSGABE_TEXT_3,PRUEFSUMME_BPG_AKTUELL);
 inttostr(ausgabe,Pruefnummer_Programm[Programm_Nr_Pruefung-1]);
 strcat(AUSGABE_TEXT_3," - ");
 strcat(AUSGABE_TEXT_3,ausgabe);
 
 // Scannungen löschen, wenn nicht weiter gescannt wurde
 if(((NEUE_SCANNUNG_1_TYP==1)&&(NEUE_SCANNUNG_1_BPG==0))||((NEUE_SCANNUNG_1_TYP==1)&&(NEUE_SCANNUNG_1_BPG==0)))
  {
   TIMER_START[0] = 1;
  }
 if(TIMER_ENDE[0]==1)
  {
   NEUE_SCANNUNG_1_TYP=0;
   NEUE_SCANNUNG_1_BPG=0;
   TIMER_ENDE[0]=0;
   SUMME_VERSION_EMPFANGEN=0;
   PROGRAMM_VERSION_BPG = 0;
   PRUEFSUMME_BPG_AKTUELL = 0;
  }
}
```
 
Die Variable nennt sich PRUEFSUMME_BPG_AKTUELL
Da ich in der 1. Funktion sie mittlerweilen feste auf 918 gesetzt habe, 
dachte ich, sei ich das Problem los.
Aber das paradoxe daran ist, das trotz der festen Zuweisung mit der
Zahl 918, trotzdem irgendwann eine 768 darin steht. 
Und zwar immer dann, wenn SUMME_VERSION_EMPFANGEN (Ein sogenannter Schrittmerker, also der die Nummer des Aktuellen Schrittes
gespeichert hat)
den Wert 4 erreicht hat. 

Warum???? Ich verstehs einfach nicht. Absolut keinen Plan, warum die
Variable plötzlich 768 hat.

Hat jemand irgendeine Idee????? Danke


----------



## Zottel (3 Juli 2008)

Du gibst die Deklarationen nicht an!
Ohne deine Code zu lesen tippe ich darauf, daß du ein Problem dieser Art hast:

char a;
char b;
a=0;
b=3;
printf ("a ist jetzt %d",a);

gibt a ist jetzt  768 
wenn:
- a und b ohne Lücke aufeinander folgen.
- Der Prozessor little endian (Intel) Bytereihenfolge verwendet
- b im Speicher auf a folgt
Warum? 
printf ("a ist jetzt %d",a);
erwartet die Adresse eines Worts.
Das Wort steht im Speicher bei (Adresse von a) und umfaßt a UND b!
Es besethet aus dem low byte a(=0) und dem high byte b(=3) und ist daher 3*256+0 = 768.

Da du nicht printf sondern was anderes nutzt, kann ich nicht sagen, wie das wohl funktioniert. Es gibt eine Menge Möglichkeiten, solche Effekte zu erzeugen.


----------



## Krumnix (4 Juli 2008)

printf hab ich net 


```
unsigned int PRUEFSUMME_BPG_AKTUELL;     // Aktuelle Prüfsumme des Handgeräts
 
unsigned int PROGRAMM_VERSION_BPG;      // Aktuelle Programmversion im Handgerät
 
unsigned char SUMME_VERSION_EMPFANGEN;
```
 
Initialisierung:

```
PRUEFSUMME_BPG_AKTUELL = 0;
PROGRAMM_VERSION_BPG = 0;
SUMME_VERSION_EMPFANGEN = 0;
```
 
Ob der Prozessor "little endian" verwendet kann ich dir leider net sagen -.-

Aber durch das Tool MapViewer stimmt es, das beide Variablen im Speicher
direkt nacheinander allociert werden.

Nur wie kann ich das umgehen und warum wir die Variable intern auch auf
der Wert gesetzt und net nur die Anzeige?? Das sie intern darauf gesetzt
wird steht 100% fest, weil die Funktion, die auf != abfrägt plötzlich 
gestartet wird.

Gruß und erstmal Danke.
Muss mal schauen, ob ich eins der Sachen von dir nachforschen und ggf.
beseitigen kann.

Zusatz: Das Programm läuft in einer do-while schleife. Ein Abbruch der Schleife
gibt es nicht. DH. sie rennt immer wieder durch. Das ist auch Absicht.
Die Zahl wird am Anfang als 0 angezeigt. Erst, wenn die If-Bedingung das 1.
Mal erfüllt ist, ändert sich die Zahl auf 918. Danach wird sie dann auf 768
gesetzt.


----------



## Tapio Bearking (4 Juli 2008)

Hm.
Erstmal würde ich sagen, das die Big / Little Endianess bei integer auf einer 32 Bit Maschine in dem Fall nix ausmachen sollte.

Kannst du zu Debugzwecken einen Memorybreakpoint für Schreibzugriffe auf die Betreffende Stelle im Speicher einschalten?
Dann siehst du an welcher Stelle der Wert überbügelt wird.


----------



## Krumnix (4 Juli 2008)

Nein. Debuging steht mir leider nicht zur Verfügung.
Das Programm wird über RS232 übertragen, mehr geht nicht.
Das ist ja mein Problem. Wenn man es beobachten könnte, würde sich
der Fehler ja finden lassen


----------



## Tapio Bearking (4 Juli 2008)

Welchen Inhalt hat die Variable Programmversion?

Kannst du sie ändern und dann das Programm noch mal an die Stelle laufen lassen?


----------



## Krumnix (4 Juli 2008)

PROGRAMM_VERSION_BPG
Beim Start: 0
Beim Aufruf der Bedingung: 15
Beim rumzicken der anderen Variable: 15
Die ganze Zeit: 15

Beim Ende des Ablaufes: 0

Also diese macht absolut keine Probleme. Das ist ja das komische an der Sache....


----------



## Tapio Bearking (4 Juli 2008)

Kannst du testweise aus der Programmversion anstelle der 0xF eine 0x8000000F machen? Also das oberste Bit bei dem Integer setzen und dann schauen, was du in PRUEFSUMME_BPG_AKTUELL stehen hast?

Ich habe nämlich die dumpfe Vermutung, das sich 3 Byte überlappen, warum auch immer...
Wenn dem so ist, sollte etwas der Art 896 drin stehen.


----------



## Krumnix (4 Juli 2008)

Ok, hab ich gemacht.
PROGRAMM_VERSION_BPG blieb auf 15.
PRUEFSUMME_BPG_AKTUELL hatte zuerst 918 und danach 768.

Hat sich somit leider nix geändert.
Was ich aber nicht verstehe ist folgendes. 
Ich habe PRUEFSUMME_BPG_AKTUELL = 918; direkt an den Anfang der 2.
Funktion (im 1. Post) gesetzt. 
Da ging garnix mehr. Also mein KOM_PUFFER hat sich total komisch 
verhalten. Wenn ich die Variable wieder oben setze ist alles ok.

Ich verzweifle langsam total. 

Das Programm ist compaliert jetzt 140K groß. Der Speicher im Prozessor ist
256K groß. Also sollte ich noch locker drin sein.
Der Ram ist 32K groß, laut Mapviewer hab ich 14K Ram verbraucht.
Somit sind die Werte sauber. 
Aber warum zickt genau diese Variable so extrem rum -.-


----------



## Zottel (4 Juli 2008)

Tapio Bearking schrieb:


> Hm.
> Erstmal würde ich sagen, das die Big / Little Endianess bei integer auf einer 32 Bit Maschine in dem Fall nix ausmachen sollte.


Das hat nix mit 32-bit zu tun. Es darum, was rauskommt, wenn man eine Wort-Operation auf eine Byte-Adresse anwendet:
Mein Beispiel setzte ferner voraus, daß %d ein 16-Bit integer erwartet.

char a;
 char b;
 a=0;
 b=3;
 printf ("a ist jetzt %d",a);
 gibt a ist jetzt 768 

Bei gleicher Reihenfolge im Speicher würde eine Big-endian Maschine mit 16 bit integer "3" ausgeben, Während bei 32bit integer 3*65536+Inhalt der nächsten beiden Speicherzellen herauskäme.

Falls es ein Problem dieser Art ist, kannst du folgendes versuchen:

Erzeuge Lücken zwischen deinen Variablen:
int a; // eine Variable die du gebrauchst
int dummy1; // wird nie gebraucht, erzeugt nur "Abstand" im Speicher
int dummy2; // wird nie gebraucht, erzeugt nur "Abstand" im Speicher
int b; // eine Variable die du gebrauchst
int dummy3; // wird nie gebraucht, erzeugt nur "Abstand" im Speicher
int dummy4; // wird nie gebraucht, erzeugt nur "Abstand" im Speicher
Daß die Lücke jetzt 2 Variablen breit ist, ist wohl nicht nötig, schadet aber auch nicht.
Möglicherweise optimiert dir der Compiler diese Variablen weg.
Falls das passiert ist, packe irgendwo in den Code eine Zuweisung an diese:
dummy1=0;
dummy2=0;
, aber BEVOR du mit deinen eigentlichen Variablen arbeitest.

Zuletzt kannst du noch die Byte-Werte aus dem Speicher lesen, etwa so:

void dump(int count) {
 unsigned int hilfsWert;
 char * mZ =&meineErsteVariable;
 do {
 hilfsWert=*mZ;
 printf("byte %d  %04x\n",count, hilfsWert);
 mZ++;
count--;
} while (count);
}


----------



## Thomas_v2.1 (4 Juli 2008)

Hi,
werden die betroffenen Variablen evtl. in Interrupts verwendet?


----------



## Krumnix (4 Juli 2008)

Nein. Nur an den Stellen, die ich gepostet habe.

Problem ist auch noch, das ich NIX beobachten kann. 
Noch nichtmal mal ne Ausgabe steht mir zur Verfügung. Nur die RS232-Schnittstelle.
Jedoch kann ich auf der nix schicken, ohne das ich den anderen Teilnehmer
damit störe und somit eine Situation habe, die sonst nie vorkommt.
Darauf müsste ich dann ne Reaktion programmieren. Das wäre bissel
viel Aufwand 

Also die Zahl ist ein Integer und wird nirgends in einer anderen Art
behandelt, außer wie ich es gepostet habe. Bin die ganzen Dateien jetzt 3
Mal durch. Diese Aussage ist also sicher.


----------



## Thomas_v2.1 (4 Juli 2008)

Hm, ich programmiere öfters mal was auf den AVR-Controllern. Solche Phänomene kenne ich wie schon geschrieben von Interrupts die evtl. Werte verändern. Aber der AVR ist auch ein 8-Bit Controller, da sind Befehle mit 16-Bit Variablen nie atomar.

Zu dem Tip von Zottel, Fill-Variablen einzufügen kann ich dir noch einen Hinweis geben, bei diesen Variablen den Modifizierer "volatile" zu verwenden. Zumindest aktuelle der avr-gcc optimiert schon ziemlich heftig am Quellcode herum.

Hast du vielleicht eine Möglichkeit eine LED anzuschließen, oder einen freien Port-Pin zu setzen um diesen zu beobachten wenn sich die Variable vom eingestellten Wert ändert? Dann hätte einen groben Hinweis was eintreten muss damit sich der Wert ändert.


----------

