Hallo zusammen,
nun bin ich scheinbar doch wieder auf die Hilfe aus dem großen weiten
Internetz angewiesen.
Folgende Grundinfos: PIC16F688, Assembler, pic-as in MPLAB X v6.00
Das Problem: Ich bekomme einfach keinerlei Interrupts hin...
Z.B. mit Timer1: Der Timer selbst läuft und setzt auf das TMR1IF bit
(lässt sich ja einfach durch dauerhaftes Prüfen herausfinden), alle
"Anzeigeräte" und deren Software (LED-Ansteuerung, etc.) läuft auch. GIE
und PEIE sind gesetzt.
Das Zwischenspeichern des W- und STATUS-Registers ist meine ich zwar
auch noch nicht richtig, ist im Moment aber noch unerheblich. Die ISR
ist mit dem Linkerbefehl -pInterrupt=0x04 an die richtige Position
gesetzt.
Die ISR lautet:
1
PSECT Interrupt, class=CODE, delta=2
2
ISR:
3
BANKSEL WREG_Temp
4
MOVWF WREG_Temp ;WREG zwischenspeichern
5
BANKSEL STATUS
6
MOVF STATUS, 0 ;STATUS zwischenspeichern
7
MOVWF Status_Temp
8
9
BANKSEL INTCON
10
BTFSC INTCON, 3 ;Prüfen ob RAIE gesetzt
11
BTFSS INTCON, 0 ;Prüfen ob RAIF gesetzt
12
goto $+2
13
goto ISR_PORTA
14
15
BANKSEL PIE1
16
BTFSS PIE1, 0 ;Prüfen ob TMR1IE gesetzt
17
goto $+4
18
BANKSEL PIR1
19
BTFSC PIR1, 0 ;Prüfen ob TMR1IF gesetzt
20
goto ISR_Timer1 ;Gehe zu ISR_Timer1
21
22
goto EndeInterrupt
23
24
ISR_Timer1:
25
BCF PIR1, 0 ;TMR1IF löschen
26
BANKSEL PORTA
27
MOVLW PORTA ;PORTA ins WREG laden
28
XORLW 00100000B ;LED an RA5 ändern
29
MOVWF PORTA ;Wieder in PORTA laden
30
goto EndeInterrupt
31
32
ISR_PORTA:
33
BANKSEL PORTA
34
MOVF PORTA, 0
35
BANKSEL INTCON
36
BCF INTCON, 0
37
LEDRotAN
38
goto EndeInterrupt
39
40
41
EndeInterrupt:
42
MOVF Status_Temp, 0 ;Zwischengespeicherten Status wieder laden
43
MOVWF STATUS
44
MOVF WREG_Temp, 0 ;Zwischengespeichertes WREG wieder laden
45
RETFIE
46
;Ende Interrupt
Und jetzt weiß ich mir nicht mehr zu helfen und hoffe, dass die
Gruppenintelligenz des Internetz zur Hilfe kommt (-;
Viele Grüße und schonmal vielen Dank,
Ron
Täusche ich mich da oder ist da was falsch:
MOVLW PORTA ;PORTA ins WREG laden
???????????
Um porta nach w zu laden schreibe ich üblicherweise den pseudobefehl
"movfw".
"movlw" soll hingegen eine folgend angegebene Zahl in's w-reg. laden.
Wenn dieser Zeile keine Fehlermeldung folgt wird vermutlich die Adresse
von porta und nicht der Inhalt nach w geladen!
Schlage vor, das anhand des Datenblattes zu klären.
Das ist mir nur ins Auge gefallen - den code hab ich sonst nicht
geprüft.
Hallo Hans,
da hast du natürlich völlig recht. Da muss natürlich stehen
MOVF PORTA, 0
Bringt aber leider nichts. Das Problem scheint nichts in der ISR zu
sein, denn ich habe da auch schon sehr primitiven Code (also ohne Umwege
LED anschalten) in die ISR geschrieben, da springt er einfach nicht hin.
Aber trotzdem schonmal danke, hat der Code schon einen Fehler weniger.
Grüße Ron
Hallo Ron,
vielleicht finde ich morgen zeit und schau nochmal.....
Nicht überprüfen kann ich -obwohl sehr wichtig- ob die ISR an der
richtigen Adresse steht und ob. die Befehle an der Anfangsadr. d.
Pgm-Speichers passend sind. Empfehlung: nochmals genau selbst prüfen.
PS.
MOVF PORTA, 0 bzw. MOVF PORTA, .0 (dec. null) ist sicher ok.
Am einfachsten das Programm im Emulator oder In-Circuit-Debugger laufen
lassen und dann absolut alle Register überprüfen, die das Datenblatt im
Kapitel TMR1 erwähnt.
Hallo,
im MPLAB X eigenen Debugger bin ich schonmal alles durchgegangen. Kann
man da eigentlich auch die Timer simulieren inkl. Interrupt simulieren?
Der Timer selbst ist sicher nicht das Problem, das konnte ich ja schon
durch dauerhaftes Prüfen des TMR1IF-Bits prüfen. Das wird ja gesetzt, es
wird nur offensichtlich kein Interrupt ausgelöst oder die ISR steht an
der falschen Stelle. Habe ich hier eine Möglichkeit, die Position zu
prüfen, außer auf die Linker Option -pInterrupt=0x04 zu vertrauen?
Grüße Ron
nochwas ist mir aufgefallen:
mehrmals kommt vor: "goto EndeInterrupt"
Aber der Label lautet dann "EndeInterrupt:"
Was macht die IDE aus dem dann plötzlich vorhandenem Doppelpunkt?
Hallo Hans,
danke für den ersten Tipp, das ist auf jeden Fall mal sehr interessant.
Allerdings ist dort klar die ISR ab der Adresse 004 zu erkennen.
Deine zweite Frage verstehe ich nicht. Welcher Doppelpunkt? Doppelpunkt
im Sinne des Zeichens ':' oder im Sinne dass ich zu einem Programmpunkt
doppelt gehe? Ich darf doch von beliebig vielen Stellen an das selbe
Label springen?
Grüße Ron
ich nehme an:
wenn dort z.B. steht "goto mittwoch"
dann sucht die IDE nach der zeichenfolge "mittwoch" und nicht nach der
zeichenfolge "mittwoch:"
Ob das trotzdem funktioniert kann man z.B. aus dem programmspeicher
sehen.
Der Doppelpunkt zeichnet die Zeichenfolge ja gerade erst als Label aus.
Ohne Doppelpunkt gibt er dann auch nur aus, dass er den Befehl nicht
kennt.
Das wäre auch hier nochmals auf Seite 274 nachzulesen:
https://ww1.microchip.com/downloads/en/devicedoc/50002053g.pdf
Solche Sprünge funktionieren an anderer Stelle im Programm hervorragend
und selbst wenn sie in der ISR nicht gehen würden, so müsste ich doch
wenigstens in der ISR rauskommen.
Danke und Grüße
Ron
Nachtrag:
.....allerdings verwende ich den compiler mpasm.
und das *.pdf bezieht sich auf den XC8 C compiler.
Ob und welche Unterschiede in der zuläsigen Bezeichnung der labels
bestehen müsste man nachsehen - wenn man es genau wissen will oder muss.
Nachtrag:
Ich hab nachgelesen. Für den von mir verwendeten Assembler MPASM gelten
folgende Regeln für die Schreibweise von labels.
"Labels should start in column 1. They may be followed by a colon (:),
space, tab or the end of line. Labels must not begin with number."
Guten Morgen,
ja, das wird wohl dann an den kleinen aber feinen Unterschieden zwischen
MPASM und pic-as liegen.
Ich habe mir nun nochmal die Mühe gemacht, im Simulator alle für die
Interrupts wichtigen Register zu beobachten, und nun habe ich
tatsächlich die Lösung gefunden!
INTCON = 11000000B ;GIE und PIE an, das hat geklappt
PIE1 = 00000001B ;T1IE an, hier war der Fehler
Denn das Register INTCON ist ja in allen Bänken erreichbar und so stand
nach vor dem setzen von PIE1 kein BANKSEL. D.h. er hat an die selbe
Stelle in der Bank 1 geschrieben, also in PIR1. Somit läuft der
Interrupt durch Timer1 und auch durch Änderung an PORTA.
Zuletzt noch eine Verständnisfrage: Einige Register finden sich ja nur
in einer Bank, während sich andere in mehreren oder sogar allen finden.
Wie funktioniert das technisch? Gehen dann die "Leitungen" bei denen man
mit Adresse 8B (INTCON in Bank 1) mit denen direkt logisch zusammen, wo
man mit Adresse 0B (INTCON in Bank 0) zusammen?
Auf jeden Fall vielen Dank für die Hilfe, die dieses mal wirklich
lobenswert konstruktiv und ohne die so oft zu lesenden Angeifereien
funktioniert hat. So stelle ich mir ein Forum vor!
Danke und viele Grüße,
Ron
Ja, die Bankumschaltungen sind immer fehlerträchtig.
Im Datenblatt hab ich auch den Hinweis gefunden, dass in der ISR
möglicherweise das banksel.-register geändert wird und nach dem
Rücksprung aus der ISR geändert bleibt. -daher ist eventuell auch das zu
sichern.
(Aber ist das Benksel-reg. nicht im status enthalten und dort
gespeichert???)
Auch ist ein Code zur Sicherung von w u. status vorgeschlagen:
MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
;Swaps are used because they do not affect the status bits
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
:
:(ISR) ;Insert user code here
:
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W
Ein Interrupt oder eine aufgerufene Funktion kennen die gerade aktive
Bank nicht. Sie müssen also die Bank sichern, ihre gewünschte Bank
setzen und am Ende die Bank restoren.
Peter D. schrieb:> Ein Interrupt oder eine aufgerufene Funktion kennen die gerade> aktive> Bank nicht. Sie müssen also die Bank sichern, ihre gewünschte Bank> setzen und am Ende die Bank restoren.
Ist das nicht bei den moderneren Typen nicht mehr nötig, zB PIC16F1825,
die haben doch einen Hardware-Stack
OldMan schrieb:> Ist das nicht bei den moderneren Typen nicht mehr nötig, zB PIC16F1825,
Die sichern das BSR im Interrupt, aber in einem Call muß man das immer
noch selber machen.
Hans B. schrieb:> ich nehme an:> wenn dort z.B. steht "goto mittwoch"> dann sucht die IDE nach der zeichenfolge "mittwoch" und nicht nach der> zeichenfolge "mittwoch:"
Ähem... naja, sowas hängt am konkreten Assembler. Normalerweise schreibt
man ein Label
KarlheinzOtto:
wobei der Doppelpunkt anzeigt, daß das ein Label ist und bei einem
Sprung oder Call muß man den Doppelpunkt weglassen und nur den
eigentlichen Namen hinschreiben.
W.S.
OldMan schrieb:> Ist das nicht bei den moderneren Typen nicht mehr nötig, zB PIC16F1825,> die haben doch einen Hardware-Stack
Den Stack in Hardware hatten die PIC16 schon immer. Aber es hat wohl
beim Übergang von den dreistelligen Nummern auf vierstellige Nummern im
Namen auch einige Änderungen beim Interrupt gegeben.
Ron S schrieb:> PSECT Interrupt, class=CODE, delta=2> ISR:> BANKSEL WREG_Temp> MOVWF WREG_Temp ;WREG zwischenspeichern> BANKSEL STATUS> MOVF STATUS, 0 ;STATUS zwischenspeichern> MOVWF Status_Temp
Mir fällt da auf, daß dieses BANKSEL ja (bislang) kein Maschinenbefehl
war, sondern ein Macro und das könnte das W Register benutzen.
Wenn man die Rett-Register im Bereich 70h..7fh anordnet, dann sind die
(zumindest bei den Typen, die ich kenne) von allen Bänken erreichbar. Zu
bedenken wäre auch, daß MOVF IrgendeinRegister immer auch die Flags
ändert. Folglich sah das Registerretten etwa so aus:
1. W in W-Rettregister speichern (das ist in 70h..7fh)
2. Status nach W swappen (nicht laden)
3. W in Status-Rettregister speichern (das speichert auch die
Bank-Einstellung, ist ebenfalls in 70h..7fh)
4. FSR retten und alles weitere
Ob das bei deinem PIC auch so ist oder bereits anders, hab ich jetzt
nicht nachgelesen. Irgendwo hab ich bei den neueren Typen auch in
Erinnerung, daß bei Interrupts das GIE gelöscht wird. Falls da was bei
deinem PIC zutrifft und du keine Vorkehrungen getroffen hast, dann wäre
der Interrupt nach dem allerersten Mal abgeschaltet.
W.S.
W.S.
Beim pic16f1688 muss man (noch) selbst für die Sicherung von STATUS und
ARBEITSREGISTER sorgen.
Der Code dafür steht im Datenblatt. (SWAP für STATUS verwenden -wie von
W.S. erwähnt)
Der GIE wird automatisch mit dem Einsprung in den Interrupt abgeschaltet
und mit dem Endbefehl "RETFIE" wieder eingeschaltet.