PIC16F676的WDT、TIMER0延迟计算问题:MPASM预分频器异常排查
PIC16F676 LED每秒闪烁问题修复
原代码核心问题分析
- 预分频器配置错误:原代码设置
BSF OPTION_REG, 3(PSA=1),把预分频器分配给了看门狗(WDT),导致TMR0无预分频支持,中断触发频率远高于预期。 - TMR0中断周期计算偏差:未结合PIC16F的指令周期(4MHz内部RC振荡器下,指令周期为1us)和预分频器参数计算重载值,中断触发时间完全不符合预设逻辑。
- LED翻转逻辑错误:原代码用
MOVLW 0x01+MOVWF PORTA直接赋值,并非引脚电平翻转,无法实现闪烁效果。 - 缺少秒级累加逻辑:仅对
usec变量做简单累加,没有完成从微秒到毫秒再到秒的层级累计,根本无法实现每秒闪烁的目标。 - 中断现场保护不完整:只保存了W寄存器,未保存STATUS寄存器,会破坏主程序的状态标志位,引发未知异常。
修正后的完整代码
#include "p16F676.inc" ; CONFIG:关闭看门狗,启用内部RC振荡器,关闭上电延时等 __CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _BOREN_ON & _CP_OFF & _CPD_OFF ; 定义变量:使用通用寄存器区0 ms_count EQU 0x20 ; 毫秒级计数 sec_flag EQU 0x21 ; 秒级触发标志 org H'0000' goto INIT ; 中断向量 org H'0004' isr: ; 完整保存现场:W和STATUS寄存器 MOVWF 0x5E ; 保存W到临时寄存器 SWAPF STATUS, W ; 保存STATUS到W(避免改变原有状态) MOVWF 0x5F ; 保存STATUS到临时寄存器 ; 重载TMR0:预分频1:4时,(256-6)*4*1us=1000us=1ms,实现每1ms触发一次中断 MOVLW 0x06 MOVWF TMR0 BCF INTCON, T0IF ; 清除TMR0中断标志 ; 累加毫秒计数,判断是否到达1秒 INCF ms_count, F MOVLW 0x03E8 ; 1000ms = 1秒 SUBWF ms_count, W BTFSS STATUS, Z ; 未到1000ms则直接退出中断 goto isr_exit ; 到达1秒,翻转RA0引脚并重置计数 MOVLW 0x01 XORWF PORTA, F ; 翻转RA0引脚电平 CLRF ms_count ; 重置毫秒计数 isr_exit: ; 恢复现场 SWAPF 0x5F, W ; 恢复STATUS寄存器 MOVWF STATUS SWAPF 0x5E, F SWAPF 0x5E, W ; 恢复W寄存器(避免改变STATUS) RETFIE INIT: ; 配置端口方向:PORTA所有引脚设为输出 BSF STATUS, RP0 ; 切换到寄存器组1 CLRF TRISA CLRF TRISC BCF STATUS, RP0 ; 切回寄存器组0 ; 初始化端口电平 CLRF PORTA CLRF PORTC ; 配置TMR0 BSF STATUS, RP0 BCF OPTION_REG, T0CS ; TMR0使用内部指令时钟 BCF OPTION_REG, PSA ; 预分频器分配给TMR0 BSF OPTION_REG, PS2 ; 设置预分频比为1:4(PS2=1, PS1=0, PS0=0) BCF OPTION_REG, PS1 BCF OPTION_REG, PS0 BCF STATUS, RP0 ; 初始化TMR0和计数变量 MOVLW 0x06 MOVWF TMR0 CLRF ms_count ; 启用中断 BSF INTCON, T0IE ; 启用TMR0中断 BSF INTCON, GIE ; 启用全局中断 loop: goto loop ; 主循环空转 end
关键修正点说明
- 预分频器配置:设置
BCF OPTION_REG, PSA将预分频器分配给TMR0,搭配PS2=1, PS1=0, PS0=0得到1:4的预分频比,结合TMR0重载值6,精准实现每1ms触发一次中断。 - 中断现场保护:完整保存并恢复W和STATUS寄存器,避免中断操作破坏主程序的运行状态。
- 层级计数逻辑:通过
ms_count累计到1000次(即1秒)时触发LED翻转,确保每秒闪烁一次的效果。 - LED翻转逻辑:使用
XORWF PORTA, F实现RA0引脚电平的翻转,正确完成闪烁动作。
内容的提问来源于stack exchange,提问作者Albpy
相关产品推荐
相关产品推荐

