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参数设置,这个参数是用来频闭闹钟某些参数,若闹钟响铃以时、分、秒为参考,则应该对周进行频闭,否则会发生闹钟无法触发中断的现象;
本文来自博客园,作者:伽椰子真可爱,转载请注明原文链接:https://www.cnblogs.com/jiayezi/p/17536964.html