Forum: Mikrocontroller und Digitale Elektronik Zeitschleife mittels Timer


von PIC N. (eigo) Benutzerseite


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?

von PIC N. (eigo) Benutzerseite


Lesenswert?

Keiner eine Idee?

von iCarly (Gast)


Lesenswert?

PIC ASM das tun sich nur wenige an.
War auch ein Grund warum ich damals auf AVR umgestiegen bin.

von Peter D. (peda)


Lesenswert?

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.


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


Peter

von aha (Gast)


Lesenswert?

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

von PIC N. (eigo) Benutzerseite


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?

von Karl H. (kbuchegg)


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.

von PIC N. (eigo) Benutzerseite


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...

von PIC N. (eigo) Benutzerseite


Angehängte Dateien:

Lesenswert?

>>Ich habe nochmal im Anhang dem kompletten Quellcode gesetzt!

von Stefan E. (sternst)


Lesenswert?

>  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.

Wie Karl-Heinz aber schon sagte, testet XOR nicht nur das eine Bit. Wenn 
auch noch irgendein anderes Bit in dem Register 1 ist, läuft die 
Schleife endlos.

von Sebastian (Gast)


Lesenswert?

Ich verstehe jetzt nicht so viel vom PIC, aber ist INTCON das richtige 
Register? Vom AVR her kenne ich das so, daß es ein Timer-Overflow bew. 
Compare-Register gibt. Kann aber beim PIC anders sein. Schon mal auf 
sprut.de nachgesehen?

von PIC N. (eigo) Benutzerseite


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:
>>  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.
>
> Wie Karl-Heinz aber schon sagte,

Ehre, wem Ehre gebührt.
PeDa hat das aufs Tapet gebracht.

von Karl H. (kbuchegg)


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.

von PIC N. (eigo) Benutzerseite


Lesenswert?

Hey, klar hab ich das kapiert, deswegen will ich es ja jetzt auch mit 
dem Interrupt machen! Sprich, XOR ist ganz raus!

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

von kurz (Gast)


Lesenswert?

Du hast irgendwie nix kapiert. Interrupt ist doch ne ganz andere Liga. 
Da kannst Du mit Deinem fundamentalen Wissen noch wesentlich mehr falsch 
machen.

Was ist so schwierig den XOR gegen einen AND-Befehl zu tauschen? Diese 
Antwort bleibst Du Dir selbst wohl schuldig.

von Karl H. (kbuchegg)


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.

von PIC N. (eigo) Benutzerseite


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 :/

von PIC N. (eigo) Benutzerseite


Lesenswert?

Tippfehler:

  movlw  D'15'
  movwf  counter

von PIC N. (eigo) Benutzerseite


Lesenswert?

Okay, nochmal vielen Dank an alle!
Ich hab es jetzt mit dem Interupt geschafft.

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.