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
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.
> 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; |
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..
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.
ich hab mir auch schon überlegt einfach nicht auf null sondern so abzufragen:
1 | if(( TOut < 100 )&&(TOut > 5)) |
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.