Forum: Mikrocontroller und Digitale Elektronik TimerO Problem MEGA88


von NobbyH (Gast)


Lesenswert?

Hallo Forengemeinde,

benötige bei der Timerprogrammierung einen Denkanstoss.

Habe testweise einmal die folgende Programme erstellt.

Programm 1:
--------------------------------------------------
.include "m88def.inc"

.equ fq     = 16000000    ; Quarzfrequenz
.equ baud   = 19200       ; Baudrate RS-232 Schnittstelle
.equ bddivH = 0x00        ; Teilfaktor für Baudrate Highbyte
.equ bddivL = (fq/(16*baud))-1       ; Teilfaktor für Baudrate Lowbyte

.def temp = r16
.def leds = r17
.def temp2= r18

.org 0x0000
  rjmp main        ; Reset Handler
  reti             ; IRQ0 Handler
  reti             ; IRQ1 Handler
  reti             ; PCINT0 Handler
  reti             ; PCINT1 Handler
  reti             ; PCINT2 Handler
  reti             ; Watchdog Timer Handler
  reti             ; Timer2 Compare A Handler
  reti             ; Timer2 Compare B Handler
  reti             ; Timer2 Overflow Handler
  reti             ; Timer1 Capture Handler
  reti             ; Timer1 Compare A Handler
  reti             ; Timer1 Compare B Handler
  reti             ; Timer1 Overflow Handler
  reti             ; Timer0 Compare A Handler
  reti             ; Timer0 Compare B Handler
  reti             ; Timer0 Overflow Handler
  reti             ; SPI Transfer Complete Handler
  reti             ; USART, RX Complete Handler
  reti             ; USART, UDR Empty Handler
  reti             ; USART, TX Complete Handler
  reti             ; Analog Comparator Handler
  reti             ; 2-wire Serial Interface Handler
  reti             ; Store Programm Memory Ready Handler

main:

        ; Initialisieren
        ldi   temp, high(RAMEND) ; Stackpointer H initialisieren
        out   SPH, temp
        ldi   temp, low(RAMEND)  ; Stackpointer L initialisieren
        out   SPL, temp

        ldi   temp, 0b00000111   ; Port C0,C1 und C2 Ausgang, Rest 
Eingänge
        out   DDRC, temp         ; in Register schreiben

        ldi   leds, 0xFF         ; alle Ausgänge auf high

        ; Timer0 initialisieren
        ldi   temp, (1<<CS01|0<<CS00) ; CS1 setzen: Teiler 8
        out   TCCR0B, temp        ; in Register speichern

        ldi   temp, (1<<TOIE0)    ; TOIE0: Interrupt bei Timer Overflow
        sts   TIMSK0, temp        ; in Register speichern

        sei                       ; Interupts aktivieren

loop:   out   PORTC,leds

wait:   in    temp, TIFR0
        sbrs  temp, $0
        rjmp  wait

        ldi   temp, 0x01
        out   TIFR0, temp

        com   leds
        out   PORTC,leds

wait1:  in    temp, TIFR0
        sbrs  temp, $0
        rjmp  wait1

        ldi   temp, 0x01
        out   TIFR0, temp

rjmp    loop                     ; Schleife
------------------------------------------------

Dieses Programm erzeugt mir einen Rechteckimpuls mit einer Periodendauer 
von 1792 µs.

-------------------------------------------------
.include "m88def.inc"

.equ fq     = 16000000    ; Quarzfrequenz
.equ baud   = 19200       ; Baudrate RS-232 Schnittstelle
.equ bddivH = 0x00        ; Teilfaktor für Baudrate Highbyte
.equ bddivL = (fq/(16*baud))-1       ; Teilfaktor für Baudrate Lowbyte

.def temp = r16
.def leds = r17
.def temp2= r18

