ATtiny13A自制micros()函数运行速度慢10倍的问题排查
问题分析与解决
核心问题:系统时钟与预期不符
你的代码逻辑计算本身是正确的,但实际延时是设置值的10倍,说明micros变量的累加速度比预期慢了10倍,根源大概率是单片机实际运行时钟不是你认为的9.6MHz,而是默认的1MHz内部RC振荡器。
误差验证计算:
如果系统时钟是1MHz,分频8后定时器时钟为125kHz,每个tick时长为1/125000 = 8µs。定时器从184计数到256溢出,共256-184=72个tick,总时长为72*8=576µs。但你在ISR中每次只累加60µs,相当于实际每576µs只记录了60µs,时间流速被低估了9.6倍(576/60=9.6),和你观察到的10倍误差完全吻合。
解决步骤
重新确认熔丝位配置:
- 确保外部9.6MHz晶振的熔丝位已正确烧录,尤其是时钟源选择熔丝(比如ATmega328P的
CKSEL位),需设置为外部晶振模式,而非默认的内部RC。 - 可通过读取熔丝位或用示波器测量IO口翻转频率来验证实际时钟频率。
- 确保外部9.6MHz晶振的熔丝位已正确烧录,尤其是时钟源选择熔丝(比如ATmega328P的
代码优化建议:
- 用标准
sei()函数开启全局中断,替代直接操作SREG,提升代码规范性:sei(); // 替换 SREG |= (1<<7); - 用宏定义封装计算逻辑,避免硬编码,提升可读性和可维护性:
#define F_CPU 9600000UL #define TIMER_PRESCALER 8 #define TICKS_PER_OVERFLOW (256 - 184) #define MICROS_PER_OVERFLOW ((TICKS_PER_OVERFLOW * TIMER_PRESCALER * 1000000UL) / F_CPU) // ISR中使用宏定义的值 ISR(TIM0_OVF_vect){ micros += MICROS_PER_OVERFLOW; TCNT0 = 184; } - 主循环中读取
volatile变量时,建议用临时变量缓存,避免中断导致的读取异常(32位变量在AVR上是原子操作,但养成习惯更稳妥):while (1) { uint32_t current_micros = micros; if(t < current_micros){ t += 1000000; // 1秒延迟 PORTB ^= 0b00011000; } }
- 用标准
额外排查点:
- 检查外部晶振是否正常工作,比如焊接是否牢固、匹配电容是否到位。
- 若使用内部RC振荡器,可通过校准熔丝位调整频率,但精度远不如外部晶振。
内容的提问来源于stack exchange,提问作者Mr Krust
相关产品推荐
相关产品推荐

