ATmega168 时钟与熔丝位怎么配:CKSEL、CKDIV8、OSCCAL、BOD 四张表一次讲透

现场常见 ISP 能读 ID、程序也能下载,串口波特率却整体差 8 倍,电池设备还偶发上电不启动。结论先给:ATmega168 的时钟是 CKSEL 选源、CKDIV8/CLKPR 分频、OSCCAL 校准、SUT 定启动延时、BOD 管低压复位五段串联,按手册四张表对着配,就不会出现"下载成功但不工作"。

2026-10-29
AVRATmega168熔丝位时钟系统BOD低功耗

新板子焊好,ISP 能读出 ID,程序也能下载,串口波特率却整体偏了 8 倍,延时函数跟着一起错;实验室用 USB 供电一切正常,装到电池设备上偶尔上电不启动。这类"程序没错、就是不对劲"的问题,十有八九出在 AVR 的时钟链上。结论先给:ATmega168 的时钟是 CKSEL 选源、CKDIV8/CLKPR 分频、OSCCAL 校准、SUT 定启动延时、BOD 管低压复位这五段串联,任何一段配错,现象都像软件 bug。

一、CKSEL 先选源:六种时钟不只是"内部还是外部"

ATmega48/88/168 的时钟源全部由熔丝位 CKSEL3..0 决定,数据手册 Table 4 给了完整编码。真正需要工程师拿主意的,是三个晶振档位之间的差别:

时钟选项CKSEL3..0手册要点适合场景
低功耗晶振1111~1000XTAL2 摆幅低、功耗最低,不能驱动其它时钟输入电池节点、通用 8MHz 晶振
满振幅晶振0111~0110满幅输出,可驱动外部时钟输入,仅 2.7~5.5V 可用需要对外供时钟、噪声环境
低频晶振0101~010032.768kHz 表用振荡器走时、RTC 计时
内部 128kHz RC0011片内低功耗振荡器,标称 128kHz极低占空比待机唤醒
校准内部 RC00108MHz,出厂已标定,无需外部器件省晶振、精度要求 ±1% 以内
外部时钟0000由外部有源时钟直接驱动 XTAL1板级统一时钟
保留0001手册标注保留,不要使用—

低功耗晶振是默认推荐:功耗最小,代价是不能拿它去驱动板上别的芯片,噪声环境下也更脆弱。满振幅晶振摆幅到满幅,可以给外部器件当时钟源,但手册限定它只在 Vcc = 2.7~5.5V 可用,1.8V 的电池系统就得换档。两个档位的外部电容 C1、C2 必须相等,手册给的推荐范围是 12~22pF,具体值还要算上 PCB 杂散电容和晶振的负载电容。

还有一个容易忽略的前提:16MHz 不是任何电压都能跑。ATmega48/88/168 在 4.5~5.5V 下才保证 16MHz,2.7~5.5V 下最高 8MHz;V 版本在 2.4~5.5V 下最高 8MHz,1.8~5.5V 下只有 2MHz。先把供电和频率对上,再谈晶振选型,否则熔丝按 16MHz 配好,电池一掉压就等着跑飞。

二、CKDIV8 与 CLKPR:出厂 1MHz 是怎么来的

很多"新片子上电就慢吞吞"的板子其实没坏:ATmega48/88/168 出厂时 CKSEL = 0010(校准内部 RC)、SUT = 10、CKDIV8 已编程,系统时钟就是 8MHz 再 8 分频后的 1MHz。CKDIV8 决定 CLKPS 的初始值——未编程是 0000,已编程是 0011,也就是上电即 8 分频。

运行中改频率走 CLKPR,分频因子共九档。写这个寄存器有硬性时序:先把 CLKPCE 置 1 且其余位写 0,然后在随后的 4 个时钟周期内写入 CLKPS 并同时清 CLKPCE,CLKPCE 会在 4 个周期后由硬件自动清除。这 4 个周期内必须关中断,否则一次定时器中断就能把写时序打断,分频值写不进去。

CLKPS3..0分频因子8MHz 源下的系统时钟典型用途
000018 MHz全速运行
000124 MHz降功耗起步档
001042 MHz低速采集
001181 MHz出厂默认
0100 / 010116 / 32500 / 250 kHz传感器轮询
0110 / 011164 / 128125 / 62.5 kHz低占空比待机
100025631.25 kHz极限省电

改分频之前还有一条约束:如果选的时钟源超过了器件在该电压下的最大频率,一定要编程 CKDIV8 或软件分频,手册原文是"必须保证所得时钟符合器件的频率要求"。

三、OSCCAL:内部 RC 的 ±1% 是标定出来的

校准内部 RC 在 3V、25℃ 下的标称频率是 8.0MHz,复位时硬件把校准字节自动装进 OSCCAL 寄存器,标称精度 ±1%。可调范围是 7.3~8.1MHz:CAL7 选择低端还是高端频率段,CAL6..0 在段内调节,每加 1 频率增加不到 2%。手册特别提醒,这个振荡器同时给 EEPROM 和 Flash 的写操作定时,要写 Flash 或 EEPROM 就不要把频率校到 8.8MHz 以上,否则写操作会失败。这条在产线做 OSCCAL 微调时最容易被忽略。

四、SUT 与启动延时:复位释放之后还没完

复位源消失后芯片并不会立刻跑程序,而是先等一个由看门狗振荡器计时的 tTOUT,周期数由 SUT 与 CKSEL 共同决定。手册 Table 5 给的典型值是:4K 个周期在 5V 下约 4.1ms,8K 个周期约 65ms(3V 下分别是 4.3ms 和 69ms)。

SUT1..0内部 RC 启动时间复位后额外延时说明
006 CK14CK电源快速上升,且有 BOD 兜底
016 CK14CK + 4.1ms电源快速上升,但无 BOD
106 CK14CK + 65ms电源缓慢上升,出厂默认
11—保留不要使用

这张表的用法是反的:先量电源上升时间,再选延时。上升快的板子选 14CK 就够;电池供电、大电容缓升的板子必须选 14CK + 65ms。如果为了省电把 BOD 关了又不留超时延时,手册直接写"不推荐"——延时期间 MCU 并不监控实际电压,没有 BOD 兜底就没有任何东西保证 Vcc 已经够高。

另外两条细节:RSTDISBL 熔丝被编程后,启动时间会强制增加到 14CK + 4.1ms,目的是留出进入编程模式的时间;用外部有源时钟时,工作频率突变超过 2% 会产生异常,要改频率就让 MCU 保持在复位状态再改。

五、BOD 与熔丝位:低压复位和"锁死"只差一个位

BOD 的触发电平由 BODLEVEL2..0 三个熔丝位决定:

BODLEVEL2..0触发电平说明
111BOD 禁用靠外部复位芯片或上电时序兜底
1101.8V1.8V 供电系统
1012.7V3.3V 系统,留出约 0.6V 余量
1004.3V5V 系统
011~000保留不要使用

BOD 比较器带约 50mV 的典型迟滞,Vcc 跌破 VBOT- 立即复位,回到 VBOT+ 以上再等一个 tTOUT 才恢复。要注意 BOD 是"常开"的:一旦使能,在各种休眠模式下都继续工作并消耗电流,深睡时这部分电流占比很高。电池节点要么选 1.8V 档并接受这点电流,要么彻底关掉 BOD 改用外部复位芯片,两头都想占通常两头都不讨好。

复位原因靠 MCUSR 区分:WDRF 看门狗、BORF 掉电、EXTRF 外部复位、PORF 上电(PORF 只能写 0 清除)。正确做法是在初始化最前面把 MCUSR 读进变量再清零,后面慢慢判断;如果先清零再读,一次叠加复位就把原因冲掉了。

