hallo,
ich arbeite mit einem PIC18LF25K50 MPLABX v2.25 und C18 Compiler
(v.3.47).
Ich lese von einem externen Device den Status an RB2 aus. Hierfür möchte
ich gerne den externen Interrupt 2 an RB2 nutzen. Der Interrupt soll bei
ansteigender Flanke Triggern, d.h. wenn ich der Pin von LOW auf HIGH
wechselt. RB2 habe ich als Input deklariert. Das ganze sieht in etwa wie
folgt aus:
1
#pragma interrupt extern_interrupt
2
voidextern_interrupt(void){
3
4
if(INTCON3bits.INT2IF)
5
{
6
// tue irgendetwas
7
INTCON3bits.INT2IF=0;// cleare Interrupt Flag wieder, damit dieser wieder ausgelöst werden kann
// PIR1bits.RCIF = 0; // make sure the RX flag is clear
23
24
TRISBbits.TRISB2=1;// Input
25
INTCON3bits.INT2IE=1;// Enables the INT2 external interrupt
26
INTCON3bits.INT2IF=0;// Internal 2 external interrupt Flag bit zurücksetzen
27
INTCON2bits.INTEDG2=1;// INT2 bei ansteigender Flanke, d.h. er triggert wenn er von LOW auf HIGH
28
}
Ich nutze also noch gleichzeitig den UART Interrupt, dieser funktioniert
tadellos.
Wenn ich jetzt debugge und sehe dass sich der Status an RB2 ändert wird
jedoch Nie die Interruptroutine ausgelöst. Woran kann dies liegen?
Was fällt auf?
Danke
Stampede schrieb:> Sind die Analogfuntkionen am RB2 deaktiviert? ANSELB Regstier> sollte das> sein.
Jop, habe ich vergessen dazuzuschreiben:
ANSELB = 0x00;
Daran kann es also nicht liegen, aber guter Hinweis!
Für IOC wird der Inhalt des PORTB mit dem gelatchten Wert der letzten
Leseroutine verglichen. Vor dem Löschen des INT2IF sollte PORTB immer
gelesen (oder geschrieben) werden.
Gruß
witkatz
Witkatz :. schrieb:> Für IOC wird der Inhalt des PORTB mit dem gelatchten Wert der> letzten> Leseroutine verglichen. Vor dem Löschen des INT2IF sollte PORTB immer> gelesen (oder geschrieben) werden.>> Gruß> witkatz
HMM ok,
habe es editiert:
1
voidextern_interrupt(void){
2
3
if(INTCON3bits.INT2IF)
4
{
5
PORTBbits.RB2;// Lese den Wert immer bevor Flag Bit gelöscht
6
INTCON3bits.INT2IF=0;
7
}
8
9
}
Dies dürfte aber nicht der Grund dafür sein, dass die Interruptroutine
gar nicht erst auslöst. Habe RB2 einmal als Output gesetzt und dann über
Latch Register den Eingang manuell von LOW auf HIGH gezogen um zu testen
ob der Interrupt dann auslöst. Ebenfalls ohne Erfolg!
INT2 ist doch gar kein IOC.
Wie sehen denn die Pegel für high und low genau aus? (und was für VDD)
Der Code für RX und INT2 ist natürlich in der gleichen Routine, oder?
Volker S. schrieb:> INT2 ist doch gar kein IOC.>> Wie sehen denn die Pegel für high und low genau aus? (und was für VDD)>> Der Code für RX und INT2 ist natürlich in der gleichen Routine, oder?
VDD ist 3,3V
Ich habe den UART Interrupt jetzt erst einmal komplett auskommentiert,
um wirklich nur den externen Interrupt zu testen. RB2 ist in der Tat ein
EXT Interrupt (INT 2) Pin, d.h. KEIN Interruput on Change Pin -> IOC
Register müßte demzufolge wegfallen.
Mich interessiert gerade nur warum der Interrupt nicht triggert, obwohl
der Pin nachweislich von Low auf High gezogen wird!
Volker S. schrieb:> INT2 ist doch gar kein IOC.
Sorry, mein Fehler.
Du könntest in main das INT2IF auf einem Testausgang ausgeben, um zu
schauen ob das Flag gesetzt wird.
Ich bin mit C18 nicht so vetrtraut, aber sollte nicht vor dem #pragma
interrupt der Funktionsprototyp void extern_interrupt(void); deklariert
werden?
Unterbrecher schrieb:> VDD ist 3,3V
low = ?
high = ?
Hagi schrieb:> Stimmt auch das "Interrupt Priority" INTCON3bits.INT2IP ?
Ist völlig egal, da IPEN = 0...
Witkatz :. schrieb:> Ich bin mit C18 nicht so vetrtraut, aber sollte nicht vor dem #pragma> interrupt der Funktionsprototyp void extern_interrupt(void); deklariert> werden?
Nein, nicht unbedingt. Leider fehlt der Teil im Post :-(
Im "compatibility mode" (nur eine Ebene/Vektor) muss man nur dafür
sorgen, dass die Funkion an der richtigen Stelle steht.
1
#pragma interrupt extern_interrupt
2
3
4
#pragma code high_vector=0x0008
5
voidextern_interrupt(void){
6
...
Im "priority mode" kann ja am high-priority Vektor nur ein Sprung zur
Funktion stehen. Dann braucht man den Prototyp. (wenn der Vektor nicht
nach der Routine seht)
Volker S. schrieb:> #pragma code high_vector=0x0008
Daran scheint es gelegen zu haben. Wird hier die Prirität des Interrupts
angegeben, obwohl ich diese enablet habe? Warum ist diese Zeile für die
Funktion so wichtig?
Nutze ich für den UART und externen Interrupt jetzt am besten dieselbe
ISR oder zwei verschiedene Interrupt Routinen schreiben?
Unterbrecher schrieb:> Warum ist diese Zeile für die> Funktion so wichtig?
C18 User's Guide Kap. 2.9.2.3 INTERRUPT VECTORS:
"MPLAB C18 does not automatically place an ISR at the interrupt vector."
Puuuhhhh, ganz schön viele Fragen auf einmal;-)
Also die 0x0008 ist eine der beiden Adressen im Programmspeicher auf die
gesprungen wird, wenn ein Interrupt ausgelöst wird. Da du den Priority
Mode nicht aktiviert hast, ist es sogar die einzige Adresse.
An dieser Adresse muss jetzt ein Sprung zu deiner IR-Service Routine
oder eben die Routine selbst stehen.
Somit kann es auch nur eine Funktion geben in der alle deine IRs
abgearbeitet werden...
Etwas ausführlicher ist das Thema im Kapitel 5 von uC_Quick-X.pdf
dargestellt. (google...)
Mit was programmierst du deinen PIC? PICKITx?
Volker S. schrieb:> Puuuhhhh, ganz schön viele Fragen auf einmal;-)>> Also die 0x0008 ist eine der beiden Adressen im Programmspeicher auf die> gesprungen wird, wenn ein Interrupt ausgelöst wird. Da du den Priority> Mode nicht aktiviert hast, ist es sogar die einzige Adresse.>> An dieser Adresse muss jetzt ein Sprung zu deiner IR-Service Routine> oder eben die Routine selbst stehen.> Somit kann es auch nur eine Funktion geben in der alle deine IRs> abgearbeitet werden...
Super vielen Dank. Ich beschäftige mich erst seit kurzen mit Interrupts,
deswegen ist jeder Input willkommen :)
Vielleicht noch eine Frage:
Wenn ich den PIC vorher in den Sleep Modus versetzt habe, wird der Pic
wenn der externe Interrupt über RB2 ausgelöst wird dann automatisch aus
dem Sleep Modus herausgeholt? Dies ist nämlich genau das, was ich
realisieren möchte. Was anderes soll der externe Interrupt eigentlich
nicht tun. Getestet habe ich dies nun wie folgt:
1
// start ISR code
2
#pragma interrupt isr // let the compiler know that the function isr() is an interrupt handler
3
#pragma code isr = 0x08 // store the below code at address 0x08
4
voidisr(void)
5
{
6
7
Nop();
8
Nop();
9
10
if(INTCON3bits.INT2IF)
11
{
12
// bei Triggerung des externen Interrupts erwacht der Controller automatisch aus dem Sleep Modus
13
INTCON3bits.INT2IF=0;
14
}
15
16
if(PIR1bits.RCIF==1)// if the USART receive interrupt flag has been set
17
{
18
19
rx_char=getcUSART1();
20
21
}
22
}
23
24
25
voidmain(void){
26
...
27
#pragma code // return to the default code section
Unterbrecher schrieb:> Vielleicht noch eine Frage:> Wenn ich den PIC vorher in den Sleep Modus versetzt habe, wird der Pic> wenn der externe Interrupt über RB2 ausgelöst wird dann automatisch aus> dem Sleep Modus herausgeholt? Dies ist nämlich genau das, was ich> realisieren möchte. Was anderes soll der externe Interrupt eigentlich> nicht tun. Getestet habe ich dies nun wie folgt:
Ja, das sollte so sein ;-) Was ist bei deinem Test heraus gekommen?
Der externe Interrupt löst wie gewünscht an RB2 aus. Leider funktioniert
dann der UART Interrupt nicht mehr wie gewünscht :(
Ohne Sleep() Funktion läuft es einwandfrei.
Wie implementiert: Wird der PIC bei externen Interrupt immer aus dem
Sleep Modus geholt? Ist dies richtig so? Gewollt ist:
1. Setze PIC in Sleep
2. Durch externen Interrupt PIC "awaken"
3. Wach bleiben und über UART Interrupt Daten einlesen
4. Wenn fertig PIC wieder in Sleep Modus setzen und auf externen
Interrupt warten!
INTCON2bits.INTEDG2=1;// INT2 bei ansteigender Flanke, d.h. er triggert wenn er von LOW auf HIGH
39
// INTCON3bits.INT2IP = 1; //High Priority
40
INTCON3bits.INT2IE=1;// Enables the INT2 external interrupt
41
INTCON3bits.INT2IF=0;// Internal 2 external interrupt Flag bit zurücksetzen
42
INTCON2bits.INTEDG2=0;
43
44
Sleep();// gehe per default in Sleep Modus
45
while(1)
46
{
47
// wenn Uart Verbindung beendet gehe wieder in Sleep Mode
48
if(UART_END)
49
Sleep();
50
51
}
Das scheint per Software schon einmal so zu funktionieren. Dumme Frage
zum Schluß: Kann ich per Software kontrollieren, ob der PIC sich
wirklich im Sleep Modus befindet oder ist dies nur meßtechnisch zu
ermitteln? Habe leider nur nen Voltmeter und kein Oszi oder ähnliches
hier.
> ob der PIC sich wirklich im Sleep Modus befindet
Einfach schauen, wie schnell die Spannung sinkt, nachdem du das
Netzgerät ausschaltest. Größenordnung - Ohne sleep() nicht mal eine
Sekunde, mit sleep() 20 Sekunden.
Hmm in dem Zeitintervall kann ich leider keinen großen Unterschiede im
Sleep oder ohne Sleep entdecken. Die Spannung fällt innerhalb einer
Sekunde auf 0,5V rapide ab und dann in etwa 10 Sec gegen 0V (sowohl im
Sleep Mod als auch im "normalen" Modus).
Das ist natürlich sehr unprofessionell ohne Oszi aufgenommen.
Warim sollte der pic nicht in den sleep gehen? Setz einfach einen
Ausgang auf high nach dem Sleep und vor dem while.
Ob man das auch mit dem Debugger testen kann, weiss ich jetzt nicht...
> keinen großen Unterschiede
Hmm... wer weiß, was das Netzgerät macht. Besser nur einen Elko
entladen. Elko an die Pic-Platine und einen Schalter in die Zuleitung.
> Warim sollte der pic nicht in den sleep gehen?
Die Frage ist eher, bring es was? Wieso mit sleep() und Interrupts
rumärgern, wenn da ein Spannungsteiler mehr Strom verbraucht, als der
Controller.