在项目中使用STM32RTC闹钟过程中遇到几个问题,百思不得其解,在百度搜索中也没有找到相关内容于是决定打开数据手册深入学习下这个RTC。以往虽然也有使用过RTC这个外设,不过都是拿来主义,导致这次遇到点问题就懵逼了![]() 先用神器配置CUBE一下:
然后点一下齿轮生成代码。7 y; X7 I$ r: y& p RTC初始化代码,做了一点小改动:' s+ M6 Z4 `- ?% Q. m0 a void MX_RTC_Init(void) {2 m/ k! g* Z# E: ?+ U LL_RTC_InitTypeDef RTC_InitStruct;& [- p# K" G* b3 L6 J. I3 ]. e" ~ LL_RTC_TimeTypeDef RTC_TimeStruct; LL_RTC_DateTypeDef RTC_DateStruct;1 L7 O( a% a" o 4 X% _4 E* N: C: u! D LL_RTC_AlarmTypeDef RTC_AlarmStruct; /* Peripheral clock enable */8 K8 m+ i; T4 y' E# L4 z P- g8 A // LL_RCC_EnableRTC();0 _5 o* O |% g3 C6 @+ Y 6 t4 T! H$ g2 }7 L2 K7 b$ z/ u+ h // if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) != 0x32F2)7 c; f* I: V. [7 j( o7 e // { / K+ `: b5 r3 a+ M5 A /**Initialize RTC and set the Time and Date * m: q, M# V2 J# p */; ^( ^* d9 B$ C6 a* r5 N9 F* P& p RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR; M0 k! z' f2 L7 I+ }% O& d) L RTC_InitStruct.AsynchPrescaler = 127; RTC_InitStruct.SynchPrescaler = 255;* v4 F, o: c: l# ^* B7 z LL_RTC_Init(RTC, &RTC_InitStruct); /**Initialize RTC and set the Time and Date */6 t% s4 G, s1 b) ?' B+ W% h) S( B RTC_TimeStruct.Hours = 12;! P1 X h3 a5 r+ b+ ` RTC_TimeStruct.Minutes = 50; RTC_TimeStruct.Seconds = 40;& z- G1 \# A% @7 d( H' k# ` LL_RTC_TIME_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_TimeStruct);6 k( Q0 b. b$ _5 D( X# R) J 8 U, a# P7 [: k RTC_DateStruct.WeekDay = LL_RTC_WEEKDAY_MONDAY;+ X) V2 G( b2 n1 } RTC_DateStruct.Month = LL_RTC_MONTH_JANUARY; RTC_DateStruct.Year = 19;! ~. I8 \' P* B LL_RTC_DATE_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_DateStruct); - V5 P0 k& h, J( P LL_RTC_BAK_SetRegister(RTC,LL_RTC_BKP_DR0,0x32F2);) h8 k+ f# D, U: ~; G# {& M2 } , J9 z: Z+ X% o$ v: s0 K: _/ Z/ c if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) != 0x32F2) {. f$ g0 g7 E+ F( @6 v3 i LL_RTC_BAK_SetRegister(RTC,LL_RTC_BKP_DR0,0x32F2);: ~5 c3 d- ~! b( @ M& m }7 t+ r( V6 U' F- j: D$ j /**Initialize RTC and set the Time and Date 0 k x9 ?2 x, D' g; x. d _ */: U* f7 H, L* {* w if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) != 0x32F2): G# H$ l8 a* i2 `. C" u6 l& h {; ^% M8 I1 O% @* q( s+ H9 K LL_RTC_BAK_SetRegister(RTC,LL_RTC_BKP_DR0,0x32F2); } // }8 {8 b/ U5 i) o4 X( M /* RTC interrupt Init */ NVIC_SetPriority(RTC_IRQn, 0);0 Z# p8 k& u% E) I NVIC_EnableIRQ(RTC_IRQn);7 U: d! ^9 t( m* J- o0 _ ~ /* RTC Alarm Interrupt Configuration: EXTI configuration */ LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_17); LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_17); // RTC_AlarmStruct.AlarmTime.Hours = 12;! m$ d2 d2 g! J6 m& b8 ]: i RTC_AlarmStruct.AlarmTime.Minutes = 51;# k/ z& W( A: z2 F3 a# _, U // RTC_AlarmStruct.AlarmTime.Seconds = 0; // RTC_AlarmStruct.AlarmTime.TimeFormat = LL_RTC_HOURFORMAT_24HOUR;. V( n; |: g* d/ h. M- ?8 r; v. b // RTC_AlarmStruct.AlarmDateWeekDay = 1; // RTC_AlarmStruct.AlarmDateWeekDaySel = LL_RTC_ALMA_DATEWEEKDAYSEL_DATE;) R& S$ A4 p. |& O RTC_AlarmStruct.AlarmMask = LL_RTC_ALMA_MASK_DATEWEEKDAY|LL_RTC_ALMA_MASK_HOURS|LL_RTC_ALMA_MASK_SECONDS;//LL_RTC_ALMA_MASK_NONE|LL_RTC_ALMA_MASK_MINUTES;1 Y- `3 n/ w# E8 }# s3 o M LL_RTC_ALMA_Init(RTC,LL_RTC_FORMAT_BIN,&RTC_AlarmStruct); LL_RTC_DisableWriteProtection(RTC); LL_RTC_ALMA_Enable(RTC);5 A! ]# e1 G) H2 G' ] LL_RTC_ClearFlag_ALRA(RTC); LL_RTC_EnableIT_ALRA(RTC);) t1 l+ {5 W6 _) [ LL_RTC_EnableWriteProtection(RTC); }8 d; V7 n+ ?1 j T) u RTC的闹钟中断是内部连接到外部中断控制器的,所以使能了还要记得使能外部中断线路和设置中断方式,手册上写的闹钟中断使用17号且只能配置成上升沿
时间走到设置的闹钟时间后就会进入中断了 void RTC_IRQHandler(void) { if(LL_RTC_IsEnabledIT_ALRA(RTC))! |3 B+ {, C) z j9 w { if(LL_RTC_IsActiveFlag_ALRA(RTC)) {2 j: x0 b( `0 {6 |4 _9 L, j LL_RTC_DisableWriteProtection(RTC); LL_RTC_ALMA_Disable(RTC);& r; A( ~/ J8 M/ R( b) A+ L LL_RTC_ClearFlag_ALRA(RTC);4 M2 [! b9 {7 K3 N, U2 H LL_RTC_EnableWriteProtection(RTC); LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_17);. G6 F8 Y- K- N+ ?! n6 Q rtc_flag = 1;, `* s2 {! b2 N6 O# Q } }( ]- O6 z; F2 h+ F- R7 B! N }6 `" }2 U- e! d( | 这里需要注意使用库函数操作RTC后一般都会使能写保护寄存器,所以到中断后先取消写保护然后关闭闹钟A并清除闹钟A的中断标志和17号外部中断标志,这里我用了一个 rtc_flag代表进入了闹钟中断,在主程序中检测到这个标志后设置新的闹钟时间(这里关闭闹钟是为了后面重新设置闹钟,因为不关闭闹钟是无法重新设置闹钟的,我之前出错就是没有看数据手册导致闹钟只能第一次进中断)。. o* |) T0 m6 { 8 `8 V3 P% H% m6 i7 L* N7 l 在主程序中重新设置新的闹钟: void RTC_AlarmA_Callback() { LL_RTC_AlarmTypeDef RTC_AlarmStruct; // RTC_AlarmStruct.AlarmTime.Hours = 12;# i1 q2 c1 `! w$ [3 X RTC_AlarmStruct.AlarmTime.Minutes = 52; // RTC_AlarmStruct.AlarmTime.Seconds = 0;$ B- t2 o6 {/ a6 Y i% j3 m // RTC_AlarmStruct.AlarmTime.TimeFormat = LL_RTC_HOURFORMAT_24HOUR;; R- K( {: e ~/ X // RTC_AlarmStruct.AlarmDateWeekDay = 1;6 a7 [) d$ J8 D // RTC_AlarmStruct.AlarmDateWeekDaySel = LL_RTC_ALMA_DATEWEEKDAYSEL_DATE; {) D% g; f9 p" f RTC_AlarmStruct.AlarmMask = LL_RTC_ALMA_MASK_DATEWEEKDAY|LL_RTC_ALMA_MASK_HOURS|LL_RTC_ALMA_MASK_SECONDS;//LL_RTC_ALMA_MASK_NONE|LL_RTC_ALMA_MASK_MINUTES; LL_RTC_ALMA_Init(RTC,LL_RTC_FORMAT_BIN,&RTC_AlarmStruct);+ W7 q. l1 O, V6 d$ ` LL_RTC_DisableWriteProtection(RTC); LL_RTC_ALMA_Enable(RTC);+ h$ Y( L0 `: H8 O* B3 n0 F LL_RTC_ClearFlag_ALRA(RTC); f' y* ?$ d* Y0 R LL_RTC_EnableWriteProtection(RTC); } 6 E6 g: n0 d# ]/ R& z" Z5 l6 ^) } 这里设置了闹钟时间后记得重新使能闹钟A,最后再使能一下写保护,防止意外操作改变RTC里面的数据。只要每次进入中断后读出当前时间并设置新的闹钟时间,就能连续的通过闹钟中断做需要准时做的事情了。1 k: ^* s7 T, \ r V1 G 总结一下,RTC设置时间日期寄存器的时候不是直接设置,而是需要先进入到初始化模式才能设置,设置完成后退出初始化模式开始重新按照设置的时间计时,设置闹钟中断的时候要记得先取消写保护,并且要在闹钟关闭的情况下写入闹钟时间,写入完成后开启闹钟。设置对应的闹钟外部中断线就OK啦。就这样吧,有没写到的下次补充。 , F n: Z, N O2 _! z: X. C# A7 e |
STM32L071_LL_RTC.rar
下载10.75 MB, 下载次数: 336
| 谢谢分享 |
| 感謝分享 |
| 谢谢,这个又学了些东西 |
| 感谢 |
| 谢谢楼主分享! |
| 很仔细了,谢谢分享 |
|
好厉害的样子 |
| 大神,我参考了您的代码成功实现了stm32l051的RTC闹钟唤醒待机模式,请问您代码中把LL_RCC_EnableRTC();注释了,这个作用是什么呢 |
| 我也看看研究下。 |
|
t同样遇到了问题 不过我是G0系列 ^2 r+ C, S$ n8 V- A6 t/ v |
微信公众号
手机版