Zeitschleife mittels Timer

Persönliche Seite #1261953
Lesenswert?

Hallo,
ich wollte ein Zeitverzögerung von circa 1 Sekunde
mit dem Timer0 realisieren.
Der Pic Takt liegt bei 4Mhz d.h. 1Mhz intern.
Ich benutze den Vorteiler vom Teiler und zwar 256:1!

Also 1Mhz:256 = 3906,25Hz
Das heisst ein Takt ist 1:3906,25Hz = 256µS
Also dauert ein Timerüberflow 256µSx256 = 0,066S
Das heisst für 1 Sekunde müsste ich den Timer
1S:0,066S = ca. 15 mal durchlaufen lassen.
Bitte korrigiert mich, wenn ich mich irre!

Also ich habe es so aufgebaut:

>movlw  B'00000111'
>movwf  OPTION_REG

Das geschiet in Speicherbank 0

>Zeitreset

>  clrf  INTCON
>  clrf  TMR0
>  movlw  D'15'
>  movfw  counter

>Wait

>  clrz
>  movf  INTCON,0
>  XORLW  B'00000100'
>  bnz   Wait

>  clrf  INTCON
>  decfsz  counter
>  goto  Wait
>  return

Ich hoffe ihr steigt durch den Kram durch =)
Meine Frage ist also wo liegt hier ein Fehler?
Persönliche Seite #1263006
Lesenswert?

Peter Dannegger schrieb:
> Ich vermute mal, XORLW soll ein EX-OR machen, was willst Du damit
> erreichen?
> Mußt Du wirklich alle 8 Bits testen?
 Üblicher Weise nimmt man ein AND um ein bestimmtes Bit zu testen.

Hi, ob ich xor mache oder and.. ist doch wurscht.
Aber trotzdem wäre es cool, wenn du mir zeigen könntest wie es mit and 
geht =)


> Und überwinde mal Deine große Angst vor Kommentaren. Kommentiere Deinen
> Code, das hilft nämlich auch Dir selbst, ihn zu verstehen!

Ich verstehe es =)

>Wenn schon ein timer, dann doch eher mit Interrupt, dann kann der
>Prozessor was anderes machen.

Soll er aber gar nicht.

Also kann mir jemand sagen was hier falsch ist?
#1263032
Lesenswert?

Nicolas Meyertöns schrieb:

>  Üblicher Weise nimmt man ein AND um ein bestimmtes Bit zu testen.
>
> Hi, ob ich xor mache oder and.. ist doch wurscht.

Nicht ganz.
Wenn du sicherstellen kannst, dass alle anderen Bits des getesteten 
tatsächlich 0 sind, dann ist es tatsächlich egal.

Ansonsten nimmt man AND um sicherzugehen, dass einem nicht ein anderes 
Bit dazwischenfunkt.

Ohne jetzt jemals PIC programmiert zu haben, würde ich mal sagen

Wait
   clrz
   movf  INTCON,0
   ANDLW  B'00000100'
   bz   Wait

Keine Ahnung, ob der OpCode tatsächlich  ANDLW heist (einfach nur die 
Analogie zu XORLW) bzw. ob der Branch_if_zero  tatsächlich bz heisst 
(auch hier wieder die Analogie zu bnz benutzt). Die Idee im Original war 
wohl solange in der Schleife zu bleiben, wie Bit 2 in INTCON gleich 0 
ist.

>> Und überwinde mal Deine große Angst vor Kommentaren. Kommentiere Deinen
>> Code, das hilft nämlich auch Dir selbst, ihn zu verstehen!
>
> Ich verstehe es =)

Na, dann reicht das ja auch.
Blöd ist nur: Du verstehst es und findest trotzdem den Fehler nicht.
Persönliche Seite #1263049
Lesenswert?

Danke für deine Antwort=)

>Na, dann reicht das ja auch.
>Blöd ist nur: Du verstehst es und findest trotzdem den Fehler nicht.

Das ist allerdings blöd! xD

>Die Idee im Original war wohl solange in der Schleife zu bleiben,
>wie Bit 2 in INTCON gleich 0 ist.

Genau, weil beim Timer-Overflow ja das Bit gesetzt wird,
so wollte ich halt herraus finden, ob er schon 1 mal durch ist,
wenn ja dann wird die 15 in "counter" um 1 verringert.

Bis das irgendwann mal 0 ergibt, dann sollte er zurück springen.

>Zeitreset

>  clrf  INTCON
>  clrf  TMR0
>  movlw  D'15'
>  movfw  counter

Hier soll erstmal das INTCON gelöscht werden
(Mein Gedanke: so kann ich sicherstellen, dass nachher die
Abfrage des Intcons kein Fehlergebniss liefert.)

>Wait

>  clrz
>  movf  INTCON,0
>  XORLW  B'00000100'
>  bnz   Wait

Hier soll er dann halt in der Schleife bleiben, bis Timeroverflow
und eben entsprechend das Bit im INTCON gesetzt ist.

>  clrf  INTCON
>  decfsz  counter
>  goto  Wait
>  return

