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
相关产品推荐
相关产品推荐

