Forum: Mikrocontroller und Digitale Elektronik PIC Assemblerprogramm- Problem


von Michael R. (elektr-hobbyist)


Angehängte Dateien:

Lesenswert?

Hallo liebe Forumteilnehmer.

Ich beschäftige mich erst seit kurzem mit PICs und 
Assemblerprogrammierung.
Um den Umgang mit Timern und Interupts zu lernen, wollte ich mit diesen 
gerne eine Einschaltverzögerung programmieren.
Ca. 5 Sekunden nach dem Anlegen der Betriebsspannung, sollen mehrere 
LEDs angehen.

Erstmal ein paar Worte zur Hardware.
Ich benutze die Testplatine von „sprut“ mit dem PIC 16f877.
Getaktet ist der mit 8MHz.
Am Port D hängt eine 7- Segment- Platine mit 4 Anzeigen (meine LEDs).
Am Port B sind die Steuerleitungen zur Auswahl der Anzeige 
angeschlossen.
Es sollen alle LEDs von Anzeige 1 zum leuchten gebracht werden.

Nun meine Grundsatzüberlegungen zur Programmgestaltung.
Ich Benutze den Timer 0. Seine Impulse erhält er vom internen PIC- Takt.
Mein PIC ist mit 8MHz getaktet. Über den bei Timer 0 obligatorischen 
Vorteiler, wird dieser auf ein ¼ des PIC- Taktes reduziert. Also auf 
2MHz. Dann benutze ich den Vorteiler von Timer 0, mit einem 
eingestellten Teilverhältnis von 256:1. Dadurch kommt man noch auf 
7812,5 Hz. Das bedeutet der Timer bekommt aller 128 µs einen Impuls.
Bis zum Überlauf, und somit zum Überlaufinterupt, benötigt der Timer 256 
Impulse.
256 x 128 µs = ~0,033 s.
Um auf meine gewünschten 5s zu kommen, braucht es also ~152 
Timerdurchläufe (5s / 0,033s = 151,5).
Um dieses Problem zu lösen, war meine Idee eine reservierte 
Speicherzelle („loop“) mit 152 zu beschreiben, und in jedem Timer 0 
Interupt zu decrementieren. Ich prüfe dann ob „loop“ = 0 ist. Wenn nicht 
dann wird ein neuer Timerdurchlauf gestartet, wenn ja dann werden die 
LEDs eingeschaltet.

Daraufhin habe ich das im Anhang zu findende Programm geschrieben.
Leider Funktioniert es aber nicht.
Beim ersten Einschalten nach der Programmierung tut sich gar nichts. 
Beim zweiten Einschalten leuchten dann alle LEDs sofort.

Kann mir vielleicht jemand weiterhelfen, wo der Fehler liegt?

L.G.

Micha

von Michael L. (michaelx)


Lesenswert?

Hi, ich hab grad nicht mehr den Nerv, deinen ganzen Code zu 
durchforsten. Aber beim Thema ISR hast du was falsch verstanden.

Das GIE ist beim Eintritt in die ISR disabled, und wird mit dem RETFIE 
wieder enabled. Außerdem darf vor dem Sichern des Kontexts und nach 
dessen Wiederherstellen kein kein anderer Befehl ausgeführt werden, der 
den Kontext verändert.

Das erst mal für den Moment.

Ach, und wenn du wieder mal Code postest, dann nicht als xxxx.txt 
sondern als xxx.asm bitte. Dann bietet das Forum eine Code-Ansicht, das 
liest sich besser.

Grüße.

von Michael R. (elektr-hobbyist)


Angehängte Dateien:

Lesenswert?

Hallo Micha.

Danke für Deine Tipps.
Ich habe Deine Anregung bezüglich der ISR gleich mal umgesetzt.
Jetzt leuchten die LEDs nicht erst beim zweiten Einschalten sofort, 
sondern gleich beim ersten Einschalten nach der Programmierung.

