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

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倍误差完全吻合。

解决步骤

  1. 重新确认熔丝位配置:

    • 确保外部9.6MHz晶振的熔丝位已正确烧录,尤其是时钟源选择熔丝(比如ATmega328P的CKSEL位),需设置为外部晶振模式,而非默认的内部RC。
    • 可通过读取熔丝位或用示波器测量IO口翻转频率来验证实际时钟频率。
  2. 代码优化建议:

    • 用标准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; 
          }       
      }
      
  3. 额外排查点:

    • 检查外部晶振是否正常工作,比如焊接是否牢固、匹配电容是否到位。
    • 若使用内部RC振荡器,可通过校准熔丝位调整频率,但精度远不如外部晶振。

内容的提问来源于stack exchange,提问作者Mr Krust

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:47:23