Forum: Mikrocontroller und Digitale Elektronik Denkblockade Schieberegister mit Timer


von Peter B. (pebez)


Lesenswert?

Hallo Wissende,

wieder einmal ein Anfänger der auf dem Schlauch steht :-)

Ich habe ein Lauflicht mit 3 Schieberegistern aufgebaut.
Jede Sekunde soll eine Led aktiviert werden, sind 24 Sekunden vorbei
(24Led's leuchten)wird die Kette gelöscht und das Spiel beginnt von 
vorn.

Die ungefähre Sekunde habe ich mit einer Warteschleife (dly) realisiert.
Diese "Sekunde" ist jedoch logischerweise total ungenau.

Nun möchte ich gern diese dly Schleife durch ein Timer ersetzen.
Im Code ist der Timer auskommentiert, da er nur die Neustartzeit nach
24 Led's verzögert, die jedoch unmittelbat starten soll.

Ohne Timer funktioniert es, aber eben sehr ungenau.
Hier der Code:

.include "m8def.inc"

.def temp1 = r16
.def temp2 = r17
.def temp3 = r18
.def temp4 = r19
.def cnt   = r20
.def SubCount = r21

.equ SCHIEBE_DDR  = DDRB
.equ SCHIEBE_PORT = PORTB
.equ RCK          = PB3 ;PIN 12  ,  PIN 10 auf Vcc
.equ SCK          = PB1 ;PIN 11
.equ SIN          = PB0 ;PIN 14

.org 0x0000
        rjmp    main

.org OVF1addr
        rjmp timer1_compare


main:

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

;***************************Timer initialisieren ********************

    ldi temp1, high(40000)    ;Vergleichswert für Timer1
    out OCR1AH, temp1
    ldi temp1, low(40000)
    out OCR1AL, temp1                  ; 4 MHz / 40.000 / 100 = 1
    ldi temp1, (1 << CS10)| (1<<WGM12) ;Vorteiler=1, Timer im CTC-Modus
    out TCCR1B, temp1
    ldi temp1, 1 << OCIE1A      ;OCIE1A: Interrupt bei Timer Compare
    out TIMSK, temp1
  sei

;     Die Port Pins auf Ausgang konfigurieren

    ldi   temp1, (1<<RCK) | (1<<SCK) | (1<<SIN)
    out   SCHIEBE_DDR, temp1

loop:

  rjmp loop

timer1_compare:

    ;inc SubCount
    ;cpi SubCount, 100
    ;brne end
    ;clr SubCount


; Ein Datenbyte ausgeben

Anfang:
    ldi   temp2, 255          ; Anfangsmuster laden
    ldi   temp3, 255
    ldi   temp4, 255
    ldi   cnt, 25             ; Schleifenzähler laden

Ausgabe:
    mov   temp1, temp4
    rcall Schiebe               ; Daten schieben
    mov   temp1, temp3
    rcall Schiebe               ; Daten schieben
    mov   temp1, temp2
    rcall Schiebe               ; Daten schieben
    rcall SchiebeOut            ; Daten in Ausgangsregister übernehmen

dly:            ; Diese Wartefunktion soll duch ein Timerinterrupt 
ersetzt werden

         dec r21
         brne dly
         dec r22
         brne dly
         inc r23
         cpi r23, 21
         brne dly
         clr r23

      lsl temp2
      rol temp3
      rol temp4
      dec cnt                ; Schleifenzähler verringern
      brne ausgabe


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

; Die Ausgabe im Schieberegister in das Ausgaberegister übernehmen
;
; Dazu am RCK Eingang am Schieberegister einen 0-1-0 Puls erzeugen
;
SchiebeOut:
    sbi   SCHIEBE_PORT, RCK
    cbi   SCHIEBE_PORT, RCK
    ret

;----------------------------------------------------------------------- 
------
;
; 8 Bits aus temp1 an das Schieberegister ausgeben
Schiebe:
    push  temp2
    ldi   temp2, 8             ; 8 Bits müssen ausgegeben werden


Schiebe_1:

    rol  temp1                 ; MSB -> Carry
    brcs Schiebe_One           ; Carry gesetzt? -> weiter bei 
Schiebe_One
    cbi  SCHIEBE_PORT, SIN     ; Eine 0 ausgeben
    rjmp Schiebe_Clock         ; und Sprung zur Clock Puls Generierung

Schiebe_One:
    sbi  SCHIEBE_PORT, SIN     ; Eine 1 ausgeben


     ; einen Impuls an SCK zur Übernahme des Bits nachschieben

Schiebe_Clock:
    sbi   SCHIEBE_PORT, SCK    ; Clock-Ausgang auf 1 ...
    cbi   SCHIEBE_PORT, SCK    ; und wieder zurück auf 0

    dec   temp2                ; Anzahl der ausgegebenen Bits 
runterzählen
    brne  Schiebe_1            ; Wenn noch keine 8 Bits ausgegeben -> 
Schleife bilden

    pop   temp2
    ret

end:
    out SREG, temp1        ;sreg wiederherstellen
    pop temp1            ;temp wiederherstellen
    reti
;---- Interrupt-Routine  Ende


Entschuldigt bitte diesen wüsten Code.

Kann mir jemand mitteilen, wo der Timer_compare1 hinein muss?
Habe schon alle möglichen Stellen probiert, jedoch ohne Erfolg.
Vielleicht muss man so etwas auch ganz anders Programmieren?

Wäre nett, wenn mir hier weitergeholfen würde.

Gruß Peter

von holger (Gast)


Lesenswert?

>Kann mir jemand mitteilen, wo der Timer_compare1 hinein muss?

>.org OVF1addr
>        rjmp timer1_compare

Na, auf jeden Fall nicht in den Overflow Interrupt.
Wie wäre es mit dem timer1_compare Interrupt?

>Habe schon alle möglichen Stellen probiert, jedoch ohne Erfolg.

Probieren bringt bei Interrupts nicht viel.

>Entschuldigt bitte diesen wüsten Code.

Kein Wunder das der nicht funktioniert.

von Peter B. (pebez)


Lesenswert?

holger schrieb:
>>Kann mir jemand mitteilen, wo der Timer_compare1 hinein muss?
>
>>.org OVF1addr
>>        rjmp timer1_compare
>
> Na, auf jeden Fall nicht in den Overflow Interrupt.
> Wie wäre es mit dem timer1_compare Interrupt?

Ist er ja, Interrupt wird ja ausgelöst.

>
>>Habe schon alle möglichen Stellen probiert, jedoch ohne Erfolg.
>
> Probieren bringt bei Interrupts nicht viel.

Mir schon klar, deshalb wende ich mich ans Forum.

>
>>Entschuldigt bitte diesen wüsten Code.
>
> Kein Wunder das der nicht funktioniert.

Der Code funktioniert doch. Ich möchte nur dly durch eine Timerfunktion 
ersetzen.
Die dly befindet sich aber mitten im Ablauf der Schieberei.

Gruß  Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Bednarz schrieb:

> Der Code funktioniert doch. Ich möchte nur dly durch eine Timerfunktion
> ersetzen.
> Die dly befindet sich aber mitten im Ablauf der Schieberei.

Deine Frage läst sich nicht mit einem einfachen "da und dort" 
beantworten. Du musst die ganze Programmsystematik umstellen.

Bei jedem Aufruf der ISR muss 1 Schiebeoperation und nur 1 erfolgen.

Die Frage ist also nicht, wie kriegst du die Pausen zwischen die 
Schiebeoperationen rein, sondern wie teilst du die Schiebeoperationen 
auf, so dass du immer nur die nächste anstehende Schiebeoperation 
ausführst. Und diesen Code baust du dann in die ISR ein.

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.