Tengo un mal comportamiento alucinante en mi PIC16F1825. Básicamente, estoy usando el pin 3 (RA4) para alternar un LED usando una interrupción en el cambio. El problema es que, aunque cambia el LED cada vez que presiono el botón (que se levanta externamente), después de un segundo, el LED cambia de nuevo, lo que significa que la rutina de interrupción se llamó nuevamente, y no debería, aunque borre la bandera de interrput.
Aquí está el código (solo la función IOconfig_portA() y toggleLed() son importantes para el problema en cuestión:
#include <stdio.h>
#include <stdlib.h>
#include <PIC16F1825.h>
char temp=0;
void interrupt toggleLed() {
INTCONbits.GIE = 0;
if(INTCONbits.IOCIF == 1) {
temp = PORTA;
INTCONbits.IOCIF = 0;
LATC3 = ~LATC3;
for (int i = 0; i < 100000; i++);
}
INTCONbits.GIE = 1;
}
void CLOCKconfig() {
OSCCON = 0x6A; //Sets the internal oscillator fosc = 4 MHz
OSCSTAT = 0x00;
OSCTUNE = 0x00;
}
void IOconfig_portA() {
ANSELA = 0x00; // All ports set as DIGITAL
TRISAbits.TRISA4 = 1; // Set as input
//OPTION_REG &= 0x7F; // Clear bit 7, to enable the weak pull-up
//WPUA |= (1<<2); // Enable the WPU for RA2
CM1CON0 = 0x00;
CM1CON1 = 0x00;
IOCANbits.IOCAN4 = 1; // Generate Interrupt on Negedge
IOCAP = 0x00; // Disable Interrupt on Posedge
INTCON = 0x88; // Enable GIE and IoC interrupts
}
int main(int argc, char** argv) {
TRISC = 0;
CLOCKconfig();
ANSELC &= 0x00; // All bits on port C are set to Digital I/O's
TRISC &= 0x00; // All bits on Port C are set to Outputs
APFCON0 |= (1<<5); // Don't use special features on Pin RC3
APFCON1 |= (1<<2); // Don't use special features on Pin RC3
IOconfig_portA();
LATC |= (1<<3);
while(1) {
}
return (EXIT_SUCCESS);
}
¡Gracias de antemano!
De acuerdo con la página 92 de la hoja de datos PIC16F1825 :
Nota 1: El bit de indicador IOCIF es de solo lectura y se borra cuando el software borra todos los indicadores de interrupción por cambio en el registro IOCxF.
Básicamente, cuando haces esto en tu código:
INTCONbits.IOCIF = 0;
En realidad, no hace nada en absoluto: el indicador de interrupción no se borra porque ese bit es de solo lectura.
Para borrar el indicador de interrupción para las fuentes de Interrupción por cambio, debe escribir en el IOCAF
registro para borrar los indicadores que desea. Si desea borrarlos todos, puede hacer lo siguiente:
IOCAF = 0x0;
Si solo desea borrar ciertos bits, como IOCAF4 en su caso, puede hacer:
IOCAFbits.IOCAF4 = 0;
¡Encontré la respuesta! Es bastante oscuro, debo decir. Básicamente, el PIC tiene un temporizador Watchdog que reinicia el dispositivo cada 4 segundos. Por extraño que parezca, viene habilitado de forma predeterminada (¿eso tiene sentido?). Para deshabilitar el temporizador de vigilancia, debe agregar la siguiente directiva de compilación previa:
#pragma config WDTE = OFF
¿Es posible que el circuito se restablezca debido a múltiples interrupciones (por ejemplo, desbordamiento de pila).
En un reinicio, repetiría todo el código y volvería a habilitar la interrupción. (Como en la otra respuesta, podría haber un rebote del interruptor que provoque esto).
El retraso del contador de 100k puede ser demasiado corto, intente aumentar esto a algo humanamente medible como un retraso total de 500ms si es posible.
Además, para probar un reinicio no deseado, realice una rutina de encendido única para que destelle un código único en el LED, que le indicará si todo se recicló.
tom carpintero
jose fonseca
tom carpintero
for (int i = 0; i < 100000; i++);
eso no tiene cabida en un ISR! La primera regla de las interrupciones es que los controladores deben terminar lo más rápido posible y no bloquearse durante largos períodos de tiempo. También lasINTCONbits.GIE = ...
líneas son innecesarias (lo hace internamente el PIC al entrar y salir del ISR).jose fonseca
tom carpintero