PIC16F877A超2kword代码搭配中断的可行性及异常问询
PIC16F877A超2K代码与中断共存的实现方案
问题根源
PIC16F877A的GOTO/CALL指令仅支持11位寻址,只能覆盖2K字的程序空间,跨页执行依赖PCLATH寄存器的高5位确定当前代码页。但中断触发时,硬件仅自动保存PCL和STATUS寄存器,不会保存PCLATH:
- 若中断发生在非0页的代码段,中断服务程序(ISR)执行
RETFIE返回时,PCLATH可能已被ISR修改,或未恢复到中断前的页值,导致主程序跳转到错误代码页,引发随机复位或执行异常。 - 当代码全部在PAGE0时,
PCLATH始终为0,自然不会出现冲突。
解决方法
1. 中断前后严格保存/恢复PCLATH
在ISR开头必须手动保存当前PCLATH的值,切换到PAGE0执行中断逻辑,结束后再恢复原PCLATH。示例(MikroC环境):
void interrupt() { unsigned char temp_pclath; temp_pclath = PCLATH; // 保存中断前的PCLATH状态 PCLATH = 0; // 强制切换到PAGE0执行ISR // 此处编写中断处理逻辑 PCLATH = temp_pclath; // 恢复PCLATH到中断前状态 RETFIE; }
2. 主程序跨页操作的中断防护
编译器自动生成的跨页GOTO/CALL会自动设置PCLATH,但为避免中断在PCLATH修改过程中触发(导致页状态混乱),可在跨页操作前后临时禁用中断:
void func_in_page1() { // 编译器自动插入PCLATH设置代码 // 函数业务逻辑 } void main() { // 初始化配置(含中断使能) while(1) { GIE = 0; // 临时禁用中断 func_in_page1(); // 执行跨页函数 GIE = 1; // 重新启用中断 } }
3. 强制ISR及依赖函数在PAGE0执行
将ISR和其调用的所有子函数强制分配到PAGE0(0x0000-0x07FF地址范围),避免ISR内部出现跨页操作,减少PCLATH的修改风险。可通过编译器的地址定位关键字实现:
void interrupt() __at 0x0004; // 指定中断向量到固定地址(PAGE0内) void isr_sub_func() __at 0x0100; // 强制子函数在PAGE0
4. 避免ISR内使用跨页指令
ISR逻辑应尽量精简,若需复杂处理,将核心逻辑封装在PAGE0的函数中,绝对不要在ISR内调用非PAGE0的函数,防止PCLATH被意外修改。
总结
完全可以实现超2K代码与中断共存,核心是精准管理PCLATH寄存器的状态:中断触发时保存当前页状态,ISR全程在PAGE0执行,返回前恢复原页状态,同时主程序跨页操作时做好中断防护。
内容的提问来源于stack exchange,提问作者Arvin Baba
相关产品推荐
相关产品推荐