Den geänderten Code habe ich angehängt. Diesmal als xxx.asm.

L.G.

Micha

von Michael L. (michaelx)


Lesenswert?

Hallo nochmal.

Du hast den Code etwas verbastelt ...

Hier mal die "Grundkonstruktion" der ISR
1
isr
2
; Kontext sichern
3
movwf  w_temp              ; save off current W register contents
4
movf   STATUS,w            ; move status register into W register
5
movwf  status_temp         ; save off contents of STATUS register
6
7
; hier der eigentliche ISR-Code
8
9
10
; Kontext wiederherstellen
11
movf   status_temp,w       ; retrieve copy of STATUS register
12
movwf  STATUS              ; restore pre-isr STATUS register contents
13
swapf  w_temp,f
14
swapf  w_temp,w            ; restore pre-isr W register contents
15
16
retfie

Das hier beschriebene Sichern und Wiederherstellen des Kontexts ist das 
absolute Minimum, bitte lese mal unter "Context Saving During 
Interrupts" im Datenblatt.

von Ottmar K. (wil1)


Lesenswert?

Hallo Michael R.

Ich kommentiere mal Deinen Text zu den wichtigsten Auffälligkeiten 
welche ich beim Durchlesen so gesehen habe:

Struktur des Codes:
Halte Dich am Besten immer an ein einheitliches Schema im 
Programmaufbau. Sprut macht das sehr schön, aber auch in den mit MPLAB 
gelieferten Beispielfiles wird das deutlich gezeigt. Siehe dazu
"MPLAB\MPASM Suite\Template\Code\16F877TEMP.ASM"

****** VARIABLE DEFINITIONS
w_temp        EQU     0x7E
status_temp   EQU     0x7F

cblock  0x10  ;das ist die Adresse des Registers T1CON!
    loop      ;   solange dieses Register nicht als T1CON
    endc      ;   verwendet wird bleibt das noch ohne Auswirkungen!
              ;   Glück gehabt!

Du hast jetzt einmal die Register  7E,7F und dann mit der Variable 
"loop" Register 10 belegt. Sinnvoller ist es alle Variablen in einen 
Adressbereich, optimal am Beginn des GPR.Memory reinzupacken:

  CBLOCK 0x20  ;20h Beginn des General Purpose Register-Memory (GPR)
  w_temp
  status_temp
  loop
  ENDC

Das dekrementieren und Auswerte des Interruptzählers "loop" - ich würde 
ihn im Klartext "cntOverflow" nennen - lässt sich vereinfachen:
  decfsz loop,f
  Goto  Befehl1
  Befehl2
