|
[STM32 ] RTC 实时时钟的系统时间维护 0 j5 m s- _- ^& ]9 r& b3 ]STM32内部带有RTC时钟,可以使用内部LSI和外部晶振LSE提供时钟源。2 g- L, r/ J1 T 1 E& v: v2 \% e6 {5 X4 [6 w 9 N# ]7 A( _" g( Y% ^ Z2 a LSI:单片机内部的晶振,受外部环境影响比较大,比如温度等因素;大概40Khz左右;: e+ E7 y3 t# k' ~ - t/ s) p; i( {& @1 W& T' x LSE:外接32.768KHz的晶振,比较稳定;2 w: E, q$ P% d# y- q 软件可配置选择时钟源,可判断识别是否起振。 ( }# K- ^* q, _! O6 p" L! R9 L 驱动:! u, G- T9 A* Z8 r6 Q , ]% F9 @/ `0 T. g8 S9 r2 F 1、首先要启动对应的时钟, r3 f3 _, ^2 T7 n( A W: C E: E7 m RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);6 z! x, Y& [( k% \8 @0 R X+ V3 M 9 K9 M) t' y2 v2 |3 I. ~ 8 x0 w8 |# | e8 ~' H 2、使能RTC功能 PWR_BackupAccessCmd(ENABLE);- p. N" i6 X% ^, f- y* t# c# H' _ ' j7 @% M5 }0 p2 O) S2 ?0 t 3、配置时钟 , Q, ~, [$ ~! O. ?+ n& k& o / m, g6 f* b8 [" }1 n RCC_LSICmd(ENABLE); //内部晶振 RCC_LSECmd(ENABLE); //外部晶振' n0 \* w( j# ?: `$ D 读取LSE状态# M. G. f& z2 F' P" M! ^: p7 i * w! O( T7 p0 S RCC_GetFlagStatus(RCC_FLAG_LSERDY) % N/ i Z* [2 u3 I" v/ a 读取LSI状态8 `5 ?3 x2 C1 G1 w 9 X: ~0 v( ?( t# ^ J d G$ y 7 b w3 I& Z3 S+ N5 ]$ e4 y9 r RCC_GetFlagStatus(RCC_FLAG_LSIRDY)" u6 t4 }2 y+ b1 Z% Q4 C$ S1 f 4、操作RTC所有寄存器之前需要先确定总线为空闲才能操作成功;$ j7 h5 B. q/ u! m ; I! @8 p- u% ~( \: D# j; } RTC_WaitForSynchro();//等待上一个指令执行完成;8 q, W5 n+ \& |6 }4 v + @; h9 \" q5 i ( _# N; B( `# a9 M$ G 5、初始化配置属性% Q* P- V6 D6 X3 A% L7 w W " a0 r% f* a0 k, }0 | ; n: l' |$ f6 i& Y& Y1 T //软件对时钟进行校准,HSE 按照32.768KHZ接入,公式如下: uwAsynchPrediv = 0xFF& C7 k2 i0 _$ s; L- T, @ uwSynchPrediv = 0x7F % t1 \& b, x6 i# g2 p, ^ : z6 L2 P, h$ I: a ck_spre(1Hz)=RTCCLK(LSE)/(uwAsynchPrediv + 1)*(uwSynchPrediv+1)5 X# ?: z5 _6 S% F$ C& k& ~ & H: r ~4 i: N% }+ Y / H1 K2 B5 k) [ RTC_InitStructure.RTC_AsynchPrediv=uwAsynchPrediv; ' _+ ]1 e, m/ u% v3 w Q/ b6 Y . t- o1 g- i: O4 \9 t, V RTC_InitStructure.RTC_SynchPrediv=uwSynchPrediv;( F8 p! t, h8 I9 [, {# p //24/12小时制 * T! ] y" Q+ j7 q& \# c RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24; ) E& |' L" P+ L RTC_Init(&RTC_InitStructure); a4 [7 V0 W N0 D 6、时钟在不掉电的情况下只需要初始化一次即可,程序复位防止多次初始化,在BAK区域写初始化标志,可解决;1 B9 {+ E* u% E; }. r- J* V* s * F+ L4 R4 D' i$ r$ } RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);# j0 m6 C8 ]7 ~. ^1 S9 W2 K 初始化前,读取RTC_BKP_DR0,查看是否为0x32F2,如果是,表示已经初始化成功。 # Y d) x# |9 f- ^+ a% j0 m5 | " L7 X6 x& X9 H; [! C' k; } if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2) 2 m4 B, r8 b& |' {) @$ L9 M$ n" e 7、读取日期时间9 W, ]# l" u& R5 R8 Z* A. B: N # x K" b4 ?+ R+ a$ G RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure); 8 g2 r6 I, N/ n6 [3 h( Z ! p$ I. p; g. E2 I1 o 8、写入日期时间" V/ }5 [: n4 H3 x8 ] RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure); # m/ d* T/ F _1 r6 ~" F) | 9 _1 |6 V" A; T" q% t9 h+ H 下面为此篇文章的重点 系统里面保存事件或者打印信息,都带有时标,不可能每次都去操作MCU的总线去读取RTC寄存器获取;或者是外部RTC芯片8025,IIC接口;& |2 z8 Z# v; ^ w+ w/ U, M - `0 w+ w! T' T! G, d. ^ 直接操作硬件缺点如下:- \6 V7 F, F, d3 e 2 L' @* { V4 R {1 r . @2 R& \; i i 1、直接从硬件中获取事件,精度很难取到ms级别,芯片最小刻度为秒;$ d1 h' V% L& B% I f( T' j 2、操作总线占用系统资源,降低MCU性能; $ r: p( d' e4 {) H5 l ' J: v0 B; B* C, a$ K5 | 为解决这个事情,需要系统中有个维护软时钟功能,接替RTC的走时; ; f( Z( T; r' d4 n1 }& X : q& p6 S( j3 Y1 X 具体做法为: 1、开启定时器,具体根据需求定义周期,可开启一个1ms定时器; 2、软时钟1ms累加计数,1S=1000ms;累加到1000,秒数加1;: `% b9 V0 H& I* {8 R1 R, x 3、防止走时误差大,一小时建议同步一次时钟,从硬件RTC中,把时间读取一次到软时钟同步;2 ~( Q: g8 u8 h& w. I: Q e2 n4 k* Q. Q( L. o |
实战经验 | 基于STM32G0B1的全桥移相+同步整流PWM解决方案
DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
【福利三:逢7发帖赢大礼】8、基于STM32G070板子的Ymodem串口协议IAP Bootloader开发
【福利三:逢7发帖赢大礼】7、基于STM32G070板子TF卡的FATFS移植
【福利三:逢7发帖赢大礼】6、基于STM32G070板子spiflash的FATFS移植
【福利三:逢7发帖赢大礼】5、基于STM32G070板子IRDA红外遥控接收解码
【福利三:逢7发帖赢大礼】4、基于STM32G070板子SPI flash 移植SFUD库
【福利三:逢7发帖赢大礼】基于STM32G070板子的uart shell移植设计
【福利三:逢7发帖赢大礼】3、基于STM32G070板子的YModem串口协议通信
【福利三:逢7发帖赢大礼】2、基于STM32G070板子的OLED移植U8G2库
微信公众号
手机版