Forum: Mikrocontroller und Digitale Elektronik CompareInterruptauslösung vor Erreichen des Endwertes


von Alex Th. (Gast)


Lesenswert?

Hallo,

ich habe 2 (Verständnis-)Probleme:

Den unten angegebenen Code simuliere ich im AVRStudio, dabei fällt mir 
folgendes auf:

1. Der erste Interrupt wird direkt nach Aktivierung der Interrupts (sei) 
ausgelöst, wenn ich nicht den auskommentierten Teil einfüge:
1
;ldi temp, 0b00010000
2
;out TIFR, temp
Aber der Zähler hat laut Simulation noch gar nicht den vorgegebenen Wert 
erreicht? Wieso gibt es dann bereits einen Interrupt?

2. Damit zusammen hängt auch meine zweite Beobachtung: OC1A wird nach 
Setzen des Highregisters von OCR1A getoggelt, genauso nach Setzen des 
Lowteils. Eigentlich hätte ich erwartet, dass OC1A erst nach Auftreten 
des Interrupts getoggelt wird. Wo ist mein Denkfehler?

Das Programm soll eigentlich mehrere Rechteckimpulse nacheinander 
ausgeben, deren Länge durch Festsetzen des CTC-Wertes vorgegeben wird. 
Die Schleife wird also für weitere Rechteckimpulse (deren Länge jedes 
Mal anders ist, daher ist wahrscheinlich PWM nicht so günstig) noch 
erweitert.
Da die einzelnen Impulse im Mikrosekundenbereich liegen, arbeite ich mit 
Assembler, da die Zeit dann doch ein kritisches Problem ist.

1
;Importieren der Definitionen fuer den ATMega16
2
.include "m16def.inc"
3
4
;temporaeres Register definieren
5
.def temp  = r16
6
.def temp2 = r17
7
 
8
;Interrupts initialisieren
9
.org 0x0000
10
        rjmp    main          ; Reset Handler
11
        reti; EXT_INT0        ; IRQ0 Handler
12
        reti; EXT_INT1        ; IRQ1 Handler
13
        reti; TIM2_COMP
14
        reti; TIM2_OVF
15
        reti; TIM1_CAPT        ; Timer1 Capture Handler
16
        reti; TIM1_COMPA       ; Timer1 CompareA Handler
17
        reti; TIM1_COMPB       ; Timer1 CompareB Handler
18
        reti; TIM0_OVF        ; Timer0 Overflow Handler
19
        reti; SPI_STC          ; SPI Transfer Complete Handler
20
        reti; USART RX       Complete Handler
21
        reti; UDR         Empty Handler
22
        rjmp timer1_compare   ; Timer1 Compare Handler
23
        reti; USART_TXC       ; USART TX Complete Handler
24
        reti; ADC             ; ADC Conversion Complete Interrupthandler
25
        reti; EE_RDY          ; EEPROM Ready Handler
26
        reti; ANA_COMP        ; Analog Comparator Handler
27
        reti; TWSI            ; Two-wire Serial Interface Handler
28
        reti; SPM_RDY  
29
30
;Hauptroutine
31
main:
32
        ldi   temp, LOW(RAMEND)     ; Stackpointer initialisieren
33
        out   SPL, temp
34
        ldi   temp, HIGH(RAMEND)
35
        out   SPH, temp
36
  
37
        ldi   temp, 0b00100001            
38
        out   DDRD, temp      ; PortD0+1 auf Ausgang
39
        ldi   temp, 0x01
40
        out   PORTD,temp      ; PortD0 auf High setzen
41
42
;CompareInterrupt aktivieren
43
        ldi   temp, 0b00010000      ; COIE1A: Interrupt bei Timer1 Compare Match
44
        out   TIMSK, temp
45
46
;Clear Timer on Compare Match: Toggeln des OC1A bei Erreichen des CTC Wertes=> Mode 4
47
        ldi   temp, 0<<COM1A1 | 1<<COM1A0 | 0<<WGM11 | 0<<WGM10
