-
Problem mit Interrupt
Guten Tag!
Ich arbeite gerade an einer Schaltung die Akkus bis zu einer bestimmten Spannung entladen soll. Der ATMEGA8515, überwacht dabei die Spannung und schaltet ein Relais zum Entladewiderstand ein und aus. Später soll noch ein Display dazu kommen wo man die wichtigsten Werte ablesen kann.
Mein Problem ist das sich die Schaltung nach einer unbestimmten Zeit einfach abschaltet.
Ich verwende 2 Timer, einer zum Entprellen der Ein/Aus-Taste und einmal einen Sekundenzähler der ca. 30 Sekunden warten soll sobald die min.Spannung erreicht wurde und dann nochmals entladen soll.
Hab das Programm jetzt Zeile für Zeile verfolgt und mir ist aufgefallen das wenn ein Timer-Interrup ausgelöst wird und der Rücksprung zufällig auf einen Branch-Befehl trifft, dieser Branch-Befehl ausgeführt wird, obwohl laut dem Compare-Befehl kein Branch stattfinden sollte.
Gibt es dafür irgendeine Lösung?
mfg
Stefan
-
hast du eventuell vergessen irgendwelche register zu sichern ? sodass sie nach dem interrupt falsche werte tragen ? zur not kurz vor dem branch das interruptenable flag löschen und kurz danach wieder setzen ...
-
Das hört sich an als würde der Interrupt das Stautsflag verändern. In der Interruptroutine muß man das Statusbyte sichern und am Ende wieder herstellen.
-
Erstmal danke für die Antworten!
Das mit den Interrupts funktioniert jetzt mal grundsätzlich. Warum weiß ich leider nicht? Hab den ganzen Quellcode in ein neues Projekt kopiert und das Problem war weg.
Leider schaltet die Schaltung immer noch ab, auch wenns jetzt noch etwas länger dauert. Also genauer gesagt springt das Programm in die Funktion die aufgerufen wird man die Stop-Taste drückt. Passiert auch nicht immer zur selben Zeit. Muss aber erst genauer schauen wo jetzt noch ein Problem sein könnte. Passiert halt immer nach ca. 1.000.000 Cycles +/- 200.000. Daher ist es fast nicht möglich das solange Zeile für Zeile anzuschauen.
Ich meld mich wenn ich was weiß!!
Trotzdem danke erst mal.
Stefan
-
Hi da,
am besten, du postest mal deinen Code
mfg
-
Mach ich!
Muss euch aber warnen, mir wurde schon öfter gesagt das ich einen katastrophalen Programmierstil hab.
Code:
;*****************************************************************************
;*
;* DATEINAME: entlader.asm
;* TITEL :
;* DATUM : 16.6.08
;* AUTOR : STK
;* VERSION : 1.0
;*
;*
;*****************************************************************************
.include "m8515def.inc"
;--KONSTANTENDEKLARATION---------------------------------------------
; status register bits
.equ CarryFlag = 0
.equ ZeroFlag = 1
.equ NegativeFlag = 2
.equ TwosFlag = 3
.equ SignFlag = 4
.equ HalfCarryFlag = 5
.equ TransferFlag = 6
.equ GlobalFlag = 7
.equ Frequenz = 4000000
.equ Teiler = 4000
;--VARIABLENDEKLARATION----------------------------------------
.def tmp = R16 ;Temp. Variable
.def tmp2 = R17
.def sek_zaehler = R18
.def spg = R19
.def entprell = R20
.CSEG
.org 0x0000
rjmp MAIN ;Reset
rjmp UnusedInt_ISR ;Ext. Int0
rjmp UnusedInt_ISR ;Ext. Int1
rjmp UnusedInt_ISR ;Timer1 Capture Event
rjmp timer ;Timer1 Compare Match A
rjmp UnusedInt_ISR ;Timer1 Compare Match B
rjmp UnusedInt_ISR ;Timer1 Overflow
rjmp UnusedInt_ISR ;Timer0 Overflow
rjmp UnusedInt_ISR ;Serial Transfer Complete
rjmp UnusedInt_ISR ;USART Rx Complete
rjmp UnusedInt_ISR ;USART Data Reg. Empty
rjmp UnusedInt_ISR ;USART Tx Complete
rjmp UnusedInt_ISR ;Analog Comperator
rjmp UnusedInt_ISR ;Ext. Int Request 2
rjmp pause ;Timer0 Compare Match
rjmp UnusedInt_ISR ;EEPRom Ready
rjmp UnusedInt_ISR ;Store Program memory ready
UnusedInt_ISR: reti
;--Hauptprogramm------------------------------------------------
MAIN:
;Stackpointer initialisieren
ldi tmp,low (RAMEND) ; RAMEND ist eine im include file vorgegebene Konstante,
out SPL,tmp
ldi tmp, high(RAMEND)
out SPH,tmp
rjmp init
Main_loop:
;Hauptprogramm
;Akku angesteckt?
in tmp2, pina
ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;Akku ist angeschloßen
cp tmp2,tmp
brsh akku_an
;Akku ist nicht angeschloßen
cp tmp2, tmp
brlo akku_ab
rjmp Main_loop;
;--Unterprogramme-----------------------------------------------------
akku_ab:
;Ausgabe auf Display
;"Akku"
;"anhängen"
rjmp main_loop
akku_an:
;Ausgabe auf Display
;SPG:x,xx
;Entl:x,x
;Warte auf Start-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq start ;Ist Bit gesetzt, Spring in die Start- Fkt.
;Warte auf Entladespg senken:
;Warte auf Entladespg erhöhen
rjmp main_loop
start:
;Akku wurde erkannt und die Starttaste gedrückt
;Start-Taste entprellen
clr entprell
wh1:
ldi tmp, 0b00000010
cp entprell, tmp
brlo wh1
clr sek_zaehler
;Entladevorgang starten
rjmp entladen_ein
entladen_ein:
;Kontrolle ob der Akku noch angeschloßen ist
;Wenn nicht ins Startmenü zurück springen
in tmp, pinc
ori tmp, 0b00000001 ;Relais aktivieren
out portc, tmp
;in tmp2, pina
;ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;cp tmp2, tmp
;brlo entladen_aus
;Akkuspg. überwachen
;Wenn zu niedrig Entladevorgang abbrechen
in tmp2, pina
ldi tmp, 0b10000000
cp tmp2, tmp
brlo entladen_aus
;Warte auf Stop-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq entladen_stop ;Ist Bit gesetzt, Spring in die Start- Fkt.
;Ausgabe auf Display
;A: x,xx
;00:00
rjmp entladen_ein
entladen_aus:
;Entladevorgang stoppen weil die Akkuspannung unter
;einem bestimmter Wert gefallen ist
in tmp, pinc
andi tmp, 0b11111110
out portc, tmp
clr sek_zaehler
rcall automatik
rjmp akku_an
automatik:
;Nach 30 Sekunden soll der Entladevorgang erneut
;gestartet werden
ldi tmp, 0b00011110
cp sek_zaehler,tmp
brsh start
;Schreibe auf Display
;Beendet
;WH in xx
;Warte auf Stop-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq akku_an
in tmp2, pina
ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;Akku ist nicht angeschloßen
cp tmp2, tmp
brlo main_loop
rjmp automatik
entladen_stop:
clr entprell
wh2:
ldi tmp, 0b00000010
cp entprell, tmp
brlo wh2
;Entladevorgang abbrechen
in tmp, pinc
ldi tmp2, 0b00000001
sub tmp, tmp2
out portc, tmp
rjmp main_loop
init:
ldi spg, 0b01010000 ;vorderen 4 Bit vor Komma, hinteren 4 Bit nach Komma
clr sek_zaehler
;Ausgänge setzen
ser tmp
out ddrc, tmp
;Eingänge setzen
clr tmp
out ddra, tmp
out ddrd, tmp
;Timer1 setzen
clr tmp
out tccr1a, tmp
ldi tmp, 0b00001001 ;nur zu Testzwecken (normal 0b00001101)
out tccr1b, tmp
ldi tmp, 0b01100001 ;Timer Einstellungen
out tIMSK, tmp
ldi tmp, HIGH(Frequenz / Teiler)
out ocr1ah, tmp
ldi tmp, LOW(Frequenz / Teiler)
out ocr1al, tmp
;Timer0 setzen
ldi tmp, 0b00000001 ;nur zu Testzwecken (normal 0b00000101)
out tccr0, tmp
ldi tmp, 0b01001110
out ocr0, tmp
sei
rjmp main_loop
;*********Interrupt***********
;Zähler für die Sekundenzählung
timer:
inc sek_zaehler
reti
;Zähler für die Entprellung
pause:
inc entprell
reti
Danke
Stefan
-
Hi Stefan,
wie meine Vorgänger schon sagten, du musst das Status Register retten.
Ich will dir nicht auf den Schlips treten wenn ich frage ob du weißt, was das ist?
Ich hab die entsprechenden Zeilen in den ISR´s geändert und das bei den Registerdefinitionen eingefügt : .def sreg_save = r21
Schon einfache Operationen auf Register "effecten" das Statusregister, was einen vor der ISR gemachten Vergleich verfälschen kann.
Z.B. wird das Statusbit "S" verändert, das für manche branches als Initiator dient.
mfg,
The Man
Code:
;*****************************************************************************
;*
;* DATEINAME: entlader.asm
;* TITEL :
;* DATUM : 16.6.08
;* AUTOR : STK
;* VERSION : 1.0
;*
;*
;*****************************************************************************
.include "m8515def.inc"
;--KONSTANTENDEKLARATION---------------------------------------------
; status register bits
.equ CarryFlag = 0
.equ ZeroFlag = 1
.equ NegativeFlag = 2
.equ TwosFlag = 3
.equ SignFlag = 4
.equ HalfCarryFlag = 5
.equ TransferFlag = 6
.equ GlobalFlag = 7
.equ Frequenz = 4000000
.equ Teiler = 4000
;--VARIABLENDEKLARATION----------------------------------------
.def tmp = R16 ;Temp. Variable
.def tmp2 = R17
.def sek_zaehler = R18
.def spg = R19
.def entprell = R20
.def sreg_save = r21
.CSEG
.org 0x0000
rjmp MAIN ;Reset
rjmp UnusedInt_ISR ;Ext. Int0
rjmp UnusedInt_ISR ;Ext. Int1
rjmp UnusedInt_ISR ;Timer1 Capture Event
rjmp timer ;Timer1 Compare Match A
rjmp UnusedInt_ISR ;Timer1 Compare Match B
rjmp UnusedInt_ISR ;Timer1 Overflow
rjmp UnusedInt_ISR ;Timer0 Overflow
rjmp UnusedInt_ISR ;Serial Transfer Complete
rjmp UnusedInt_ISR ;USART Rx Complete
rjmp UnusedInt_ISR ;USART Data Reg. Empty
rjmp UnusedInt_ISR ;USART Tx Complete
rjmp UnusedInt_ISR ;Analog Comperator
rjmp UnusedInt_ISR ;Ext. Int Request 2
rjmp pause ;Timer0 Compare Match
rjmp UnusedInt_ISR ;EEPRom Ready
rjmp UnusedInt_ISR ;Store Program memory ready
UnusedInt_ISR: reti
;--Hauptprogramm------------------------------------------------
MAIN:
;Stackpointer initialisieren
ldi tmp,low (RAMEND) ; RAMEND ist eine im include file vorgegebene Konstante,
out SPL,tmp
ldi tmp, high(RAMEND)
out SPH,tmp
rjmp init
Main_loop:
;Hauptprogramm
;Akku angesteckt?
in tmp2, pina
ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;Akku ist angeschloßen
cp tmp2,tmp
brsh akku_an
;Akku ist nicht angeschloßen
cp tmp2, tmp
brlo akku_ab
rjmp Main_loop;
;--Unterprogramme-----------------------------------------------------
akku_ab:
;Ausgabe auf Display
;"Akku"
;"anhängen"
rjmp main_loop
akku_an:
;Ausgabe auf Display
;SPG:x,xx
;Entl:x,x
;Warte auf Start-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq start ;Ist Bit gesetzt, Spring in die Start- Fkt.
;Warte auf Entladespg senken:
;Warte auf Entladespg erhöhen
rjmp main_loop
start:
;Akku wurde erkannt und die Starttaste gedrückt
;Start-Taste entprellen
clr entprell
wh1:
ldi tmp, 0b00000010
cp entprell, tmp
brlo wh1
clr sek_zaehler
;Entladevorgang starten
rjmp entladen_ein
entladen_ein:
;Kontrolle ob der Akku noch angeschloßen ist
;Wenn nicht ins Startmenü zurück springen
in tmp, pinc
ori tmp, 0b00000001 ;Relais aktivieren
out portc, tmp
;in tmp2, pina
;ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;cp tmp2, tmp
;brlo entladen_aus
;Akkuspg. überwachen
;Wenn zu niedrig Entladevorgang abbrechen
in tmp2, pina
ldi tmp, 0b10000000
cp tmp2, tmp
brlo entladen_aus
;Warte auf Stop-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq entladen_stop ;Ist Bit gesetzt, Spring in die Start- Fkt.
;Ausgabe auf Display
;A: x,xx
;00:00
rjmp entladen_ein
entladen_aus:
;Entladevorgang stoppen weil die Akkuspannung unter
;einem bestimmter Wert gefallen ist
in tmp, pinc
andi tmp, 0b11111110
out portc, tmp
clr sek_zaehler
rcall automatik
rjmp akku_an
automatik:
;Nach 30 Sekunden soll der Entladevorgang erneut
;gestartet werden
ldi tmp, 0b00011110
cp sek_zaehler,tmp
brsh start
;Schreibe auf Display
;Beendet
;WH in xx
;Warte auf Stop-Taste
in tmp2, pind ;Liest Eingangsport ab
andi tmp2, 0b00000001 ;Nur das Start-tasten-Bit einlesen
ldi tmp, 0b00000001
cp tmp2,tmp
breq akku_an
in tmp2, pina
ldi tmp, 0b01001101 ;Akku erkennung ab 3V
;Akku ist nicht angeschloßen
cp tmp2, tmp
brlo main_loop
rjmp automatik
entladen_stop:
clr entprell
wh2:
ldi tmp, 0b00000010
cp entprell, tmp
brlo wh2
;Entladevorgang abbrechen
in tmp, pinc
ldi tmp2, 0b00000001
sub tmp, tmp2
out portc, tmp
rjmp main_loop
init:
ldi spg, 0b01010000 ;vorderen 4 Bit vor Komma, hinteren 4 Bit nach Komma
clr sek_zaehler
;Ausgänge setzen
ser tmp
out ddrc, tmp
;Eingänge setzen
clr tmp
out ddra, tmp
out ddrd, tmp
;Timer1 setzen
clr tmp
out tccr1a, tmp
ldi tmp, 0b00001001 ;nur zu Testzwecken (normal 0b00001101)
out tccr1b, tmp
ldi tmp, 0b01100001 ;Timer Einstellungen
out tIMSK, tmp
ldi tmp, HIGH(Frequenz / Teiler)
out ocr1ah, tmp
ldi tmp, LOW(Frequenz / Teiler)
out ocr1al, tmp
;Timer0 setzen
ldi tmp, 0b00000001 ;nur zu Testzwecken (normal 0b00000101)
out tccr0, tmp
ldi tmp, 0b01001110
out ocr0, tmp
sei
rjmp main_loop
;*********Interrupt***********
;Zähler für die Sekundenzählung
timer:
in sreg_save,SREG
inc sek_zaehler
out SREG,sreg_save
reti
;Zähler für die Entprellung
pause:
in sreg_save,SREG
inc entprell
out SREG,sreg_save
reti
-
kann es sein das start und stopp-taste bei dir ein und dasselbe sind ? beide liegen auf bit 0 von PIND ???
brsh start
weis ja nicht genau was das bewirkt, bis kein assemlberspezi, ist in deiner automatikschleife, womöglich änderst du irgendwo deine "entprell" in der startfunktion ungewollt ? tut mir echt leid, ich kann kein assembler(VIEL ZU LANG HER) aber wenn ich so drübergehe sind mir die 2 sachen halt aufgefallen
-
Ja das mit dem Taster stimmt. Es soll nur einen Taster für Start und Stop geben.
Ich vermute mal du meinst den "brsh start"-Befehl in der Automatik- Funktion.
Da wird die Variable in der die Sekunden hochgezählt werden mit einem von mir festgelegten Wert (30) vergliechen. Sobald der Sekundenzähler gleich oder höher (brsh) ist springt das Programm zurück zum Start der Entladefunktion um noch einen Entladeversuch durch zu führen
mfg
-
Hab das mal eine weile Laufen lassen. Nicht nur das es in die Stop-Funktion springt, es springt später auch wieder in die Start-Funktion.
Die Branch-Befehle werden aus irgend einem mir noch unklaren Grund ausgeführt obwohl die Bedingung nicht erfüllt werden.
Hab es weiter eingegrenzt. Es passiert nur wenn der Timer1 Interrupt aktiv ist!!
Ich versteh aber einfach nicht warum!