由中断服务例程切换的易失性变量的更改未反映在 main() 中
Changes to volatile variable toggled by interrupt service routine not reflected in main()
我有一个真正的问题,我已经被困了一段时间了。我正在用 C 编写 PIC16F15376 微控制器 Xpress 板。
我将一个名为buttonIntention
的volatile变量初始化为0。当中断服务程序发生时,调用buttonSet(1)
,有效地设置buttonIntention = 1
。 [注意:我也试过直接切换 buttonIntention
变量,没有 get 或 set 函数。] 在 main()
中,不断轮询的 while(1)
检查 ISR 是否已经关闭(这将设置 buttonIntention = 1
),如果 ISR 设置了,TESTPIN
设置为高,我可以在我的 o-scope 上查看它。
我确定当我按下一个按钮时,ISR 确实触发了。 buttonIntention
然后在 ISR 中设置为 1,因为我尝试在 ISR 末尾注释掉的代码工作正常。
但是,我在 main()
中的 while(1)
中的 if(buttonIntention)
实际上从未看到 buttonIntention 设置为 1。我认为将此变量设置为 volatile
可以解决此问题,因为它在 ISR 和 main()
之间共享,我认为在我的 8 位微控制器上使用 uint8_t
类型可以解决我读到但并不真正理解的任何 "atomic" 问题。 .. 但是,if 语句永远看不到 1 仍然有问题。
有什么想法吗?
这是我的代码:
// CONFIG1
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits->HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1
#pragma config CLKOUTEN = OFF // Clock Out Enable bit->CLKOUT function is disabled; i/o or oscillator function on OSC2
#pragma config CSWEN = ON // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit->FSCM timer enabled
// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit->MCLR pin is Master Clear function
#pragma config PWRTE = OFF // Power-up Timer Enable bit->PWRT disabled
#pragma config LPBOREN = OFF // Low-Power BOR enable bit->ULPBOR disabled
#pragma config BOREN = ON // Brown-out reset enable bits->Brown-out Reset Enabled, SBOREN bit is ignored
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices
#pragma config ZCD = ON // Zero-cross detect disable->Zero-cross detect circuit is disabled at POR.
#pragma config PPS1WAY = ON // Peripheral Pin Select one-way control->The PPSLOCK bit can be cleared and set only once in software
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit->Stack Overflow or Underflow will cause a reset
// CONFIG3
#pragma config WDTCPS = WDTCPS_31 // WDT Period Select bits->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled, SWDTEN is ignored
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC // WDT input clock selector->Software Control
// CONFIG4
#pragma config WRTC = OFF // UserNVM self-write protection bits->Write protection off
//#pragma config SCANE = available // Scanner Enable bit->Scanner module is available for use
#pragma config LVP = ON // Low Voltage Programming Enable bit->Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.
// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit->UserNVM code protection disabled
//#pragma config CPD = OFF // DataNVM code protection bit->DataNVM code protection disabled
// ==========================================================================
// Import Header Files
// ==========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xc.h>
#include <math.h>
// ==========================================================================
// Define statements
// ==========================================================================
// Inputs from buttons
#define startButton PORTCbits.RC4
#define profileButton PORTCbits.RC5
#define incrementButton PORTCbits.RC6
#define decrementButton PORTCbits.RC7
#define TESTPIN LATCbits.LATC0
// ==========================================================================
// Global Variables
// ==========================================================================
// ISR Toggle Variables (MUST be declared volatile)
volatile uint8_t buttonIntention = 0;
// ==========================================================================
// General Configuration
// ==========================================================================
// --- --- --- --- --- --- ---
// Configure Inputs and Outputs
// --- --- --- --- --- --- ---
void config_IO(void) {
// --- Set output for 5 gate drivers and LCD rs and en: ---
TRISA = 0; // Set all Port A I/O to output
LATA = 0; // Set all Port A outputs to LOW/0
ANSELA = 0; // Turn Port A analog off (Digital only)
// --- Set output for LCD data: ---
TRISB = 0; // Set all Port B I/O to output
LATB = 0; // Set all Port B outputs to LOW/0
ANSELB = 0; // Turn Port B analog off (Digital only)
// --- Set input from buttons: ---
//TRISC = 0b11111000; // Set Port C 3-7 to input for the buttons
TRISC = 0xF8; // Set Port C 3-7 to input for the buttons
LATC = 0; // Set all Port C outputs LOW
ANSELC = 0; // Turn Port C analog off (Digital only)
}
// --- --- --- --- --- --- ---
// Configure Change Notification for Button Interrupts
// --- --- --- --- --- --- ---
void config_CN(void){
//Clear Interrupt flag
IOCIF = 0;
// Clear all of Port C 0-7 interrupt flags
IOCCF = 0x00;
// Enable interrupts on Positive Edge of the buttons RC3-RC7
IOCCP3 = 1;
IOCCP4 = 1;
IOCCP5 = 1;
IOCCP6 = 1;
IOCCP7 = 1;
IOCIE = 1; //Enable Interrupt
}
// --- --- --- --- --- --- ---
// Configure the oscillator:
// --- --- --- --- --- --- ---
void config_OSC (void) {
// Clear registers
OSCCON1 = 0x00;
OSCCON2 = 0x00;
OSCCON3 = 0x00;
// OSCCON1:
// Use High Freq. Internal Oscillator (HFINTOSC @ 1 - 32 MHz)
//OSCCON1bits.NOSC = 0b110;
OSCCON1bits.NOSC = 0x6;
// OSCFRQ:
// Configure HFINTOSC to 32 MHz
// OSCFRQbits.HFFRQ = 0b110;
OSCFRQbits.HFFRQ = 0x6;
// Divide clock by 1
//OSCCON1bits.NDIV = 0b0000;
OSCCON1bits.NDIV = 0x0;
}
// ==========================================================================
// Button Function
// ==========================================================================
void buttonSet(uint8_t setter){
buttonIntention = setter;
}
uint8_t buttonGet(void){
return buttonIntention;
}
// ==========================================================================
// Interrupt service routine
// ==========================================================================
void __interrupt() isr(void)
{
// If button is pressed...
if(IOCIF == 1 && buttonIntention == 0) {
//buttonIntention = 1; // Change state to indicate that button was somehow pressed intentionally or unintentionally
//OR
buttonSet(1);
IOCIF = 0; //Clear Interrupt flag
}
//if(buttonIntention){
//TESTPIN = 1;
//}
}
// ==========================================================================
// Main function
// ==========================================================================
int main(void) {
WDTCON0bits.SWDTEN = 0x0; // Ensure Watchdog Timer is totally disabled
// Register 10-1 INTCON
INTCONbits.PEIE = 1; // Enable peripheral interrupt
INTCONbits.GIE = 1; // Enable global interrupt
// --- Call configuration functions: ---
config_IO();
config_OSC();
config_CN();
// --- Loop forever: ---
while (1) {
if(buttonGet()){
TESTPIN = 1;
}
}
return 0;
}
我不知道这个 MCU 但请允许我在黑暗中拍摄两张。
我觉得很奇怪,你可以用一个简单的赋值指令 WDTCON0bits.SWDTEN = 0;
关闭 W/D。也许看门狗重置了你的 MCU。
我在 spec of PIC16F15376 中阅读了第 155 页:
The IOCIF bit is the logical OR of all the IOCAF-IOCEF flags.
Therefore, to clear the IOCIF flag, application firmware must clear
all of the lower level IOCAF-IOCEF register bits.
我认为简单的 IOCIF=0
无法按预期工作。
我有一个真正的问题,我已经被困了一段时间了。我正在用 C 编写 PIC16F15376 微控制器 Xpress 板。
我将一个名为buttonIntention
的volatile变量初始化为0。当中断服务程序发生时,调用buttonSet(1)
,有效地设置buttonIntention = 1
。 [注意:我也试过直接切换 buttonIntention
变量,没有 get 或 set 函数。] 在 main()
中,不断轮询的 while(1)
检查 ISR 是否已经关闭(这将设置 buttonIntention = 1
),如果 ISR 设置了,TESTPIN
设置为高,我可以在我的 o-scope 上查看它。
我确定当我按下一个按钮时,ISR 确实触发了。 buttonIntention
然后在 ISR 中设置为 1,因为我尝试在 ISR 末尾注释掉的代码工作正常。
但是,我在 main()
中的 while(1)
中的 if(buttonIntention)
实际上从未看到 buttonIntention 设置为 1。我认为将此变量设置为 volatile
可以解决此问题,因为它在 ISR 和 main()
之间共享,我认为在我的 8 位微控制器上使用 uint8_t
类型可以解决我读到但并不真正理解的任何 "atomic" 问题。 .. 但是,if 语句永远看不到 1 仍然有问题。
有什么想法吗?
这是我的代码:
// CONFIG1
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits->HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1
#pragma config CLKOUTEN = OFF // Clock Out Enable bit->CLKOUT function is disabled; i/o or oscillator function on OSC2
#pragma config CSWEN = ON // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit->FSCM timer enabled
// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit->MCLR pin is Master Clear function
#pragma config PWRTE = OFF // Power-up Timer Enable bit->PWRT disabled
#pragma config LPBOREN = OFF // Low-Power BOR enable bit->ULPBOR disabled
#pragma config BOREN = ON // Brown-out reset enable bits->Brown-out Reset Enabled, SBOREN bit is ignored
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices
#pragma config ZCD = ON // Zero-cross detect disable->Zero-cross detect circuit is disabled at POR.
#pragma config PPS1WAY = ON // Peripheral Pin Select one-way control->The PPSLOCK bit can be cleared and set only once in software
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit->Stack Overflow or Underflow will cause a reset
// CONFIG3
#pragma config WDTCPS = WDTCPS_31 // WDT Period Select bits->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled, SWDTEN is ignored
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC // WDT input clock selector->Software Control
// CONFIG4
#pragma config WRTC = OFF // UserNVM self-write protection bits->Write protection off
//#pragma config SCANE = available // Scanner Enable bit->Scanner module is available for use
#pragma config LVP = ON // Low Voltage Programming Enable bit->Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.
// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit->UserNVM code protection disabled
//#pragma config CPD = OFF // DataNVM code protection bit->DataNVM code protection disabled
// ==========================================================================
// Import Header Files
// ==========================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xc.h>
#include <math.h>
// ==========================================================================
// Define statements
// ==========================================================================
// Inputs from buttons
#define startButton PORTCbits.RC4
#define profileButton PORTCbits.RC5
#define incrementButton PORTCbits.RC6
#define decrementButton PORTCbits.RC7
#define TESTPIN LATCbits.LATC0
// ==========================================================================
// Global Variables
// ==========================================================================
// ISR Toggle Variables (MUST be declared volatile)
volatile uint8_t buttonIntention = 0;
// ==========================================================================
// General Configuration
// ==========================================================================
// --- --- --- --- --- --- ---
// Configure Inputs and Outputs
// --- --- --- --- --- --- ---
void config_IO(void) {
// --- Set output for 5 gate drivers and LCD rs and en: ---
TRISA = 0; // Set all Port A I/O to output
LATA = 0; // Set all Port A outputs to LOW/0
ANSELA = 0; // Turn Port A analog off (Digital only)
// --- Set output for LCD data: ---
TRISB = 0; // Set all Port B I/O to output
LATB = 0; // Set all Port B outputs to LOW/0
ANSELB = 0; // Turn Port B analog off (Digital only)
// --- Set input from buttons: ---
//TRISC = 0b11111000; // Set Port C 3-7 to input for the buttons
TRISC = 0xF8; // Set Port C 3-7 to input for the buttons
LATC = 0; // Set all Port C outputs LOW
ANSELC = 0; // Turn Port C analog off (Digital only)
}
// --- --- --- --- --- --- ---
// Configure Change Notification for Button Interrupts
// --- --- --- --- --- --- ---
void config_CN(void){
//Clear Interrupt flag
IOCIF = 0;
// Clear all of Port C 0-7 interrupt flags
IOCCF = 0x00;
// Enable interrupts on Positive Edge of the buttons RC3-RC7
IOCCP3 = 1;
IOCCP4 = 1;
IOCCP5 = 1;
IOCCP6 = 1;
IOCCP7 = 1;
IOCIE = 1; //Enable Interrupt
}
// --- --- --- --- --- --- ---
// Configure the oscillator:
// --- --- --- --- --- --- ---
void config_OSC (void) {
// Clear registers
OSCCON1 = 0x00;
OSCCON2 = 0x00;
OSCCON3 = 0x00;
// OSCCON1:
// Use High Freq. Internal Oscillator (HFINTOSC @ 1 - 32 MHz)
//OSCCON1bits.NOSC = 0b110;
OSCCON1bits.NOSC = 0x6;
// OSCFRQ:
// Configure HFINTOSC to 32 MHz
// OSCFRQbits.HFFRQ = 0b110;
OSCFRQbits.HFFRQ = 0x6;
// Divide clock by 1
//OSCCON1bits.NDIV = 0b0000;
OSCCON1bits.NDIV = 0x0;
}
// ==========================================================================
// Button Function
// ==========================================================================
void buttonSet(uint8_t setter){
buttonIntention = setter;
}
uint8_t buttonGet(void){
return buttonIntention;
}
// ==========================================================================
// Interrupt service routine
// ==========================================================================
void __interrupt() isr(void)
{
// If button is pressed...
if(IOCIF == 1 && buttonIntention == 0) {
//buttonIntention = 1; // Change state to indicate that button was somehow pressed intentionally or unintentionally
//OR
buttonSet(1);
IOCIF = 0; //Clear Interrupt flag
}
//if(buttonIntention){
//TESTPIN = 1;
//}
}
// ==========================================================================
// Main function
// ==========================================================================
int main(void) {
WDTCON0bits.SWDTEN = 0x0; // Ensure Watchdog Timer is totally disabled
// Register 10-1 INTCON
INTCONbits.PEIE = 1; // Enable peripheral interrupt
INTCONbits.GIE = 1; // Enable global interrupt
// --- Call configuration functions: ---
config_IO();
config_OSC();
config_CN();
// --- Loop forever: ---
while (1) {
if(buttonGet()){
TESTPIN = 1;
}
}
return 0;
}
我不知道这个 MCU 但请允许我在黑暗中拍摄两张。
我觉得很奇怪,你可以用一个简单的赋值指令 WDTCON0bits.SWDTEN = 0;
关闭 W/D。也许看门狗重置了你的 MCU。
我在 spec of PIC16F15376 中阅读了第 155 页:
The IOCIF bit is the logical OR of all the IOCAF-IOCEF flags. Therefore, to clear the IOCIF flag, application firmware must clear all of the lower level IOCAF-IOCEF register bits.
我认为简单的 IOCIF=0
无法按预期工作。