interrumpir usando Timer0 en PIC18f

Estoy buscando un poco de ayuda y consejo sobre mi código.

Estoy usando C18 en el entorno MPLab, PIC18f4520 con Fosc @ 4MHz, y usando timer0 en modo de 16 bits para contar hasta el desbordamiento, establecer el bit de desbordamiento y el indicador de interrupción, luego saltar a ISR e incrementar un 'conteo' variable. Esto se envía a un puerto con LED conectados para que pueda obtener una confirmación visual del funcionamiento del programa.

Sin embargo, el recuento emitido siempre es '1' (es decir, 0x01) y creo que el ISR solo ocurre una vez, si es que ocurre.

Cualquier ayuda que pueda ofrecer sería muy apreciada.

Aquí está mi código:

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);
    }

Gracias de antemano por cualquier orientación que pueda ofrecer.

¿ Dónde se countdefine? ¿ Lo has marcado volatile?
Deberías hacer count++;en lugar de count = count++;. El ++operador guarda el nuevo valor para usted.

Respuestas (3)

Está llamando a RTOS() en su interrupción y la función RTOS() tiene "while (1);" en él (¿bucle infinito?)

No estoy seguro de por qué restablecería los registros de interrupción completos dentro de su interrupción.

Tener un bucle infinito en su interrupción probablemente hará que su programa no funcione correctamente.

Además, revisa el comentario de Roger Rowland: "¿Dónde está countdefinido? ¿Lo has marcado volatile? – Roger Rowland hace 15 minutos". Este es un error bastante común y también podría ser el punto aquí.

Sí, tengo una llamada adicional a RTOS() que debo eliminar.
Dentro de ISR, todo lo que estoy restableciendo es el indicador de interrupción, de modo que si el indicador de interrupción se establece poco después de la salida de ISR, volverá a llamar a ISR.
count se define en el encabezado y se define como int. Como soy relativamente inexperto en CI nunca he tenido que usar "volátil" para nada
@ user32851 Luego simplemente agregue la palabra clave volatilea su int, así que volatile int count;vea si eso hace la diferencia y, en cualquier caso, lea por qué a veces es necesario .
@ user32851 Tiene un while (1);RTOS() que está en su interrupción. ¡Incluso si restablece el indicador de interrupción, la interrupción no interrumpirá en su rutina de interrupción actual! Por lo tanto, se quedará atascado en el tiempo. Le sugiero que ponga el while(1);en su principal, o lo borre por completo. `while(1){ //algún código }' a menudo se realiza en main para mantener el programa en ejecución/bucle en ese código. Pero no debe hacer este ciclo en una rutina de servicio de interrupción.
void timer_isr (void) { INTCONbits.TMR0IF = 0; count = count++; LATD = count; RTOS(); }Este es su código de rutina de interrupción. Llama RTOS()... Y RTOS()tiene un while(1)modo de que nunca salga del bucle o ISR (rutina de servicio de interrupción). Entonces sí, la interrupción solo ocurre una vez, como pensabas.
He eliminado la llamada a la función RTOS() de la rutina ISR timer_isr. El código aún no funciona según lo previsto. no puedo eliminar el while (1) de la función void RTOS (void) ya que el timer0 está diseñado para ejecutarse continuamente y dar interrupciones periódicas, que luego usaré para llamar a otra rutina que probará usando esta interrupción periódica
Las interrupciones de @user32851 no requieren una while(1);para que se ejecuten continuamente. . Sin embargo, para ejecutar su código de forma continua, while(1);a menudo se coloca en el archivo main. Aunque esto no resuelve el problema. (siempre y cuando no tenga el CTOS() en su interrupción. Le sugiero que revise su programa paso a paso, o verifique si alguna vez sale de la interrupción.

No estoy familiarizado con C18, pero uso su sucesor XC8.

Con respecto a su ISR, ¿el compilador C18 sabe ejecutar void low_interrupt (void) cuando se genera una interrupción de baja prioridad? He visto funciones designadas para interrupciones con algunos compiladores, pero XC8 funciona de la siguiente manera:

// 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)

Si C18 usa nombres de funciones designados en su lugar, asegúrese de que los tenga correctos.

En segundo lugar, así es como habría manejado el desbordamiento del temporizador:

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

Espero que esto ayude.

Tengo que programar el código para cada ISR, luego usar los nombres de función de interrupción predefinidos. Una cosa que no he hecho es dar una acción para el ISR alto, o incluso incluir la función; entonces es posible que el ISR alto esté haciendo algo. gracias por el fragmento de código, en realidad tengo la intención de hacer que el ISR salte a una nueva rutina en el desbordamiento, pero ayuda un poco
Si es probable que la rutina a la que está saltando haga un trabajo significativo, es mejor hacer que su ISR establezca una bandera que se sondee dentro de su programa principal. Luego haga el trabajo de rutina en su programa principal. Pero siempre que su rutina sea corta y dulce, entonces debería estar bien saltar a ella desde el ISR. El fragmento de código que le di es lo que uso para confirmar que mi micro aún se está ejecutando en muchos de mis proyectos. Simplemente parpadea un LED continuamente siempre que el ISR esté respondiendo a los desbordamientos de TIMER0 :) Disfrute :)

Gracias por toda la ayuda.

Con un poco de trabajo en MPLabSim, encontré mi error y el código corregido a continuación funciona correctamente, al menos en MPLabSim:

EDITAR: ¡ahora también funciona en hardware real!

 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;
}