vermindert bei jedem Durchlauf loop um 1. Bei Erreichen von 0 wird der 
folgende Befehl1 übersprungen (z.B. Flag setzen/löschen u.a.
Wenn Du die ISR nicht mehr durchlaufen willst, schaltets Du einfach den 
aufrufenden Interrupt ab z.B.
  bcf  INTCON,T0IE  ;TMR0-Overflow-Interrupt disabled

Die Interrupt-Start - und Ende-Sequenz übernimmst Du im Prinzip am 
Besten immer aus dem Datenblatt!

Init
Initialisierungen nicht in "main" sondern im Abschnitt "Init" 
unterbringen
nachfolgend kannst Du Dir 2x banksel sparen denn alle 3 Register sind in 
der gleichen Bank (bank 1)

  banksel OPTION_REG
  clrf OPTIN_REG
  banksel  TRISD
  clrf  TRISD
  movlw  0x0    ; alle pins von D sollen output pins werden
  movwf  TRISD
  banksel  TRISB
  clrf  TRISB
  movlw  0x0    ; alle pins werden als output pins geschaltet
  movwf  TRISB

Vorschlag:
  banksel  TRISB    ;wechselt zu bank 1
  clrf  TRISB       ;bank1
  clrf  TRISD       ;bank1
  clrf  OPTION_REG  ;bank1
  .....

In der ISR würde ich nur ein Flag setze, welches dann im Hauptprogramm 
"Main" ausgewertet wird

ISR
  decfsz cntOverflow,f  ;Dekrement counter
  bsf  Flag,0      ;wenn counter=0 dann Flag,0=1
  .....
Dann vereinfacht sich Main deutlich
Main
  btfsc Flag,0          ;prüfen ob Flag,0=1
  CALL  LED_Einschalten ;Ja, LED einschalten
  ; sonstigr Code       ;NEIN-dann hier weiter
  ; ...............
  GOTO Main

GOTO's machen den Code unübersichtlich, Unterprogramm-CALL's sind 
dagegen auf den ersten Blick klar zu verstehen (vorausgesetzt ihre 
Labels sind auch verständlich (LED_Einschalten -> LEDswtch0 <- ????
  ;
LED_Einschalten
  movlw b'00001000' ;Wert zum setzen von Pins (0/1 LED aus/ein)
  movwf PORTD       ;über das WREG in PORTD kopieren
  bcf  Flag,0       ;Flag wieder zurücksetzen
  RETURN

Das wär was mir so beim Überfliegen aufgefallen ist.

mfG Ottmar

von Erich (Gast)


Lesenswert?

Ein PIC ist nicht so dolle für Assemblerprogrammierung.
Jeder 2. Befehl muss ein banksel oder retlw sein, grausam.
Du solltest auf C umstellen.
Beschaffe die das "Pickit3" bzw. "pickit 3 debug express tutorial".

Heutzutage macht man Fahrzeugführerschein auch auf PKW und nicht mehr 
auf Pferdekutschen mit Gäulen.

Gruss

von Erich (Gast)


Lesenswert?

Nachtrag zu  09.01.2013 13:21 :
Gute Seite ist hier
http://www.norbertmoch.de/_elektronik/PIC/PIC.html

Gruss

von Ottmar K. (wil1)


Lesenswert?

Erich schrieb:
> Ein PIC ist nicht so dolle für Assemblerprogrammierung.
> Jeder 2. Befehl muss ein banksel oder retlw sein, grausam.

So ein einseitiger Quatsch!
Hast wohl noch nie nen PIC in Assembler programmiert!

mfG Ottmar

von Erich (Gast)


Lesenswert?

>Hast wohl noch nie nen PIC in Assembler programmiert!

Leider doch.
Aber das war früher, als ich noch jung und dumm war.

Gruss

von Teo D. (teoderix)


Lesenswert?

Ottmar K. schrieb:
> In der ISR würde ich nur ein Flag setze, welches dann im Hauptprogramm
> "Main" ausgewertet wird

Da reichts doch gleich nur das Interrupt-Flag im Hauptprogramm aus zu 
werten.


Erich schrieb:
> Aber das war früher, als ich noch jung und dumm war.

Na ja, man könnte vermuten viel schlauer bist Du Heute auch nich, wen 
man deine Aussage liest :P
Aber viel Tipperrei ist das schon und manchmal glaubt man auch zu hören 
wie sich die Gehirnwindungen verbiegen :)
Ist allerdings meiner Meinung nach der vernünftigste weg sich das erste 
mal mit µC's zu beschäftigen.

von Ottmar K. (wil1)


Lesenswert?

Teo Derix schrieb:
> Da reichts doch gleich nur das Interrupt-Flag im Hauptprogramm aus zu
> werten.

Nach RETFIE ist INTCON,GIE automatisch wieder gesetzt. Sollte 
INTCON,T0IE wieder aktiv sein - was bei fortlaufend aktivem 
TMR0-overflow-Interrupt ja wohl die Regel sein muss - wird sofort wieder 
die ISR aufgerufen! ????

Für den Rest Deines Kommentares hast Du meine volle Zustimmung!:-)

mfG Ottmar

von Teo D. (teoderix)


Lesenswert?

Der Interrupt ist natürlich gesperrt, es wird keine ISR aufgerufen.  Das 
Flag per Hand zurücksetzen. Darum gehts ja, man muss keine ISR dafür 
einrichten wenn man darin eh nur ein Flag setzt.
Ich dachte das sei klar.

von Michael R. (elektr-hobbyist)


Angehängte Dateien:

Lesenswert?

Hallo alle zusammen.

Ich habe mein Programm, unter Berücksichtigung der von euch angeratenen 
Änderungen, umgeschrieben.
Es scheint jetzt auch zu funktionieren. :-)

