externer Interrupt an PIC18

Gast #4345199
Lesenswert?

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
void extern_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
8
    }
9
    
10
}
11
#pragma code
12

13
void main(void) {
14
...
15

16
 // interrupts / USART interrupts configuration
17
    RCONbits.IPEN   = 0;    // disable interrupt priority
18
    INTCONbits.GIE  = 1;    // enable interrupts
19
    INTCONbits.PEIE = 1;    // enable peripheral interrupts.
20
    PIE1bits.RCIE   = 1;    // enable USART receive interrupt
21
    PIE1bits.TXIE   = 0;    // disable USART TX interrupt
22
//    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
Gast #4345296
Lesenswert?

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
void extern_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!
Gast #4345324
Lesenswert?

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!
#4345425
Lesenswert?

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
void extern_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)
Gast #4345453
Lesenswert?

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?
#4345468
Lesenswert?

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?
Gast #4345505
Lesenswert?

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
void isr(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
void main(void) {
26
...
27
#pragma code // return to the default code section
28
     // interrupts / USART interrupts configuration
29
    RCONbits.IPEN   = 0;    // disable interrupt priority
30
    INTCONbits.GIE  = 1;    // enable interrupts
31
    INTCONbits.PEIE = 1;    // enable peripheral interrupts.
32
    PIE1bits.RCIE   = 1;    // enable USART receive interrupt
33
    PIE1bits.TXIE   = 0;    // disable USART TX interrupt
34
//    PIR1bits.RCIF = 0;    // make sure the RX flag is clear
35

36
    TRISBbits.TRISB2 = 1;       // Input an RB2
37
    ANSELBbits.ANSB2 = 0;       // digitaler pin
38

39
    INTCON2bits.INTEDG2 = 1;    // INT2 bei ansteigender Flanke, d.h. er triggert wenn er von LOW auf HIGH
40
//    INTCON3bits.INT2IP = 1;     //High Priority
41
    INTCON3bits.INT2IE = 1;     // Enables the INT2 external interrupt
42
    INTCON3bits.INT2IF = 0;     // Internal 2 external interrupt Flag bit zurücksetzen
43
    INTCON2bits.INTEDG2 = 0;
44

45

46
...
47
while(1)
48
{
49
Sleep();    // Sleep Modus
50
}
51
}
#4345510
Lesenswert?

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?
Gast #4345561
Lesenswert?

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!
Gast #4345669
Lesenswert?

Is natürlich quatsch :)

Habe es jetzt 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
void isr(void)
5
{
6

7
    if(INTCON3bits.INT2IF)
8
    {
9

10
        // bei Triggerung des externen Interrupts erwacht der Controller automatisch aus dem Sleep Modus
11
        INTCON3bits.INT2IF = 0;
12
    }
13

14
    if(PIR1bits.RCIF == 1) // if the USART receive interrupt flag has been set
15
    {
16
         Nop();
17
         Nop();
18
        
19
         rx_char = getcUSART1();  
20

21
        
22
    }
23
}
24
#pragma code // return to the default code section
25

26

27
void main(void) {
28
    
29
    ...
30

31
     // interrupts / USART interrupts configuration
32
    RCONbits.IPEN   = 0;    // disable interrupt priority
33
    INTCONbits.GIE  = 1;    // enable interrupts
34
    INTCONbits.PEIE = 1;    // enable peripheral interrupts.
35
    PIE1bits.RCIE   = 1;    // enable USART receive interrupt
36
    PIE1bits.TXIE   = 0;    // disable USART TX interrupt
37

38
    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.
Gast #4345761
Lesenswert?

> 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.
Gast #4345803
Lesenswert?

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.
Gast #4346285
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren