You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:57:04