4、时钟系统设计:低速时钟与高速时钟的切换,时钟门控技术,外部晶振选择

时钟,说白了就是嵌入式系统的「心跳」。

心跳快了,功耗就上去了。心跳慢了,活儿可能干不完。我做了这么多年低功耗设计,发现时钟系统往往是整个功耗优化的「牛鼻子」。你把它管好了,功耗能降一大截。

今天咱们就聊聊时钟系统的三个核心话题:高低速时钟切换、时钟门控、外部晶振选型。嗯,都是实战中绕不开的硬骨头。

4.1 低速时钟与高速时钟的切换

为什么要有两套时钟?

你想想看,MCU平时大部分时间都在「摸鱼」——等着按键、等着定时器、等着外部事件。这时候跑个几十兆赫兹的高速时钟,纯粹是浪费电。我习惯的做法是:干活用高速,待机用低速

举个例子,一个剃须刀的主控芯片:

  • 工作模式:电机转动、检测堵转、处理按键 → 跑 16MHz 高速内部振荡器
  • 待机模式:等待用户按下开关 → 切换到 32.768kHz 低速时钟

这一下子,功耗就从毫安级降到了微安级。差别有多大?差不多是「一天一充」和「一月一充」的区别。

关键点:切换时钟时,一定要确保目标时钟已经稳定,再关闭源时钟。否则系统会「断气」——直接死机。

我在项目中遇到过一个问题:某次切换时钟后,外设莫名其妙不工作了。查了半天,发现是切换时没有重新配置外设的时钟源。很多MCU的外设(比如定时器、UART)在时钟切换后,需要重新设置时钟分频系数。这个坑,我踩过。

代码示例(伪代码,基于常见MCU):

// 切换到低速时钟
void switch_to_low_speed_clock(void) {
    // 1. 使能低速时钟
    RCC->CR |= RCC_CR_LSION;
    
    // 2. 等待低速时钟稳定
    while(!(RCC->CR & RCC_CR_LSIRDY));
    
    // 3. 选择低速时钟作为系统时钟源
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_LSI;
    
    // 4. 等待切换完成
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_LSI);
    
    // 5. 关闭高速时钟(可选)
    RCC->CR &= ~RCC_CR_HSION;
}

我的小技巧:切换前,先把关键外设(比如看门狗)切换到低速时钟域,否则切换后看门狗可能因为时钟源变化而误复位。

4.2 时钟门控技术

时钟门控,说白了就是「用不到的模块,就别给它发时钟」。

很多工程师觉得,外设不用就不耗电。其实不是。只要时钟还在跑,寄存器就在翻转,动态功耗就在产生。哪怕你只是把外设使能位清0,时钟树上的功耗依然存在。

我个人的习惯是:每个外设用完后,立刻关闭它的时钟。别偷懒。

举个例子:

// 使用ADC前,打开时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// ... 做ADC转换 ...
// 使用完ADC,立刻关闭时钟
RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN;

就这么几行代码,能省下几百微安的电流。你想想看,一个剃须刀待机时,几百微安可能就是「放一个月没电」和「放半年还有电」的区别。

注意:关闭外设时钟前,一定要确保外设已经完成当前操作。我曾经在UART发送数据时关闭了时钟,结果数据只发了一半,另一半永远留在了移位寄存器里。

还有一个容易被忽略的点:GPIO的时钟。很多MCU的GPIO模块也有独立的时钟门控。如果你某个端口不用,记得关掉它的时钟。我见过有人把所有GPIO时钟都开着,结果待机电流多了几十微安。

嗯,这里要注意:有些外设的配置寄存器在时钟关闭后,内容会丢失。下次开启时需要重新配置。所以,关时钟前保存状态,开时钟后恢复状态——这是基本功。

4.3 外部晶振选择

外部晶振,选对了省心,选错了糟心。

我见过太多人随便买个晶振就往板子上焊,结果不是起振困难,就是频率不准,要么就是功耗高得离谱。

选晶振,我一般看这几点:

参数 说明 我的建议
负载电容 晶振需要匹配的电容值 严格按datasheet选,别自己瞎配
等效串联电阻 ESR,越小越容易起振 低功耗设计选ESR < 50Ω的
频率精度 ppm值 普通应用±50ppm够用,RTC要±20ppm以内
工作电流 晶振本身消耗的电流 低功耗场景选1μA以下的

我个人的经验是:32.768kHz的RTC晶振,一定要选低ESR的。为什么?因为ESR高了,MCU内部的振荡器需要更大的驱动电流才能让它起振。这个电流,在待机模式下就是「隐形杀手」。

我曾经在一个项目中,待机电流怎么也降不下来。查来查去,发现是RTC晶振的ESR偏高,导致MCU内部振荡器一直处于高驱动模式。换了个低ESR的晶振,待机电流直接降了30%。

避坑指南:外部晶振的匹配电容,不是随便选的。它和PCB走线的寄生电容、MCU引脚的输入电容都有关系。我一般会在PCB上预留两个电容位置,调试时用网络分析仪或者直接看波形,找到最佳匹配值。

另外,高速晶振(比如8MHz、16MHz)的功耗比低速晶振大得多。如果你的应用不需要高精度时钟,可以考虑用内部RC振荡器。内部RC虽然精度差一点(通常±1%~±3%),但功耗低、启动快。我习惯在不需要高精度定时的场景下,直接用内部RC代替外部晶振。

嗯,最后说一句:外部晶振的PCB走线要短、要直、要远离高频信号。否则,你可能会遇到「手一摸晶振就停振」的诡异问题。这个我遇到过,调试了整整两天才发现是走线太长,耦合了噪声。

好了,时钟系统设计就聊到这儿。记住三个关键词:切换要稳、门控要狠、晶振要准。下一章咱们聊聊电源管理单元(PMU)的设计,那个更刺激。