www.mikrocontroller.net

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


Autor: Alex Th. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
;ldi temp, 0b00010000
;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.

;Importieren der Definitionen fuer den ATMega16
.include "m16def.inc"

;temporaeres Register definieren
.def temp  = r16
.def temp2 = r17
 
;Interrupts initialisieren
.org 0x0000
        rjmp    main          ; Reset Handler
        reti; EXT_INT0        ; IRQ0 Handler
        reti; EXT_INT1        ; IRQ1 Handler
        reti; TIM2_COMP
        reti; TIM2_OVF
        reti; TIM1_CAPT        ; Timer1 Capture Handler
        reti; TIM1_COMPA       ; Timer1 CompareA Handler
        reti; TIM1_COMPB       ; Timer1 CompareB Handler
        reti; TIM0_OVF        ; Timer0 Overflow Handler
        reti; SPI_STC          ; SPI Transfer Complete Handler
        reti; USART RX       Complete Handler
        reti; UDR         Empty Handler
        rjmp timer1_compare   ; Timer1 Compare Handler
        reti; USART_TXC       ; USART TX Complete Handler
        reti; ADC             ; ADC Conversion Complete Interrupthandler
        reti; EE_RDY          ; EEPROM Ready Handler
        reti; ANA_COMP        ; Analog Comparator Handler
        reti; TWSI            ; Two-wire Serial Interface Handler
        reti; SPM_RDY  

;Hauptroutine
main:
        ldi   temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out   SPL, temp
        ldi   temp, HIGH(RAMEND)
        out   SPH, temp
  
        ldi   temp, 0b00100001            
        out   DDRD, temp      ; PortD0+1 auf Ausgang
        ldi   temp, 0x01
        out   PORTD,temp      ; PortD0 auf High setzen

;CompareInterrupt aktivieren
        ldi   temp, 0b00010000      ; COIE1A: Interrupt bei Timer1 Compare Match
        out   TIMSK, temp

;Clear Timer on Compare Match: Toggeln des OC1A bei Erreichen des CTC Wertes=> Mode 4
        ldi   temp, 0<<COM1A1 | 1<<COM1A0 | 0<<WGM11 | 0<<WGM10
        out   TCCR1A, temp

;kein Vorteiler => 1 Zaehlschritt = 1 Taktschritt
        ldi   temp, 0<<WGM13 | 1<<WGM12 | 0<<CS12 | 0<<CS11 | 1<<CS10
        out   TCCR1B, temp

;Wert bei dem Ueberlauf stattfindet
        ldi   temp, 0x00
        out   OCR1AH, temp
        ldi   temp, 0x1F
        out   OCR1AL, temp
;       ldi   temp, 0b00010000
;       out   TIFR, temp ;Löschen des TIFR, damit Interrupt nicht zu frueh ausgeloest wird




;Interrupts aktivieren 
sei
;nix tun, waehrend Zaehler zaehlt
loop:   rjmp  loop

;Ausfuehren bei Auftreten des Interrupts
timer1_compare:                    ; Timer1 Compare Handler
        ldi   temp, 0x01      
        in    temp2, PORTD    ; Einlesen des PortD Registers
        EOR   temp2,temp      ; XOR um PORTD0 zu Toggeln
        out   PORTD, temp2 
        ldi   temp, 0x00
        out   OCR1AH, temp
        ldi   temp, 0x1F
        out   OCR1AL, temp
        reti            ;fertig, Ruecksprung


Vielen Dank für eure Hilfe im Voraus,
Alex

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
;ldi temp, 0b00010000
> ;out TIFR, temp
> 
> 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)...

Autor: Alex Th. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.