Vielen Dank an dieser Stelle für eure Hilfe.

Ich schreibe „scheint zu funktionieren“, da nun ein Phänomen auftritt, 
auf das ich mir noch keinen rechten Reim machen kann.
Beim ersten Einschalten nach der Programmierung, Funktioniert die 
Einschaltverzögerung wunderbar. Schalte ich aus und wieder ein, leuchten 
die LEDs sofort. Schalte ich allerdings nicht aus, sondern ziehe nur den 
Stecker vom Steckernetzteil ab, und stecke diesen dann wieder an, dann 
funktioniert die Einschaltverzögerung. Kann mir das vielleicht jemand 
erklären?

Dann noch eine zweite Frage. Die Verzögerung funktioniert zwar, unter 
den geschilderten Umständen, jedoch beträgt die Verzögerungszeit ca. 8s, 
statt meiner gewünschten 5s.
Das lässt sich in der Software einfach beheben. Allerdings weicht die 
tatsächliche Verzögerung, von der geplanten doch deutlich ab.
Kann dies daran liegen, dass meine obige Rechnung, nicht die für die 
Befehlabarbeitung benötigte Zeit mit berücksichtigt?

Ich habe mal das geänderte Programm als xxx.asm angehängt.
Wer dazu noch Anregungen hat, kann diese gern äußern.
Ich möchte ja dazu lernen.

Außerdem habe ich den Schaltplan, von meinem Testboard, als PDF 
angehängt, weil ich mir vorstellen kann, dass die Ursache für das erst 
geschilderte Phänomen, auf der Hardwareseite liegt.

L.G.

Micha

von Ottmar K. (wil1)


Angehängte Dateien:

Lesenswert?

Hallo Michael R. (elektr-hobbyist)

Wenn Du MPLAB verwenden solltest, stehen Dir verschiedene Tools zur 
Verfügung. So ist im Menü "Debugger" der Eintrag "StopWatch" zu finden. 
Mit dieser Stoppuhr kannst Du zyklengenau die Verarbeitungszeiten 
messen. Dein Programm beendet z.B. nach ca.8.3s mit dem setzen von 
flag,0 die ISR.Routine. An Deiner Platine liegt es also nicht.

Aber:
Eine einmalige Einschaltverzögerung nach Power-ON-Reset (POR) würde ich 
nicht per Interrupt sondern mit einer simplen Delay-Routine erledigen:

Main
  CALL Delay_5s
  ;mach dies
  CALL Delay_5s
  ;mach jenes
Main_Loop
  ;warte auf irgendwas
  GOTO  Main_Loop

Delay_5s
; Generated by http://www.piclist.com/cgi-bin/delay.exe
; See also various delay routines at
; http://www.piclist.com/techref/microchip/delays.htm
; Delay = 5 seconds Clock frequency = 4 MHz
  movlw  0x2D
  movwf  d1
  movlw  0xE7
  movwf  d2
  movlw  0x0B
  movwf  d3
Delay_0
  decfsz  d1, f
  goto  $+2
  decfsz  d2, f
  goto  $+2
  decfsz  d3, f
  goto  Delay_0
   RETURN
;
Wenn Du eine sich imemr wiederholende Aufgabe hast, z.B. Zeittakt für 
eine Uhr, oder andere per Interrupt wiederholt zu steuernde Vorgänge, 
ist eine ISR von Vorteil.
Allerdings musst Du Dir klar sein, dass bis zum 1. Aufruf der ISR etwas 
mehr Zeit verstreicht als durch das eigentliche ISR-Intervall vorgegeben 
ist. Schließlich ist ja die Initialisierung durchzuführen, main ist zu 
durchlaufen usw. Allerdings kann man das auch -falls notwendig- mit 
entsprechenden Presets abgleichen.

Als Anlage habe ich Dir mal so eine Routine beigefügt, welche Du ja nach 
eigenem Gutdünken verwerten/ändern kannst. Auf jeden Fall liefert sie 
auf die µs 5 Sekunden-ISR-Intervalle (5s =1 5s=0 usw) des Flags 
"FLAG_5s" mit dem 8MHz-Quarz. Den Abgleich habe ich mit MPLAB-Sim und 
der dort integrierten StopWatch vorgenommen.

Noch was: versuche einen noch klareren Programmaufbau zu realisieren. 
Nimm Dir dazu für das Erste die Lernbeispiele von www.sprut.de als 
Vorbild.

mfG Ottmar

von stepp64 (Gast)


Lesenswert?

Ottmar K. schrieb:
> Du hast jetzt einmal die Register  7E,7F und dann mit der Variable
> "loop" Register 10 belegt. Sinnvoller ist es alle Variablen in einen
> Adressbereich, optimal am Beginn des GPR.Memory reinzupacken:
>
>   CBLOCK 0x20  ;20h Beginn des General Purpose Register-Memory (GPR)
>   w_temp
>   status_temp
>   loop
>   ENDC

Also die Rettungsregister in der ISR (w_temp, status_temp) müssen im 
Bereich ab 70h liegen. Die Adressen von 70h bis 7Fh werden in alle Bänke 
"gespiegelt". Und da du nie weist, in welcher Bank du dich bei Eintritt 
in die ISR befindest, muss sichergestellt sein, dass die 
Rettungsregister von allen Bänken aus erreichbar sind.

Gruß Sven

von Michael R. (elektr-hobbyist)


Lesenswert?

Hallo Ottmar.

Vielen Danke für deine Tipps.
Die beiden Links sind Super.
Meine Programme klarer zu strukturieren, werde ich beherzigen.

> Dein Programm beendet z.B. nach ca.8.3s mit dem setzen von
> flag,0 die ISR.Routine. An Deiner Platine liegt es also nicht.

Die Sache mit der Hardware meinte ich, im Zusammenhang mit dem Phänomen, 
das nach dem ersten Einschalten, nach der Programmierung, alles nach 
Wunsch funktioniert, beim zweiten Einschalten aber sofort alle LEDs 
leuchten.
Lasse ich das Board eingeschaltet, und ziehe stattdessen den 
Stromversorgungsstecker ab, und stecke ihn wieder an, funktioniert auch 
alles nach Wunsch.
Schalte ich das Board aus, und ziehe den Stromversorgungsstecker, und 
stecke ihn wieder an, leuchten die LEDs wieder sofort.
Schalte ich das Board nur mit dem Schalten aus, und drücke danach den 
"reset"- Taster, und schalte wieder ein, klappt auch alles.

???

L.G.

Micha

von Michael R. (elektr-hobbyist)


Lesenswert?

Hallo Sven.

> Also die Rettungsregister in der ISR (w_temp, status_temp) müssen im
> Bereich ab 70h liegen. Die Adressen von 70h bis 7Fh werden in alle Bänke
> "gespiegelt". Und da du nie weist, in welcher Bank du dich bei Eintritt
> in die ISR befindest, muss sichergestellt sein, dass die
> Rettungsregister von allen Bänken aus erreichbar sind.

Danke für den Hinweis.

L.G.

Micha

