RT-Thread 硬件RTC单片机唤醒及闹钟响铃

单片机硬件上的RTC既可以为单片机提供准确的时间,也可以对单片机进行定时唤醒(wakeup)

以正点原子阿波罗 STM32F429IGT6为例,具体实现方式如下:

第一步:打开CubeMX,对相关功能进行配置

①、打开LSE

②、 设置RTC;

 ③、配置RTC时钟

 第二步:打开RT-Thread Settings 打开其中的RTC配置

 第三步:在stm32f4xx_hal_conf_bak.h中取消HAL_RTC_MODULE_ENABLED的注释

第四步:在board.h中取消BSP_USING_ONCHIP_RTC的注释;

第五步:将stm32f4xx_hal_msp.c下的HAL_RTC_MspInit复制到board.c文件下;

第六步:开始编写程序代码如下

  1 /*
  2  * Copyright (c) 2006-2021, RT-Thread Development Team
  3  *
  4  * SPDX-License-Identifier: Apache-2.0
  5  *
  6  * Change Logs:
  7  * Date           Author       Notes
  8  * 2023-07-07     Lenovo       the first version
  9  */
 10 
 11 /*
 12 *   int tm_sec;        秒 – 取值区间为[0,59]
 13     int tm_min;        分 - 取值区间为[0,59]
 14     int tm_hour;       时 - 取值区间为[0,23]
 15     int tm_mday;       一个月中的日期 - 取值区间为[1,31]
 16     int tm_mon;        月份(从一月开始,0代表一月) - 取值区间为[0,11]
 17     int tm_year;       年份,其值等于实际年份减去1900
 18     int tm_wday;       星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一
 19     int tm_yday;       从每年1月1日开始的天数– 取值区间[0,365],其中0代表1月1日
 20     int tm_isdst;      夏令时标识符,夏令时tm_isdst为正;不实行夏令时tm_isdst为0
 21  * */
 22 
 23 /*   函数名                                                                    功能描述                                                                                         原型
 24  *    time                      返回从19970-1-1,00:00:00至今的秒数
 25  *  localtime                   获取本地时间,年、月、日、时、分、秒、周
 26  *   mktime                     将当前时间还原成自19970-1-1,00:00:00至今的秒数
 27  *  rtc_init                    rtc相关参数设置初始化                                                                                 int rtc_init(void)
 28  *  rtc_wakeup_time_set         设置单片机唤醒时间                                                                                       int rtc_wakeup_time_set(rt_uint32_t time)
 29  *  rtc_set_date                设置rtc日期                                                                                                   int rtc_set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day, rt_uint32_t week)
 30  *  rtc_set_time                设置rtc时间                                                                                                   int rtc_set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
 31  *  rtc_bkp_reset               复位BKP,下次启动时可复位rtc时间设置                                                     int rtc_bkp_reset(void)
 32  *  rtc_Set_AlarmA              设置闹钟A                                                   void rtc_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
 33  *
 34  * */
 35 #include <rtthread.h>
 36 #include <rtdevice.h>
 37 #include <rtdbg.h>
 38 #include <board.h>
 39 #include "time.h"
 40 
 41 #define BKUP_REG_DATA 0xA5A5
 42 #define BKUP_RE_REG_DATA 0x0000
 43 static RTC_HandleTypeDef RTC_Handler;
 44 
 45 /**
 46   * @brief RTC Initialization Function
 47   * @param None
 48   * @retval None
 49   */
 50 int rtc_init(void)
 51 {
 52   RTC_TimeTypeDef sTime = {0};
 53   RTC_DateTypeDef sDate = {0};
 54 
 55   /** Initialize RTC Only
 56   */
 57   RTC_Handler.Instance = RTC;
 58   RTC_Handler.Init.HourFormat = RTC_HOURFORMAT_24;
 59   RTC_Handler.Init.AsynchPrediv = 127;
 60   RTC_Handler.Init.SynchPrediv = 255;
 61   RTC_Handler.Init.OutPut = RTC_OUTPUT_DISABLE;
 62   RTC_Handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
 63   RTC_Handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
 64   if (HAL_RTC_Init(&RTC_Handler) != HAL_OK)
 65   {
 66     Error_Handler();
 67   }
 68 
 69   /** Initialize RTC and set the Time and Date
 70   */
 71   if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR1) != BKUP_REG_DATA)
 72   {
 73       sTime.Hours = 0x0;
 74       sTime.Minutes = 0x0;
 75       sTime.Seconds = 0x0;
 76       sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
 77       sTime.StoreOperation = RTC_STOREOPERATION_RESET;
 78 
 79       if (HAL_RTC_SetTime(&RTC_Handler, &sTime, RTC_FORMAT_BIN) != HAL_OK)
 80       {
 81           Error_Handler();
 82       }
 83       HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_REG_DATA);
 84   }
 85 
 86 
 87   if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR0) != BKUP_REG_DATA)
 88   {
 89       sDate.WeekDay = RTC_WEEKDAY_MONDAY;
 90       sDate.Month = RTC_MONTH_JANUARY;
 91       sDate.Date = 0x1;
 92       sDate.Year = 0x0;
 93       if (HAL_RTC_SetDate(&RTC_Handler, &sDate, RTC_FORMAT_BIN) != HAL_OK)
 94       {
 95           Error_Handler();
 96       }
 97       HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR0, BKUP_REG_DATA);
 98   }
 99 
