Interrupt mit Timer0 auf PIC18f

Ich suche ein wenig Hilfe und Ratschläge zu meinem Code.

Ich verwende C18 in der MPLab-Umgebung, PIC18f4520 mit Fosc bei 4 MHz und usnig timer0 im 16-Bit-Modus, um bis zum Überlauf zu zählen, das Überlaufbit und das Interrupt-Flag zu setzen, dann zu ISR zu springen und eine Variable "count" zu inkrementieren. Dies wird an einen Port mit angeschlossenen LEDs ausgegeben, so dass ich eine visuelle Bestätigung der Programmfunktion erhalten kann.

Die ausgegebene Zählung ist jedoch immer '1' (dh 0x01) und ich glaube, dass die ISR nur einmal auftritt, wenn überhaupt.

Jede Hilfe, die Sie anbieten können, wird am meisten geschätzt.

Hier ist mein Code:

void main (void)        /*                                                                                      */
{                   
TRISA = 0;          /*                                                                                      */
TRISC = 0;          /*                                                                                      */
TRISB = 0;
TRISD = 0x00;
RTOS();
}
void low_interrupt (void)
    {
    _asm GOTO timer_isr _endasm
    }
    #pragma code
    #pragma interruptlow timer_isr 

void timer_isr (void)
    {
    INTCONbits.TMR0IF = 0;
    count = count++;
    LATD = count;
    RTOS();
    }
void RTOS (void)
    {
    T0CONbits.T08BIT = 0;   // 16-bit timer
    T0CONbits.T0CS = 0;     // increment on instruction cycle input
    T0CONbits.T0SE = 0;     // increment on low--> high transition of clock
    T0CONbits.PSA = 1;      // T0 prescaler not assigned i.e. 1:1 prescaler.
    RCONbits.IPEN       = 1;    //Enable Interrupt Priorities
    INTCONbits.GIEL     = 1;    //Enable Low Priority Interrupt
    INTCONbits.GIE      = 1;    //Enable Global Interrupts            
    INTCONbits.TMR0IE   = 1;    //Enable Timer0 Interrupt
    INTCON2bits.TMR0IP  = 0;    //TMR0 set to Low Priority Interrupt
    INTCONbits.TMR0IF = 0;  // T0 int flag bit cleared before starting
    T0CONbits.TMR0ON = 1;   // timer0 START
    while (1);
    }

Vielen Dank im Voraus für jede Anleitung, die Sie anbieten können.

Wo ist countdefiniert? Hast du es markiert volatile?
Sie sollten count++;stattdessen tun count = count++;. Der ++Operator speichert den neuen Wert für Sie.

Antworten (3)

Sie rufen RTOS() in Ihrem Interrupt auf und die RTOS()-Funktion hat "while (1);" darin (Endlosschleife?)

Ich bin mir nicht sicher, warum Sie die vollständigen Interrupt-Register innerhalb Ihres Interrupts zurücksetzen würden.

Eine Endlosschleife in Ihrem Interrupt führt höchstwahrscheinlich zu einer Fehlfunktion Ihres Programms.

Sehen Sie sich auch den Kommentar von Roger Rowland an: „Wo ist countdefiniert? Haben Sie es markiert volatile? – Roger Rowland vor 15 Minuten“. Dies ist ein ziemlich häufiger Fehler und könnte auch hier der Punkt sein.

