AT89C51 Reboot & zerschossene Variablen?

Gast #3155432
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
#3155456
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;
Gast #3155487
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..
#3155547
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.
Gast #3155562
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren