www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Stoppuhr-Programm für ATmega8 bleibt immer an der gleichen Stelle hängen


Autor: n-regen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich versuche gerade, anhand dieses Tutorials 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_Uhr) ein 
Assembler-Programm für den ATmega8 zu schreiben, das eine Stoppuhr auf 
einer 4-Zeichen-7-Segment-Anzeige anzeigen soll.
Allerdings bleibt dieses Programm zwischen der 9. und 10. Sekunde hängen 
(vermutlich in der Schleife zum Ermitteln der Zehnerziffer des 
Sekundenregisters). Sobald allerdings die nächste Minute anfängt, zeigt 
das Display wieder 10 Sekunden (z.B. von 1:00 bis 1:09) die aktuelle 
Zeit an, um dann beim Umschalten von 9:59 auf 10:00 wieder (allerdings 
für 50 Minuten) hängen zu bleiben. Ist die Stunde vorbei, werden wieder 
(mit den genannten Aussetzern) die ersten 9 Sekunden der ersten 9 
Minuten angezeigt.
Während das Programm hängt, wird auf der Anzeige nur die 9 als 4. Ziffer 
angezeigt (um eine Zahl anzuzeigen, zeige ich normalerweise die erste 
Ziffer an, warte 2,5ms, zeige die zweite Ziffer an, usw.).

Hat irgendwer von euch eine Idee, wo der Fehler liegt, der zu dieser 
Endlosschleife führt (wobei allerdings ein Interrupt den µC aus der 
Schleife holt - was ja normal ist - und außerdem die normale 
Funktionalität wiederherstellt - was ich mir nicht erklären kann)?

Hier ist mein aktueller Quelltext (ich habe mich allerdings nicht um das 
Hinzufügen sinnvoller und Entfernen sinnloser Kommentare gekümmert, die 
Kommentare sind also nutzlos):
.include "m8def.inc"
 
.def temp1 = r16
.def temp2 = r17
 
.def SubCount = r21
.def Sekunden = r22
.def Minuten  = r23
.def Stunden  = r24

.def digit1 = r25
.def digit2 = r26
.def digit3 = r27
.def digit4 = r28
 
.org 0x0000
        rjmp    main                ; Reset Handler
.org OVF0addr
        rjmp    timer0_overflow     ; Timer Overflow Handler
 
main:
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
        out     SPL, temp1
        ldi     temp1, HIGH(RAMEND)
        out     SPH, temp1
 
        ldi     temp1, 0b00000101   ; Teiler 1024
        out     TCCR0, temp1
 
        ldi     temp1, 0b00000001   ; TOIE0: Interrupt bei Timer Overflow
        out     TIMSK, temp1
 
        clr     Minuten             ; Die Uhr auf 0 setzen
        clr     Sekunden
        clr     Stunden
        clr     SubCount

    ldi digit1, 0x00
    ldi digit2, 0x00
    ldi digit3, 0x00
    ldi digit4, 0x00
    ldi r16, 0b11111111
    out DDRB, r16
    out DDRC, r16
 
        sei
 
loop:   rcall zehner
    ldi r31, 0b00000001
    sbrc digit1,7
    ori r31, 0b00100000
    sbrc digit1,6
    ori r31, 0b00010000
    mov r18, digit1
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21
    WGLOOP0:  ldi  R30, $64
    WGLOOP1:  dec  R30
    brne WGLOOP1
    dec  R29
    brne WGLOOP0

    ldi r31, 0b00000010
    sbrc digit2,7
    ori r31, 0b00100000
    sbrc digit2,6
    ori r31, 0b00010000
    mov r18, digit2
    andi r18, 0b00110111
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21
    WGLOOP2:  ldi  R30, $64
    WGLOOP3:  dec  R30
    brne WGLOOP3
    dec  R29
    brne WGLOOP2

    ldi r31, 0b00000100
    sbrc digit3,7
    ori r31, 0b00100000
    sbrc digit3,6
    ori r31, 0b00010000
    mov r18, digit3
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21
    WGLOOP4:  ldi  R30, $64
    WGLOOP5:  dec  R30
    brne WGLOOP5
    dec  R29
    brne WGLOOP4

    ldi r31, 0b00001000
    sbrc digit4,7
    ori r31, 0b00100000
    sbrc digit4,6
    ori r31, 0b00010000
    mov r18, digit4
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21
    WGLOOP6:  ldi  R30, $64
    WGLOOP7:  dec  R30
    brne WGLOOP7
    dec  R29
    brne WGLOOP6
 
        rjmp    loop
 
timer0_overflow:                    ; Timer 0 Overflow Handler
 
        push    temp1               ; temp 1 sichern
        in      temp1,sreg          ; SREG sichern
        push    temp1
 
        inc     SubCount            ; Wenn dies nicht der 15. Interrupt
        cpi     SubCount, 60        ; ist, dann passiert gar nichts
        brne    end_isr
 
                                    ; Überlauf
        clr     SubCount            ; SubCount rücksetzen
        inc     Sekunden            ; plus 1 Sekunde
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon
                                    ; gemacht werden
 
                                    ; Überlauf
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür
        inc     Minuten             ; plus 1 Minute
        cpi     Minuten, 100         ; sind 60 Minuten vergangen ?
        brne    Ausgabe             ; wenn nicht, -> Ausgabe
 
                                    ; Überlauf
        clr     Minuten             ; Minuten zurücksetzen und dafür
        inc     Stunden             ; plus 1 Stunde
        cpi     Stunden, 24         ; nach 24 Stunden, die Stundenanzeige
        brne    Ausgabe             ; wieder zurücksetzen
 
                                    ; Überlauf
        clr     Stunden             ; Stunden rücksetzen
 
Ausgabe: 
end_isr:
 
        pop     temp1
        out     sreg,temp1          ; sreg wieder herstellen
        pop     temp1
        reti                        ; das wars. Interrupt ist fertig

zehner:                
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einer        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehner
einer:
        mov r20, temp2
    rcall vergleich
    mov digit1, r20
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
                                    ; vorhergehende Schleife 10 zuviel
                                    ; abgezogen hat
                                    ; das Subtrahieren von -10
                                    ; = Addition von +10 ist ein Trick
                                    ; da kein addi Befehl existiert
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
        ;add     temp1, temp2        ; noch ausgeben
        mov r20, temp1
    rcall vergleich
    mov digit2, r20
zehnerb:                
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Sekunden
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einerb        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehnerb
einerb:
        mov r20, temp2
    rcall vergleich
    mov digit3, r20
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
                                    ; vorhergehende Schleife 10 zuviel
                                    ; abgezogen hat
                                    ; das Subtrahieren von -10
                                    ; = Addition von +10 ist ein Trick
                                    ; da kein addi Befehl existiert
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
        ;add     temp1, temp2        ; noch ausgeben
        mov r20, temp1
    rcall vergleich
    mov digit4, r20
    ret

vergleich:
    cpi     r20,9
    brne    zweig_0
  ;9
  ldi r20, 0b00001010
    rjmp    ende_vergleich
zweig_0:
    cpi     r20,1
    brne    zweig_1
  ;1
  ldi r20, 0b11101110
    rjmp    ende_vergleich
zweig_1:
    cpi     r20,2
    brne    zweig_2
  ;2
  ldi r20, 0b10011000
    rjmp    ende_vergleich
zweig_2:
    cpi     r20,3
    brne    zweig_3
  ;3
  ldi r20, 0b10001010
    rjmp    ende_vergleich
zweig_3:
    cpi     r20,4
    brne    zweig_4
  ;4 
  ldi r20, 0b01001110
    rjmp    ende_vergleich
zweig_4:
    cpi     r20,5
    brne    zweig_5
  ;5
  ldi r20, 0b00001011
    rjmp    ende_vergleich
zweig_5:
    cpi     r20,6
    brne    zweig_6
  ;6
  ldi r20, 0b00001001
    rjmp    ende_vergleich
zweig_6:
    cpi     r20,7
    brne    zweig_7
  ;7
  ldi r20, 0b10101110
    rjmp    ende_vergleich
zweig_7:
    cpi     r20,8
    brne    zweig_8
  ;8
  ldi r20, 0b00001000
    rjmp    ende_vergleich
zweig_8:
    ;0
  ldi r20, 0b00101000
ende_vergleich:
  ret

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau mal hier:
Beitrag "Re: 7 Segmentanzeige falsch eingekauft, reagiert nur auf low"
http://www.mikrocontroller.net/attachment/23620/eieruhr1.asm

Achte besonders darauf, wie die Umwandlung Ziffer->Segment-Bitmuster 
erfolgt. Das löst zwar Dein Problem noch nicht, versetzt Dich aber in 
die Lage, etwas effizienteren Code zu schreiben, in dem es auch Spaß 
macht, einen Fehler zu suchen.

Und gib Dir bitte auch etwas mehr Mühe mit den Kommentaren. Es macht 
keinen Spaß, in einem nicht bzw. falsch kommentierten Programm Fehler zu 
suchen. Meine eigene Erfahrung sagt mir, dass man viele Fehler bereits 
(selbst) dadurch findet, dass man das Programm kommentiert, also dass 
man den Programmablauf mit verständlichen Worten beschreibt.

...

Autor: brumbaer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zehner:
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einer        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehner

Wenn du mehr als 9 Minuten hast, erhöhst du temp2 und springst nach 
zehner, dadurch setzt tu temp1 wieder auf den Anfangswert und hast eine 
Endlos Schleife.

Eher so was:

zehner:
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
zehner_loop:
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einer        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehner_loop

Nach weiteren Schleifen habe ich nicht gesucht.

mfg
SH

Autor: Nils ‫‪ (n-regen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ES FUNKTIONIERT!

Das Problem war tatsächlich die Endlosschleife, die brumbaer entdeckt 
hat.
Ich habe das Setzen der Register temp1 und temp2 jetzt vor den Aufruf 
von zehner bzw. von zehnerb geschrieben (und den Code ansatzweise 
kommentiert) und jetzt funktioniert die Stoppuhr.
Vielen Dank für deine Hilfe, brumbaer.
Den Vorschlag von Hannes werde ich vielleicht beim Verbessern des Codes 
(nach den Berechnungen aus dem Tutorial geht die Stoppuhr um 1,7% vor, 
das lässt sich sicher noch verbessern) umsetzen.

Hier noch der korrigierte Code:
.include "m8def.inc"
 
.def temp1 = r16
.def temp2 = r17
 
.def SubCount = r21
.def Sekunden = r22
.def Minuten  = r23

.def digit1 = r25
.def digit2 = r26
.def digit3 = r27
.def digit4 = r28
 
.org 0x0000
        rjmp    main                ; bei Reset zum Hauptprogramm springen
.org OVF0addr
        rjmp    timer0_overflow     ; bei Timer-Overflow zur Behandlungsroutine springen
 
main:
        ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren
        out     SPL, temp1
        ldi     temp1, HIGH(RAMEND)
        out     SPH, temp1
 
        ldi     temp1, 0b00000101   ; Teiler des Timers auf 1024 setzen
        out     TCCR0, temp1
 
        ldi     temp1, 0b00000001   ; TOIE0: Interrupt bei Timer-Overflow
        out     TIMSK, temp1
 
        clr     Minuten             ; Uhr und Digit-Register auf 0 setzen
        clr     Sekunden
        clr     SubCount
    clr digit1
    clr digit2
    clr digit3
    clr digit4

    ldi r24, 0b11111111      ; Port B und C auf "Ausgabe" schalten
    out DDRB, r24
    out DDRC, r24
 
        sei              ; Interrupts aktivieren
 
loop:   ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Minuten
    rcall zehner        ; Aktuelle Zeit abfragen und digit1-4 entsprechend setzen
    ldi r31, 0b00000001      ; erste Ziffer der Anzeige aktivieren
    sbrc digit1,7        ;  und digit1 in die benötigten Bitmuster für Port B und C
    ori r31, 0b00100000      ;  zerlegen
    sbrc digit1,6
    ori r31, 0b00010000
    mov r18, digit1
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31        ; Bitmuster ausgeben
    out PORTC, r18

    ldi  R29, $21        ; 2,5ms warten
    WGLOOP0:  ldi  R30, $64
    WGLOOP1:  dec  R30
    brne WGLOOP1
    dec  R29
    brne WGLOOP0

    ldi r31, 0b00000010      ; zweite Ziffer und Punkt ausgeben
    sbrc digit2,7
    ori r31, 0b00100000
    sbrc digit2,6
    ori r31, 0b00010000
    mov r18, digit2
    andi r18, 0b00110111    ; die 0 bei Bit 3 ist der Punkt
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21        ; 2,5ms warten
    WGLOOP2:  ldi  R30, $64
    WGLOOP3:  dec  R30
    brne WGLOOP3
    dec  R29
    brne WGLOOP2

    ldi r31, 0b00000100      ; dritte Ziffer ausgeben
    sbrc digit3,7
    ori r31, 0b00100000
    sbrc digit3,6
    ori r31, 0b00010000
    mov r18, digit3
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21        ; 2,5ms warten
    WGLOOP4:  ldi  R30, $64
    WGLOOP5:  dec  R30
    brne WGLOOP5
    dec  R29
    brne WGLOOP4

    ldi r31, 0b00001000      ; vierte Ziffer ausgeben
    sbrc digit4,7
    ori r31, 0b00100000
    sbrc digit4,6
    ori r31, 0b00010000
    mov r18, digit4
    andi r18, 0b00111111
    ori r18, 0b00001000
    out PORTB, r31
    out PORTC, r18

    ldi  R29, $21        ; 2,5ms warten
    WGLOOP6:  ldi  R30, $64
    WGLOOP7:  dec  R30
    brne WGLOOP7
    dec  R29
    brne WGLOOP6
 
        rjmp    loop
 
timer0_overflow:                    ; Timer 0 Overflow Handler
 
        inc     SubCount            ; Wenn dies nicht der 60. Interrupt (Vorteiler 1024, 4MHz, also 60 Interrupts pro Sekunde)
        cpi     SubCount, 60        ; ist, dann passiert gar nichts
        brne    end_isr
 
                                    ; Überlauf
        clr     SubCount            ; SubCount rücksetzen
        inc     Sekunden            ; plus 1 Sekunde
        cpi     Sekunden, 60        ; sind 60 Sekunden vergangen?
        brne    Ausgabe             ; wenn nicht kann die Ausgabe schon
                                    ; gemacht werden
 
                                    ; Überlauf
        clr     Sekunden            ; Sekunden wieder auf 0 und dafür
        inc     Minuten             ; plus 1 Minute
        cpi     Minuten, 100         ; sind 60 Minuten vergangen ?
        brne    Ausgabe             ; wenn nicht, -> Ausgabe
 
                                    ; Überlauf
        clr     Minuten             ; Minuten zurücksetzen
        brne    Ausgabe             ; und zu reti springen
 
Ausgabe: 
end_isr:
        reti                        ; Interrupt-Behandlung abgeschlossen

zehner:                
        subi    temp1, 10           ; vor dem Aufruf von zehner wurde temp1 mit den Minuten gefüllt
        brcs    einer            ; Zehnerstellen zählen und pro Zehnerstelle temp2 um 1 erhöhen
        inc     temp2
        rjmp    zehner
einer:
        mov r20, temp2
    rcall vergleich
    mov digit1, r20
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
                                    ; vorhergehende Schleife 10 zuviel
                                    ; abgezogen hat
                                    ; das Subtrahieren von -10
                                    ; = Addition von +10 ist ein Trick
                                    ; da kein addi Befehl existiert
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
        ;add     temp1, temp2        ; noch ausgeben
        mov r20, temp1
    rcall vergleich
    mov digit2, r20
    ldi temp1, 0x00
    ldi temp2, 0x00
    mov temp1, Sekunden
zehnerb:                
        subi    temp1, 10           ; abzählen wieviele Zehner in
        brcs    einerb        ; der Zahl enthalten sind
        inc     temp2
        rjmp    zehnerb
einerb:
        mov r20, temp2
    rcall vergleich
    mov digit3, r20
        subi    temp1, -10          ; 10 wieder dazuzählen, da die
                                    ; vorhergehende Schleife 10 zuviel
                                    ; abgezogen hat
                                    ; das Subtrahieren von -10
                                    ; = Addition von +10 ist ein Trick
                                    ; da kein addi Befehl existiert
        ;ldi     temp2, '0'          ; die übrig gebliebenen Einer
        ;add     temp1, temp2        ; noch ausgeben
        mov r20, temp1
    rcall vergleich
    mov digit4, r20
    ret

vergleich:
    cpi     r20,9
    brne    zweig_0
  ;9
  ldi r20, 0b00001010
    rjmp    ende_vergleich
zweig_0:
    cpi     r20,1
    brne    zweig_1
  ;1
  ldi r20, 0b11101110
    rjmp    ende_vergleich
zweig_1:
    cpi     r20,2
    brne    zweig_2
  ;2
  ldi r20, 0b10011000
    rjmp    ende_vergleich
zweig_2:
    cpi     r20,3
    brne    zweig_3
  ;3
  ldi r20, 0b10001010
    rjmp    ende_vergleich
zweig_3:
    cpi     r20,4
    brne    zweig_4
  ;4 
  ldi r20, 0b01001110
    rjmp    ende_vergleich
zweig_4:
    cpi     r20,5
    brne    zweig_5
  ;5
  ldi r20, 0b00001011
    rjmp    ende_vergleich
zweig_5:
    cpi     r20,6
    brne    zweig_6
  ;6
  ldi r20, 0b00001001
    rjmp    ende_vergleich
zweig_6:
    cpi     r20,7
    brne    zweig_7
  ;7
  ldi r20, 0b10101110
    rjmp    ende_vergleich
zweig_7:
    cpi     r20,8
    brne    zweig_8
  ;8
  ldi r20, 0b00001000
    rjmp    ende_vergleich
zweig_8:
    ;0
  ldi r20, 0b00101000
ende_vergleich:
  ret

Autor: Martin Vogel (oldmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Du hast eine schöne große Programmschleife. Da was zu ändern oder u 
erweitern wird schwierig und irgendwann verlierst du den Überblich. 
Daher empfehle ich dir viel mehr Variable einzusetzen und mehr 
verteilung auf Unterprogramme. Sind diese in sich getestet, kannst du 
sie abhaken. Bei einer Fehlersuche wirst du dankbar sein, nicht immer 
den ganzen Code durchsehen zu müssen. Hier mal ein Vorschlag, ist aber 
nur ein grobes Gerüst:
Ich hab das bei meinem Atmega8 bei 8MHz folgendermaßen gemacht:
.DEF ms0    = R4   ; Millisekunden einer
.DEF ms1    = R5  ; Millisekunden Zehner
.DEF ms2    = R6  ; Millisekunden Hunderter
.DEF Sekunden  = R7  ; Sekunden 
.DEF Minuten  = R8  ; Minuten 
.DEF Stunden  = R9  ; Stunden 

.DSEG
ms0_Var:  .Byte
ms1_Var:  .Byte
ms2_Var:  .Byte
Sek_Var:  .Byte
Min_Var:  .Byte
Std_Var:  .Byte
Segment0:  .Byte  ; Aufnahme vom Bittmuster für die 7 Segmente
Segment1:  .Byte  ; zuordnen in einer Initialisierung
Segment2:  .Byte   ; in Unterprogramm Set_Segment wird aus einer 
Segment3:  .Byte  ; Zahl das Segmentmuster in Anzeige kopiert
Segment4:  .Byte  ; welche Zahl dargestellt werden soll steht in 
Segment5:  .Byte  ; der Variablen Anz_Nr
Segment6:  .Byte
Segment7:  .Byte
Segment8:  .Byte
Segment9:  .Byte
Anzeige:  .Byte  ; Anzuzeigendes Bitmuster
Anz_Nr:  .Byte  ; Bit Nummer der anzuzeigenden Stelle 
Gem_Anz:  .Byte  ; Bit wird geschoben und steuert Anode oder Kathode 

Danach am Anfang meines Programmes, nicht in der Programmschleife, 
sondern direkt nach der Stack-Initialisierung das UP für die 
Parametrierung des Timers 1 aufgerufen.
.CSEG
Start: .....                         ; Stack setzen
          RCALL  Init_Timer1  ; Timer 1 initialisieren 
          weitere Initialisierungen
Loop:  Read_Port  ; Programmschleife beginne mit Eingaben lesen
         ....
         Set_Segment  ; Bitmuster für 7Segment setzen
  Write_Port  ; Ausgänge schreiben  
       RJMP Loop

; --------- Bereich Unterprogramme -----------

;-----------Timer 1 Parametrierung -----------
;----------aus dem Tutorial angepaßt----------
Init_Timer1:  LDI  Temp_Reg, high( 8000 - 1 )
    OUT  OCR1AH, Temp_Reg        
    LDI  Temp_Reg, low( 8000 - 1 )        
    OUT  OCR1AL, Temp_Reg  ; CTC Modus                                   ; Vorteiler auf 1        
    LDI  Temp_Reg, ( 1 << WGM12 ) | ( 1 << CS10 )        
    OUT  TCCR1B, Temp_Reg         
    LDI  Temp_Reg, 1 << OCIE1A          OUT  TIMSK, Temp_Reg
    RET
 

;----------Interruptroutine Timer 1 Zeitzähler----------

isrTimer1:  PUSH  Temp_Reg    ; temp_Reg sichern
    IN  Temp_Reg, SREG  ; SREG sichern    
    PUSH  Temp_Reg
    PUSH  Calc_Reg  
    INC  ms0
    CPI  ms0, 10
    BRLO  End1_Isr
    CLR  ms0
    INC  ms1
    CPI  ms1, 10
    BRLO  End1_Isr
    CLR  ms1
    INC  ms2
    CPI  ms2, 10
    BRLO  End1_Isr
    CLR  ms2
    INC  Sekunden  
    CPI  Sekunden, 60
    BRLO  End1_Isr
    CLR  Sekunden
    INC  Minuten  
    CPI  Minuten, 60                 
    BRLO  End1_Isr
    CLR  Minuten
    INC  Stunden
    CPI  Stunden, 24
    BRLO  End1_Isr
    ;usw
End1_Isr:  POP  Calc_Reg
    POP  Temp_Reg    
    OUT  SREG, Temp_Reg  ; SREG wiederherstellen
    POP  Temp_Reg
    RETI              ;Ende der Interrupt-Service-Routine
Ich habe mal nicht allzuviele Komentare stehen lassen, aber diese ISR 
zählt die Zeit. Um eine Stoppuhr draus zu machen, kannst du dir ein Bit 
irgendwo setzen und in der ISR abfragen. Nenn die Bytevariable Time_Ctrl
 dann ergänzt du z. B: in der ISR folgendermaßen:
 am Anfang
  LDS Temp_Reg, Time_Ctrl ; Kontrollbyte holen
  ANDI Temp_Reg, 0b00000001  ; Zählerfreigabe-Bit abfragen
  BREQ End1_Isr
Um eine Möglichkeit zur Anzeige von Zwischenwerten zu haben, kopierst du 
am Ende der ISR die Zeitwerte in Variablen
Vorher fragst du aber dein Kontrollbyte, ob der Zähler laufen, oder ob 
die Anzeige stehen bleiben soll

End1_Isr:   LDS   Temp_Reg, Time_Ctrl   ; Kontrollbyte holen
  ANDI   Temp_Reg, 0b00000010   ; Zähleranzeige aktuell halten
  BREQ End2_Isr
  STS ms0_Var, ms0      ; Registerwerte in Variablen schreiben
  STS ms1_Var, ms1
  STS ms2_Var, ms2
  STS Sek_Var, sekunden
  STS Min_Var, minuten
  STS Std_Var, Stunden
End2_Isr:  POP .
Wenn du nun in einer der ms den Aufruf zur Anzeige bringst und dort 
entsprechend durchzählst, das Bit für die Stelle schiebst und die 
Ausgabe an die Anzeige schickst, steht die Anzeige lange genug, damit 
sie erkennbar ist. Willst du diese Werte nun auch mal an einen PC 
schicken, so greifst du auf die Variablen zu. Um das Programm zu 
kontrollieren, kannst du über RS232 und PC mein hier veröffentlichtes 
OpenEye nutzen. Es zeigt dir die Werte im µC in den Variablen sind. Ist 
unter dem Thread "UART mit atmega 16" zu finden.
Ich hoffe, dir weiter geholfen zu haben.
Gruß oldmax

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.