Ja, ich habe einen zusätzlichen Aufruf an RTOS(), den ich entfernen sollte.
Innerhalb der ISR setze ich nur das Interrupt-Flag zurück, so dass, wenn das Interrupt-Flag kurz nach dem Verlassen der ISR gesetzt wird, die ISR erneut aufgerufen wird.
count ist im Header definiert und wird als int definiert. Da ich relativ unerfahren in CI bin, musste ich noch nie "volatile" für irgendetwas verwenden
@user32851 Fügen Sie dann einfach das Schlüsselwort volatilezu Ihrer hinzu int, also volatile int count;sehen Sie, ob das einen Unterschied macht, und lesen Sie auf jeden Fall, warum es manchmal notwendig ist .
@ user32851 Sie haben ein while (1);in RTOS(), das sich in Ihrem Interrupt befindet. Selbst wenn Sie das Interrupt-Flag zurücksetzen, unterbricht der Interrupt Ihre aktuelle Interrupt-Routine nicht! Es wird also in der Zwischenzeit stecken bleiben. Ich schlage vor, Sie legen das while(1);in Ihre Hauptdatei oder löschen es vollständig. `while(1){ //some code }' wird oft in main ausgeführt, um das Programm am Laufen zu halten/diesen Code in einer Schleife zu durchlaufen. Aber Sie sollten diese Schleife nicht in einer Interrupt-Service-Routine machen.
void timer_isr (void) { INTCONbits.TMR0IF = 0; count = count++; LATD = count; RTOS(); }Dies ist Ihr Interrupt-Routinencode. Es ruft RTOS()... und RTOS()hat eine while(1), damit es die Schleife oder ISR (Interrupt Service Routine) nie verlässt. Also ja, der Interrupt passiert nur einmal, wie Sie dachten.
Ich habe den Funktionsaufruf RTOS() aus der ISR-Routine timer_isr entfernt. Der Code funktioniert immer noch nicht wie vorgesehen. Ich kann while(1) nicht aus der Funktion void RTOS (void) entfernen, da der timer0 dazu bestimmt ist, kontinuierlich zu laufen und periodische Interrupts zu geben, die ich dann verwenden werde, um eine andere Routine aufzurufen, die mit diesem periodischen Interrupt abtastet
@ user32851 Interrupts benötigen keinen, while(1);damit sie kontinuierlich ausgeführt werden. . Um Ihren Code jedoch kontinuierlich auszuführen, while(1);wird oft in die Hauptdatei gestellt. Obwohl dies das Problem nicht löst. (Solange Sie das CTOS() nicht in Ihrem Interrupt haben. Ich würde vorschlagen, Ihr Programm Schritt für Schritt durchzugehen oder zu prüfen, ob es den Interrupt jemals verlässt.

Ich kenne C18 nicht, aber ich benutze seinen Nachfolger XC8.

Weiß der C18-Compiler in Bezug auf Ihre ISR, dass er void low_interrupt (void) ausführen soll, wenn ein Interrupt mit niedriger Priorität generiert wird? Ich habe bestimmte Funktionen für Interrupts bei einigen Compilern gesehen, aber XC8 funktioniert wie folgt:

// HP int declared with 'high_priority' identifier, name function as you see fit
interrupt high_priority void isr_high(void)

// LP int declared with 'low_priority' identifier, name function as you see fit
interrupt low_priority void isr_low(void)

Wenn C18 stattdessen bestimmte Funktionsnamen verwendet, vergewissern Sie sich, dass Sie sie richtig eingegeben haben.

Zweitens, hier ist, wie ich mit Ihrem Timer-Überlauf umgegangen wäre:

interrupt high_priority void isr_high(void)
{  
    // TIMER0 Overflow
    if (INTCONbits.TMR0IF)
    {
        LATEbits.LE0 ^= 1;               // Toggle RE0
        INTCONbits.TMR0IF = 0;           // Clear the interrupt flag
    }
}

Hoffe das hilft.

Ich muss für jede ISR einen Pragma-Code erstellen und dann die vordefinierten Interrupt-Funktionsnamen verwenden. Eine Sache, die ich nicht getan habe, ist, eine Aktion für den hohen ISR anzugeben oder sogar die Funktion einzubeziehen. Es ist also möglich, dass der hohe ISR etwas tut. danke für das Code-Snippet, ich beabsichtige eigentlich, die ISR bei Überlauf zu einer neuen Routine springen zu lassen, aber es hilft einigen
Wenn die Routine, zu der Sie springen, wahrscheinlich erhebliche Arbeit leisten wird, ist es besser, Ihren ISR dazu zu bringen, ein Flag zu setzen, das in Ihrem Hauptprogramm abgefragt wird. Erledigen Sie dann die Routinearbeiten in Ihrem Hauptprogramm. Aber solange Ihre Routine kurz und bündig ist, sollte es in Ordnung sein, von der ISR zu ihr zu springen. Das Code-Snippet, das ich Ihnen gegeben habe, verwende ich, um zu bestätigen, dass mein Mikro in vielen meiner Projekte noch läuft. Es blinkt einfach eine LED kontinuierlich, vorausgesetzt, der ISR reagiert auf TIMER0-Überläufe :) Viel Spaß :)

Danke für all die Hilfe.

Mit ein bisschen Arbeit in MPLabSim habe ich meinen Fehler gefunden und der korrigierte Code unten funktioniert korrekt, zumindest in MPLabSim:

EDIT: Funktioniert jetzt auch auf echter Hardware!!!!

 void main (void)       /*                                                                                      */
    {                   
    TRISA = 0;          /*                                                                                      */
    TRISC = 0;          /*                                                                                      */
    TRISB = 0;
    TRISD = 0x00;
    RTOS();
    }
void low_interrupt ()
    {
    _asm GOTO timer_isr _endasm
    }
    #pragma code
    #pragma interrupt low_interrupt //save =PROD
void timer_isr ()
    {
    if(INTCONbits.TMR0IF==1)
    {
    count++;
    INTCONbits.TMR0IF = 0;
    }
    }
void RTOS ()
    {
    T0CONbits.T08BIT = 0;   // 16-bit timer
    T0CONbits.T0CS = 0;     // increment on instruction cycle input
    T0CONbits.T0SE = 0;     // increment on low--> high transition of clock
    T0CONbits.PSA = 1;      // T0 prescaler not assigned i.e. 1:1 prescaler.
    RCONbits.IPEN       = 1;    //Enable Interrupt Priorities
    INTCONbits.GIEL     = 1;    //Enable Low Priority Interrupt
    INTCONbits.GIEH     = 0;    // disable high priority interrupts
    INTCONbits.GIE      = 1;    //Enable Global Interrupts            
    INTCONbits.TMR0IE   = 1;    //Enable Timer0 Interrupt
    INTCON2bits.TMR0IP  = 0;    //TMR0 set to low Priority Interrupt

    INTCONbits.TMR0IF = 0;  // T0 int flag bit cleared before starting
    T0CONbits.TMR0ON = 1;   // timer0 START
    counter(count);
    }   
void counter ()
{
LATD = count;
}