使用Timer0与Timer1无delay实现1Hz LED闪烁程序故障排查求助
修复AVR单片机PB1 LED 1Hz闪烁问题
代码中的关键错误及修复
- 未配置PB1为输出引脚:原代码注释了
DDRB |= (1 << DDB1);,必须取消注释,否则引脚无法输出电平驱动LED。 - Timer1未设置时钟分频器:Timer1默认无时钟输入,不会计数,需要在
initTimer1中添加256分频配置(TCCR1B |= (1 << CS12);)。 - TIMER0溢出中断的错误操作:
PORTB ^= (1 << DDRB);是错误的,DDRB是寄存器地址而非引脚位,且Timer0的使用在此场景中完全多余,可直接移除Timer0相关代码简化逻辑。 - 主循环中的无效逻辑:
TCNT1 >= 65536永远不成立(16位寄存器最大值为65535),且直接赋值DDB1 = ~DDB1;属于错误操作(DDB1是位定义,不能直接修改),主循环只需保留空循环即可。 - Timer1溢出中断功能缺失:原中断仅重置了TCNT1,未添加翻转LED电平的逻辑,需在
ISR(TIMER1_OVF_vect)中加入引脚翻转代码。
修正后的完整代码
#include <avr/io.h> #include <avr/interrupt.h> #define F_CPU 16000000UL void initTimer1() { TCNT1 = 3036; // 设置初始值,实现约1秒溢出 TCCR1B |= (1 << CS12); // 配置256分频 TIMSK |= (1 << TOIE1); // 使能Timer1溢出中断 } ISR(TIMER1_OVF_vect) { TCNT1 = 3036; // 重置计数初始值 PORTB ^= (1 << PB1); // 翻转PB1引脚电平 } int main(void) { DDRB |= (1 << DDB1); // 配置PB1为输出引脚 initTimer1(); sei(); // 开启全局中断 while (1) { // 空循环,所有逻辑由中断处理 } return 0; }
逻辑说明
- 时钟计算:16MHz主频经256分频后,Timer1的时钟频率为
16000000 / 256 = 62500Hz,单个计数周期为16µs。 - 溢出时间:Timer1从3036计数到65535,共
65535 - 3036 = 62499个周期,总耗时约62499 * 16µs ≈ 1秒,刚好实现1Hz的闪烁频率。 - 中断触发时,自动重置Timer1初始值并翻转PB1电平,主循环仅维持程序运行,无需额外操作。
内容的提问来源于stack exchange,提问作者Julius
相关产品推荐
相关产品推荐

