Ich habe ein überwältigendes Fehlverhalten in meinem PIC16F1825. Grundsätzlich verwende ich Pin 3 (RA4), um eine LED mit einem Interrupt-on-Change umzuschalten. Das Problem ist, obwohl es die LED umschaltet, wenn ich die Taste drücke (die extern hochgezogen wird), schaltet die LED nach einer Sekunde erneut um, was bedeutet, dass die Interrupt-Routine erneut aufgerufen wurde und dies nicht sollte, obwohl ich lösche das Interrput-Flag.
Hier ist der Code (nur die Funktionen IOconfig_portA() und toggleLed() sind für das vorliegende Problem von Bedeutung:
#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);
}
Vielen Dank im Voraus!
Gemäß Seite 92 des PIC16F1825- Datenblatts :
Hinweis 1: Das IOCIF-Flag-Bit ist schreibgeschützt und wird gelöscht, wenn alle Interrupt-on-Change-Flags im IOCxF-Register per Software gelöscht wurden
Also im Grunde, wenn Sie dies in Ihrem Code tun:
INTCONbits.IOCIF = 0;
Es tut eigentlich überhaupt nichts - das Interrupt-Flag wird nicht gelöscht, da dieses Bit schreibgeschützt ist.
Um das Interrupt-Flag für Interrupt-on-Change-Quellen zu löschen, müssen Sie in das IOCAF
Register schreiben, um die gewünschten Flags zu löschen. Wenn Sie sie alle löschen möchten, können Sie Folgendes tun:
IOCAF = 0x0;
Wenn Sie nur bestimmte Bits löschen möchten, wie in Ihrem Fall IOCAF4, können Sie Folgendes tun:
IOCAFbits.IOCAF4 = 0;
Antwort gefunden! Es ist ziemlich undurchsichtig, muss ich sagen. Grundsätzlich verfügt der PIC über einen Watchdog-Timer, der das Gerät alle 4 Sekunden zurücksetzt. Seltsamerweise ist es standardmäßig aktiviert (macht das überhaupt Sinn?). Um den Watchdog-Timer zu deaktivieren, müssen Sie die folgende Pre-Compiler-Direktive hinzufügen:
#pragma config WDTE = OFF
Ist es möglich, dass die Schaltung aufgrund mehrerer Unterbrechungen (z. B. Stapelüberlauf) zurückgesetzt wird?
Bei einem Reset würden Sie den gesamten Code wiederholen und den Interrupt erneut aktivieren. (Wie in der anderen Antwort könnte es einen Schaltersprung geben, der dies verursacht.)
Die Zählerverzögerung von 100k kann zu kurz sein, versuchen Sie, diese auf etwas menschlich Messbares zu erhöhen, wie eine Gesamtverzögerung von 500 ms, wenn möglich.
Um auch auf einen unerwünschten Reset zu testen, geben Sie sich eine einmalige Einschaltroutine, um einen eindeutigen Code auf der LED zu blinken, der Ihnen sagt, ob das Ganze recycelt wurde.
Tom Tischler
José Fonseca
Tom Tischler
for (int i = 0; i < 100000; i++);
das in einer ISR nichts zu suchen hat! Die erste Regel für Interrupts ist, dass die Handler so schnell wie möglich fertig werden und nicht für längere Zeit blockieren sollten. Auch dieINTCONbits.GIE = ...
Linien sind unnötig (wird intern vom PIC beim Betreten und Verlassen des ISR durchgeführt).José Fonseca
Tom Tischler