48
        out   TCCR1A, temp
49
50
;kein Vorteiler => 1 Zaehlschritt = 1 Taktschritt
51
        ldi   temp, 0<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10
52
        out   TCCR1B, temp
53
54
;Wert bei dem Ueberlauf stattfindet
55
        ldi   temp, 0x00
56
        out   OCR1AH, temp
57
        ldi   temp, 0x1F
58
        out   OCR1AL, temp
59
;       ldi   temp, 0b00010000
60
;       out   TIFR, temp ;Löschen des TIFR, damit Interrupt nicht zu frueh ausgeloest wird
61
62
63
64
65
;Interrupts aktivieren 
66
sei
67
;nix tun, waehrend Zaehler zaehlt
68
loop:   rjmp  loop
69
70
;Ausfuehren bei Auftreten des Interrupts
71
timer1_compare:                    ; Timer1 Compare Handler
72
        ldi   temp, 0x01      
73
        in    temp2, PORTD    ; Einlesen des PortD Registers
74
        EOR   temp2,temp      ; XOR um PORTD0 zu Toggeln
75
        out   PORTD, temp2 
76
        ldi   temp, 0x00
77
        out   OCR1AH, temp
78
        ldi   temp, 0x1F
79
        out   OCR1AL, temp
80
        reti            ;fertig, Ruecksprung


Vielen Dank für eure Hilfe im Voraus,
Alex

von Johannes M. (johnny-m)


Lesenswert?

Erstens hat das nichts mit GCC zu tun. Falsches Forum.

Zweitens ist Deine Vektortabelle völlig falsch. Der Mega16 hat mehr als 
8 KiB Flash und demzufolge sind die Interrupt-Vektoren 32 Bit breit. 
reti und rjmp sind aber nur 16 Bit breit. Nimm doch einfach die 
Vektortabelle, die im Datenblatt steht. Die stimmt nämlich.

von Johannes M. (johnny-m)


Lesenswert?

Alex Th. wrote:
> 1. Der erste Interrupt wird direkt nach Aktivierung der Interrupts (sei)
> ausgelöst, wenn ich nicht den auskommentierten Teil einfüge:
>
>
1
;ldi temp, 0b00010000
2
> ;out TIFR, temp
3
>
> Aber der Zähler hat laut Simulation noch gar nicht den vorgegebenen Wert
> erreicht? Wieso gibt es dann bereits einen Interrupt?
Doch, hat er. In dem Moment, wenn Du den Timer startest und im OCR noch 
0 steht, ist der Compare-Wert bereits erreicht und dementsprechend wird 
beim nächsten Takt das Flag gesetzt (Prescaler ist ja 1). Wenn Dir das 
händische Löschen des Flags Unannehmlichkeiten bereitet, dann solltest 
Du den Timer erst dann starten, wenn alle Initialisierungen gemacht sind 
(also wenn im OCR ein sinnvoller Wert steht)...

von Alex Th. (Gast)


Lesenswert?

Hi Johannes,

mit dem gcc habe ich mir fast gedacht, aber nicht besser gewusst. In 
welches Unterforum gehört eine solche Frage denn eigentlich? Bei µC und 
Elektronik wird ja mehr der Hardwarebereich besprochen, zumindest nach 
den Topics, die ich dort gesehen habe.

Die Interrupttabelle habe ich erst vom ATMega8 übernommen, als das nicht 
passte, habe ich mir den richtigen Interrupt per Breakpoint bei 
AVRStudio rausgesucht. Das mit dem Datenblatt hätte mir selber einfallen 
können, weil ich da heute den gesamten Tag nach dem Fehler gesucht habe. 
;)


Nun aber zum eigentlichen: Danke! Das war es tatsächlich, so ist 
natürlich auch das Toggeln des OC1A zu erklären. Hab den Code jetzt 
umgestellt. Vielen Dank noch mal.

Schönen Gruß,
Alex

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.