功能背景
想使用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。
第二步 配置工程
创建工程后,点击左边项目资源管理器中的创建的项目文件夹,双击CubeMX Settings,配置芯片。
修改芯片封装为LQFP64,打开RCC时钟,配置时钟频率为72Mhz,打开RTC,打开USART1,project name修改封装后清空,要把cubemx重新写上,Application Structure选Basic,Toolchain/IDE默认为EWARM即可,Code Generator中Copy only the necessary library files即可,生成项目。
成功配置好芯片后,双击项目中的RT-Thread Settings,点击更多配置,勾上使用RTC设备驱动程序和使用RTC alarm。
第三步 配置RTC 和 RTC alarm文件
打开drivers,找到board.h,找到并打开
#define BSP_USING_ONCHIP_RTC
然后找到drv_rtc.c进行修改,主要是添加了rtc alarm的相应设置,以及解决STM32F103系列芯片RTC没有日历功能的问题。源代码来自https://club.rt-thread.org/ask/article/2501.html 具体代码如下:
#include "board.h"
#include <rtdevice.h>
#include <sys/time.h>
#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 <rtdbg.h>
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,对其进行修改,最终的具体代码如下:
alarm.c
完成上面的修改后,在同一层目录中找到include/drivers/alarm.h文件,对其进行修改,具体代码如下:
alarm.h
第四步 编写功能代码和用户功能接口
右键applications文件夹生成一个myalarm.c源文件和myalarm.h头文件,源文件实现功能代码,头文件提供用户接口。具体代码如下:
myalarm.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 <rtdbg.h>
#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文件:
/*
- 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 <rtthread.h>
#include "board.h"
#include <rtdevice.h>
#include <time.h>
/*
- @Author: Yang.
- @brief: 创建alarm接口
- @param: buf 输入进来的命令
- @param: length 输入命令的字节长度
- [url=home.php?mod=space&uid=1141835]@Return[/url] 创建成功返回RT_EOK,否则返回RT_ERROR
/
rt_err_t rtc_myalarm_create(rt_uint8_t * buf, rt_uint8_t length);
#endif / APPLICATIONS_SUPERALARM_H_ /
添加了上述的文件后,可以在main.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 <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#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中的函数调用就可以使用了。
总结
本次使用到stmf103rct6的rtc alarm,需要注意的地方是:
stmf103系列rtc没有日历功能,即保存的时间只有时、分、秒,年、月、日是默认保存不了的,要自行调用rtc的备用寄存器写保存年月日数据。具体代码在上面修改后的drv_rtc.c第97-103行:
#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行
#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()函数初始化。由于文章内容有上限,部分代码就以文件形式上传了。
原作者:巴菲特不非