-
在實際的開發項目中,很多時候我們需要定時的做一些事情,舉例:
- ①路上的路燈,每天晚上6:00準時打開,每天早上6:00準時關閉;
- ②定時鬧鐘,起床上班。這些行為其實都是定時任務--鬧鐘。
-
大部分單片機都提供了rtc alarm硬件鬧鐘,但是實際很少人使用,就舉個簡單的例子,rt-thread的BSP中也沒有幾個芯片適配了alarm硬件鬧鐘。但是我們要使用怎么辦??
-
我受到RTOS的調度的啟發,像M3/M4這種內核都是SysTick產生時鐘節拍,以供系統處理所有和時間有關的事情,如線程延時,線程的時間片輪轉,以及定時器超時等。
-
有了第3點的經驗,那么我們可以寫一個軟件鬧鐘功能就容易多了,只需要提供一個刷新節拍,定時查看哪一個鬧鐘需要喚醒,就可以解決鬧鐘的管理了。
-
鬧鐘組件名字:RAlarm(全稱Rice Alarm),源碼連接:https://gitee.com/RiceChen0/ralarm
RAlarm
RAlarm接口說明:
跨平臺
- RTOS的種類很多,接口差異性打,所以RAlarm為了解決這個問題,統一為上層提供一整套接口。
- 線程接口。
typedefvoid*ralarm_task_id;
structralarm_task_attr{
constchar*name;//nameofthetask
uint32_tstack_size;//sizeofstack
uint8_tpriority;//initialtaskpriority
};
typedefvoid(*ralarm_task_func)(void*arg);
ralarm_task_idralarm_task_create(ralarm_task_funcfunc,void*arg,conststructralarm_task_attr*attr);
voidralarm_task_delete(ralarm_task_idthread);
- 互斥量接口。
typedefvoid*ralarm_mutex_id;
ralarm_mutex_idralarm_mutex_create(void);
ralarm_err_tralarm_mutex_lock(ralarm_mutex_idmutex);
ralarm_err_tralarm_mutex_unlock(ralarm_mutex_idmutex);
voidralarm_mutex_delete(ralarm_mutex_idmutex);
- 事件接口。
typedefvoid*ralarm_event_id;
ralarm_event_idralarm_event_create(void);
uint32_tralarm_event_recv(ralarm_event_idevent,uint32_tflags);
ralarm_err_tralarm_event_send(ralarm_event_idevent,uint32_tflags);
voidralarm_event_delete(ralarm_event_idevent);
- RAlarm目前已經提供了兩個環境的適配,如cmsis,rtthread。
接口使用簡單
接口 | 說明 |
---|---|
ralarm_init | 初始化 |
ralarm_deinit | 去初始化 |
ralarm_create | 創建鬧鐘 |
ralarm_start | 啟動鬧鐘 |
ralarm_stop | 停止鬧鐘 |
ralarm_modify | 修改鬧鐘 |
ralarm_delete | 刪除鬧鐘 |
- 鬧鐘初始化接口:初始化鬧鐘的鏈表,鬧鐘任務,事件,互斥鎖;去初始化接口:注銷鬧鐘組件
/*鬧鐘初始化*/
ralarm_err_tralarm_init(void);
/*鬧鐘去初始化*/
voidralarm_deinit(void);
- 鬧鐘創建:
- 參數說明:
「參數」 | 「描述」 |
---|---|
setup | 鬧鐘的時間和標志,flag可為:RALARM_ONESHOT(只設置一次)和RALARM_DAILY(每天都設置) |
cb | 鬧鐘時間到了,喚醒的回調函數指針:typedef void (*ralarm_response_cb)(ralarm_t alarm) |
userData | 設置鬧鐘時,自帶的用戶數據的指針 |
「返回」 | —— |
ralarm_t | 鬧鐘創建成功,放回鬧鐘句柄 |
NULL | 鬧鐘創建失敗 |
- 函數說明:
- ①申請鬧鐘控制塊的空間。
- ②設置鬧鐘參數到控制塊中。
- ③將鬧鐘加入到鬧鐘鏈表中。
structralarm_setup{
ralarm_flagflag;
structralarm_timetime;
};
typedefstructralarm_setup*ralarm_setup_t;
structralarm{
ralarm_statestate;
structralarm_setupsetup;
ralarm_response_cbcb;
void*userData;
ralarm_list_tlist;
};
typedefstructralarm*ralarm_t;
ralarm_tralarm_create(ralarm_setup_tsetup,ralarm_response_cbcb,void*userData)
{
ralarm_talarm=NULL;
if(setup==NULL){
RALARM_LOGE("Createalarmfailed,SetupparamisNULL");
returnNULL;
}
alarm=RALARM_MALLOC(sizeof(structralarm));//----①
if(alarm==NULL){
RALARM_LOGE("Mallocalarmmemoryfailed");
returnNULL;
}
ralarm_list_init(&alarm->list);//----②
memset((void*)alarm,0,sizeof(structralarm));
memcpy((void*)&alarm->setup,setup,sizeof(structralarm_setup));
alarm->cb=cb;
alarm->userData=userData;
ralarm_mutex_lock(g_container.mutex);
ralarm_list_insert_after(&g_container.list,&alarm->list);//----③
ralarm_mutex_unlock(g_container.mutex);
returnalarm;
}
- 鬧鐘啟動:將鬧鐘的狀態的start bit置為1。
ralarm_err_tralarm_start(ralarm_talarm)
{
if(alarm==NULL){
returnRALARM_ERROR;
}
ralarm_mutex_lock(g_container.mutex);
alarm->state|=RALARM_STATE_START;
ralarm_mutex_unlock(g_container.mutex);
returnRALARM_EOK;
}
- 鬧鐘停止:將鬧鐘的狀態的start bit置為0。
ralarm_err_tralarm_stop(ralarm_talarm)
{
if(alarm==NULL){
returnRALARM_ERROR;
}
ralarm_mutex_lock(g_container.mutex);
alarm->state&=~RALARM_STATE_START;
ralarm_mutex_unlock(g_container.mutex);
returnRALARM_EOK;
}
- 鬧鐘修改:修改鬧鐘的標志和鬧鐘的時間
- 參數說明:
「參數」 | 「描述」 |
---|---|
alarm | 鬧鐘的句柄 |
setup | 要修改鬧鐘的時間和標志參數 |
「返回」 | —— |
RALARM_EOK | 修改成功 |
RALARM_ERROR | 修改失敗 |
ralarm_err_tralarm_modify(ralarm_talarm,ralarm_setup_tsetup)
{
if(alarm==NULL){
returnRALARM_ERROR;
}
ralarm_mutex_lock(g_container.mutex);
memcpy((void*)&alarm->setup,setup,sizeof(structralarm_setup));
ralarm_mutex_unlock(g_container.mutex);
returnRALARM_EOK;
}
- 刪除鬧鐘:
- 函數說明:
- ①將鬧鐘的狀態的start bit置為0。
- ②將鬧鐘從鬧鐘鏈表中移除。
- ③釋放鬧鐘的內存。
ralarm_err_tralarm_delete(ralarm_talarm)
{
if(alarm==NULL){
returnRALARM_ERROR;
}
ralarm_mutex_lock(g_container.mutex);
alarm->state&=~RALARM_STATE_START;//---①
ralarm_list_remove(&alarm->list);//---②
RALARM_FREE(alarm);//---③
alarm=NULL;
ralarm_mutex_unlock(g_container.mutex);
returnRALARM_EOK;
}
適配簡單
- 根據系統能力,提供獲取時間方法,創建ralarm的ops并注冊獲取時間接口。
structralarm_ops{
ralarm_err_t(*time_get)(ralarm_time_ttime);
};
ralarm_err_tralarm_register_ops(structralarm_ops*ops);
- 提供刷新節拍,然后調用刷新接口。
voidralarm_refresh(void);
RAlarm運行邏輯:
- 鬧鐘的refresh接口需要用戶提供一個刷新節拍,以提供鬧鐘的生命。
- refresh皆苦根據鬧鐘鏈表是否存在已設置的鬧鐘,選擇發送事件給更新任務,更新檢測鬧鐘的狀態。
- 如下圖:當檢測鬧鐘鏈表無設置的鬧鐘,則不會發送事件給更新任務
- 如下圖:
- 當用戶創建了鬧鐘,則會將鬧鐘掛在鬧鐘量表中。
- 刷新節拍調用refresh之后,發送事件給更新任務,然后調用wakeup檢測鬧鐘的狀態。
- 如果某個鬧鐘時間到,則會調用對應鬧鐘的回調函數。
RAlarm的使用
-
在RT-Thread下使用ralarm組件:
- ① 鬧鐘的處理函數,當鬧鐘時間到了,則會調用這個函數。
- ② 提供給ralarm組件時間接口。
- ③ 創建ops,提供時間接口。
- ④ 軟件定時器的處理函數,調用ralarm的刷新函數,提供刷新節拍。
- ⑤ ralarm組件初始化,注冊ops。
- ⑥ 創建鬧鐘。
- ⑦ 創建一個軟件定時器,為ralarm組件提供刷新節拍。
staticrt_timer_ttimer;
ralarm_talarm_test=NULL;
staticvoidalarm_handler(ralarm_talarm)//---①
{
rt_kprintf("Time:%02d:%02d:%02drn",alarm->setup.time.hour,
alarm->setup.time.minute,alarm->setup.time.second);
ralarm_stop(alarm);
ralarm_dump();
}
staticralarm_err_talarm_time_get(ralarm_time_ttimer)//---②
{
time_tcurrent;
structtm*local;
time(¤t);
local=localtime(¤t);
timer->hour=local->tm_hour;
timer->minute=local->tm_min;
timer->second=local->tm_sec;
returnRALARM_EOK;
}
staticstructralarm_opsops={//---③
.time_get=alarm_time_get,
};
staticvoidtime_handler(void*param)//---④
{
ralarm_refresh();
}
intmain(void)
{
ralarm_init();//---⑤
ralarm_register_ops(&ops);
structralarm_setupsetup;
setup.flag=RALARM_DAILY;
setup.time.hour=15;
setup.time.minute=0;
setup.time.second=0;
alarm_test=ralarm_create(&setup,alarm_handler,NULL);//---⑥
ralarm_start(alarm_test);
ralarm_dump();
timer=rt_timer_create("timer",time_handler,//---⑦
RT_NULL,800,
RT_TIMER_FLAG_PERIODIC);
if(timer!=RT_NULL)
rt_timer_start(timer);
}
- 驗證結果:
審核編輯黃宇
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
接口
+關注
關注
33文章
8645瀏覽量
151399 -
RTOS
+關注
關注
22文章
817瀏覽量
119720
發布評論請先 登錄
相關推薦
SILABS CP2103芯片是否不依賴于我錯過的微/ picoblaze處理器?
/TechnicalDocs/CP2103.pdf幾乎沒有說明這個芯片的使用情況(除了告訴我RTS和CTS之外)活躍的低)。這個芯片的vhdl或verilog示例代碼是否不依賴于我錯過的微/ picoblaze處理器
發表于 07-23 13:00
一種不依賴于棋盤格等輔助標定物體實現像素級相機和激光雷達自動標定的方法
主要內容本文提出了一種不依賴于棋盤格等輔助標定物體,實現像素級相機和激光雷達自動標定的方法。方法直接從點云中提取3D邊特征,一避免遮擋問題,并且使用了精確度更高的深度連續邊。文中首先指出:以下四種
發表于 09-01 07:42
是否可以在主內核處于喚醒狀態時在ESP32-S3上使用ULP?
我認為 ULP 協處理器是 ESP32 系列中的一個獨立硬件單元,不依賴于主內核。如果這是真的,那么它可以在主內核運行時用作硬件??看門狗(比如計算滴答)。不確定這是否可行,是否值得嘗
發表于 03-02 07:51
據調查64%的人表示:日常生活中不依賴物聯網設備
大多數人(64%)表示,他們不依賴連網設備來完成日常活動,這一比例是36%的人表示他們依靠設備來度過日常生活的兩倍。領先的B2B研究、評級和評論公司Clutch一項新調查發現,67%擁有連網設備的人擁有智能家用電器,如智能冰箱、烤箱或電視。
發表于 10-27 10:13
?1850次閱讀
量子技術革GPS的命:不依賴衛星就可以進行導航
導航衛星系統(GNSS),這類系統可以發送和接收來自繞地球運行的衛星的信號。量子加速度計是一個獨立的系統,不依賴任何外部信號。 這一點尤其重要,因為衛星信號可能因高層建筑物等阻礙因素而無法使用,或者可能被堵塞、模仿或拒絕,因而無法進行
發表于 11-19 16:22
?397次閱讀
PHP簡單實現不依賴于Unix系統Cron的定時任務程序資料說明
本文檔的主要內容詳細介紹的是PHP簡單實現不依賴于Unix系統Cron的定時任務程序資料說明。
發表于 03-01 16:52
?2次下載
INS是一種不依賴于外部信息的自主式導航系統
慣性導航系統(INS)也稱作慣性參考系統,是一種不依賴于外部信息、也不向外部輻射能量(如無線電導航那樣)的自主式導航系統。其工作環境不僅包括空中、地面,還可以在水下。 慣性導航的基本工作原理是以牛頓
發表于 06-08 15:29
?2745次閱讀
一個種不依賴昂貴檢測設備的偏置電流測試方法
本篇介紹一個種不依賴昂貴檢測設備的偏置電流測試方法,同時配合LTspice仿真增強理解。工程師可以在普通實驗室環境中,根據該方法調整放大器局部電路實現偏置電流的準確測量。 如圖2.36為
以色列成立新研究中心,開發不依賴GPS的導航系統
以色列開發不依賴GPS的導航技術 據C4ISR網站2021年3月18日報道,以色列國防部和以色列航空工業公司(IAI)成立了一個新的研究中心,開發不依賴于易中斷的GPS的導航系統。全球軍事力量都在
智行者發布國內首款不依賴高精地圖的高級別自動駕駛解決方案
與市場上其他高速領航系統不同,智行者的H-INP采用了“重感知 輕地圖”的技術方案,成為國內首款不依賴高精地圖的高級別自動駕駛解決方案。
一個種不依賴昂貴檢測設備的偏置電流測試方法
本篇介紹一個種不依賴昂貴檢測設備的偏置電流測試方法,同時配合LTspice仿真增強理解。工程師可以在普通實驗室環境中,根據該方法調整放大器局部電路實現偏置電流的準確測量。
發表于 02-22 14:17
?844次閱讀
原生鴻蒙系統正式發布,余承東宣布不依賴國外核心技術
’,標志著華為在移動操作系統領域邁出了堅實的一步。” 這款原生鴻蒙系統作為中國自主研發的移動操作系統,其最大的亮點在于不依賴于國外的編程語言和操作系統內核等核心技術,實現了真正的自主可控。這一突破對于提升我國在全球科技領域的競爭力具有重要意義。 然而,對于
評論