Forum: Mikrocontroller und Digitale Elektronik PIC18F Interrupt Routinen


von Ingo S. (schicki)


Lesenswert?

Hallo Zusammen,

Ich habe ein ein kleines Betriebbssystem geschreiben. Frpher alles über 
Timer.

Jetzt habe ich die wichtisten Teile auf die High und Low Interrupt 
Routinen aufgeteilt.
- Das Programm startet. Der Timer 0 aktualisiert die Uhrzeit und 
Temperatur.
- Ich kann Daten senden. Diese werden verabeitet.

Das Problem:
Das Programm springt mit aus diesen Programmteil, nicht zurück. 
Sämtliche Tests waren erfolglos.
Es muss etwas ganz einfaches bedingt durch die beiden Einsprungsadressen 
sein.

Was mache ich falsch?
1
void __interrupt() INTERRUPT_InterruptManagerHigh (void)
2
{
3
    // interrupt handler
4
    if(PIE1bits.RC1IE == 1 && PIR1bits.RC1IF == 1)
5
    {       
6
        INTCONbits.TMR0IE = 0;
7
        SSP4();    // serrielle Daten abrufen und verarbeiten
8
        INTCONbits.TMR0IE = 1; 
9
        
10
  // Löschen der High Interrupt Flags und Rückkkehr zu Timeer 0 funktioniert nicht 
11
12
    }
13
    else
14
    {
15
        //Unhandled Interrupt
16
    }
17
}
18
19
void __interrupt(low_priority) INTERRUPT_InterruptManagerLow (void)
20
{
21
    // interrupt handler
22
    if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF == 1)
23
    {
24
        TMR0_ISR(); //Uhrzeit und Temperatur aktualiseren 
25
    }
26
    else
27
    {
28
        //Unhandled Interrupt
29
    }
30
}

Viele Grüße
Ingo

von Bratmaxxe (Gast)


Lesenswert?

Ist zwar schon ne Weile her bei mir mit PIC aber du musst die Interrupt 
Flag bei Peripherie manuell zurück setzen soweit ich mich erinnere (im 
Interrupt)

Heißt, INTCON.TMR0IF = 0. Sonst bleibt die Flag permanent gesetzt.

von Bratmaxxe (Gast)


Lesenswert?

Steht übrigens auch im Datenblatt :)

" Before re-enabling the  interrupt,  the  TMR0IF  bit  must  be
cleared by software in the Interrupt Service Routine"

von Ingo S. (schicki)


Lesenswert?

Ja stimmt, das wäre mal ein Ansatz. Der Befehl ist in der Timer Routine 
drin. Aber was passiert, wenn der Interrupt unterbricht, und das Flag 
noch gesetzt ist. Ich werde das mal testen..
1
C-Code
2
void TMR0_ISR(void)
3
{
4
    // clear the TMR0 interrupt flag
5
    INTCONbits.TMR0IF = 0;
6
7
    // reload TMR0
8
    // Write to the Timer0 register
9
    TMR0H = timer0ReloadVal >> 8;
10
    TMR0L = (uint8_t) timer0ReloadVal;
11
12
    // ticker function call;
13
    // ticker is 1 -> Callback function gets called every time this ISR executes
14
    TMR0_CallBack();
15
16
    dt.Stunden = MCP794XX_Read_Stunden(&dt);
17
    dt.Minuten = MCP794XX_Read_Minuten(&dt);
18
    dt.Sekunden = MCP794XX_Read_Sekunden(&dt);
19
    
20
    dt.Tag = MCP794XX_Read_Tag(&dt);
21
    dt.Monat = MCP794XX_Read_Monat(&dt);
22
    dt.Jahr = MCP794XX_Read_Jahr(&dt);
23
    dt.Wochentag = MCP794XX_Read_Wochentag(&dt);
24
25
    #ifdef __DISPLAY_ON
26
    strcpy(chr_Wochentag, Wochentag_Namen[dt.Wochentag]); 
27
    sprintf(chr_Temp, "%s %02u.%02u.20%02u %02u:%02u:%02u ",chr_Wochentag, dt.Tag, dt.Monat, dt.Jahr, dt.Stunden, dt.Minuten, dt.Sekunden);
28
    LcdPrintf(1,0, chr_Temp);        
29
    sprintf(chr_Temp, "Temp: %.4u°C",int_Temp = GetTempLM75(1));
30
    LcdPrintf(1,24, chr_Temp);
31
    #endif
32
}

von Peter D. (peda)


Lesenswert?

Die PIC bilden eine Ausnahme gegenüber den üblichen Mikrocontrollern, 
sie haben keine nach Quelle unterschiedlichen Interruptvektoren.
Daher müssen in den beiden Interrupthandlern erstmal alle freigegebenen 
Quellen abgeklappert werden, ob das Pending-Flag gesetzt ist und dann 
muß es gelöscht werden.

