www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Denkblockade Schieberegister mit Timer


Autor: Peter Bednarz (pebez)
Datum:

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

Autor: holger (Gast)
Datum:

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

Autor: Peter Bednarz (pebez)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

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.