Uso de la función de interrupción PORTB al cambiar con XC8

1

Estoy creando un programa para aprender a usar las interrupciones de portB en PIC18F2520 .

Hice un programa, pero no funciona correctamente. El programa está encendido todo el tiempo y apagando el led, y el estado del led debe cambiarse solo con un cambio en algún pin del puerto B (estoy usando un botón).

Te muestro mi código:

#include <xc.h>


#define _XTAL_FREQ 4000000
#define LED_OUTPUT LATC3

unsigned char config1;
unsigned int timer_value;
unsigned int tpr;
int counter=0;

void main(void) {


TRISCbits.RC3 = 0;

   ADCON1 |= 0b1111;

   EnablePullups();

   INTCONbits.RBIE = 1;
   //RCONbits.IPEN = 0;
   //INTCONbits.PEIE = 1; // Enable Perpherial Interrupt

   INTCONbits.GIE = 1; // Enable Global Interrupt

   INTCON2bits.INTEDG0 = 1;
   //INTCON2bits.NOT_RBPU = 0;
   //TMR1 = 0;
   while(1)
   {
       __delay_ms(100);

   }
}


void interrupt isr(void) {

// Was it the port B interrupt on change?
if (INTCONbits.RBIF) {
    // Dummy read of the port, as per datasheet

    // Use XOR to toggle the pin, saving a variable
    LED_OUTPUT ^= 1;

    // Reset the interrupt flag
    INTCONbits.RBIF = 0;

            if (PORTB) {
        asm("nop");
    }
     __delay_ms(100);
}

}

Aquí te muestro mi esquema en Proteus !.

El botón está unido al pin RB0. A ver si podemos encontrar los errores juntos.

¡Saludos!

    
pregunta Manuel Joaquín

1 respuesta

5

Una cosa que ayudaría (y definitivamente es la mejor práctica) sería verificar qué está causando la interrupción. También debe escribir en el latch ( LATx register) en un 18F y necesita deshabilitar las funciones analógicas.

El código de ejemplo para esto podría ser:

#define LED_OUTPUT LATC3

void main(void) {
    // .. other setup here .. 

    // Disable analogue functions
    ADCON1 |= 0b0011;

    // .. interrupt setup ..
}

void interrupt isr(void) {

    // Was it the port B interrupt on change?
    if (INTCONbits.RBIF) {
        // Dummy read of the port, as per datasheet
        if (PORTB) {
            asm("nop");
        }

        // Use XOR to toggle the pin, saving a variable
        LED_OUTPUT ^= 1;

        // Reset the interrupt flag
        INTCONbits.RBIF = 0;
    }
}

Usar la función de interrupción en cambio con un pin de entrada específico es un poco más difícil, pero puede verificar en el ISR si el valor de entrada actual es 0 o 1 (lo que sea más relevante). No te olvides de rebotar en tu conmutador también, ya sea en hardware o en software.

condición de desajuste de PORTB

Note esta parte críptica de la hoja de datos en la sección 9.1 "Registros INTCON" con respecto al RBIF bit:

  

Nota 1: una condición de falta de coincidencia continuará configurando este bit. Leyendo   PORTB finalizará la condición de discrepancia y permitirá que se borre el bit.

Para evitar que su código se atasque en el ISR (configurando repetidamente RBIF ), debe leer el puerto en su ISR incluso si no hace nada con el valor. El ejemplo de código anterior muestra esto.

(nota que encontré esta respuesta que es casi lo mismo)

Errata

La errata para tu dispositivo es otro excelente lugar para ir. Aquí está la errata para el 18F2520 , sin embargo, en este caso, no parece haber ninguna relación a las interrupciones o los puertos de datos.

Funciones especiales

Es posible que también deba desactivar otras funciones especiales en PORTB. Específicamente las funciones analógicas, que siempre deben estar deshabilitadas si está utilizando el pin como entrada digital.

// Make just AN12 (on pin B0) a digital input
ADCON1 |= 0b0011;

// Make all external pins digital inputs
ADCON1 |= 0b1111;

Mecanismos de interrupción alternativos

Tenga en cuenta que en el 18F2520 tiene tres interrupciones externas dedicadas disponibles como INT0 a INT2. Estos mapean a los pines B0 a B2. Consulte la sección 9.6 "INTx Pin Interrupts", donde encontramos lo siguiente:

  

Las interrupciones externas en los pines RB0 / INT0, RB1 / INT1 y RB2 / INT2 están   disparado por el borde. Si el bit INTEDGx correspondiente en el INTCON2   el registro se establece (= 1), la interrupción se activa por un flanco ascendente; Si   el bit está despejado, el disparador está en el flanco descendente.

En su lugar, podría utilizar la interrupción INT0, lo que significa que no depende de los valores de todo PORTB. Debido a que se activan en el borde, obtendrás menos interrupciones espúreas, pero aún tendrás que rebotar el interruptor.     

respondido por el David

Lea otras preguntas en las etiquetas