Wenn dann der Timer-Overflow da war, soll er diesen Part durchlaufen,
(BNZ = Springe, wenn Z-Flag nicht gesetzt ist)
also wenn das Z-Flag dann mal gesetzt ist, weil das Bit im INTCON High
war, dann löscht er erstmal das INTCON Register (für die nächste runde)
und verringert den Wert aus "counter" um 1.

Ja aber iwie kommt er da nicht mehr raus, sprich er erreicht den Return
Befehl nicht...
#1263118
Lesenswert?

Nicolas Meyertöns schrieb:
> Hi, ja habe es nachgelesen:
>
> "Jedes mal, wenn der Timer0 überläuft setzt er das Bit T0IF (Bit 2 im
> Register INTCON) auf 1"
>
> Ich versuche das ganze jetzt mit dem T0IF Interrupt.
> Ich melde mich später wenn ich weiter gekommen bin, danke schonmal an
> alle!

Du hast es immer noch nicht kapiert.
Es geht nicht um das T0IF Bit.
Es geht um all die anderen Bits die noch im INTCON Register 
untergebracht sind!
Wenn auch nur eines davon auch auf 1 steht, dann geht deine XOR 
Geschichte in die Hose.

Was ist so schwer daran, die beiden Zeilen einfach mal auszutauschen? 
Mag sein, dass das dein Problem nicht löst. Aber es ist auf jeden Fall 
die sauberere Lösung, denn mit deinem XOR schlummerte da ein Problem, 
dass nur darauf wartet hervorzukommen.
#1263174
Lesenswert?

Nicolas Meyertöns schrieb:
> Hey, klar hab ich das kapiert, deswegen will ich es ja jetzt auch mit
> dem Interrupt machen!

Den logischen Spring versteh ich jetzt nicht wirklich.
Das ganze über einen tatsächlichen Interrupt abzuhandeln ist zwar 
grundsätzlich die bessere Lösung. Wenns aber mit Polling schon nicht 
funktioniert, wird dir ein Interrupt Handler auch nicht helfen. Es ist 
nur etwas komplizierter einen Imterrupt Handler aufzusetzen und man kann 
mehr falsch machen.

> So brauche ich überhaupt gar nicht mehr ständig fragen ob sich der
> Zustand T0IF auf High geändert hat auch nicht mit AND!

Wenn du dir von einem Interrupt Handler dadurch einfacheren Code 
erwartest, muss ich dich leider enttäuschen. Denn letzten Endes kann 
dein Interrupt Handler auch nur irgendwo ein Bit setzen, dass die Zeit 
abgelaufen ist. Und rate mal, was die Hauptschleife in der Zwischenzeit 
machen wird? Warten und testen ob das Bit schon gesetzt ist :-)
Also irgendwer muss auf jeden Fall warten, ob ein Bit gesetzt wird, egal 
wie man es dreht und wendet. Und um das zu testende Bit zu isolieren 
benutzt man einen AND und keinen XOR.
Persönliche Seite #1263202
Lesenswert?

Hi, ja ok ich sehe es ein. Ich habe es durch ANDLW getauscht, das hat 
aber leider auch nicht geholfen...

Das mit dem Interupt interessiert mich dann aber doch noch..
Was sagst du/ihr dazu:


Sobald, aus dem Hauptprogramm ins UP gesprungen wird (call):

;••••••••••••••••••••••••••••••••••••••••
Zeitreset
;••••••••••••••••••••••••••••••••••••••••

  movlw  D'15'
  movfw  counter

  movlw  B'00000111'
  movwf  OPTION_REG

  movlw  B'10100000'
  movwf  INTCON

Hier soll dann halt die 15 in counter geschrieben werden,
damit er 15 Timer-Overflows verweilt sage ich jetzt mal.
Dann die Einstellungen für den Timer.
Und anschließend noch, das Interupts genrell erlaubt sind
und, dass mein Interupt erlaubt ist Timer-Overflow.

Dann geht es im Quellcode direkt hiermit weiter:

;••••••••••••••••••••••••••••••••••••••••
Wait
;••••••••••••••••••••••••••••••••••••••••

  tstf  counter
  btfss  STATUS,Z
  goto   Wait
  return

Hier fragt er im Grunde die ganze Zeit immer nur ab ob in counter
schon eine 0 steht, wenn ja, dann wird der return ausgeführt
(also zurück in das Hauptprogramm).

Hier verweilt er also bis in counter eine "0" steht.
Das soll mit dem Interupts passieren:

ORG   0x04

movlw  B'10100000'
movwf  INTCON
decf  counter

RETFIE

Also: ORG 0x04 weil ja hier die Interuptsroutine anfängt.
Dann muss als erstes das T0IF wieder auf 0 gesetzt werden,
weil er sonst nach dem Interupt direkt wieder rein springt.
Und dann wird halt counter um 1 verringert und anschließend
durch den RETFIE Befehl zurück zum Programm wo durch den Interupt
unterbrochen wurde dadurch wird auch autom das GIE wieder gesetzt.

Das muss dann eben 15 mal passieren, damit in counter eine 0 steht
und er wieder zurück in das Hauptprogramm kommt.

Bitte nicht wieder so agresive reagieren ich will nur lernen :/

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren