PIC-Microcontroller

Elektronik u. Mikrocontroller => Mikrocontroller => Thema gestartet von: picass in 27.07.2025, 15:21:40 CEST

Titel: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 27.07.2025, 15:21:40 CEST
Mal wieder meine Haß-Liebe mit und zu Interrupts: ein PIC18F14K22 soll in seiner Counter-Funktion genutzt werden, wozu ich zwecks der 16-bit den Timer1 ausgewählt hatte. Das Prog ist erfrischend kurz: der PIC bewegt sich gemütlich (31 kHz) in einer Nichts-Tun-Schleife und soll durch den Ablauf des Timers1 in die Irq-Routine springen, in welcher er eigentlich auch nur - zunächst aus Testgründen - eine LED toggeln soll. Das im Kreis-Laufen funktioniert, aber der Irq klemmt wieder, der PIC kommt nicht in seine Service-Routine. Der PIC zählt an seinem Port A5 einen externen Takt. Der wird abgeleitet aus der Netzfrequenz. Über einen Optokoppler wird je nur die positive Halbwelle genutzt, was zu sehr sauberem Rombus an a5 führt. Der Counter1 wird mit seinem Maximalwert minus 50 befüllt, will sagen, der müsste noch genau 50 positive Schwinger abzählen - was einer Sekunde entsprechen sollte  - und dann überlaufen. Und Interrupten. Aber da hat der andere Vorstellungen.

Der Umgang mit Timern ist mir nur rudimentär geläufig, bei einem Timer0 ohne Irq klappte das mal. Wenn ich das Datenblatt richtig verstehe, wird das sonst unvermeidbare INTCON-Register gar nicht benötigt. Das Prog ist von allem Unnötigen befreit und meiner Meinung nach gut lesbar. Das ASM-File ist hier als Text-File angefügt. Ach ja, das Prog läuft mit dem "mittleren" Assembler, also MPLAB X 5.20 (geht bis 5.35). Vielleicht schaut ja jemand mal rein. Is klar, da fehlt - wie so üblich - ein "nur........". Seufz, wenn nur das "nur" nicht wäre!
Grüße, picass
stundenzaehler03.txt
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 27.07.2025, 16:45:32 CEST
Kaum eingestellt und auf dem Weg zum Kaffee-Zubereiten. aber zu spät für eine sofortige Korrektur  fiel mir auf, wo im obigen Prog ein "NUR" zu finden ist: falsche Zuordnung beim Rücksprung nach einem Durchlauf der Dauerschleife. Da wurde etwas zu weit zurück gesprungen und dadurch das 16-bit-Counter-Register immer wieder neu befüllt. Das ist nun geändert. Aber der IRQ klemmt nach wie vor. Auch im Simulator wird der Überlauf zwar angezeigt, aber nix weiter passiert, also kein Einsprung in die IRQ-Routine. Hier das überarbeitete Prog:
Grüße, picass
stundenzaehler03.txt
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 27.07.2025, 18:36:44 CEST
Hallo picass,

ich nutze ASM zwar nur, wenn es absolut nötig ist, aber ich sehe kein setzen des GIE- Bit!?

Gruß
PICkel
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 27.07.2025, 20:05:34 CEST
Du bist wieder beim Pic zurück! 8)
Welches Signal hast Du denn? Ist es ein sauberes Rechtecksignal? Ansonsten würde ich es zuerst über einen Schmitt-Tricker aufbereiten. (z.B. 7414)

Ich würde folgender Maßen vorgehen.
Zuerst nach dem Start würde ich alle Parameter initialisieren. Ich habe jetzt im Überflug nicht gesehen, wo der Port als Eingang für den Timer initialisiert ist.

INTCON Byte setzen:
GIE/GIEH PEIE/GIEL TMR0IE INT0IE RABIE TMR0IF INT0IF RABIF
GIE muss gesetzt werden
PEIE
IPR1,TMR1IP (HI Prio)
PIE1,TMR1IE (1)
PIR1,TMR1IF (0)

T1CON Byte setzen, 
TMR1CS: Timer1 Clock Source Select bit
TMR1ON
T1CKPS<1:0>: Timer1 Input Clock Prescale Select bits
T1RUN: Timer1 System Clock Status bit

Nach der Initialisierung würde ich im Hauptprogramm (Main) eine Endlosschleife machen.
zb. 
main nop
bra main

im Interrupt:
hier würde ich zuerst einmal abfragen, ob der Interrupt vom Timer ausgelöst wurde. 
wenn ja, dann das TMR1IF löschen.
nicht das TMR1IE, das wird noch benötigt. 
nun kannst Du im Interrupt den Zählstand abfragen. Ich meine der Timer zählt rückwärts. Und bei erreichen den Zählerstand neu setzen, bzw den Zähler-Offset einfach Timerwert hinzuaddieren bzw abziehen
Den Interrupt beendest Du mit.
RETFIE (Return from Interrupt), kein Sprung nach Main oder sonst wohin!!
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 27.07.2025, 20:47:17 CEST
Ich habe im Archiv ein Beispiel gefunden, dies ist ein Zeitprogramm welches mit dem Systemtakt ich meine 40Mhz arbeitet. Ich hatte dies im meiner Anfangszeit programmiert, heute würde ich es etwas anders machen. Nicht den Timer direkt setzen, sondern die Zyklen abziehen. Dadurch gibt es keine Ungenauigkeiten. interr_b_txt.txt
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 28.07.2025, 12:39:29 CEST
Zitat von: pic18 in 27.07.2025, 20:05:34 CESTIch meine der Timer zählt rückwärts.
Über das "Zurück-beim PIC" schreibe ich an anderer Stelle.
Nix, der Timer/Counter zählt nach oben:"The TMR1 register pair (TMR1H:TMR1L) increments
from 0000h to FFFFh and rolls over to 0000h." So das Datenblatt.

Das INICON-Register ! Das beschäftigt mich auch, schon alleine, weil man bei Interrupts bislang an dem nicht vorbei kam. Aber......, da gibt es gleich mehrere "Aber": aber für den Time/Counter1 gibt es ein eigenes Register, über welchen der IRQ ein- u. ausgeschaltet wird. Und das Reg wird in jedem Fall benötigt. Käme nun das INTCON auch noch dazu, würde doppelt gemoppelt und welche Ein-oder-Ausschaltung würde denn dann greifen? Weiter: in dem Beispiel-Code für Timer1 im Datenblatt steht nix von INTCON, nur das Sonder-Reg..

Muss da mal 'ne gehörige Runde experimentieren, gleich heute Nachmittag gehts los.
Ach ja, wie schon beschrieben: das Taktsignal ist ausgesprochen sauber zwischen 0,6 Volt und 4,9 Volt. Der Port A Eingang hat eine Schmitt-Trigger-Funktion.
Grüße, picass
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 28.07.2025, 13:40:16 CEST
Zitat von: picass in 28.07.2025, 12:39:29 CESTDas INICON-Register !

Um das INTCON- Register kommt man halt nicht drumherum!
Und das 7. Bit im INTCON ist das GIE-Bit. GIE = Global Interrupt Enable, dieses Bit schaltet also alle Interrupts ein oder aus, egal welche Interrupts (TMR0IE, TMR1IE,...) aktiviert sind.
Das ist wichtig, um bspw. in der Interruptroutine das "dazwischenfunken" eines weiteren INT's bei mehreren möglichen Interruptquellen zu verhindern. Man setzt also am Anfang der INT-Routine
  bcf    INTCON,GIE
und am Ende
  bsf    INTCON,GIE   
  RETFIE

Außerdem müsste doch wohl in Deinem Prog. statt
blink:                   ;
     bsf    PIE1,TMR1IF  ;enable timer1 interrupt

stehen:

blink:
     bsf    PIE1,TMR1IE  ;enable timer1 interrupt

Gruß
PICkel
(der hoffentlich die paar ASM- Zeilen richtig geschrieben hat  :)  )
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 28.07.2025, 15:49:58 CEST
Das INTCON Register ist schon wichtig, zum einen schaltest du den Interrupt ein, zum anderen kannst Du auch den Lo Interrupt einschalten. Ich kann mich erinnern, das früher ein Fehler in der Doku war das der Lo Interrupt auch ohne Hi Interrupt eingeschaltet werden kann. Dies ist aber nicht so. 
T1CON wird auch benötigt, zum einen wegen der Zählung 8 oder 16 Bit  T1CKPS1 benötigst Du für den Vorteiler.
So weit erstmal, ich melde mich später wieder
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 28.07.2025, 16:03:39 CEST

Ich habe hier die Register mal herauskopiert
Name Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Reset Values on page 
INTCON GIE/GIEH PEIE/GIEL TMR0IE INT0IE RABIE TMR0IF INT0IF RABIF 245 
IPR1 — ADIP RCIP TXIP SSPIP CCP1IP TMR2IP TMR1IP 248 
PIE1 — ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE 248 
PIR1 — ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF 248 
TMR1H Timer1 Register, High Byte 246 
TMR1L Timer1 Register, Low Byte 246 
TRISA — — TRISA5 TRISA4 —(1) TRISA2 TRISA1 TRISA0 248 
T1CON RD16 T1RUN T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON 246
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 28.07.2025, 16:34:42 CEST
Einige Strampelübungen weiter...., aber nur Teilerfolge. Zunächst war eine der beiden Kontroll-LEDs am falschen Portpin angeschlossen...Shit happens. Aber die andere wollte ja genauso wenig. Das lag dann wiederum daran, dass ich nur ganz rasch im Vorbeigehen auf ein andere, als die bislang genutzte interne Osillator-Quelle geschaltet hatte, nämlich auf den LP-Oszillator. Der machte dann alles derart grauenhaft langsam, dass ich allein deswegen an Defekte dachte. Nu flitzt wieder alles und die LEDs blinken, wie sie sollen. Und dann das INTCON-Reg. Wie konnte ich das nur verschmähen?! Das ist nun wieder im Spiel. Nutzt nur auch nichts, der IRQ klemmt nach wie vor: die IRQ-Routine wird nicht angesprungen.
Das RETFIE ist die übliche Variante, es geht aber auch mit Sprüngen in andere Progteile. Aber dessen Einfügen konnte nichts nützen, soweit kam der PIC erst gar nicht. Jetzt findet sich alles, was in einem meiner erfolgreichen IRQ-Programme auch findet, nur das dort ein Port-on-Change interruptet wird, hier halt der Timer1...... oder halt gerade leider nicht. Es läuft auf das völlig Übliche raus: irgendwo sitzt der dicke Floh und grinst sich einen! :-[ Grüße, picass
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: ^Cobra in 29.07.2025, 08:08:47 CEST
Stell Mal den aktuellen Code rein. 
Bei dein alten waren ja einige Fehler drin welche genannt wurden.
Ich würde im simolator Mal die Register kontrollieren. Eventuell wird auf einer falschen Bank noch geschrieben o.ä. 
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 29.07.2025, 08:46:18 CEST
@ PICkel 
Zitat von: PICkel in 28.07.2025, 13:40:16 CESTMan setzt also am Anfang der INT-Routine
  bcf    INTCON,GIE
und am Ende
  bsf    INTCON,GIE   
  RETFIE
ich denke dass dies nicht notwendig ist, der PIC sichert ja die Parameter und ich denke dass er einen zweiten Interrupt nicht zu lässt. Es sei dem es wird in einem Lo Interrupt ein Hi Interrupt ausgelöst. Dieser hat natürlich Vorrang. Beim Lo-Interrupt müssen natürlich auch die Statusregister usw. separat gesichert werden.
Zitat von: PICkel in 28.07.2025, 13:40:16 CESTbsf    PIE1,TMR1IF  ;enable timer1 interrupt
bsf PIR1, TMR1IF  

@picass 
hast Du mal meine Beispiele angeschaut, diese müssten eigentlich funktionieren. Es muss nur der Vorteiler geändert werden. Du arbeitest ja mit nur 31Khz
Zitat von: picass in 28.07.2025, 16:34:42 CESTDas RETFIE ist die übliche Variante, es geht aber auch mit Sprüngen in andere Progteile
ich bezweifle, dass du dann aus dem Interrupt wieder richtig zurückkommst. Außerdem läuft der bei ständigen Sprungbefehlen der 31-Level-Stack über. Ein Absturz ist dann programmiert. 
Bei RETFIE und RETURN würde ich FAST nehmen. Ich glaube das macht der Compiler automatisch. 

Du kannst ja mal dein überarbeitest Prog. hochladen, dann schaue ich mir es mal an. 
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: ^Cobra in 29.07.2025, 10:26:44 CEST
Zumindest die 'alten' Pics wie 16f628 war es nötig am Anfang einer int Routine GIE aus zu schalten. Ansonsten könnte es passieren das man nie mehr aus der Schleife kam weil ein Ereignis eintrat bevor die Routine komplett durch lief. 
Nach meinen Erinnerungen noch... Oder habe ich das nur aus Bauchgefühl gemacht?






Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 29.07.2025, 10:39:02 CEST
Verdammt, ich bekomme dieses Exopand, rsp. das Verkürzen nicht raus. Oder doch jetzt?
Zitat von: pic18 in 29.07.2025, 08:46:18 CEST@ PICkel

Zitat von: PICkel in 28.07.2025, 13:40:16 CESTbsf    PIE1,TMR1IF  ;enable timer1 interrupt

bsf PIR1, TMR1IF
;--------------------------------------

Ja Jungs, das ist so was mit den Assembeler-Direktriven!
Der gerötete Befehlssatz ist nicht zum Ein-(Aus-)Schalten des timer1-Irq's, das ist dasjenige Flag, welche beim Überlauf des Counters anzeigt.

Versuche mich gleich im Einzelschritt-Debuggen.
Im wahren PIC-Leben wäre im Falle meiner Anwendung eine Störung durch erneuten Irq während des Ablaufes der Irq-Routine nicht zu befürchten. Der gezählte externe Takt der 50-Hz-Netzfrequenz liegt bei 20 mS. In dieser Zeit kann auch der gemütliche 31 kHz-PIC 'ne Menge Cyclen abarbeiten, die arsch-kurze Irqu-Routine allemal.
Muss jetzt wech' und erst mal einen Einzelschritt-Taktgenerator erstellen und dann ein scharfes Auge auf das Counter-Register-Paar werfen.
Grüße, picas
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: ^Cobra in 29.07.2025, 11:01:14 CEST
also geht es jetzt?

TMR1IF wird ja automatisch gesetzt beim Überlauf und die Routine muss diese zurücksetzen.
Naürlich muss aber TMR1IE gesetzt sein.

Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 29.07.2025, 14:42:02 CEST
@^Cobra, @pic18:

Also es wirklich so, dass beim PIC18F14K22 und anderen das GIE-Bit beim Eintritt in den Interrupt gelöscht und bei RETFIE wieder gesetzt wird. Das wusste ich noch nicht.

Siehe DaBla Punkt 7.3:
7.3 Interrupt Response
When an interrupt is responded to, the global interrupt
enable bit is cleared to disable further interrupts.

Und weiter unten steht:
The "return-from-interrupt" instruction, RETFIE, exits
the interrupt routine and sets the GIE bit (GIEH or GIEL
if priority levels are used), which re-enables interrupts.

Das liest sich m.E. aber so, dass bei einem normalen Rücksprung (RETURN) dieses Bit nicht wieder gesetzt wird. Ganz zu schweigen davon, dass der Stack beim Interrupt-Eintritt gefüllt, aber bei den ganzen Sprungbefehlen (BC,BN,...,BRA,...) nicht wieder geleert wird und irgendwann überläuft.

Gruß
PICkel
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 29.07.2025, 16:08:23 CEST
Das Einzelschritt-Debuggen musste noch warten, auch wenn der dazu nötige Schrittgeber mit einem LM555 verwirklicht werden konnte. Erst hatte ich noch die zu dem Counter und Interrupt gehörenden Befehle überarbeitet, was auch notwendig war. Das erneut korrigierte Prog-File ist unten angefügt. Auch das externe Taktsignal wurde noch mal bearbeitet, sodass die "null"-Schwelle auf ca. 0,3 Volt absackert. Nutzte aber alles nichts, nach wie vor wird die IRQ-Routine noch nicht angesprungen. Gettz ab zum Kaffetrinken und wenn meine Frau nicht dazwischen grätscht, geht es gleich danach weiter.
Grüße, picass
clock-signal.jpgstundenzaehler05.txt

Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 29.07.2025, 17:26:11 CEST
Hallo picass,

in der Programmscheife blink: wird mit
bsf    LATB,7       ;test-led an
PORTB.7 eingeschaltet, aber nicht wieder ausgeschaltet.

Setze doch mal
bcf    LATB,7       ;test-led aus
vor den BRA blink - Befehl.
Damit solltest Du (ohne Interrupt- Signal) mit dem Oszi an PORTB.7 einen Takt von ca. 1kHz messen können.
Damit ist erstmal sichergestellt, dass der PIC korrekt arbeitet.
Gruß
PICkel
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 29.07.2025, 17:44:56 CEST
Es gibt einen Teilerfolg: im Simulator funktioniert das zuletzt eingestellte Prog in der Version "05" ! Weil man im Simulatorbetrieb die Port-Eingänge stimulieren kann, ist es möglich, mit Einzelschritt (F7-Taste) und entsprechendem Stimulieren des Port A,5-Pins den Timer zu Überlauf zu bewegen. Sobald das Low-Register des Zähler-Paares von h'ff' auf h'00' springt, wird im Register PIR1 das TMR1IF-Flag gesetzt. Und - tusch - der Simulator springt zur Speicherstelle 00008, wo der Irq-Vektor für die High-Irq's hinterlegt ist. Von dort in die Irq-Routine, löscht brav das Irq-Flag, toggelt die dortige LED und springt nach "retfie" wieder an die vorige Position in der nop-Schleife.

Also dann ist sowohl die Irq-Einstellung als auch die Timer-Einstellung passend - so meine Schlussfolgerung. Was nicht passt ist das Fehlen des Zählens: die externen Impulse kommen nicht durch. Passend dazu ist auch jeder Test mit dem Debugger, als der Live-Test-Version, ein Fehlschlag. Da kann ich mit dem Einzelschritt-Generator noch so viele Schritte auslösen, nix ist mit counten. Das Taktsignal ist ein super Rechteck zwischen 0,3 und 4,7 Volt. Da in der Praxis der Port A,5 Pin als Eingang geschaltet und die digitale Signalform gewählt ist, arbeitet der Pin als Schmitt-Trigger. Der muss schalten. Das tut er wohl auch, aber das Signal wird nicht weiter gereicht.

Hmmmmmm..... jetzt muss noch ein Test her, welcher nur das Verarbeiten des externen Counter-Taktes überprüft.
Grüße, picass
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 29.07.2025, 18:29:35 CEST
Beim Timer1 gibt es ein spezielles 7.Bit: RD16 im T1CON- Register. Der Timer1 stellt für den Zugriff eine spezielle Funktion zum Lesen und Schreiben beider Bytes bereit. Das ist bei Dir aktiviert:
movlw  b'10000111'  ;timer1 controll reg:16bit/timer1-oszi aus/keine
Stelle mal testweise um auf:
movlw  b'00000111'
Vielleicht hilft das weiter, es kann ja sein, dass beim Schreiben von TMR1H und TMR1L irgendwas schiefgeht.

PICkel
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 29.07.2025, 18:46:25 CEST
KLATSCH und KREISCH !

Es ist vollbracht: die angesprochene LED blinkt im Sekundentakt!
Neben den ersten, zweiten und dritten Fehlern war es letztlich das Konfigurations-Register für die Timer1-Einstellung, welche alles verhinderte. Da hatte ich das "Timer1 Block Diagramm" - also die stark vereinfachte Skizze der Funktionsblöcke für die Timer1-Funktion - studiert und messerscharf geschlossen, dass das Taktsignal an den Port A,5 zu legen wäre, welcher in dieser Skizze als "OSC1/T13CLK" benannt ist. Und von da aus ginge das Signal über die dargestellte durchgehende interne Leitung zu einem Schmitt-Trigger und von dort weiter zum Übergabepunkt ""Timer1 Clock Input". Anders gesagt: das Signal würde am Timer1-Oszillator vorbei gelenkt, der würde ergo nicht gebraucht.

Weswegen ich ihn im Config-Word abgeschaltet hatte. Das war das Bit 3 oder anders: T1CON,T1OSCEN. Dieser Oszillator war also still gelegt in dem Glauben, dass es ja wegen der durchgängigen Verbindung den nicht braucht. Zudem wird der PIC selbst ja über seinen LFINTOSC angetrieben, was braucht es da noch einen weiteren Oszillator. Aber wie das so ist mit dem Glauben. Tatsächlich läuft das Prog, sobald dieser Oszi doch wieder enabled ist, er läuft nicht, wenn disabled, er läuft, wenn......Er läuft und auch dieser Floh wurde ertappt und zerquetscht ! Schwitz, wieder so'n Kampf und die Stunden gingen dahin. Nun gehe ich dahin, kaufe erst noch schnell 'ne Runde ein und freue mich heute Abend dann mal 'ne etwas größere Runde.
Sehr herzlichen Dank für eure zahlreichen Bemühungen, das war ganz toll von euch. Danke.
Grüße, picass
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 29.07.2025, 21:44:42 CEST
Ich habe mir mal das Datenblatt angeschaut und schon einen Fehler aus Seite 10 gefunden :o
Timer0 and Timer3 external clock input

Nun zu deinem Prog.
Du hast T1CON geschrieben:
movlw  b'10000111'  ;timer1 controll reg:16bit/timer1-oszi aus/keinemuss aber
movlw  b'10000011'  ;timer1 controll reg:16bit/timer1-oszi aus/keineheißen

/T1SYNC: Timer1 External Clock Input Synchronization Select bit
When TMR1CS = 1:
1 = Do not synchronize external clock input
0 = Synchronize external clock input

außerdem würde ich noch Priorität vom Timer 1 auf Hi setzen.
IPR1 TMR1IP

was mir auch aufgefallen ist, du tust deinen Timer nur beim start in Main "Befüllen" sollte dies nicht in jeden Interrupt sein?
in blink die Test LED einschalten würde ich anders lösen, die LED leuchtet sonst ständig. Das siehst Du nicht, wenn im Interrupt der Ausgang mal kurz toggle wird.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 29.07.2025, 21:49:25 CEST
irgendwie war ich etwas zu spät  :(
freud mich wenn das Prog. läuft
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 29.07.2025, 22:00:59 CEST
Hallo picass,
habe mal Dein ASM-File "stundenzaehler05.txt" mit einer funktionierenden ISR versehen. Jetzt blinkt die LED im 1s-Takt. Das ASM-file müßte auch bei Dir funktionieren, habe es im relocatable Code geschrieben.
Das mit dem Input einer Halbwelle habe ich noch nicht richtig verstanden.. naja.

mfG Ottmar

P.S.: was um alles in der Welt veranlasst Dich immer fosc=31kHz zu nehmen?
Bis die LED anfängt zu blinken, erschrickt man regelrecht, man glaubt der Code stimmt nicht.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 29.07.2025, 22:03:39 CEST
Zitat von: pic18 in 29.07.2025, 21:44:42 CESTin blink die Test LED einschalten würde ich anders lösen, die LED leuchtet sonst ständig. Das siehst Du nicht, wenn im Interrupt der Ausgang mal kurz toggle wird.
vergiss die Zeile, das ist ja ein anderer Port.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 29.07.2025, 22:17:32 CEST
@Ottmar ich habe mal dein Prog. angeschaut, dies arbeitet mit den 31Khz (internal clock (FOSC/4)), nicht mit dem RA5 Takteingang. Da müsste das eine Bit noch gedreht werden. 
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 29.07.2025, 23:43:31 CEST
picass,
PIC18
ich habe es verstanden. Wenn der unten stehende Code über den bestehenden in dem von mitgeteilten ASM-File kopiert wird, klappt das so wie von picass beabsichtigt.Was er beabsichtigt hat, habe ich erst nach dem Upload meiner Datei bemerkt.
Bei mir wird RA5 mit 130 kHz Sinus 2,2Vss direkt beaufschlagt, bei dem der Sinus gerade noch über die interne Triggerschwelle rutscht damit die LED blinkt. 
fosc in   . 130kHz -> LEDfosc ca. 0,9Hz

Bei wechselnder Frequenz, folgt die Blinkfrequenz dieser Änderung. und die LED bei wechselnder frequenz, entsprechend langsamer/schneller analog blinken läßt.

;---T1CON: TIMER1 CONTROL REGISTER                             DS.94
; external TMR1 oscillator is enabled when T1OSCEN = 1
; and TMR1CS is set to 1 external clock enabled
; the signal goes straight from pin RA5 throug a schmitt-trigger
; to the clock input of TMR1. 
;;   movlw    b'00000000'
   movlw    b'00001010'
   ;          ....1..   b3/T1OSCEN 0/1 external Tmr1-clock disabled/enabled
   ;          ......1.  b1/TMR1CS 0/1 = Internal(external clock (FOSC/4)
   ;          .......0  b0/TMR1ON 0/1 disable/enable TMR1
   movwf    T1CON
   clrf     TMR1H       ;clear Hi-Byt  ;TMR1 is set o 0x0000
   clrf     TMR1L       ;clear Lo-Byte
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 30.07.2025, 12:49:28 CEST
Auf diese Darstellung in der angehängten Skizze - ein Auszug aus dem Microchip-Datenblatt - bin ich rein gefallen, was meiner Art entspricht, zunächst alles wörtlich zu nehmen. Da gibt es die scheinbar direkte Verbindung vom Eingangsport PA5 zum internen Übergabepunkt für das Timer1-Signal. Auch jetzt nach Entdeckung des wahren Sachverhaltes ist mir nicht eingängig, warum das nicht direkt durch geht. U.a. geht es ja direkt durch, denn dieser Port kann ja sowohl für digitale wie auch analoge Signale als Eingangspin genutzt werden, ohne dass dieser vermaledeite Oszi in Betrieb gesetzt wird.
Die Synchronisations-Möglichkeit hat keinen Einfluss auf die Funktion meiner Schaltung, egal, ob on oder off, da ändert sich nichts Erkennbares.

Der Input über die Halbwelle ist schlicht erklärbar. Es sollte halt als einfache Taktquelle die 230-V-Netzfrequenz gewählt werden. Bei Vollgleichrichtung müsste dann durch 100 geteilt werden, um auf eine Sekunde zu kommen. Bei Halbwellen reicht ein 50-Teiler, der auch noch den Vorteil hat, dass die Null-Stelle weitaus ausgeprägter ist.

Nicht alles aus der Welt, aber eine nüchterne Betrachtung veranlasst mich, bei dem überwiegenden Teil meiner Schaltungen die niedrige interne Taktfrequenz von 31 kHz zu wählen. Ist an diesem Beispiel wunderbar zu erklären. Die Erzeugung eines Sekunden-Taktes gelingt über diese Halbwellen und einem "speed" mit 20 mS-Taktzyklus. Das ist selbst für den gemütlichen 31-er-PIC noch ein Schnarchmodus, weil...... weil selbst diese Schnarch-Frequenz im Programm noch durch 50 geteilt werden muss. Selbstredend könnte man den PIC auch mit 4 MHz rasen lassen und dann...? Dann müsste man einen irren Teilungsfaktor erstellen, um wieder auf das Ein-Herz-Signal zu kommen. Aus meiner Sicht: was soll der Quatsch?!
Ein passender Vergleich: um mit einem Kfz auf eine Geschwindigkeit von 20 km/h zu kommen, könnte man einen leistungsschwachen und mit nur 1.800 U/min ruhig dahin nagelnden Diesel greifen und den sogar noch im dritten Gang fahren. Genauso könnte man einen Ferrari mit 700 Newtonmeter bei 5.000 U/min betreiben, bei dem dann allerdings vorher noch ein Spezialgetriebe eingeflanscht werden müsste, um die irre Drehzahl runter zu bekommen für den Antrieb.
Bei meiner PIC-Testplatine dauert nach dem Starten auch nichts. Die erste Dunkelpause nach dem Einschalten dauert exakt genau so lang, wie die späteren Dunkelpausen beim Blinken im 1-Herz-Rhytmus. Zudem: wie oft wird eine Schaltung, welche sich im Jahres-Dauer-Einsatz befindet überhaupt eingeschaltet?! Ne, lass ma, für mich und meine PICs passt das.
Grüße, picass
counter1.jpg
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 30.07.2025, 15:17:17 CEST
Hi picass,
langer Rede kurzer Sinn: Es geht einfacher, ohne Netzanbindung/Optokoppler und Halbwellenbildung, eine exakte 50Hz-Frequenz zu generieren.

Nimm das von mir anfänglich übermittelte ASM-File mit diesen Änderungen:
Internen Oszillator, Fosc = 4Mhz, das ergibt Fosc/4=1.000.000 wc (working cycles). 

Diese nimmst Du als clock für den TMR1, dazu den TMR1 overflow-Interrupt. In der ISR machst Du einen Preset 2^16us - 20.000us = 45536 = 0xB1EO.

Die "Denkpause" wird  vermieden, wenn man direkt vor Freigabe des Interrupts, (bsf INTCON,GIE) den TMR1 auf den Preset wie nachstehend setzt.

ZitatISR_H:
bcf        PIR1,TMR1IF
movlw   0xB1
movwf   TMR1H
movlw   0xE0
movwf   TMR1L
movlw   b'10000000' ;LED ist an bit 7
xorwf    PORTA,f        ;RA7 toggelt alle 200ms und LED blinkt mt 50Hz
RETFIE  FAST
Voila - das geht ganz ohne Vorteiler... fertig! Solls genauer sein, nimm einen 4MHz Quarz.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 30.07.2025, 15:41:50 CEST
A
Zitateinen Preset 2^16us - 20.000us = 45536 = 0xB1EO
richtig ist: 
2^16us - 10.000us = 55536us = 0xDBF0
denn die Periodendauer von 50Hz ist 20ms und dafür bedarf es 2 ISR-Intervalle zu je 10ms.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: picass in 31.07.2025, 12:03:03 CEST
Hallo Ottmar !
Deine Rechenübung kann ich nicht nachvollziehen.
Zunächst stimmt deine Zuordnung nicht: h'dbf0' sind d'56.304'

Dann ist völlig unklar, was genau du denn nun den PIC zählen lassen willst, um von seiner hohen Frequenz runter zu kommen auf 1 Hz. Takt soll 4 Mhz sein, ein Cyclus dann 1 Mhz, also jeder Cyclus belegt 1 µS. Dann soll nach deiner Rechnung der Counter1 gesamt 55.536 µS abzählen. Und wie kommt man nun auf eine Sekunde ?
Grüße, picass
 
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 31.07.2025, 14:54:52 CEST
Hi picass,
Du hast recht. das war von mir ein Ablesefehler auf dem Windowsrechner "Programmierer", habe "B" anstatt korrekt "8" abgelesen. Die dezimale Berechnung stimmt jedoch, hättest Du das beim Nachvollziehen der Berechnung bemerken können?
Die Blinkfrequenz 1Hz mit dem LF-Osillator habe ich in dem ASM-File vom 25.7 bereits dargestellt.

Ok, ich gebe Dir 2 Beispiele für 50 Hz bzw. 1 Hz Blinkfrequenz mittels TIMER1-overflow-Interrupt, wie man dafür den Vorteiler und den Preset berechnet. Beachte bitte, daß der Arbeitstakt stets 1/4 der Oszillatorfrequenz beträgt. TMR1 zählt nur den Arbeitstakt.
;
a) 50Hz, Periodendauer 0,02s, zusammengesetzt aus
   0,01s High, 0,01s Low

b) 1Hz, Periodendauer 1s, zusammengesetzt aus 0,5s High, 0,5s Low
 
Gesucht a) Interrupt-intervall 0,01s (50Hz
        b) "                "              0,5s  (1Hz)
        dazu TMR1.Prescaler

Gegeben:fosc=4MHz (eingestellt z.B. mit OSCCON)
        TMR1-Modul (Zählbereich 0-2^16) + TMR1 overflow interrupt
        und Prescaler 1:1-1:8 vgl. Register TMR1CON

a) TMR1-Zähltakt = fosc/4 also 1.000.000 wc (Arbeitszyklen/sek.)
   ISR-Aufruf muss  für 10ms  (Peridodendauer 2x10ms) alle 10ms
   erfolgen. 
   Prescaler 1:1 wird verwendet, da TMR1 den Zählbereich offensichtlich
   ohne Vorteiler überstreicht, was Rechenarbeit erspart.

   Preset: = 2^16 - 10.000 = 55536 = 0xD8F0

b) TMR1-Zähltakt = fosc/4 also 1.000.000 wc (Arbeitszyklen/sek.)
   ISR-Aufruf muss  für 1Hz (Peridodendauer 2x0,5s) alle 0,s erfolgen

   Prescaler: 500.000 wc / 65536 = 7,6 nicht verfügbar!
   daher: nächsthöherer, verfügbarer Prescale: 1:8
   Preset TMR1: 2^16 - (500.000/8) = 3036 = 0x0BDC
   TMR1CON,T1CKPS<1:0>  = 11

   Der Vorteil einer zweckentsprechend gewählten Oszillatorfrequenz
   liegt damit wohl auf der Hand.

   mdG Ottmar

  
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 31.07.2025, 16:14:41 CEST
das mit dem Timer stellen mache ich schon lange nicht mehr, das ist mir zu ungenau.
Ich würde es so machen:
den Vorteiler auf 32 setzen Timer auf 8 Bit (256 Überlauf)
bei 4Mhz würde ich dann 100ms zählen.
| bedeutet hoch, kann ich hier nicht darstellen.

