有小伙伴在问RTC如何配置亚秒闹钟的参数。这个问题其实非常有价值,本文会做一个相对详尽的讲解。
亚秒闹钟用在什么地方?
需要用到周期性唤醒的场合,几十毫秒或者几百毫秒的唤醒间隔。有些MCU没有LPTIM(低功耗定时器),如果对精度要求不高,RTC的亚秒闹钟可以很好的胜任
什么是亚秒
这里看到,亚秒并不是一个固定的时间间隔,它的分辨率由同步预分频器RTC_PRE –〉DIVS[14:0]决定。
通常情况下,如果使用的是LSE(32,768K)的时钟源
1 | SynchPrediv = 0xFF; // 32.768KHz |
根据上面的公式可以知道,此时亚秒的分辨率为(1/(255+1))秒,即亚秒记数器每记一个脉冲值为3.9ms。这个值非常重要,请务必注意。
1 | //@brief Configure the RTC AlarmA/B Subseconds value and mask.* |
第一个参数是你RTC_AlarmA/B,第二个参数是亚秒的数值,第三个参数是亚秒的掩码。
为了便于理解,这里插入一个简单的数学题:
如果固定住一个十进制的数的个位,比如固定个位为5,那么可以知道,每一个“个位”与其相同的数之间都是相差10.
例如15、25、35、45…
如果固定住一个十进制的数的个位和十位,比如固定为34,能知道,每一个“个位和十位”与其相同的数之间都是相差100.
例如134、234、334、434…
再回到二进制,看RTC_ConfigAlarmSubSecond的第三个参数“RTC_AlarmSubSecondMask”
1 | * @arg RTC_SUBS_MASK_SS14_1 SS[14:1] are don't care in Alarm comparison. |
以RTC_SUBS_MASK_SS14_7为例,它会匹配SS[6:0],固定后7位
1 | *128* 64 32 16 8 4 2 1 |
根据上面的经验可以知道,每一个被固定后7位的二进制,都是相差128的记数脉冲
即相差128*(3.9ms)== 499.2ms 约等于500ms
实际测试结果与预期相符。
到这里我们似乎忘记了第二个参数“RTC_AlarmSubSecondValue”,实际上这个确实不会影响亚秒闹钟的周期,到第三个参数选定时,周期就已经被确定下来了。这个参数就可以理解成是上面数据题上面被提到的实际被固定的数.我们只关心它固定了多少位,至于它实际固定了什么,这并不重要。
如果选择RTC_SUBS_MASK_SS14_5,即匹配SS[4:0],第二个参数随意填了一个2025
1 | 128 64 *32* 16 8 4 2 1 |
32*(3.9ms) == 124.8ms
1 | RTC_ConfigAlarmSubSecond(RTC_A_ALARM, 2025, RTC_SUBS_MASK_SS14_5); |
由此我们可以得到下面这个表格:
掩码定义 | 实际比较位 | 固定位数 N | 周期 ≈ N×3.9ms |
---|---|---|---|
RTC_SUBS_MASK_SS14_7 |
SS[6:0] |
7 | ≈ 499.2ms |
RTC_SUBS_MASK_SS14_6 |
SS[5:0] |
6 | ≈ 249.6ms |
RTC_SUBS_MASK_SS14_5 |
SS[4:0] |
5 | ≈ 124.8ms |
RTC_SUBS_MASK_SS14_3 |
SS[2:0] |
3 | ≈ 31.2ms |
RTC_SUBS_MASK_SS14_X |
SS[X-1:0] |
X | ≈ X×3.9ms |
可以观察到由于都不能整除,所以这种方法只适合对精度要求不高的场景。不过这个API的参数配置还是非常有趣的。水平有限,如有疏漏,还请指正。