Forum: Mikrocontroller und Digitale Elektronik AT89C51 Reboot & zerschossene Variablen?


von Patrick (Gast)


Lesenswert?

Hallo,

ich hab folgendes Problem mit einem uC Atmel AT89C51.

Zur Vorgeschichte:

In der Software (Keil) gibt es eine Funktion die einen Zähler TOut auf 0 
überprüft und dann einen Fehler ausgibt.

if(!TOut)
{
 bPosFehler=1;
}

Während dem normalen Programmablauf wird der Zahler immer wieder auf 
10000 gesetzt und mit dem Timer ISR dekrementiert

Wie sich bei der Softwar Analyse gezeigt hat wurde jedoch durch einen 
Programm Fehler die Bedingung falsch gesetzt, so dass TOut nie 0 werden 
kann.

Leider und dass ist nun der Fehler tritt der Zustand scheinbar trotzdem 
während es normales Betriebs sporadisch auf und der Fehler bPosFehler 
wird gemeldet.

Mein Ansatz ist nun der dass ich Annehme das der uC während des Betriebs 
zb. durch eine (EMC, Spikes) Störung „abstürzt“ oder zumindest Variablen 
den Wert 0 annehmen und so trotz dass die Bedingung nicht erfüllt wurde 
der Fehler ausgelöst wird da zb. TOut null ist.

Lt Handbuch von Atmel gibt es im uC einen Power Monitor der im Falle 
wenn die Spg. einbricht einen Reset auslöst.

Ist ein solches Ereignis denkbar und wie könnte ich dem auf die Schliche 
kommen. Ein normaler Programmstart nach einem WD Reset scheidet 
eigentlich aus da dann alle Variablen zuerst initialisiert werden.

Gruss Patrick

von Peter II (Gast)


Lesenswert?

Patrick schrieb:
> Ist ein solches Ereignis denkbar und wie könnte ich dem auf die Schliche
> kommen.

viel wahrscheinlicher ist ein Programmierfehler wo der speicher 
überschrieben wird.

von Jim M. (turboj)


Lesenswert?

> Ist ein solches Ereignis denkbar

Denkbar: Ja. Aber dann ist Deine Spannungsversorgung 
überarbeitungsbedürftig, und auf einem Oszilloskop würde man den 
Einbruch der Spannung leicht erkennen.

> Während dem normalen Programmablauf wird der Zahler immer wieder auf
> 10000

Was bedeutet, dass er vom Typ int und damit länger als ein Byte ist. 
Dann ist der Zugriff nicht-atomar. Damit kann die 0x0000 auftreten, wenn 
der Interrupt zufällig genau zwischen den 2 Schreibvorgägen auftritt. 
Nämlich genau dann wenn von 256 (0x0100) auf 255 (0x00FF) dekrementiert 
wird. Dann schreibt er zuerst das High-Byte (0x00) während das Low Byte 
ebenfalls 0x00 ist. Danach würde er das 0xFF in das Low Byte schreiben - 
kommt aber der Interrupt dazwischen, dann sieht die Routine ein 0x0000 
in der Variablen.

Einfache Abhilfe: Interrupts temporär verbieten.
1
EA = 0;
2
TOut--;
3
EA = 1;

von Patrick (Gast)


Lesenswert?

also Tout ist xdata unsigned short

hier wird runter gezählt :

void timer0Int (void) interrupt 1 using 2
{
..

if(TOut)TOut--;


dass ggf. ein Zustand auftritt der durch die ISR unterbrochen wird 
klingt plausibel. Jedoch tritt das Verhalten extrem selten auf, im Labor 
quasi nie..

von Karl H. (kbuchegg)


Lesenswert?

Jim Meba schrieb:

> Einfache Abhilfe: Interrupts temporär verbieten.
>
1
EA = 0;
2
> TOut--;
3
> EA = 1;

Das reicht nicht.
Da das 'Problem' hier entsteht (enstehen kann)

   if(!TOut)

muss es auch hier behoben werden.
Tout muss unter Interrupt-Sperre ausgelesen werden.

von Patrick (Gast)


Lesenswert?

also so?

1
EA = 0;
2
 if(!TOut)
3
EA = 1;

von Patrick (Gast)


Lesenswert?

ich hab mir auch schon überlegt einfach nicht auf null sondern so 
abzufragen:
1
if(( TOut < 100 )&&(TOut > 5))

von Karl H. (kbuchegg)


Lesenswert?

Patrick schrieb:
> also so?
>
>
>
1
> EA = 0;
2
>  if(!TOut)
3
> EA = 1;
4
>

nicht ganz.
Wenn du es dir leisten kannst, die Interrupts mal etwas länger als 
minimal notwendig gesperrt zu haben
1
  EA = 0;
2
  if(!TOut)
3
    bPosFehler=1;
4
  EA = 1;


> ich hab mir auch schon überlegt ....
> if(( TOut < 100 )&&(TOut > 5))

Und? Was bringt dir das? Wenn der Interrupt zum falschen Zeitpunkt 
zuschlägt, vergleichst du wieder eine Zahl, die mit dem eigentlichen 
Inhalt von TOut nichts zu tun hat.

von Wilhelm F. (Gast)


Lesenswert?

Patrick schrieb:

> also so?

Ja, fast. Freigabe am besten wieder hinter dem If-Block, denn sonst 
bleiben die Interrupts für immer gesperrt, wenn die If-Bedingung nicht 
eintritt.

Im Interrupt selbst muß man natürlich nichts ändern, wenn dieser nicht 
noch von einem anderen Interrupt durchbrochen wird, wo die Variable auch 
verwendet wird.

Man kann natürlich überlegen, Interrupts nicht global zu sperren, 
sondern nur den betreffenden Interrupt.

von Peter D. (peda)


Lesenswert?

1
void timer0Int (void) interrupt 1
2
{
3
  if(TOut != 128)
4
    TOut--;
5
}
6
// und
7
  if( Tout == 128 )

Dann ist das High-Byte beim Test stabil.

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.