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

AVR ATmega328P TIMER1测量延时精度结果异常问题排查

AVR Timer1延时测量偏差问题排查

核心配置疏漏

  • 定时器初始值计算错误,未符合硬件溢出规则:ATmega系列16位Timer1在普通模式下,从计数初始值累加至0xFFFF后,需要再经过1个计数时钟才会触发溢出中断、计数器跳回0x0000,因此单次溢出的总计数个数为 0xFFFF - TCNT1初始值 + 1。
    你设置的初始值为0xFFF5,计算可得单次溢出实际需要0xFFFF - 0xFFF5 +1 = 11个计数周期,对应溢出周期为11 / 10800 ≈ 1.0185ms,但代码中计算时间时按10个计数(即10/10800秒/次)换算,直接导致计算结果为真实值的10/11 ≈ 90.9%,和测试得到的227ms/250ms≈90.8%的偏差比例完全吻合。
  • 缺失全局中断使能配置:代码仅开启了Timer1的溢出中断使能位TIMSK1=0x01,但未置位AVR状态寄存器的全局中断位SREG |= (1<<7),正常情况下未开全局中断时中断服务函数ISR(TIMER1_OVF_vect)不会执行,wdttime_count会保持为0,当前能读到计数大概率是其他代码片段隐含开启了全局中断,该配置属于必须补全的疏漏。
  • ISR重装载时序误差未处理:溢出触发中断后,CPU需要等待当前指令执行完成、完成现场压栈后才会进入ISR执行重装载TCNT1的操作,这段响应时间内TCNT1已经从0x0000开始累加了3~7个计数周期,直接重装载固定值会吃掉这部分计数,带来小的累积误差,但该误差不会造成23ms级别的大偏差。

误差来源判定

该测量误差不是_delay_ms()函数导致的:
从偏差比例可以完全对应定时器计数计算的错误,修正计数换算系数后(按11个计数/次溢出计算),测试得到的245次溢出对应的实际时间为245 * 11 /10800 ≈ 250ms,和_delay_ms(250)的预期值完全匹配,说明_delay_ms()本身的延时精度是正常的。

补充:_delay_ms()的精度仅依赖编译时定义的F_CPU宏和系统时钟实际频率,只要F_CPU和实际时钟频率(此处为11059200Hz)一致,其误差在1%以内,不会出现近10%的大偏差。

修正参考代码

unsigned long slptime = 0;
unsigned long wdttime_count = 0;

void timer1_init()
{
    TCNT1 = 0xFFF5; 
    TIMSK1 = 0x01;
    TCCR1A &= ~(1<<WGM10);
    TCCR1A &= ~(1<<WGM11);
    TCCR1B &= ~(1<<WGM13);
    TCCR1B &= ~(1<<WGM12);
    TCCR1B |= (1<<CS12) | (1<<CS10); // 1024预分频,计数频率10800Hz
    SREG |= (1<<7); // 补全全局中断使能
}

void timer1_stop()
{
    TCCR1B = 0x00;
    TIMSK1 = 0x00;
}

ISR(TIMER1_OVF_vect)
{
    // 重装载时可根据实际中断响应延迟调整补偿值
    TCNT1 = 0xFFF5 + 2;
    wdttime_count = wdttime_count + 1;
}

void main()
{
    timer1_init();
    _delay_ms(250);
    timer1_stop();
    // 按实际11个计数/次溢出换算时间
    sendtimediff((wdttime_count*11*1000)/10800);
}

内容的提问来源于stack exchange,提问作者vishnu m c

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:21:26