结合RTC实现的“智能定时任务系统”:设计与实战
在低功耗嵌入式系统中,定时唤醒执行任务是一个常见需求,比如定时上传数据、定时采集传感器信息、定时进入/退出低功耗模式等。STM32系列MCU内置RTC模块,不仅可提供实时时钟,还支持低功耗唤醒和带日期的定时调度。
本文将基于STM32平台,介绍如何构建一个支持用户可配置任务 + RTC定时唤醒 + 灵活唤醒处理的“智能定时任务系统”。并通过完整的实例代码进行剖析,具有较强实用性。
一、核心需求分析
用户配置任务:支持配置多个“何时执行什么操作”的定时任务,任务存储在Flash中。
RTC定时唤醒:系统低功耗运行,RTC定时器唤醒MCU按计划执行任务。
唤醒后任务执行:自动加载任务表,匹配当前时间,执行对应动作。
任务自动循环:支持按天/小时/分钟循环任务。
二、系统结构设计
[ 配置接口 ]
↑[任务存储区] ←→ [RTC管理模块] ←→ [任务调度器] ←→ [用户任务处理]
↑ [低功耗控制模块]
三、RTC唤醒基础配置
使用STM32的RTC + Alarm A功能,作为唤醒触发源。
void RTC_AlarmAConfig(uint8_t hour, uint8_t min, uint8_t sec){
RTC_AlarmTypeDef sAlarm = {0};
sAlarm.AlarmTime.Hours = hour;
sAlarm.AlarmTime.Minutes = min;
sAlarm.AlarmTime.Seconds = sec;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY; // 只匹配时分秒
sAlarm.Alarm = RTC_ALARM_A;
HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
}
唤醒中断回调:
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){
rtc_wakeup_flag = 1;
}
四、定时任务结构设计
定义任务数据结构,支持 Flash 存储和用户配置:
#define MAX_TASK_NUM 10typedef struct {
uint8_t enable; uint8_t hour; uint8_t minute; uint8_t repeat_day; // 0x7F:每天,bit0=周日, bit1=周一...
uint8_t task_id; // 执行的任务编号} rtc_task_t;rtc_task_t g_task_list[MAX_TASK_NUM];
五、用户任务执行处理
根据任务 ID 执行实际操作:
void execute_user_task(uint8_t task_id){ switch (task_id) { case 0: toggle_led(); break; case 1: collect_sensor(); break; case 2: send_data(); break; default: break;
}
}
六、RTC时间匹配调度器
每次系统被唤醒时,匹配当前 RTC 时间是否对应一个任务:
void check_and_run_rtc_tasks(void){
RTC_TimeTypeDef time;
RTC_DateTypeDef date;
HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN);
uint8_t weekday_mask = 1 << date.WeekDay;
for (int i = 0; i < MAX_TASK_NUM; i++) {
if (!g_task_list[i].enable) continue;
if (g_task_list[i].hour == time.Hours &&
g_task_list[i].minute == time.Minutes) {
if (g_task_list[i].repeat_day & weekday_mask) {
execute_user_task(g_task_list[i].task_id);
}
}
}}
七、低功耗进入与唤醒流程
1. 设置最近的下次任务时间
每次执行完任务后,根据任务表,找出最近的下一个任务时间点,并设置为 Alarm A:
void update_next_rtc_alarm(void){ // 简单示例:找出第一个启用任务作为下次 Alarm
for (int i = 0; i < MAX_TASK_NUM; i++) { if (g_task_list[i].enable) {
RTC_AlarmAConfig(g_task_list[i].hour, g_task_list[i].minute, 0); break;
}
}
}
可进一步排序任务时间并计算最接近当前时间的任务,提高效率。
2. 进入低功耗模式
void enter_stop_mode(void)
{ HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); HAL_ResumeTick();
}
唤醒后恢复系统时钟和功能:
void system_resume_from_stop(void){
SystemClock_Config(); // 重新配置系统时钟}
八、任务配置接口(可选)
通过串口或屏幕提供简单配置接口:
// 示例:串口接收命令配置任务// 命令格式:TASK 1 08 30 7F 0// 含义:任务1,8:30,每天执行,执行任务编号0void parse_task_command(const char* cmd){ uint8_t idx, h, m, days, id; if (sscanf(cmd, "TASK %hhu %hhu %hhu %hhx %hhu", &idx, &h, &m, &days, &id) == 5) {
g_task_list[idx].enable = 1;
g_task_list[idx].hour = h;
g_task_list[idx].minute = m;
g_task_list[idx].repeat_day = days;
g_task_list[idx].task_id = id; // 保存到Flash
save_task_to_flash(g_task_list, sizeof(g_task_list));
}
}
九、整体工作流程图
上电 → 加载任务 → 设置最近Alarm A → 进入STOP模式
↑ ↓
Flash配置 ← 用户设置 ← 串口/屏幕 ← RTC唤醒 → 执行匹配任务 → 更新Alarm → 进入STOP
十、工程建议与总结
任务存储:使用内部 Flash 或外部 EEPROM 保存任务表;
时间边界判断:可引入“分钟偏移判断”,避免误判;
唤醒延迟容忍:可通过软件 Timer 判断是否错过唤醒时间;
任务重复机制:可扩展支持一次性/周期任务等多类型。
结语
结合STM32的RTC功能,我们可以构建一个低功耗、高灵活性、可配置的定时任务系统,非常适用于IoT节点、远程采集设备、智能家电等场景。通过本文的接口定义、调度策略与实例演示,你可以轻松实现自己的RTC任务系统,并为后期扩展(如OTA配置、LCD显示)打下基础。

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码