Ingo S. schrieb:
> Aber was passiert, wenn der Interrupt unterbricht, und das Flag
> noch gesetzt ist.

Ein Interrupt kann nur durch einen Interrupt höherer Priorität 
unterbrochen werden und wird nach dessen Ende weiter ausgeführt. Das 
Flag ist dabei egal.

von mh (Gast)


Lesenswert?

Peter D. schrieb:
> Die PIC bilden eine Ausnahme gegenüber den üblichen Mikrocontrollern,
> sie haben keine nach Quelle unterschiedlichen Interruptvektoren.

Das gilt nur für <= PIC18

von Danny (Gast)


Lesenswert?

Aus eigener Erfahrung kann ich nur MPLAB X IDE und den codeconfigurator 
empfehlen. Macht das Programmieren und Handling der Routinen einfacher.

von Ingo S. (schicki)


Lesenswert?

Stimmt, dass kann ich nach meinen Tests bestätigen. Unabhängig von den 
Flags bleibt der Interrupt über die serielle Schnittstelle aktiv, und 
der TMR0 startet nicht mehr. Jetzt kommt aber das was ich nicht für 
möglich gehalten habe.

- Mit der aktuellsten Version des XC8 2.32 startet der Timer nicht mehr.
- Aus Spielerei habe ich gestern dann noch die Vorgänger Version 
getestet.X8 2.31. Das kuriose in dieser Version startet der Timer 
wieder.

Wer kann mir nun sagen, welcher Compiler richtig oder falsch arbeitet.

von mh (Gast)


Lesenswert?

Ingo S. schrieb:
> Wer kann mir nun sagen, welcher Compiler richtig oder falsch arbeitet.

Ich tippe auf einen Bug in deiner Software ;-)

von (prx) A. K. (prx)


Lesenswert?

Ingo S. schrieb:
> Wer kann mir nun sagen, welcher Compiler richtig oder falsch arbeitet.

Wer anderen diese Frage stellt, kann sich ziemlich sein, dass es nicht 
der Compiler ist.

von Peter D. (peda)


Lesenswert?

Compilerbugs sind möglich. Dazu muß man aber auch einen compilierfähigen 
Code zeigen, wo der Bug auftritt.

von Bratmaxxe (Gast)


Lesenswert?

Was für Optimierungen sind default eingestellt?

von Alfred (plalf)


Lesenswert?

Ist zwar schon länger her, aber, falls doch noch jemand darüber 
stolpert, hier einige Gedanken: ganz wichtig - Interruptservice-Routinen 
sollten so kurz wie möglich gehalten werden und keine extensiven 
Funktionsaufrufe beinhalten (besonders solche, deren Quellcode man nicht 
kennt).

Ino S. hat in seiner TMR0_ISR() viele sprintf, strcopy, LCDprintf sowie 
MCP794XX...-Aufrufe. Das ist mit ziemlicher Sicherheit vom 
Zeitmanagement her problematisch.

Die Abarbeitung all dieser Dinge hat außerhalb und nach Beendigung der 
Interruptservice-Routine zu erfolgen (jeweiliges Interrupt-Flag wieder 
rücksetzen!), zB in einer Schleife, welche auf ein von der 
Interruptservice-Routine gesetztes Flag prüft, dieses löscht und zur 
Abarbeitungsfunktion (= TMR0_ISR) für den MCPxxx und dem Display 
verzweigt. Oder man implementiert eine einfache state-machine.

Was nicht aus den Codeabschnitten hervorgeht, ist, wie oft die TMR0-ISR 
pro Sekunde angesprungen wird. Kennt man das, dann vergleiche man, 
wieviel Zeit all die sprintf, strcopy, etc Funktionen benötigen - es 
wird sich bis zum nächsten TMR0_ISR-Aufruf uU nicht ausgehen und das 
TMR0-Intervall wäre daher entsprechend zu vergrößern. Werden zudem ev 
auch Interrupts in den aufgerufenen Funktionen deaktiviert (dann sieht 
es düster aus)?

Die Interruptservice-Routine für das Abfangen der seriellen Daten 
unterbricht die TMR0-Interruptservice-Routine, falls etwas daherkommt, 
da sie die höhere Priorität hat. Auch hier sollte die eigentliche 
Abarbeitung/Verarbeitung der empfangenen Daten außerhalb der 
Interruptservice-Routine erfolgen. Zudem würde ich die 
TMR0-Interruptservice-Routine als high_priority setzen, um ev 
Unterbrechungen durch andere Interruptservice-Routinen hintanzuhalten.

: Bearbeitet durch User
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.