一、前言
RT-Thread 的 alarm 是系統(tǒng)提供的鬧鐘設(shè)備接口,提供了一系列用于管理定時事件的 API。然而,在實(shí)際使用過程中,遇到了一些與時間處理相關(guān)的問題。本文將圍繞這些問題展開分析,并提出對應(yīng)的解決方案。

二、問題點(diǎn)
在使用先楫平臺的 drv_rtc 驅(qū)動時,發(fā)現(xiàn)兩個典型問題:
使用 local_time_r 設(shè)置鬧鐘時間時無法觸發(fā)回調(diào)函數(shù)
使用 gmtime_r 設(shè)置后雖然能觸發(fā)回調(diào),但通過 list_alarm 命令打印出的鬧鐘時間顯示不正確。
例如:設(shè)置為 1719 的本地時間,實(shí)際輸出卻為 919,存在 8 小時的時間差。

這不單單在先楫平臺有所體現(xiàn),在其他平臺比如STM32等都有類似現(xiàn)象。
三、原因分析
在解析原因之前,需要了解下rtthread對于ctime的實(shí)現(xiàn)。
(一)ctime相關(guān)接口的區(qū)別
在rtthread的rtc和alarm驅(qū)動中,需要調(diào)用ctime的各類時間函數(shù),其中最主要的是時間接口區(qū)別是:
local_time和local_time_t是將時間戳(time_t)轉(zhuǎn)換本地時間函數(shù),比如設(shè)置時區(qū)為東八區(qū),那么相比UTC時間就會多8個小時。
gmtime和gmtime_r是將時間戳轉(zhuǎn)換為UTC時間。
(二)rtthread的時區(qū)支持
考慮到嵌入式的場景應(yīng)用,rtthread采用的是輕量級的時區(qū)支持,沒有支持完整的時區(qū)數(shù)據(jù)庫。
默認(rèn)的時區(qū)是東八區(qū)(北京時間)
代碼宏是RT_LIBC_USING_LIGHT_TZ_DST,對應(yīng)的kconfig對應(yīng)以下,如果需要支持其他時區(qū)時間,可以改變以下配置。

(三)rtthread的時間轉(zhuǎn)換支持
在rtthread的時區(qū)支持上,主要影響localtime和mktime的行為,localtime_r和localtime會根據(jù)時區(qū)時間做偏移轉(zhuǎn)換為本地時間。
mktime會根據(jù)時區(qū)時間偏移將本地時間轉(zhuǎn)換為UTC的時間戳。

在rtthread的alarm實(shí)現(xiàn)中,涉及到時間戳轉(zhuǎn)換日歷時間的接口都使用了UTC時間的函數(shù)接口gmtime_r,而當(dāng)觸發(fā)鬧鐘更新的時候,需要使用鬧鐘時間與當(dāng)前時間做判斷以便是否到達(dá)鬧鐘觸發(fā)事件,如果此時鬧鐘時間使用的是local_time,那么判斷將永遠(yuǎn)不成立,也就無法觸發(fā)鬧鐘回調(diào)。而如果同樣使用的是gmtime,那么時間單位是一致的,就會觸發(fā)鬧鐘回調(diào),但打印的鬧鐘列表是基于UTC時間。
由此可知:在 Alarm 模塊的實(shí)現(xiàn)中,時間戳轉(zhuǎn)日歷時間的操作均使用的是 UTC 時間函數(shù)(gmtime_r)。如果用戶傳入的是基于本地時間的結(jié)構(gòu)體,則因未統(tǒng)一轉(zhuǎn)換而造成比較失敗,導(dǎo)致無法觸發(fā)回調(diào)。
三、修復(fù)
根據(jù)上述原因,問題的根本在于Alarm 模塊未正確支持本地時間的判斷邏輯。針對這一問題,社區(qū)已在最新主線代碼中進(jìn)行了修復(fù)。

在對應(yīng)的時間戳轉(zhuǎn)換日歷時間上加個宏定義來切換為本地時間計算還是UTC時間計算即可。
Kconfig配置上加了RT_ALARM_USING_LOCAL_TIME配置宏,如果打開就是基于本地時間來計算。默認(rèn)不使能。
RT-Thread Components -> Device Drivers -> Using RTC device drivers-> Using RTC alarm -> Using local time for the alarm calculation
如果使能該配置,那么鬧鐘就是以本地時間local_time為準(zhǔn)
如果禁能該配置,那么鬧鐘就是以UTC時間gmtime為準(zhǔn)。
在使用rt_alarm_create增加鬧鐘時,配置的鬧鐘時間需要區(qū)分來,即可正常工作

在list_alarm命令中加入了timezone,查找鬧鐘列表更加直觀
1、使用UTC時間的alarm
2、使用東八區(qū)的本地時間的alarm
四、BSP的drv_rtc驅(qū)動注意點(diǎn)
1. 實(shí)現(xiàn) set_timestamp 時注意時間轉(zhuǎn)換
當(dāng)啟用了 RT_ALARM_USING_LOCAL_TIME 宏定義時,必須使用 local_time 進(jìn)行時間轉(zhuǎn)換,否則可能導(dǎo)致時間偏差。

2、設(shè)置鬧鐘時必須完整填寫年月日字段
由于 RT_ALARM_ONESHOT 模式下,系統(tǒng)會將鬧鐘時間轉(zhuǎn)換為時間戳進(jìn)行比較,因此必須提供完整的日歷時間結(jié)構(gòu)(包括年、月、日)。否則可能因字段缺失導(dǎo)致匹配失敗。

而先楫只需要從鬧鐘寄存器中獲取即可。

五、總結(jié)
本文圍繞 RT-Thread 中的Alarm(鬧鐘)設(shè)備驅(qū)動展開討論,結(jié)合先楫平臺的實(shí)際開發(fā)經(jīng)驗(yàn),深入分析了在使用 rt_alarm_create 設(shè)置本地時間鬧鐘時遇到的問題,并從底層機(jī)制出發(fā),解釋了問題根源,最終提出了有效的解決方案。
核心結(jié)論如下:
Alarm 子系統(tǒng)默認(rèn)使用 UTC 時間函數(shù)(如 gmtime_r)進(jìn)行時間戳與日歷時間的轉(zhuǎn)換;
若傳入本地時間結(jié)構(gòu)體但未統(tǒng)一轉(zhuǎn)換,會導(dǎo)致比較失敗,從而無法觸發(fā)鬧鐘回調(diào);
rtthread社區(qū)已在主線中引入 RT_ALARM_USING_LOCAL_TIME 宏定義,支持基于本地時間的鬧鐘行為;
在使用 Alarm 功能時,開發(fā)者需關(guān)注系統(tǒng)時區(qū)設(shè)置以及是否啟用本地時間模式,以確保鬧鐘行為符合預(yù)期。
通過本文的分析與實(shí)踐,希望可以幫助開發(fā)者更好地理解和使用 RT-Thread 的 Alarm 子系統(tǒng),提升嵌入式設(shè)備中定時任務(wù)管理的靈活性與準(zhǔn)確性。
-
API
+關(guān)注
關(guān)注
2文章
1568瀏覽量
63726 -
設(shè)備
+關(guān)注
關(guān)注
2文章
4657瀏覽量
71605 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1387瀏覽量
41681
發(fā)布評論請先 登錄
在RT-Thread系統(tǒng)上開啟RTC驅(qū)動模塊
RT-Thread編程指南
RT-Thread用戶手冊
RT-Thread全球技術(shù)大會:螢石研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn)

RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機(jī)制

RT-Thread學(xué)習(xí)筆記 RT-Thread的架構(gòu)概述

RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

基于RT-Thread Studio學(xué)習(xí)

RT-Thread v5.0.2 發(fā)布

評論