100   return RT_EOK;
101 }
102 
103 INIT_APP_EXPORT(rtc_init);
104 
105 /*
106  * 函数功能:单片机唤醒时间设置
107  * 输入参数:time:需要设置的唤醒时间(秒)
108  * 返回参数:RT_EOK:执行成功,RT_ERROR:执行失败
109  * */
110 /*
111  * RTC时钟源选用LSE(32.768KHz),设置AsynchPrediv 、AsynchPrediv 分别为127与255;
112  * 唤醒时间基准:WakeUpClock / 32.768k = time_ms;
113  * 唤醒的时间:time = time_ms * WakeUpCounter;
114  * */
115 int rtc_wakeup_time_set(rt_uint32_t time)
116 {
117     uint32_t WakeUpCounter = 0;
118 
119     WakeUpCounter = (float)(time / 5) * 10000;
120 
121     __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RTC_Handler, RTC_FLAG_WUTF);
122     if (HAL_RTCEx_SetWakeUpTimer_IT(&RTC_Handler, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
123     {
124         Error_Handler();
125         return RT_ERROR;
126     }
127     return RT_EOK;
128 }
129 
130 
131 //设置闹钟时间(按星期闹铃,24小时制)
132 //week:星期几(1~7) @ref  RTC_WeekDay_Definitions
133 //hour,min,sec:小时,分钟,秒钟
134 void rtc_Set_AlarmA(uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
135 {
136     RTC_AlarmTypeDef RTC_AlarmSturuct;
137 
138     RTC_AlarmSturuct.AlarmTime.Hours     =hour;//小时
139     RTC_AlarmSturuct.AlarmTime.Minutes   =min; //分钟
140     RTC_AlarmSturuct.AlarmTime.Seconds   =sec; //
141     RTC_AlarmSturuct.AlarmTime.SubSeconds=0;
142     RTC_AlarmSturuct.AlarmTime.TimeFormat=RTC_HOURFORMAT12_AM;
143 
144     RTC_AlarmSturuct.AlarmMask           =RTC_ALARMMASK_DATEWEEKDAY;//精确匹配星期,时分秒
145     RTC_AlarmSturuct.AlarmSubSecondMask  =RTC_ALARMSUBSECONDMASK_NONE;
146     RTC_AlarmSturuct.AlarmDateWeekDaySel =RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;//按星期
147     RTC_AlarmSturuct.AlarmDateWeekDay    =week; //星期
148     RTC_AlarmSturuct.Alarm               =RTC_ALARM_A;//闹钟A
149 
150     HAL_RTC_SetAlarm_IT(&RTC_Handler, &RTC_AlarmSturuct, RTC_FORMAT_BIN);
151 }
152 
153 //RTC闹钟中断服务函数
154 void RTC_Alarm_IRQHandler(void)
155 {
156     HAL_RTC_AlarmIRQHandler(&RTC_Handler);
157 }
158 
159 //RTC闹钟A中断处理回调函数
160 void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
161 {
162     rt_kprintf("Alarm A\r\n");
163 }
164 
165 //RTC WAKE UP中断服务函数
166 void RTC_WKUP_IRQHandler(void)
167 {
168     HAL_RTCEx_WakeUpTimerIRQHandler(&RTC_Handler);
169 }
170 
171 //RTC WAKE UP中断处理
172 void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
173 {
174     rt_kprintf("wakeup\r\n");
175 }
176 
177 /*
178  * 函数功能:设置rtc日期,年、月、日、星期
179  * 输入参数:year:年
180  *          month:月
181  *          day:日
182  *          week:星期
183  * 返回参数:-RT_ERROR:执行有误
184  *          RT_EOK:执行成功
185  * */
186 int rtc_set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day, rt_uint32_t week)
187 {
188     RTC_DateTypeDef RTC_DateStruct = {0};
189 
190     RTC_DateStruct.Date    = day;
191     RTC_DateStruct.Month   = month ;
192     RTC_DateStruct.Year    = year;
193     RTC_DateStruct.WeekDay = week + 1;
194 
195     if (HAL_RTC_SetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN) != HAL_OK)
196     {
197         return -RT_ERROR;
198     }
199 
200     HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR0, BKUP_REG_DATA);  //写BKP寄存器BKUP_REG_DATA,表示日期已写入
201     return RT_EOK;
202 }
203 
204 /*
205  * 函数功能:设置rtc时间,时、分、秒
206  * 输入参数:hour:时
207  *          minute:分
208  *          second:秒
209  * 返回参数:-RT_ERROR:执行有误
210  *          RT_EOK:执行成功
211  * */
212 int rtc_set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
213 {
214     RTC_TimeTypeDef RTC_TimeStruct = {0};
215 
216     RTC_TimeStruct.Seconds = second;
217     RTC_TimeStruct.Minutes = minute;
218     RTC_TimeStruct.Hours   = hour;
219 
220     if (HAL_RTC_SetTime(&RTC_Handler, &RTC_TimeStruct, RTC_FORMAT_BIN) != HAL_OK)
221     {
222         return -RT_ERROR;
223     }
224 
225     HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_REG_DATA);  //写BKP寄存器BKUP_REG_DATA,表示时间已写入
226 
227     return RT_EOK;
228 }
229 
230 /*
231  * 函数功能:复位日期和时间初始化,即执行该函数后开机时将RTC时间恢复默认值
232  * */
233 int rtc_bkp_reset(void)
234 {
235     HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR0, BKUP_RE_REG_DATA);
236     HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_RE_REG_DATA);
237 
238     return RT_EOK;
239 }

注意事项:

①、RTC_BKP_DR0、RTC_BKP_DR1属于备份区域(BKP)写保护,用来保证RTC在单片机唤醒后时间维持不变;

 ②、闹钟的AlarmMask参数设置,这个参数是用来频闭闹钟某些参数,若闹钟响铃以时、分、秒为参考,则应该对周进行频闭,否则会发生闹钟无法触发中断的现象;

posted @ 2023-07-08 11:22  伽椰子真可爱  阅读(146)  评论(0编辑  收藏  举报