von Ottmar K. (wil1)


Lesenswert?

stepp64 schrieb:
> Also die Rettungsregister in der ISR (w_temp, status_temp) müssen im
> Bereich ab 70h liegen.

Dank Deinem Hinweis habe ich das Datenblatt zu diesem Thema genauer 
gelesen. Besten Dank, man lernt eben nie aus!

mfg Ottmar

von Ottmar K. (wil1)


Lesenswert?

Hallo Michael R.

Beim Programmieren von 16Fxxx- PICs mußt Du mehr auf das Banking achten. 
Schaue Dir doch mal an in welcher Bank die einzelnen Register liegen (S. 
19 Datenblatt 16F877).

Der ERSTE Eintritt in die ISR geschieht noch mit Bank 1, während aber 
das GPR in Bank 0 ist.
       decfsz   cnt_overflow,1 ; cnt_overflow wird decrementiert, und 
das
                               ;Ergebniss wieder in cnt_overflow
diese Variable wird NICHT dekrementiert!!

Ursache ist der unterlassene Bankwechsel von Bank 1 zurück zu Bank 0:
main:    .......
  bsf  STATUS,RP0      ; auf Bank 1 umschalten
  bcf  OPTION_REG,T0CS ; TMR 0 wird von externem Takt umg
;       =====================
  BCF  STATUS,RP0      ;ZURÜCK zu BANK 0 !!!
;       =====================
nach dieser Änderung  reduziert sich die Durchlaufzeit bis zur ISR, 
Programmzeite
  bsf  flag,0          ; Flag 0 wird auf 1 gesetzt
von 8,39s auf 4,98s!

Ich möchte Dir ja nicht meinen Porgrammierstil aufschwatzen, der ist bei 
weitem nicht perfekt, aber wenn Du keine Übersichtlichkeit bewahrst, 
erzeugst  Du Dir selber ohne Ende Probleme und Zeitverluste.

Warum wechselst Du eigentlich vom internen Takt für TMR0 zu externen 
Takt?

mfG Ottmar

von stepp64 (Gast)


Lesenswert?

Das ist so ein Trick. Der Timer0 lässt sich nicht abschalten. Man kann 
ihn aber auf extern legen, damit bekommt er keine Impulse mehr und 
bleibt stehen. Man sollte dann aber auch dafür sorgen, dass der externe 
Eingang nicht offen in der Luft hängt und eventuell Störimpulse 
auffängt. Also am besten auf ein definiertes  Potential legen (über 
einen 10k R).

von stepp64 (Gast)


Lesenswert?

Ich hatte mir allerdings irgendwann angewöhnt über den Timer2 und dem 
PR2 Register einen 10ms Takt zu generieren welcher auch exakt 10ms lang 
ist. Und dann halt über mehrere Variablen die benötigten Intervalle 
(100ms 1s, 10s etc.) daraus abgeleitet. Hat sich eigentlich bewährt.
Bsp. für 8MHz. Bank0 und Bank1 sind Makros. Find ich übersichtlicher.
1
Bank0      
2
movlw  B'01001111'  ;Timer2: Nachteiler 10:1, Vorteiler 16:1, Timer ON 
3
movwf  T2CON
4
Bank1
5
movlw  .124    ;PR2=124 (0 zählt mit) 8MHz:4:10:16:125= 100Hz 
6
movwf  PR2

von stepp64 (Gast)


Lesenswert?

Ach ja, nun noch ein drittes mal:

Ich hab mir auch angewöhnt, den RAM zu Löschen. Nach dem Einschalten hat 
dieser einen undefinierten Zustand, was zu Problemen führen kann. Hier 
meine Löschroutine:
1
;nun noch den RAM löschen
2
Bank0
3
  movlw  0x20      ;Bank 0 löschen
4
  movwf  FSR
5
RAMerase0        
6
  clrf  INDF
7
  incf  FSR,f
