Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
alarm
RTC
STM32F103
基于ALIENTEKMiniSTM32V35开发板使用RTC alarm
发布于 2021-07-05 12:47:42 浏览:1321
订阅该版
[tocm] **本文章实现的rtc alarm功能借鉴了以下文章代码:** 1.[【ART-PI】RT-Thread 开启RTC 与 Alarm组件](https://club.rt-thread.org/ask/article/2501.html) 2.[rt-thread/components/drivers/rtc/alarm.c](https://github.com/RT-Thread/rt-thread/blob/9bc3896e41716f6415e948ffea153a5453fe4b34/components/drivers/rtc/alarm.c) **感谢作者们的无私分享。** ### **功能背景** 想使用RT-Thread 基于STM32F1系列的RTC 与 Alarm(闹钟功能)实现项目定时控制的要求。 ### **实现环境** WIN10操作系统、RT-Thread Studio2.1.0、STM32CubeMX 6.2.0、ALIENTEKMiniSTM32V35开发板 ### **实现功能** 根据输入的uint8_t buf数组的数据,创建定时闹钟或循环闹钟,并根据输入的buf数据设置闹钟的时间,周期,星期几。**数据的格式要自己定义!!!** 参考的第一篇文章中闹钟使用到年月日的日期,我们日常实际用的大多数只需要时分秒即可,所以做出了功能代码的修改和部分定义的修改。 ### **实现过程** ### **第一步 新建工程** 新建一个rt-therad工程,配置工程名字和保存位置,选用的是**RT-Thread4.0.2**,芯片为STM32F103系列的**STM32F103RCT6**,控制台串口选用**UART1**,发送脚和接收脚选用默认的**PA9**、**PA10**,调试器使用的是**J-Link**,接口为**SWD**。 ![ca83a965a38b1c1720b7a8440141dff2.png](https://oss-club.rt-thread.org/uploads/20210705/ca83a965a38b1c1720b7a8440141dff2.png) ### **第二步 配置工程** 创建工程后,点击左边项目资源管理器中的创建的项目文件夹,双击CubeMX Settings,配置芯片。 修改芯片封装为LQFP64,打开RCC时钟,配置时钟频率为72Mhz,打开RTC,打开USART1,project name修改封装后清空,要把cubemx重新写上,Application Structure选Basic,Toolchain/IDE默认为EWARM即可,Code Generator中Copy only the necessary library files即可,生成项目。 ![1.1.png](https://oss-club.rt-thread.org/uploads/20210705/66718b7f2840dca873f7b57599971e13.png.webp) ![1.2.png](https://oss-club.rt-thread.org/uploads/20210705/587814d62e56f67fdfa1a26931b2d1ee.png.webp) ![1.3.png](https://oss-club.rt-thread.org/uploads/20210705/3785d778cdc555c35095efdca25d4c5c.png.webp) ![1.4.png](https://oss-club.rt-thread.org/uploads/20210705/fd7645fdfc617ca6af32e4285853b257.png.webp) ![1.5.png](https://oss-club.rt-thread.org/uploads/20210705/6aedda4abc6778304ff2ee2c6c496a92.png.webp) ![1.6.png](https://oss-club.rt-thread.org/uploads/20210705/71a871f528ca9fcd667ab33d61f71a31.png.webp) 成功配置好芯片后,双击项目中的RT-Thread Settings,点击更多配置,勾上使用RTC设备驱动程序和使用RTC alarm。 ![1.7.png](https://oss-club.rt-thread.org/uploads/20210705/2a0af17b26718eb5ab698932c2241127.png) ### **第三步 配置RTC 和 RTC alarm文件** 打开**drivers**,找到**board.h**,找到并打开 ```c #define BSP_USING_ONCHIP_RTC ``` 然后找到**drv_rtc.c**进行修改,主要是添加了**rtc alarm**的相应设置,以及解决**STM32F103**系列芯片**RTC**没有**日历功能**的问题。源代码来自https://club.rt-thread.org/ask/article/2501.html 具体代码如下: ```c #include "board.h" #include
#include
#ifdef BSP_USING_ONCHIP_RTC struct rt_rtc_device { struct rt_device device; #ifdef RT_USING_ALARM struct rt_rtc_wkalarm wkalarm; #endif }; #define DBG_ENABLE #define DBG_SECTION_NAME "drv_rtc" #define DBG_LEVEL DBG_INFO #include
static struct rt_rtc_device rtc_device; #ifdef RT_USING_ALARM static rt_err_t rtc_alarm_time_set(struct rt_rtc_device* p_dev); static int rt_rtc_alarm_init(void); static RTC_AlarmTypeDef salarmstructure; #endif #ifndef RTC_BKP_DR1 #define RTC_BKP_DR1 RT_NULL #endif #define BKUP_REG_DATA 0xA5A5 static RTC_HandleTypeDef RTC_Handler; RT_WEAK uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister) { return (~BKUP_REG_DATA); } RT_WEAK void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data) { return; } static time_t get_rtc_timestamp(void) { RTC_TimeTypeDef RTC_TimeStruct = {0}; RTC_DateTypeDef RTC_DateStruct = {0}; struct tm tm_new = {0}; HAL_RTC_GetTime(&RTC_Handler, &RTC_TimeStruct, RTC_FORMAT_BIN); HAL_RTC_GetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN); tm_new.tm_sec = RTC_TimeStruct.Seconds; tm_new.tm_min = RTC_TimeStruct.Minutes; tm_new.tm_hour = RTC_TimeStruct.Hours; tm_new.tm_mday = RTC_DateStruct.Date; tm_new.tm_mon = RTC_DateStruct.Month - 1; tm_new.tm_year = RTC_DateStruct.Year + 100; return mktime(&tm_new); } static rt_err_t set_rtc_time_stamp(time_t time_stamp) { RTC_TimeTypeDef RTC_TimeStruct = {0}; RTC_DateTypeDef RTC_DateStruct = {0}; struct tm *p_tm; p_tm = localtime(&time_stamp); if (p_tm->tm_year < 100) { return -RT_ERROR; } RTC_TimeStruct.Seconds = p_tm->tm_sec ; RTC_TimeStruct.Minutes = p_tm->tm_min ; RTC_TimeStruct.Hours = p_tm->tm_hour; RTC_DateStruct.Date = p_tm->tm_mday; RTC_DateStruct.Month = p_tm->tm_mon + 1 ; RTC_DateStruct.Year = p_tm->tm_year - 100; RTC_DateStruct.WeekDay = p_tm->tm_wday + 1; if (HAL_RTC_SetTime(&RTC_Handler, &RTC_TimeStruct, RTC_FORMAT_BIN) != HAL_OK) { return -RT_ERROR; } if (HAL_RTC_SetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN) != HAL_OK) { return -RT_ERROR; } LOG_D("set rtc time."); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_REG_DATA); #ifdef SOC_SERIES_STM32F1 /* F1 series does't save year/month/date datas. so keep those datas to bkp reg */ HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR2, RTC_DateStruct.Year); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR3, RTC_DateStruct.Month); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR4, RTC_DateStruct.Date); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR5, RTC_DateStruct.WeekDay); #endif return RT_EOK; } static void rt_rtc_init(void) { #if !defined(SOC_SERIES_STM32H7) && !defined(SOC_SERIES_STM32WB) __HAL_RCC_PWR_CLK_ENABLE(); #endif RCC_OscInitTypeDef RCC_OscInitStruct = {0}; #ifdef BSP_RTC_USING_LSI #ifdef SOC_SERIES_STM32WB RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_ON; #else RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_ON; #endif #else RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.LSIState = RCC_LSI_OFF; #endif HAL_RCC_OscConfig(&RCC_OscInitStruct); } #ifdef SOC_SERIES_STM32F1 /* update RTC_BKP_DRx*/ static void rt_rtc_f1_bkp_update(void) { RTC_DateTypeDef RTC_DateStruct = {0}; HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BKP_CLK_ENABLE(); RTC_DateStruct.Year = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR2); RTC_DateStruct.Month = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR3); RTC_DateStruct.Date = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR4); RTC_DateStruct.WeekDay = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR5); if (HAL_RTC_SetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } HAL_RTC_GetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN); if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR4) != RTC_DateStruct.Date) { HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_REG_DATA); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR2, RTC_DateStruct.Year); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR3, RTC_DateStruct.Month); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR4, RTC_DateStruct.Date); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR5, RTC_DateStruct.WeekDay); } } #endif static rt_err_t rt_rtc_config(struct rt_device *dev) { RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; HAL_PWR_EnableBkUpAccess(); PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; #ifdef BSP_RTC_USING_LSI PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; #else PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; #endif HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); /* Enable RTC Clock */ __HAL_RCC_RTC_ENABLE(); RTC_Handler.Instance = RTC; if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR1) != BKUP_REG_DATA) { LOG_I("RTC hasn't been configured, please use
command to config."); #if defined(SOC_SERIES_STM32F1) RTC_Handler.Init.OutPut = RTC_OUTPUTSOURCE_NONE; RTC_Handler.Init.AsynchPrediv = RTC_AUTO_1_SECOND; #elif defined(SOC_SERIES_STM32F0) /* set the frequency division */ #ifdef BSP_RTC_USING_LSI RTC_Handler.Init.AsynchPrediv = 0XA0; RTC_Handler.Init.SynchPrediv = 0xFA; #else RTC_Handler.Init.AsynchPrediv = 0X7F; RTC_Handler.Init.SynchPrediv = 0x0130; #endif /* BSP_RTC_USING_LSI */ RTC_Handler.Init.HourFormat = RTC_HOURFORMAT_24; RTC_Handler.Init.OutPut = RTC_OUTPUT_DISABLE; RTC_Handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RTC_Handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #elif defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32H7) || defined (SOC_SERIES_STM32WB) /* set the frequency division */ #ifdef BSP_RTC_USING_LSI RTC_Handler.Init.AsynchPrediv = 0X7D; #else RTC_Handler.Init.AsynchPrediv = 0X7F; #endif /* BSP_RTC_USING_LSI */ RTC_Handler.Init.SynchPrediv = 0XFF; RTC_Handler.Init.HourFormat = RTC_HOURFORMAT_24; RTC_Handler.Init.OutPut = RTC_OUTPUT_DISABLE; RTC_Handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RTC_Handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #endif if (HAL_RTC_Init(&RTC_Handler) != HAL_OK) { return -RT_ERROR; } } #ifdef SOC_SERIES_STM32F1 else { /* F1 series need update by bkp reg datas */ rt_rtc_f1_bkp_update(); } #endif return RT_EOK; } static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args) { rt_err_t result = RT_EOK; #ifdef RT_USING_ALARM struct rt_rtc_wkalarm *p_wkalarm = RT_NULL; #endif RT_ASSERT(dev != RT_NULL); switch (cmd) { case RT_DEVICE_CTRL_RTC_GET_TIME: *(rt_uint32_t *)args = get_rtc_timestamp(); LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args); break; case RT_DEVICE_CTRL_RTC_SET_TIME: if (set_rtc_time_stamp(*(rt_uint32_t *)args)) { result = -RT_ERROR; } #ifdef RT_USING_ALARM rt_alarm_update(&rtc_device.device, 1); #endif LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args); break; #ifdef RT_USING_ALARM case RT_DEVICE_CTRL_RTC_GET_ALARM: args = &rtc_device.wkalarm; LOG_D("GET_ALARM %d:%d:%d",rtc_device.wkalarm.tm_hour, rtc_device.wkalarm.tm_min,rtc_device.wkalarm.tm_sec); break; case RT_DEVICE_CTRL_RTC_SET_ALARM: LOG_D("RT_DEVICE_CTRL_RTC_SET_ALARM"); p_wkalarm = (struct rt_rtc_wkalarm *)args; if (p_wkalarm != RT_NULL) { rtc_device.wkalarm.enable = p_wkalarm->enable; rtc_device.wkalarm.tm_hour = p_wkalarm->tm_hour; rtc_device.wkalarm.tm_min = p_wkalarm->tm_min; rtc_device.wkalarm.tm_sec = p_wkalarm->tm_sec; rtc_alarm_time_set(&rtc_device); } else { result = -RT_ERROR; LOG_E("RT_DEVICE_CTRL_RTC_SET_ALARM error!!"); } LOG_D("SET_ALARM %d:%d:%d",p_wkalarm->tm_hour, p_wkalarm->tm_min,p_wkalarm->tm_sec); break; #endif } return result; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops rtc_ops = { RT_NULL, RT_NULL, RT_NULL, RT_NULL, RT_NULL, rt_rtc_control }; #endif static rt_err_t rt_hw_rtc_register(rt_device_t device, const char *name, rt_uint32_t flag) { RT_ASSERT(device != RT_NULL); rt_rtc_init(); if (rt_rtc_config(device) != RT_EOK) { return -RT_ERROR; } #ifdef RT_USING_DEVICE_OPS device->ops = &rtc_ops; #else device->init = RT_NULL; device->open = RT_NULL; device->close = RT_NULL; device->read = RT_NULL; device->write = RT_NULL; device->control = rt_rtc_control; #endif device->type = RT_Device_Class_RTC; device->rx_indicate = RT_NULL; device->tx_complete = RT_NULL; device->user_data = RT_NULL; /* register a character device */ return rt_device_register(device, name, flag); } int rt_hw_rtc_init(void) { rt_err_t result; result = rt_hw_rtc_register(&rtc_device.device, "rtc", RT_DEVICE_FLAG_RDWR); if (result != RT_EOK) { LOG_E("rtc register err code: %d\n", result); return result; } #ifdef RT_USING_ALARM rt_rtc_alarm_init(); #endif LOG_D("rtc init success\n"); return RT_EOK; } #ifdef RT_USING_ALARM void rt_rtc_alarm_enable(void) { HAL_RTC_SetAlarm_IT(&RTC_Handler,&salarmstructure,RTC_FORMAT_BIN); HAL_RTC_GetAlarm(&RTC_Handler,&salarmstructure,RTC_ALARM_A,RTC_FORMAT_BIN); LOG_D("alarm read:%d:%d:%d", salarmstructure.AlarmTime.Hours, salarmstructure.AlarmTime.Minutes, salarmstructure.AlarmTime.Seconds); HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0x02, 0); HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); } void rt_rtc_alarm_disable(void) { HAL_RTC_DeactivateAlarm(&RTC_Handler, RTC_ALARM_A); HAL_NVIC_DisableIRQ(RTC_Alarm_IRQn); } static int rt_rtc_alarm_init(void) { return RT_EOK; } static rt_err_t rtc_alarm_time_set(struct rt_rtc_device* p_dev) { if (p_dev->wkalarm.enable) { salarmstructure.Alarm = RTC_ALARM_A; salarmstructure.AlarmTime.Hours = p_dev->wkalarm.tm_hour; salarmstructure.AlarmTime.Minutes = p_dev->wkalarm.tm_min; salarmstructure.AlarmTime.Seconds = p_dev->wkalarm.tm_sec; LOG_D("alarm set:%d:%d:%d", salarmstructure.AlarmTime.Hours, salarmstructure.AlarmTime.Minutes, salarmstructure.AlarmTime.Seconds); rt_rtc_alarm_enable(); } return RT_EOK; } void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { //LOG_D("rtc alarm isr.\n"); rt_alarm_update(&rtc_device.device, 1); } void RTC_Alarm_IRQHandler(void) { HAL_RTC_AlarmIRQHandler(&RTC_Handler); } #endif INIT_DEVICE_EXPORT(rt_hw_rtc_init); #endif /* BSP_USING_ONCHIP_RTC */ ``` **修改完drt_rtc.c文件后,在项目资源管理器中,在项目中找到rt-thread文件夹,在components/drivers/rtc中找到alarm.c,对其进行修改,修改代码来自https://github.com/RT-Thread/rt-thread/blob/9bc3896e41716f6415e948ffea153a5453fe4b34/components/drivers/rtc/alarm.c 本人对其进行了部分修改,最终的具体代码如下:** [alarm.c](https://oss-club.rt-thread.org/uploads/20210705/41a7614be830998c501b792ab3b27240.c) **完成上面的修改后,在同一层目录中找到include/drivers/alarm.h文件,对其进行修改,具体代码如下:** [alarm.h](https://oss-club.rt-thread.org/uploads/20210705/160672bd0c8786b808a2f01059f52e68.h) ### **第四步 编写功能代码和用户功能接口** **右键applications文件夹生成一个myalarm.c源文件和myalarm.h头文件,源文件实现功能代码,头文件提供用户接口。具体代码如下:** **myalarm.c文件:** ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-07-02 yang。 the first version */ #include "myalarm.h" #define RTC_DEBUG #define DBG_ENABLE #define DBG_SECTION_NAME "rtc.test" #define DBG_LEVEL DBG_LOG #include
#ifdef RTC_DEBUG #define NUMBEROFALARM 20 static struct rt_alarm * p_alarm[NUMBEROFALARM] = {RT_NULL}; static uint8_t alarm_counter; static time_t rtc_gettime(void) { static time_t now; static struct tm tm; now = time(NULL); #ifdef _WIN32 _gmtime32_s(&tm, &now); #else gmtime_r(&now, &tm); #endif LOG_D("BJ time:%04d-%02d-%02d %02d:%02d:%02d.%03d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour + 8, tm.tm_min, tm.tm_sec, rt_tick_get() % 1000); return now; } static void alarm_cb(rt_alarm_t alarm, time_t timestamp) { LOG_D("alarm_cb ok!\n"); } static rt_err_t rtc_alarm_create(rt_alarm_callback_t callback, uint8_t *buf) { while(alarm_counter--) { if (p_alarm[alarm_counter] != RT_NULL) { if (rt_alarm_delete(p_alarm[alarm_counter]) == RT_EOK) p_alarm[alarm_counter] = RT_NULL; } } rt_err_t ret = RT_ERROR; struct rt_alarm_setup alarm_setup; rt_uint8_t hour = 0; rt_uint8_t min = 0; rt_uint8_t weekday = 1; //默认星期一开始,0为星期天 rt_uint8_t en = 0; rt_uint16_t interval = 0; alarm_setup.weight = 0UL; alarm_counter = 0; if (buf != NULL) { if (buf[xx] == 0xxx) //根据buf的某个位判断是定时闹钟 { switch(buf[xx]) { case 0xxx: alarm_setup.flag = RT_ALARM_ONESHOT; break; case 0xxx: alarm_setup.flag = RT_ALARM_DAILY; break; case 0xxx: alarm_setup.flag = RT_ALARM_WEEKLY; break; default: alarm_setup.flag = RT_ALARM_ONESHOT; break; } hour = (int)buf[xx]; min = (int)buf[xx]; if (hour >= 0 && hour <= 23) { alarm_setup.wktime.tm_hour = hour; } else { LOG_D("scan hours not in area: 0 ~ 23, check the buf[xx] \r\n"); return ret; } if (min >= 0 && min <= 59) { alarm_setup.wktime.tm_min = min; } else { LOG_D("scan mins not in area: 0 ~ 59, check the buf[xx] \r\n"); } //这里用buf的一个位置存放一个8位数据,最高位是闹钟使能位,其余7位对应闹钟星期几 if ((buf[xx] >> 7) & 1) { en = 1; } rt_kprintf("en = %d\r\n", en); for (int var = 0; var < 7; ++var) { alarm_setup.id = alarm_counter; if ((buf[xx] >> var) & 1) { alarm_setup.wktime.tm_wday = weekday; p_alarm[alarm_counter++] = rt_alarm_create(callback, &alarm_setup); if (en) { if (p_alarm[alarm_counter-1] != NULL) { ret = rt_alarm_start(p_alarm[alarm_counter-1]); } } } ++weekday; if (weekday >= 7) // weekday from 0 to 6; 对应星期天、星期一、、、星期六 { weekday = 0; } } ret = RT_EOK; return ret; } else if (buf[xx] == 0xxx) //根据buf的某个位数据判断循环闹钟 { switch(buf[xx]) { case 0xxx: alarm_setup.flag = RT_ALARM_HOUR_ONESHOT; break; case 0xxx: alarm_setup.flag = RT_ALARM_HOUR_WEEKLY; break; default: alarm_setup.flag = RT_ALARM_HOUR_ONESHOT; break; } interval |= buf[xx]; //用buf数组的两个位置存放闹钟间隔时间 if ( interval <= 0x18 ) //确保间隔不大于23小时 { alarm_setup.interval = ((int)interval * 3600); } else { LOG_D("interval hours > 24, check the buf[xx] \r\n"); return ret; } //interval <<= 8; interval |= buf[xx]; //确保间隔不大于59分钟 if ((interval & 0xff) <= 0x3b) { alarm_setup.interval += ((int)interval * 60); } else { return ret; } alarm_setup.weight |= buf[xx]; alarm_setup.weight <<= 7; alarm_setup.weight &= buf[xx]; alarm_setup.start_hour = (int)buf[xx]; alarm_setup.start_min = (int)buf[xx]; alarm_setup.end_hour = (int)buf[xx]; alarm_setup.end_min = (int)buf[xx]; if (alarm_setup.start_hour > 23 && alarm_setup.end_hour > 23) { LOG_D("alarm start hour > 23 or alarm end hour > 23\r\n"); return ret; } if (alarm_setup.start_min > 59 && alarm_setup.start_min > 59) { LOG_D("alarm start min > 59 or alarm end min > 59\r\n"); return ret; } if ((buf[xx] >> 7) & 1) { en = 1; } //rt_kprintf("en = %d\r\n", en); //int i = 0; for (int var = 0; var < 7; ++var) { alarm_setup.id = alarm_counter; if (buf[xx] & 1) { alarm_setup.wktime.tm_wday = weekday; p_alarm[alarm_counter++] = rt_alarm_create(callback, &alarm_setup); //++i; if (en) { if (p_alarm[alarm_counter-1] != NULL) { //rt_kprintf("p_alarm != NULL\r\n"); //rt_kprintf("alarm_counter = %d\r\n", alarm_counter); ret = rt_alarm_start(p_alarm[alarm_counter-1]); //rt_kprintf("ret = %d\r\n", ret); } } } buf[xx] >>= 1; ++weekday; if (weekday >= 7) // weekday from 0 to 6; 对应星期天、星期一、、、星期六 { weekday = 0; } } //rt_kprintf("i = %d\r\n", i); ret = RT_EOK; return ret; } } return ret; } rt_err_t rtc_myalarm_create(rt_uint8_t * buf, rt_uint8_t length) { return rtc_alarm_create(alarm_cb, buf); } //MSH_CMD_EXPORT(rtc_gettime, rtc get time); //MSH_CMD_EXPORT(rtc_alarm_create, rtc alarm_create); //MSH_CMD_EXPORT(rtc_alarm_delete, rtc alarm_delete); #endif ``` **myalarm.h文件:** ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-07-03 yang。 the first version */ #ifndef APPLICATIONS_SUPERALARM_H_ #define APPLICATIONS_SUPERALARM_H_ #include
#include "board.h" #include
#include
/** * @Author: Yang. * @brief: 创建alarm接口 * @param: buf 输入进来的命令 * @param: length 输入命令的字节长度 * @return 创建成功返回RT_EOK,否则返回RT_ERROR */ rt_err_t rtc_myalarm_create(rt_uint8_t * buf, rt_uint8_t length); #endif /* APPLICATIONS_SUPERALARM_H_ */ ``` ### 添加了上述的文件后,可以在main.c中进行功能测试,具体代码如下: ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-07-02 RT-Thread first version */ #include
#define DBG_TAG "main" #define DBG_LVL DBG_LOG #include
#include "myalarm.h" #define BUFFERLENGTH xx //输入的数据字节(整数) int main(void) { int count = 1; // uint8_t buf[BUFFERLENGTH] = { /*自定义的数据协议*/}; // rtc_myalarm_create(buf, BUFFERLENGTH); while (count++) { //LOG_D("Hello RT-Thread!"); rt_thread_mdelay(1000); } return RT_EOK; } ``` **uint8_buf[]数组的数据是一个自定义的协议数据,可以自行根据需求来设置,这里定时闹钟和循环闹钟通过buf[xx]来判断输入的命令是定时闹钟还是循环闹钟,buf[xx]是命令的字节长度,定义好上述的buf[xx]存放数据定义的内容后打开main.c中的函数调用就可以使用了。** ### **总结** **感谢互联网和各个愿意分享技术、分享源码的工程师或者IT爱好者,让学习知识的门槛越来越低,也希望更多的人愿意参与到RT-Thread社区中一起共同学习、共同进步。** 本次使用到stmf103rct6的rtc alarm,需要注意的地方是: **stmf103系列rtc没有日历功能**,即保存的时间只有时、分、秒,年、月、日是默认保存不了的,要自行调用rtc的备用寄存器写保存年月日数据。具体代码在上面修改后的**drv_rtc.c第97-103行**: ```c #ifdef SOC_SERIES_STM32F1 /* F1 series does't save year/month/date datas. so keep those datas to bkp reg */ HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR2, RTC_DateStruct.Year); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR3, RTC_DateStruct.Month); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR4, RTC_DateStruct.Date); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR5, RTC_DateStruct.WeekDay); #endif ``` **和第136-164行** ```c #ifdef SOC_SERIES_STM32F1 /* update RTC_BKP_DRx*/ static void rt_rtc_f1_bkp_update(void) { RTC_DateTypeDef RTC_DateStruct = {0}; HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BKP_CLK_ENABLE(); RTC_DateStruct.Year = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR2); RTC_DateStruct.Month = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR3); RTC_DateStruct.Date = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR4); RTC_DateStruct.WeekDay = HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR5); if (HAL_RTC_SetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } HAL_RTC_GetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN); if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR4) != RTC_DateStruct.Date) { HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR1, BKUP_REG_DATA); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR2, RTC_DateStruct.Year); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR3, RTC_DateStruct.Month); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR4, RTC_DateStruct.Date); HAL_RTCEx_BKUPWrite(&RTC_Handler, RTC_BKP_DR5, RTC_DateStruct.WeekDay); } } #endif ``` **还有注意的就是,目前rt-thread studio的rtc alarm使用介绍还是比较少,单独调用rt_alarm_create()、rt_alarm_start()等并不能实现alarm功能,需要在drv_rtc.c中添加alarm相关代码调用alarm中断,以及使用rtc alarm要先调用rt_alarm_system_init()函数初始化。由于文章内容有上限,部分代码就以文件形式上传了。**
2
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
巴菲特不非
这家伙很懒,什么也没写!
文章
3
回答
7
被采纳
1
关注TA
发私信
相关文章
1
RTC驱动框架几点建议
2
求助:RTT在STM32F407上使用内置的RTC设置日期需重启生效,设置时间即时生效,有遇到同样问题的吗?
3
[新人试水] LPC1768 Nano3_9 添加RTC
4
STM32 关于RTC的问题
5
stm32f4xx-HAL BSP的RTC设置不对
6
关于STM32的RTC设置年份不正确的问题
7
RTT的RTC驱动调试
8
rtc驱动中的bkp模块起不到防止时间的重新设置
9
rtc时钟跑十几个小时后,比实际时间快几秒怎么解决
10
stm32如何断电之后开发板rtc时间继续往前跑
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
ART-Pi
FinSH
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
cubemx
PWM
flash
packages_软件包
freemodbus
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
keil_MDK
SFUD
rt_mq_消息队列_msg_queue
C++_cpp
at_device
ulog
本月问答贡献
出出啊
1516
个答案
342
次被采纳
小小李sunny
1440
个答案
289
次被采纳
张世争
793
个答案
171
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
1
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
4
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部