.org 0x0000
     rjmp main         ; Reset Handler
     reti              ; IRQ0 Handler
     reti              ; IRQ1 Handler
     reti              ; PCINT0 Handler
     reti              ; PCINT1 Handler
     reti              ; PCINT2 Handler
     reti              ; Watchdog Timer Handler
     reti              ; Timer2 Compare A Handler
     reti              ; Timer2 Compare B Handler
     reti              ; Timer2 Overflow Handler
     reti              ; Timer1 Capture Handler
     reti              ; Timer1 Compare A Handler
     reti              ; Timer1 Compare B Handler
     reti              ; Timer1 Overflow Handler
     reti              ; Timer0 Compare A Handler
     reti              ; Timer0 Compare B Handler
     reti              ; Timer0 Overflow Handler
     reti              ; SPI Transfer Complete Handler
     reti              ; USART, RX Complete Handler
     reti              ; USART, UDR Empty Handler
     reti              ; USART, TX Complete Handler
     reti              ; Analog Comparator Handler
     reti              ; 2-wire Serial Interface Handler
     reti              ; Store Programm Memory Ready Handler

main:
     ; Initialisieren
     ldi   temp, high(RAMEND)    ; Stackpointer H initialisieren
     out   SPH, temp
     ldi   temp, low(RAMEND)     ; Stackpointer L initialisieren
     out   SPL, temp

     ldi   temp, 0b00000111      ; Port C0,C1 und C2 Ausgang, Rest 
Eingänge
     out   DDRC, temp            ; in Register schreiben
     ldi      leds, 0xFF         ; alle Ausgänge auf high

     ; Timer0 initialisieren
     ldi      temp, (1<<CS01|0<<CS00) ; CS1 setzen: Teiler 8
     out      TCCR0B, temp       ; in Register speichern

     ldi      temp, (1<<OCIE0A) ; OCIE0A: Interrupt bei Timer CompareA 
Overflow
     sts      TIMSK0, temp      ; in Register speichern

     ldi      temp, $77
     sts      OCR0A, temp

     sei          ; Interupts aktivieren

loop:out  PORTC,leds

wait:in       temp, TIFR0
     sbrs     temp, $02
     rjmp     wait

     sbi      TIFR0, (1<<OCF0A)

     com      leds
     out      PORTC,leds

wait1:in      temp, TIFR0
     sbrs     temp, $02
     rjmp     wait1

     sbi      TIFR0, (1<<OCF0A)

     rjmp    loop                  ; Schleife
------------------------------------------------
Dieses Programm erzeugt mir einen Rechteckimpuls mit einer Periodendauer 
von 512 µs.

Ich benötige aber eine Periodendauer ca. 366 µs.
Dazu lädt man doch normalerweise den benötigten Wert in das 
CompareA-Register und fragt ab ob das CompareA Register mit dem TCNTo 
identisch ist.

Was mache ich falsch oder wo liegt mein Gedankenfehler?

Ich möchte es nicht über eine Interuptroutine lösen. Das habe ich 
getestet
und dies funktioniert auch.

Gruß
NobbyH

von spess53 (Gast)


Lesenswert?

Hi

>Dazu lädt man doch normalerweise den benötigten Wert in das
>CompareA-Register und fragt ab ob das CompareA Register mit dem TCNTo
>identisch ist.

Nein. Man benutzt den CTC-Mode. Dann macht der Timer alles allein.

MfG Spess

von Krapao (Gast)


Lesenswert?

Der Interruptcontroller löscht beim Auftreten des Interrupts das 
Interruptflag TIFR0 und springt deine Interruptroutine an.

Die besteht zwar nur aus einem RETI, aber nichts desto trotz ist das 
Flag gelöscht.

Dein Hauptprogramm hat schlechte Karten, wenn es TIFR0 selbst abfragt.

Versuche eigene ISRs zu implementieren und setze dort ein eigenes Flag, 
welches du im Hauptprogramm abfragen und löschen (quittieren) kannst.

von Krapao (Gast)


Lesenswert?

> Der Interruptcontroller löscht beim Auftreten des Interrupts das
> Interruptflag TIFR0 und springt deine Interruptroutine an.

Das ist der Effekt des SEI; teste dein Programm mal ohne das SEI. 
Beachte, dass du dann das Interruptflag TIFR0 selbst löschen musst 
(durch Beschreiben mit einem 1 an der Stelle des Bitflags).

von NobbyH (Gast)


Lesenswert?

Danke an Alle für die vielen Tips.
Werde sie alle testen.

Habe mal den Vorschlag von Spess versucht zu realisieren.

Das hat soweit bei Timer1 und Timer2 funktioniert.
Leider funktioniert die gleiche Rountine (angepaßt) bei Timer0 nicht.
Mir ist nicht klar warum.
Hier die Programmsequenz für Timer2:
 ;--------------------------------------------------------------
.include "m88def.inc"

.def temp1 = r16
.def temp2 = r17
.def temp3 = r18
.def Flag  = r19
.def temp  = r20
.def leds  = r21

.org 0x0000
  rjmp main               ; Reset Handler
  reti                    ; IRQ0 Handler
  reti                    ; IRQ1 Handler
  reti                    ; PCINT0 Handler
  reti                    ; PCINT1 Handler
  reti                    ; PCINT2 Handler
  reti                    ; Watchdog Timer Handler
  rjmp    timer2_compare  ; Timer2 Compare A Handler
  reti                    ; Timer2 Compare B Handler
  reti                    ; Timer2 Overflow Handler
  reti                    ; Timer1 Capture Handler
  reti                    ; Timer1 Compare A Handler
  reti                    ; Timer1 Compare B Handler
  reti                    ; Timer1 Overflow Handler
  reti                    ; Timer0 Compare A Handler
  reti                    ; Timer0 Compare B Handler
  reti                    ; Timer0 Overflow Handler
  reti                    ; SPI Transfer Complete Handler
  reti                    ; USART, RX Complete Handler
  reti                    ; USART, UDR Empty Handler
  reti                    ; USART, TX Complete Handler
  reti                    ; Analog Comparator Handler
  reti                    ; 2-wire Serial Interface Handler
  reti                    ; Store Programm Memory Ready Handler



main:
         ldi     temp1, HIGH(RAMEND)
         out     SPH, temp1
         ldi     temp1, LOW(RAMEND) ; Stackpointer initialisieren
         out     SPL, temp1

         ; IO initialisieren
  ldi    temp,   0b00000111         ; Port C0,C1 und C2 Ausgang, Rest 
Eingänge
  out    DDRC,   temp               ; in Register schreiben

         ldi     leds, 0xFF         ; alle Ausgänge auf high

                                    ; Vergleichswert
         ldi     temp1, ( 183 - 1 )
         sts     OCR2A, temp1       ; CTC Modus einschalten
         ldi     temp1, ( 1 << WGM21 )
         sts     TCCR2A, temp1
                                    ; Vorteiler auf 32
         ldi     temp1, ( 1 << CS21 | 1<<CS20)
         sts     TCCR2B, temp1

         ldi     temp1, (1 << OCIE2A); OCIE2A: Interrupt bei Timer 
Compare
         sts     TIMSK2, temp1

         clr     Flag                ; Flag löschen

         sei

loop:
         cpi     flag,0
         breq    loop                ; Flag im Interrupt gesetzt?

         com     leds
         out     PORTC,leds

         ldi     flag,0              ; Flag löschen

         rjmp    loop

timer2_compare:                      ; Timer 2 Output Compare Handler
         ldi     flag,1              ; Flag setzen, LCD updaten

         reti                        ; das wars. Interrupt ist fertig
 ;--------------------------------------------------------------
Hier die Programmsequenz für Timer0:
.include "m88def.inc"

.def temp1 = r16
.def temp2 = r17
.def temp3 = r18
.def Flag  = r19
.def temp  = r20
.def leds  = r21

.org 0x0000
          rjmp    main             ; Reset Handler
.org OC0Aaddr
          rjmp    timer0_compare   ; Timer Compare Handler

;.org 0x0000
;  rjmp main                   ; Reset Handler
;  reti                        ; IRQ0 Handler
;  reti                        ; IRQ1 Handler
;  reti                        ; PCINT0 Handler
;  reti                        ; PCINT1 Handler
;  reti                        ; PCINT2 Handler
;  reti                        ; Watchdog Timer Handler
;  reti                        ; Timer2 Compare A Handler
;  reti                        ; Timer2 Compare B Handler
;  reti                        ; Timer2 Overflow Handler
;  reti                        ; Timer1 Capture Handler
;  reti                        ; Timer1 Compare A Handler
;  reti                        ; Timer1 Compare B Handler
;  reti                        ; Timer1 Overflow Handler
;  rjmp    timer0_compare      ; Timer0 Compare A Handler
;  reti                        ; Timer0 Compare B Handler
;  reti                        ; Timer0 Overflow Handler
;  reti                        ; SPI Transfer Complete Handler
;  reti                        ; USART, RX Complete Handler
;  reti                        ; USART, UDR Empty Handler
;  reti                        ; USART, TX Complete Handler
;  reti                        ; ADC Conversion Complete Handler
;  reti                        ; EEPROM Ready Handler
;  reti                        ; Analog Comparator Handler
;  reti                        ; 2-wire Serial Interface Handler
;  reti                        ; Store Programm Memory Ready Handler



main:
         ldi     temp1, HIGH(RAMEND)
         out     SPH, temp1
         ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
         out     SPL, temp1

         ; IO initialisieren
         ldi     temp, 0b00000111  ; Port C0,C1 und C2 Ausgang, Rest 
Eingänge
         out     DDRC, temp        ; in Register schreiben

         ldi     leds, 0xFF        ; alle Ausgänge auf high

                                    ; Vergleichswert
         ldi     temp1, ( 181 - 1 )
         out     OCR0A, temp1

                                    ; CTC Modus einschalten
         ldi     temp1, ( 1 << WGM01 )
         sts     TCCR0A, temp1
                                    ; Vorteiler auf 8
         ldi     temp1, ( 1 << CS01 | 0<<CS00)
         sts     TCCR0B, temp1

         ldi     temp1, (1 << OCIE0A); OCIE0A: Interrupt bei Timer 
Compare
         sts     TIMSK0, temp1

         clr     Flag                ; Flag löschen

         sei

loop:
         cpi     flag,0
         breq    loop                ; Flag im Interrupt gesetzt?

         com     leds
         out     PORTC,leds

         ldi     flag,0              ; Flag löschen

         rjmp    loop

timer0_compare:                      ; Timer 0 Output Compare Handler

         push    temp1               ; temp 1 sichern
         in      temp1,sreg          ; SREG sichern

         ldi     flag,1              ; Flag setzen, LCD updaten

         out     sreg,temp1          ; sreg wieder herstellen
         pop     temp1
         reti                        ; das wars. Interrupt ist fertig
-------------------------------------------------
Hat jemand eine Tip für mich? Gibt es Unterschiede zwischen Timero und 
Timer1 die ich nicht beachtet habe?

Danke und Gruß
NobbyH

von NobbyH (Gast)


Lesenswert?

Hallo,

Keiner einen Tipp für mich?

Gruß
NobbyH

von µC-Bastler (Gast)


Lesenswert?

NobbyH schrieb:
> Hat jemand eine Tip für mich? Gibt es Unterschiede zwischen Timero und
> Timer1 die ich nicht beachtet habe?

Timer1 existiert im ATmega88, Timero nicht.

von spess53 (Gast)


Lesenswert?

Hi

>         ldi     temp1, ( 1 << CS01 | 0<<CS00)
>         sts     TCCR0B, temp1     !!!!!!!!!!!!!!!!!!!!!!!!!


Die Register TCCR0A, TCCR0B, OCR0A, OCR0B, GTCCR, aber nicht TIMSK0, des 
ATMega88 werden mit out/in angesprochen.

MfG Spess

von NobbyH (Gast)


Lesenswert?

@Spess,

Vielen Dank für die sachkundige kompetente Antwort.
Das war der Fehler.
Manchmal hat man halt ein Brett vorm Kopf.

Gruß und schöne Ostertage
wünscht NobbyH

von H. Bunse (Gast)


Lesenswert?

NobbyH schrieb:
> Manchmal hat man halt ein Brett vorm Kopf.
Durch welches man schlecht auf das Datenblatt ded mega88 gucken kann.

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.