256 und 32 Teiler 4 TOS/4
4*10|-6 s|-1 = 4MHz
100|10-3s =100ms

(256*32*4)/(4*10|-6s|-1 *100|10-3s) = 8,192E-2 = (256/3125)
 
jedes mal wenn der Interrupt aufgerufen wird, Variable Z  256 addieren
wenn Z >=3125 ist dann Z=Z-3125 und hier sind 100ms vorbei.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: PICkel in 31.07.2025, 19:35:00 CEST
Noch ein Tipp zum Thema Timerauslegung:

Von mikroe gibt es ein Programm, das auch "standalone" läuft: den Timer- Calculator:  https://www.mikroe.com/timer-calculator
Hier kann man PIC-Typ, Timer, Taktfrequenz und Verzögerung eingeben und erhält einen Code wahlweise in mikro-C/-Basic oder -Pascal.
Eine Portierung in ASM ist bei den paar Zuweisungen auch kein Problem.
Aber seht selbst im Anhang. Bei Bedarf kann ich Euch ein zip-File mit den Daten bereitstellen.


Gruß
PICkel
Timer_Calculator.jpg
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 31.07.2025, 20:15:16 CEST
@pic18 
Hm... meine Interrupt-Intervalle stimmen auf den Arbeitstakt genau. In der ISR, deren Intervall fast immer einige Arbeitstakte zu kurz ist, gleiche ich das dann mit einigen sinnvollen der auch wirkungslosen Instruktionen aus.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 31.07.2025, 20:32:58 CEST
Da muss genau die Taktzyklen abgezählt werden, damit der Timer richtig gestellt wird. Bei mir gleicht sich dies automatisch aus. Gut es ist manchmal ein Takt etwas kürzer. Eine Uhr läuft aber über Monate Ganggenau.
Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: Ottmar in 31.07.2025, 21:42:02 CEST
Hi pic18,
das Abzählen fällt leicht, den in MPLAB 8 gibt es einen praktischen Timer zum Zählen der Arbeitstakte zwischen zwei Haltepunkten.
Intervall stoppen, Sollzeit - Istzeit = Extratakte (wc) hinzuzufügen. So kann auch die Ausführungszeit z.B. von Schleifen mit ein paar Clicks, taktgenau festgestellt werden. Nachstehend ein Beispiel.

ISR:
bcf  INTCON,TMR0IF
NOP        ->1wc
GOTO $ +1  ->2wc 
; und so weiter.....und wenn es ganz extrem werden sollte:

isr_taktehinzufügen:
movlw  (n)                  ->1wc   n * (8wc) = 8...-x wc zum Abgleich verfügbar
movwf  dummy                ->1wc
decfsz dummy,f              ->2-3wc
GOTO   isr_taktehinzufügen  ->2wc
;
movlw  tmr0preset
movwf  TMR0     --- hier endet das alte, beginnt das neue Intervall


Titel: Aw: Timer1 Interrupt : nix mit ruptus
Beitrag von: pic18 in 31.07.2025, 23:23:22 CEST
Ist schon richtig, nur die Zählerei ist mir zu kompliziert. Zumal ich in C programmiere. Je nachdem welchen C-Compiler genommen wird, ändert sich dann der Code. Dann stimmt alles nicht.