結合RTC實現的“智能定時任務系統(tǒng)”:設計與實戰(zhàn)
在低功耗嵌入式系統(tǒng)中,定時喚醒執(zhí)行任務是一個常見需求,比如定時上傳數據、定時采集傳感器信息、定時進入/退出低功耗模式等。STM32系列MCU內置RTC模塊,不僅可提供實時時鐘,還支持低功耗喚醒和帶日期的定時調度。
本文將基于STM32平臺,介紹如何構建一個支持用戶可配置任務 + RTC定時喚醒 + 靈活喚醒處理的“智能定時任務系統(tǒng)”。并通過完整的實例代碼進行剖析,具有較強實用性。
一、核心需求分析
用戶配置任務:支持配置多個“何時執(zhí)行什么操作”的定時任務,任務存儲在Flash中。
RTC定時喚醒:系統(tǒng)低功耗運行,RTC定時器喚醒MCU按計劃執(zhí)行任務。
喚醒后任務執(zhí)行:自動加載任務表,匹配當前時間,執(zhí)行對應動作。
任務自動循環(huán):支持按天/小時/分鐘循環(huán)任務。
二、系統(tǒng)結構設計
[ 配置接口 ]
↑[任務存儲區(qū)] ←→ [RTC管理模塊] ←→ [任務調度器] ←→ [用戶任務處理]
↑ [低功耗控制模塊]
三、RTC喚醒基礎配置
使用STM32的RTC + Alarm A功能,作為喚醒觸發(fā)源。
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; // 執(zhí)行的任務編號} rtc_task_t;rtc_task_t g_task_list[MAX_TASK_NUM];
五、用戶任務執(zhí)行處理
根據任務 ID 執(zhí)行實際操作:
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時間匹配調度器
每次系統(tǒng)被喚醒時,匹配當前 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. 設置最近的下次任務時間
每次執(zhí)行完任務后,根據任務表,找出最近的下一個任務時間點,并設置為 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();
}
喚醒后恢復系統(tǒng)時鐘和功能:
void system_resume_from_stop(void){
SystemClock_Config(); // 重新配置系統(tǒng)時鐘}
八、任務配置接口(可選)
通過串口或屏幕提供簡單配置接口:
// 示例:串口接收命令配置任務// 命令格式:TASK 1 08 30 7F 0// 含義:任務1,8:30,每天執(zhí)行,執(zhí)行任務編號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喚醒 → 執(zhí)行匹配任務 → 更新Alarm → 進入STOP
十、工程建議與總結
任務存儲:使用內部 Flash 或外部 EEPROM 保存任務表;
時間邊界判斷:可引入“分鐘偏移判斷”,避免誤判;
喚醒延遲容忍:可通過軟件 Timer 判斷是否錯過喚醒時間;
任務重復機制:可擴展支持一次性/周期任務等多類型。
結語
結合STM32的RTC功能,我們可以構建一個低功耗、高靈活性、可配置的定時任務系統(tǒng),非常適用于IoT節(jié)點、遠程采集設備、智能家電等場景。通過本文的接口定義、調度策略與實例演示,你可以輕松實現自己的RTC任務系統(tǒng),并為后期擴展(如OTA配置、LCD顯示)打下基礎。
評論