-
在實(shí)際的開發(fā)項(xiàng)目中,很多時(shí)候我們需要定時(shí)的做一些事情,舉例:
- ①路上的路燈,每天晚上6:00準(zhǔn)時(shí)打開,每天早上6:00準(zhǔn)時(shí)關(guān)閉;
- ②定時(shí)鬧鐘,起床上班。這些行為其實(shí)都是定時(shí)任務(wù)--鬧鐘。
-
大部分單片機(jī)都提供了rtc alarm硬件鬧鐘,但是實(shí)際很少人使用,就舉個(gè)簡(jiǎn)單的例子,rt-thread的BSP中也沒(méi)有幾個(gè)芯片適配了alarm硬件鬧鐘。但是我們要使用怎么辦??
-
我受到RTOS的調(diào)度的啟發(fā),像M3/M4這種內(nèi)核都是SysTick產(chǎn)生時(shí)鐘節(jié)拍,以供系統(tǒng)處理所有和時(shí)間有關(guān)的事情,如線程延時(shí),線程的時(shí)間片輪轉(zhuǎn),以及定時(shí)器超時(shí)等。
-
有了第3點(diǎn)的經(jīng)驗(yàn),那么我們可以寫一個(gè)軟件鬧鐘功能就容易多了,只需要提供一個(gè)刷新節(jié)拍,定時(shí)查看哪一個(gè)鬧鐘需要喚醒,就可以解決鬧鐘的管理了。
-
鬧鐘組件名字:RAlarm(全稱Rice Alarm),源碼連接:https://gitee.com/RiceChen0/ralarm
RAlarm
RAlarm接口說(shuō)明:
跨平臺(tái)
- RTOS的種類很多,接口差異性打,所以RAlarm為了解決這個(gè)問(wèn)題,統(tǒng)一為上層提供一整套接口。
- 線程接口。
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目前已經(jīng)提供了兩個(gè)環(huán)境的適配,如cmsis,rtthread。
接口使用簡(jiǎn)單
接口 | 說(shuō)明 |
---|---|
ralarm_init | 初始化 |
ralarm_deinit | 去初始化 |
ralarm_create | 創(chuàng)建鬧鐘 |
ralarm_start | 啟動(dòng)鬧鐘 |
ralarm_stop | 停止鬧鐘 |
ralarm_modify | 修改鬧鐘 |
ralarm_delete | 刪除鬧鐘 |
- 鬧鐘初始化接口:初始化鬧鐘的鏈表,鬧鐘任務(wù),事件,互斥鎖;去初始化接口:注銷鬧鐘組件
/*鬧鐘初始化*/
ralarm_err_tralarm_init(void);
/*鬧鐘去初始化*/
voidralarm_deinit(void);
- 鬧鐘創(chuàng)建:
- 參數(shù)說(shuō)明:
「參數(shù)」 | 「描述」 |
---|---|
setup | 鬧鐘的時(shí)間和標(biāo)志,flag可為:RALARM_ONESHOT(只設(shè)置一次)和RALARM_DAILY(每天都設(shè)置) |
cb | 鬧鐘時(shí)間到了,喚醒的回調(diào)函數(shù)指針:typedef void (*ralarm_response_cb)(ralarm_t alarm) |
userData | 設(shè)置鬧鐘時(shí),自帶的用戶數(shù)據(jù)的指針 |
「返回」 | —— |
ralarm_t | 鬧鐘創(chuàng)建成功,放回鬧鐘句柄 |
NULL | 鬧鐘創(chuàng)建失敗 |
- 函數(shù)說(shuō)明:
- ①申請(qǐng)鬧鐘控制塊的空間。
- ②設(shè)置鬧鐘參數(shù)到控制塊中。
- ③將鬧鐘加入到鬧鐘鏈表中。
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;
}
- 鬧鐘啟動(dòng):將鬧鐘的狀態(tài)的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;
}
- 鬧鐘停止:將鬧鐘的狀態(tài)的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;
}
- 鬧鐘修改:修改鬧鐘的標(biāo)志和鬧鐘的時(shí)間
- 參數(shù)說(shuō)明:
「參數(shù)」 | 「描述」 |
---|---|
alarm | 鬧鐘的句柄 |
setup | 要修改鬧鐘的時(shí)間和標(biāo)志參數(shù) |
「返回」 | —— |
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;
}
- 刪除鬧鐘:
- 函數(shù)說(shuō)明:
- ①將鬧鐘的狀態(tài)的start bit置為0。
- ②將鬧鐘從鬧鐘鏈表中移除。
- ③釋放鬧鐘的內(nèi)存。
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;
}
適配簡(jiǎn)單
- 根據(jù)系統(tǒng)能力,提供獲取時(shí)間方法,創(chuàng)建ralarm的ops并注冊(cè)獲取時(shí)間接口。
structralarm_ops{
ralarm_err_t(*time_get)(ralarm_time_ttime);
};
ralarm_err_tralarm_register_ops(structralarm_ops*ops);
- 提供刷新節(jié)拍,然后調(diào)用刷新接口。
voidralarm_refresh(void);
RAlarm運(yùn)行邏輯:
- 鬧鐘的refresh接口需要用戶提供一個(gè)刷新節(jié)拍,以提供鬧鐘的生命。
- refresh皆苦根據(jù)鬧鐘鏈表是否存在已設(shè)置的鬧鐘,選擇發(fā)送事件給更新任務(wù),更新檢測(cè)鬧鐘的狀態(tài)。
- 如下圖:當(dāng)檢測(cè)鬧鐘鏈表無(wú)設(shè)置的鬧鐘,則不會(huì)發(fā)送事件給更新任務(wù)
- 如下圖:
- 當(dāng)用戶創(chuàng)建了鬧鐘,則會(huì)將鬧鐘掛在鬧鐘量表中。
- 刷新節(jié)拍調(diào)用refresh之后,發(fā)送事件給更新任務(wù),然后調(diào)用wakeup檢測(cè)鬧鐘的狀態(tài)。
- 如果某個(gè)鬧鐘時(shí)間到,則會(huì)調(diào)用對(duì)應(yīng)鬧鐘的回調(diào)函數(shù)。
RAlarm的使用
-
在RT-Thread下使用ralarm組件:
- ① 鬧鐘的處理函數(shù),當(dāng)鬧鐘時(shí)間到了,則會(huì)調(diào)用這個(gè)函數(shù)。
- ② 提供給ralarm組件時(shí)間接口。
- ③ 創(chuàng)建ops,提供時(shí)間接口。
- ④ 軟件定時(shí)器的處理函數(shù),調(diào)用ralarm的刷新函數(shù),提供刷新節(jié)拍。
- ⑤ ralarm組件初始化,注冊(cè)ops。
- ⑥ 創(chuàng)建鬧鐘。
- ⑦ 創(chuàng)建一個(gè)軟件定時(shí)器,為ralarm組件提供刷新節(jié)拍。
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);
}
- 驗(yàn)證結(jié)果:
審核編輯黃宇
-
接口
+關(guān)注
關(guān)注
33文章
8497瀏覽量
150834 -
RTOS
+關(guān)注
關(guān)注
21文章
809瀏覽量
119432
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論