8
  btfss  FSR,7      ;0x80 erreicht (Bit7=1)?
9
  goto  RAMerase0    ;nö, dann noch mal
10
11
Bank1        ;Bank 1 löschen
12
  movlw  0xA0
13
  movwf  FSR
14
RAMerase1        
15
  clrf  INDF
16
  incf  FSR,f
17
  btfss  STATUS,Z    ;0x00 erreicht (STATUS,Z=1)?
18
  goto  RAMerase1    ;nö, dann noch mal

Das nun schon etwas tricky. Ich spreche die RAM-Zellen indirekt über das 
INDF Register an. Ist eine schöne Sache. Könnte aber noch etwas zu 
schwierig sein als Anfänger.

von Michael R. (elektr-hobbyist)


Lesenswert?

Hallo Ottmar.

Danke, ich habe die Änderung implementier.

Ottmar schrieb:

> Warum wechselst Du eigentlich vom internen Takt für TMR0 zu externen
> Takt?

stepp64 schrieb:

> Das ist so ein Trick. Der Timer0 lässt sich nicht abschalten. Man kann
> ihn aber auf extern legen, damit bekommt er keine Impulse mehr und
> bleibt stehen.

Genau das war mein Gedanke dahinter.
Der Timer 1 würde sich wohl besser dafür eignen, da er eine Torstufe 
besitzt. Allerdings schafft dessen Vorteiler nur 8:1. Das empfand ich 
als unvorteilhaft.

L.G.

Micha

von Michael R. (elektr-hobbyist)


Lesenswert?

Hallo stepp64.

Danke für deine Tipps.

stepp64 schrieb:

> Man sollte dann aber auch dafür sorgen, dass der externe
> Eingang nicht offen in der Luft hängt und eventuell Störimpulse
> auffängt. Also am besten auf ein definiertes  Potential legen (über
> einen 10k R).

Ich habe ihn direkt auf Masse gelegt.

L.G.

Micha

von Chris (Gast)


Lesenswert?

Timer0 kann man nicht abschalten, das stimmt, aber den TMR0IE kann man 
ein sowie ausschalten, damit keine Interrupts mehr kommen. Dies sollte 
reichen.
Im Interrupt sollte man schauen, ob tmr0ie eingeschaltet ist oder nicht
bevor man einen TMR0IF checkt, also

isr_tmr0
 btfsc INTCON,TMR0IE
 btfss INTCON,TMR0IF
 goto  isr_tmr0_done
 bcf   INTCON,TMR0IF
 ; tmr0 isr code goes here
 movlw 250 -2 ; 250 clk (uS) - 2 clk
 subwf tmr0,f ; udate timer for 1ms interval div 4
 incfsz tick  ; every 0.25 ms
 goto isr_tmr0_done
 incfsz tick+1 ; every 64 ms
 goto isr_tmr0_done
 incf tick+1 ; every 16.384 sec
isr_tmr0_done
isr_tmr1

Weiters ist es auch gängig, die OSCCAL so zu calibrieren, daß 1024 = 
1ms.
Damit hat man dann einen einfachen 1ms/4ms/8ms/... Zeitbasis.

Auch ist eine Möglichkeit ist, z.B. eine Variable zu haben als 
zusätzlichen
Timer. Z.B. 10ms. Beispiel  wenn man bei 0.25ms Timer 40 dazuzählt, hat
man bei jedem Überlauf 10ms Interval.

von Maik W. (werner01)


Lesenswert?

cblock(0x10) geht nicht mein besster. Auf der 0x10 liegt T1CON!

von Michael R. (elektr-hobbyist)


Lesenswert?

Maik schrieb:

> cblock(0x10) geht nicht mein besster. Auf der 0x10 liegt T1CON!

Das wurde hier schon erörtert, und ich habe es entsprechen geändert. 
Siehe Anhang "Timer_Test_V2" mein Bester.

Gruß.

Micha

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.