基于單片機的協(xié)程多任務(wù)
在很多的單片機項目中,由于操作系統的體積以及使用的背景知識,如果采用的話(huà),可能讓項目脫離主要業(yè)務(wù)方向,這個(gè)時(shí)候很有必要使用簡(jiǎn)單的協(xié)程多任務(wù)。
1協(xié)程多任務(wù)的特點(diǎn)
每個(gè)任務(wù)優(yōu)先級平等
每個(gè)任務(wù)主動(dòng)釋放CPU控制權
2 UCOS等操作系統的特點(diǎn)
任務(wù)存在不同優(yōu)先級,很方便進(jìn)行CPU資源的分配。
對于ucos的任務(wù)來(lái)說(shuō),每個(gè)任務(wù)都認為自己是獨占cpu的,可以隨便休眠之類(lèi),這樣對于代碼的風(fēng)格的限制比較小,比較好修改現存的模塊。
操作系統一般提供比較多的服務(wù),對于復雜應用比較好。
3 協(xié)程多任務(wù)的應用場(chǎng)合
協(xié)程方式適合簡(jiǎn)單的多任務(wù),每個(gè)任務(wù)要確認其符合協(xié)程的模型,不能阻塞cpu運行,要主動(dòng)釋放CPU,如果考慮到多人合作,或者引入第三方的代碼,進(jìn)來(lái),那么協(xié)程方式恐怕工作量過(guò)大(模型改造檢查),這時(shí)最好使用操作系統。
協(xié)程或者操作系統的平臺的建立,這些都需要積累,也沒(méi)有什么高級和低級的區別,只是針對不同的場(chǎng)景和開(kāi)發(fā)人員選擇不同而已。
4協(xié)程多任務(wù)的實(shí)現
為了使用方便,并且將來(lái)便于系統升級,多任務(wù)采用基于接口的方式定義和實(shí)現。
4.1 任務(wù)的定義
每個(gè)任務(wù)會(huì )管理自己的數據,提供對外接口,每個(gè)任務(wù)提供以下形式結構
Struct _task1
{
//任務(wù)對外接口,函數指針
Void (*start)(Struct _task1*handle);
Void (*run)(Struct _task1*handle);
Void (*stop)(Struct _task1*handle);
//其他對外接口
...
//任務(wù)私有數據
} task1;
之所以將對外接口放在任務(wù)結構體中,是為了強調這些是任務(wù)的對外接口,而且客戶(hù)只能調用這里面的接口,另外函數指針也很方便的提供了一個(gè)接口和實(shí)現的分隔層
4.2 任務(wù)的實(shí)現
任務(wù)的實(shí)現層面,用戶(hù)可以根據對系統和業(yè)務(wù)的理解,做系統演化,而不會(huì )影響到外部接口的使用
//任務(wù)接口實(shí)現函數
Void task1_start(Struct _task1*handle)
{
//設置任務(wù)開(kāi)始標識
}
Void task1_run(Struct _task1*handle)
{
If(handle->status1)
{
//處理
}
Else if(handle->status2)
{
//處理
}
}
Void task1_stop(Struct _task1*handle)
{
//設置任務(wù)結束標識
}
//任務(wù)初始化函數,構造任務(wù)結構體
Void task1_init(Struct _task1*handle)
{
Handle->start = task_start;
Handle->run = task_run;
Handle->stop= task_stop;
}
4.3 調用形式
4.3.1 定義全局任務(wù)結構體
Struct _task1
{
//任務(wù)對外接口,函數指針
Void (*start)(Struct _task1*handle);
Void (*run)(Struct _task1*handle);
Void (*stop)(Struct _task1*handle);
//其他對外接口
...
//任務(wù)私有數據
} task1;
4.3.2 任務(wù)初始化
Task1_init(&task1);
4.3.3 開(kāi)始任務(wù)
Task1->start(&task1);
4.3.4 結束任務(wù)
Task1->stop(&task1);
4.3.5 任務(wù)運行
一般系統在啟動(dòng)后運行的一個(gè)無(wú)限循環(huán)語(yǔ)句中有
While(1)
{
Task1->run(&task1);
Task2->run(&task2)
...其他任務(wù)運行
}
5 定時(shí)器以及延時(shí)的實(shí)現方法
協(xié)程多任務(wù)不會(huì )在代碼中使用sleep()阻塞CPU的方法做定時(shí)器或者休眠,定時(shí)器會(huì )有一個(gè)單獨的任務(wù),任務(wù)提供新增定時(shí)器、刪除定時(shí)器、查詢(xún)定時(shí)器值等接口來(lái)提供軟件定時(shí)器功能。
6 任務(wù)間通訊
原則上通過(guò)任務(wù)提供的接口來(lái)通訊,當然如果通訊工作量過(guò)大,不反對使用第三方任務(wù)來(lái)完成通訊。
7 驅動(dòng)層模塊任務(wù)例子
對于單片機協(xié)程多任務(wù)來(lái)說(shuō),應用層和驅動(dòng)層是優(yōu)先級相同的任務(wù),對于很多的驅動(dòng)來(lái)說(shuō),例如UART驅動(dòng),其發(fā)送和接收很多采用的是查詢(xún)的方式來(lái)進(jìn)行,下面簡(jiǎn)單的使用多任務(wù)的結構方式來(lái)說(shuō)明驅動(dòng)的寫(xiě)作
Struct _com{
//任務(wù)對外接口,函數指針
Void (*start)(Struct _com*handle);
Void (*run)(Struct _com*handle);
Void (*stop)(Struct _com*handle);
//其他對外接口
Void read(char* ch)
Void write(char* ch)
...
//任務(wù)私有數據
//驅動(dòng)狀態(tài),
Char status;
}com1;
//運行代碼
Void Com_run(Struct _com * handle)
{
If(read)
{
If(register1)
{
}
Else if(register2)
{
}
}
Else if(write)
{
If(register3)
{
}
Else if(register4)
{
}
}
}
從上面代碼可見(jiàn),驅動(dòng)模塊其實(shí)和普通的任務(wù)沒(méi)有區別。
評論