PIC18F Interrupt Routinen

OP #6895078
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
Gast #6895085
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.
OP #6895100
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
}
#6895153
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.
OP #6896167
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.
#7378657
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.

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