PIC XC16开发:SwitchTest函数未执行及代码烧录保存异常问题
问题分析与解决方案
一、SwitchTest函数疑似未执行的排查方向
GoSleep()未配置唤醒逻辑,MCU睡死
你写的SwitchTest逻辑是:按键未按下时调用GoSleep(),但如果GoSleep()没配置正确的唤醒源,MCU会一直处于休眠状态,根本无法回到主循环执行后续的SwitchTest调用。得检查GoSleep()的实现:- 必须将RA0(或RA6)设为唤醒源,比如使用变化通知(CN)中断或外部INT中断
- 休眠模式要匹配唤醒源,比如选SLEEP或IDLE,确保唤醒源能触发MCU唤醒
- 唤醒后必须清除中断标志位,避免重复触发中断导致卡死
先验证函数是否真的没执行
别凭猜测判断,加个简单的调试动作:在SwitchTest第一行添加LED翻转代码(比如LATBbits.LATB2 = !LATBbits.LATB2;,前提是RB2引脚接了LED),如果LED没有变化,才说明函数真的没执行;如果LED有变化,说明函数执行了,但休眠后没有被唤醒。电平逻辑是否搞反?
RA0外接上拉电阻,按键未按下时是高电平(1),按下时是低电平(0)。你的代码中,RA0为0时返回主循环,否则进入休眠。如果实际硬件中按键按下时是高电平(哪怕你说电平能正常切换,也可以再实测一遍),逻辑就会完全反转,导致MCU直接进入休眠。
二、烧录后断电丢失代码的解决
这基本是配置位设置错误导致的:
- 打开MPLABX的
Window > PIC Memory Views > Configuration Bits:- 关闭代码保护位(CODE PROTECTION相关选项),启用代码保护后烧录的代码会被加密,断电后无法读取,看起来像代码丢失
- 检查MCLR配置:如果设为
MCLR Disabled,但硬件上MCLR引脚接了VDD,可能导致复位异常,程序无法正常运行 - 确认BOOT区域配置正确,不要开启BOOT保护或选择错误的引导模式
- 烧录时选择
Program选项,不要只选Verify,确保代码和配置位都被写入MCU - 检查外部电源:电压需在2.0V-3.6V之间,电源不稳定也可能导致程序保存失败
三、PICKit调试失败的处理
提示“位设置不正确”大多和配置位或硬件连接有关:
- 配置位中必须开启调试功能:将
Debug Enable设为Enabled,否则调试器无法连接MCU - MCLR引脚需正常工作:PICKit依赖MCLR引脚进行编程和复位,硬件上要接好上拉电阻,配置位不要禁用MCLR功能
- 检查接线:确认VDD、GND、PGD、PGC引脚连接正确,无虚焊情况
- 更新PICKit固件:打开
Tools > PICKit 3 > Update Firmware,将固件更新至最新版本
补充代码参考
以下是带唤醒配置的完整示例,确保MCU休眠后能被按键唤醒:
#include <p24F16KA102.h> #define LED_ON 1 #define LED_OFF 0 unsigned char led_step; unsigned char Display; #define LED1 LATBbits.LATB0 #define LED2 LATBbits.LATB1 // 初始化变化通知中断,用于RA0唤醒 void InitCN(void) { CNEN1bits.CN0IE = 1; // 开启RA0的变化通知中断 IPC4bits.CNIP = 2; // 设置中断优先级 IFS1bits.CNIF = 0; // 清除中断标志 IEC1bits.CNIE = 1; // 启用变化通知中断 } // 变化通知中断服务函数 void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) { IFS1bits.CNIF = 0; // 必须清除标志位,避免重复触发 } void GoSleep(void) { IEC1bits.CNIE = 1; // 确保唤醒中断处于启用状态 __builtin_write_OSCCONL(OSCCON & 0xBF); // 进入休眠模式 // 唤醒后会从这里继续执行 } void SwitchTest(void) { // 加LED闪烁,验证函数是否执行 LATBbits.LATB2 = !LATBbits.LATB2; if (PORTAbits.RA0 == 0) { // 按键按下(低电平) __delay_ms(25); if (PORTAbits.RA0 == 0) { return; // 返回主循环继续执行 } } else // 未按下按键,进入休眠 { GoSleep(); } } void main(void) { AD1PCFG = 0xFFFF; // 所有端口设为数字模式 TRISA = 0x0041; // RA0、RA6设为输入 __builtin_nop(); TRISB = 0x0000; // PORTB全设为输出 __builtin_nop(); InitCN(); // 初始化唤醒用的中断 while (1) { SwitchTest(); led_step = 0b11000001; Display = led_step; LED1 = LED_ON; __delay_ms(2000); LED1 = LED_OFF; SwitchTest(); led_step = 0b10100010; Display = led_step; LED2 = LED_ON; __delay_ms(2000); LED2 = LED_OFF; } }
内容的提问来源于stack exchange,提问作者Ralph
相关产品推荐
相关产品推荐