熔丝位这一块有几个坑必须记住:熔丝位读回 0 表示"已编程",和很多人的直觉相反;芯片擦除不会改变熔丝位;LB1 锁定位一旦编程,熔丝位就被锁死,所以永远先写熔丝位、最后再上锁定位。SPIEN 出厂已编程,串行编程模式下这个位不可访问;EESAVE 决定芯片擦除时 EEPROM 内容是否保留;WDTON 编程后看门狗变成"总是使能",只能改溢出时间、不能关。

六、七步落地:一块新板子按顺序过一遍

  1. 先定供电与最高频率:5V 可跑 16MHz,3.3V 最高 8MHz,1.8V 只有 2MHz(V 版)。
  2. 再选时钟源:通用场合用内部 RC 省成本;要串口长期稳定就上晶振,电容 12~22pF 且 C1 = C2。
  3. 处理 CKDIV8:时钟源超过电压允许上限时必须编程该位,或在软件里写 CLKPR 分频。
  4. 定 SUT:量 Vcc 上升时间,缓升选 14CK + 65ms,快升且有 BOD 选 14CK。
  5. 定 BODLEVEL:按系统最低工作电压留余量选 1.8 / 2.7 / 4.3V,不用就禁用并加外部复位芯片。
  6. 排熔丝位写入顺序:先 CKSEL、SUT、BODLEVEL、EESAVE、WDTON,确认能正常启动后再考虑锁定位。
  7. 软件侧留证据:初始化最前面读 MCUSR 再清零,把复位原因存进掉电保存区,现场故障才有得查。

改分频和取复位原因这两件事都要注意时序与顺序,下面这段代码是可直接用的最小实现:

#include <avr/io.h>
#include <avr/interrupt.h>

/* 把系统时钟从出厂 1MHz 切到 8MHz:只改分频,不改时钟源 */
void clock_init_8m(void)
{
    uint8_t sreg = SREG;
    cli();                      /* 4 个周期窗口内不能被打断 */
    CLKPR = (1 << CLKPCE);      /* 只置 CLKPCE,其余位写 0 */
    CLKPR = 0x00;               /* CLKPS = 0000,分频因子 1 */
    SREG = sreg;
}

/* 复位原因要在初始化最前面取走,再清零 */
uint8_t reset_cause(void)
{
    uint8_t flags = MCUSR;
    MCUSR = 0x00;
    /* bit3 WDRF, bit2 BORF, bit1 EXTRF, bit0 PORF */
    return flags;
}

七、现象对照:先怀疑哪一个

现象优先怀疑快速核实
ISP 能读 ID,程序不跑SUT 延时太短或 BOD 档位与供电不匹配示波器看 Vcc 上升时间,对照 SUT 表
串口波特率整体差固定倍数CKDIV8 或 CLKPR 分频没改读 CLKPR,确认 CLKPS 实际值
波特率小幅漂移、温度一变就错内部 RC 未标定或温漂改外部晶振,或重新标定 OSCCAL
改完熔丝再也连不上RSTDISBL 或 SPIEN 被改动、锁定位已上用高压并行编程器恢复
电池设备深睡电流偏大BOD、看门狗常开逐项关断后用万用表对比
16MHz 下偶发跑飞供电低于 4.5V降频或改用 V 版的电压/频率档

一句话总结:AVR 的时钟问题几乎都能归结成一句话——先看供电允许多高频率,再选时钟源和分频,最后用 SUT 和 BOD 把上电这段"没人管"的时间兜住。四张表对着配,熔丝位按"先功能、后锁定"的顺序写,新板子就不会再出现"下载成功但不工作"的怪现象。

还想接着看:外部晶振电路与负载电容怎么算、STM32 时钟失效检测 CSS 怎么配、LVD/AVD 低压检测与安全关机。

本文基于 Atmel ATmega48/88/168 中文数据手册(Rev. 2545A–AVR–09/03)的时钟系统、系统控制与复位、熔丝位三章整理优化。

需要定制开发?

沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付

立即微信咨询

电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应