上一課:
【小黑嵌入式系統(tǒng)第五課】嵌入式系統(tǒng)開發(fā)流程——開發(fā)工具、交叉開發(fā)環(huán)境、開發(fā)過程(生成&調(diào)試&測試)、發(fā)展趨勢
下一課:
【小黑嵌入式系統(tǒng)第七課】PSoC? 5LP 開發(fā)套件(CY8CKIT-050B )——PSoC? 5LP主芯片、I/O系統(tǒng)、GPIO控制LED流水燈的實(shí)現(xiàn)
一 單片機(jī)的C語言簡述
1、為什么要用C語言?
理由1:大幅減少編程勞動量
理由2:代碼的通用性
- C語言可以為世界上任何一款處理器編程 (包括所有單片機(jī))
- 在任何一款單片機(jī)上開發(fā)的程序,都可以移植到別的處理器上。
- 代碼的模塊化、可復(fù)用性 => 減少重復(fù)勞動、加快開發(fā)速度。
2、單片機(jī)的C語言怎么學(xué)?
PSoC Creator集成開發(fā)環(huán)境所配備的PSoC 5LP編譯器為GCC-ARM(GNU Compiler Collection for ARM Embedded Processors),是一款免費(fèi)的C/C++編譯器。其文檔位于圖中g(shù)cc目錄內(nèi)。
C預(yù)處理器、鏈接器、匯編器、調(diào)試器、函數(shù)庫等相關(guān)軟件工具的文檔位于圖中的pdf目錄及其子目錄內(nèi)。
之一:變量定義
處理器、編譯器類型的不同,在變量定義上與VC略有不同。
幾個特殊關(guān)鍵詞的含義:
const:定義常量。const關(guān)鍵字定義的常量被放在ROM中,常用于定義如系數(shù)表、顯示段碼表等。
static :相當(dāng)于本地全局變量,在函數(shù)內(nèi)使用,可以避免全局變量使用混亂。
volatile :定義“揮發(fā)性”變量。編譯器將認(rèn)為該變量的值會隨時改變,對該變量的任何操作都不會被優(yōu)化掉。
之二:特殊寄存器操作
結(jié)論:
(1)特殊寄存器經(jīng)過定義之后,可以像變量一樣操作。
(2)包含單片機(jī)頭文件,就已經(jīng)完成了變量定義工作。
之三:位操作
結(jié)論:若處理器不支持單個位的操作,則要用左邊的方式實(shí)現(xiàn)。
之四:中斷
結(jié)論:(1)C語言將中斷作為特殊函數(shù) (2)該函數(shù)由中斷機(jī)制調(diào)用
之五:內(nèi)部函數(shù)(intrinsic Function)
結(jié)論:
(1)內(nèi)部函數(shù)是將該款單片機(jī)的一些特殊指令做成函數(shù)形式
(2)在使用前,要包含內(nèi)部函數(shù)頭文件。
之六:函數(shù)的可重入性
結(jié)論:
(1)低端單片機(jī)因資源少,函數(shù)用靜態(tài)傳遞,不可重入。
(2)中高端單片機(jī)編譯器,函數(shù)用棧傳遞,允許重入。
討論與總結(jié):
1、即使是初學(xué)者,也完全可以在不深入了解匯編指令系統(tǒng)的情況下直接開始C語言開發(fā)
2、任何一款處理器的C語言,都是在標(biāo)準(zhǔn)C語言 (ANSI-C) 上增加對相應(yīng)處理器的特殊操作而構(gòu)成。
3、C編譯器的表現(xiàn)通常非常優(yōu)秀。如果沒有幾年的手工匯編經(jīng)驗(yàn)3很難寫出比C編譯器更高效的代碼。
4、如果在編程過程中將硬件差異集中到某個很小的局部,整個程序通過很簡單的修改就能編譯成另一CPU的機(jī)器碼。這就是所謂的“代碼移植”,是嵌入式軟件設(shè)計(jì)最重要的思想之一。
5、在一開始就樹立可移植性、模塊化的概念,養(yǎng)成好的編程習(xí)慣,這正是下一部分對減少重復(fù)勞動、加快開發(fā)速度有很大幫助的主要目的。
二 程序設(shè)計(jì)規(guī)范
1、什么要學(xué)習(xí)程序設(shè)計(jì)規(guī)范?
1、程序不僅要被計(jì)算機(jī)執(zhí)行,還要給程序員閱讀,以及被今后重復(fù)使用。
2、一個風(fēng)格清爽而嚴(yán)謹(jǐn)、規(guī)范化的程序更容易被讀懂,更容易被修改、排錯和移植。
3、規(guī)范化編程、高度一致的風(fēng)格和正確的習(xí)慣還有助于保持思維清晰,寫出正確無誤的代碼。特別是一個開發(fā)團(tuán)隊(duì)共同工作時,規(guī)范一致化的編程尤其重要
4、每個初學(xué)者在項(xiàng)目初期都會因?yàn)椴涣季幊塘?xí)慣浪費(fèi)大量時間,因此若能在開始寫程序時就重視規(guī)范化問題,對順利渡過提高階段有很大幫助。
2、程序規(guī)范的基本原則?
原則:
(1)一致的代碼風(fēng)格,統(tǒng)一的變量名、函數(shù)名命名規(guī)則
(2)符合英語語法、可閱讀的代碼
(3)關(guān)鍵代碼100%注釋
(4)硬件有關(guān)、硬件無關(guān)代碼分離,可移植性強(qiáng)
(5)每個對象都具有完善的封裝,接口形式簡潔、易用
(6)對所有資源嚴(yán)格要求硬件隔離層,軟件中不允許直接訪問硬件,不允許跨層調(diào)用。
(一)編程風(fēng)格
(二)可移植性
1)消除CPU差異
若希望自己寫的程序在不同處理器上運(yùn)行,首先需要了解這些處理器的不同之處。其中包括硬件的不同以及特殊語法的差異。例如MSP430單片機(jī)沒有位操作指令,8051單片機(jī)有,若兩者之間程序需相互移植,首先需要消滅這個差異。
2)消除硬件差異
更改數(shù)碼管硬件布線,無需重寫段碼表
3)封裝
封裝是指將軟/硬件對象的屬性與行為綁定在一起,并放置在一個模塊單元內(nèi)。該單元負(fù)責(zé)將所描述的屬性隱藏起來,外界對其內(nèi)部屬性的所有訪問只能通過提供的應(yīng)用程序接口實(shí)現(xiàn)。
初學(xué)者常見問題:
4)應(yīng)用程序接口(API)
接口是對軟/硬件對象的抽象,對外提供的服務(wù)和訪問功能,
即:對象封裝后對外呈現(xiàn)成什么樣?
原則:(1)使用方便(2)功能豐富(3)但不要過多過濫
【例】為液晶顯示模塊規(guī)劃應(yīng)用程序接口:
5)軟件層次
例:菜單程序
(1)杜絕跨層調(diào)用
(2)功能模塊可以任意拼接、組合
(3)要有硬件隔離層(HAL)
(4)更換任意層代碼,上下層建筑不變
(三)版本管理、可配置
(1)盡可能減少軟件副本
(2)類似的產(chǎn)品/設(shè)計(jì)盡可能公用同一代碼
(3)利用宏定義配置功能
(4)永遠(yuǎn)在最新的代碼上開發(fā),保留最新版
三 前后臺多任務(wù)程序設(shè)計(jì)
(一)前后臺程序的基本概念
任務(wù)(Task) :指完成某一單一功能的程序
后臺程序:對時間要求不嚴(yán)格的任務(wù),通常在主循環(huán)內(nèi)執(zhí)行
前臺程序:要求快速響應(yīng)或者時間嚴(yán)格的任務(wù),通常中斷內(nèi)
隊(duì)列/緩沖:用于暫存后臺來不及處理的前臺事件
(二)前后臺程序的編寫基本原則
(1)任何一個任務(wù)都不能阻塞CPU。
每個任務(wù)都應(yīng)主動結(jié)束,讓出CPU。不能有等待、死循環(huán)、長延時等環(huán)節(jié)(對初學(xué)者來說是難點(diǎn)!)
(2)關(guān)注函數(shù)重入問題
可重入(Reentrancy):函數(shù)在自己調(diào)用自己的時候,不必?fù)?dān)心數(shù)據(jù)被破壞。
從軟件工程角度對函數(shù)可重入的作用可以解釋為:具有可重入性的函數(shù)能夠被多個任務(wù)同時調(diào)用。在后臺程序中,任務(wù)都是順序執(zhí)行的,不存在多個任務(wù)同時調(diào)用一個函數(shù)的情況。但可能出現(xiàn)前臺中斷服務(wù)程序與后臺任務(wù)同時調(diào)用某個函數(shù)。
因此對于前后臺公用函數(shù),必須是可重入的。
【例】:
(3)臨界代碼保護(hù)(Critical Code Protection)
臨界代碼:運(yùn)行時不可分割的代碼,這部分代碼不允許被中斷打斷。
1) 依靠軟件產(chǎn)生時間嚴(yán)格時序的程序段。
/***************************************************
*名稱: Pulse 10us()
*功能: 產(chǎn)生10us脈沖
*入門參數(shù): 無
**************************************************/
void Pulse_10us()
{
_DINT(); // -------以下是臨界代碼區(qū),不允許被中斷
IO=1; // 置高
_delay_cycles(8); // 高電平持續(xù)10us (O賦值身耗2us)
IO=0; //置低
_EINTO0; // -------以上是臨界代碼區(qū)-----------
}
2)共享資源互斥性造成的臨界代碼
程序中任何可被占用的實(shí)體都稱為“資源”。資源可以是硬件設(shè)備,如定時器、串口、打印機(jī)、鍵盤、LCD顯示器等,也可以是變量、數(shù)組、隊(duì)列、等數(shù)據(jù)。
被一個以上任務(wù)所占用的資源叫做“共享資源”。共享資源若不能同時被多任務(wù)占用,則具有“互斥性”(Mutual Exclusive)。
【例】:前后臺同時調(diào)用液晶顯示函數(shù)造成花屏
(4)臨界代碼的保護(hù)方法
-
關(guān)中斷、開中斷
隱患: 如果在A函數(shù)的臨界代碼區(qū)調(diào)用了另一個函數(shù)B,B函數(shù)內(nèi)也有臨界代碼區(qū),從B函數(shù)返回時,中斷被打開了,這將造成A函數(shù)后續(xù)代碼失去臨界保護(hù)。所以,使用該方法時,不能在臨界代碼區(qū)調(diào)用任何具其他有臨界代碼的函數(shù)! -
利用硬件棧保存中斷使能狀態(tài)
優(yōu)點(diǎn):不影響函數(shù)調(diào)用
缺點(diǎn):很多單片機(jī)的C語言不支持操作硬件棧 -
利用變量保存中斷使能狀態(tài)
缺點(diǎn):每一段臨界代碼要消耗2-4字節(jié)內(nèi)存 -
利用模擬棧保存中斷使能狀態(tài)
缺點(diǎn):速度慢
典型錯誤1:在臨界代碼區(qū)調(diào)用其他臨界代碼
A()
{
int_Disable();
B(); // 這期間中斷是開的,所執(zhí)行的代碼不被臨界保護(hù)
int_Enable();
}
B()
{
int_Disable();
// ...
int_Enable();
}
典型錯誤2:在主函數(shù)和中斷中都調(diào)用LCD操作函數(shù)
- LCD操作耗時長,不應(yīng)放在中斷中。
- LCD操作是臨界代碼,LCD是互斥性共享資源,LCD操作函數(shù)都是不可重入的,如果主函數(shù)里沒有做臨界代碼保護(hù),結(jié)果就是沒多久屏幕就花了或呈死機(jī)效果。
討論與總結(jié)
- 后臺中任務(wù)順序執(zhí)行。每個后臺任務(wù)中的內(nèi)存(局部變量)在任務(wù)結(jié)束后可以全部釋放,讓給下一個任務(wù)使用。即使在RAM很少的處理器上也能同時執(zhí)行眾多任務(wù)。
- 后臺中任務(wù)順序執(zhí)行。天然避免了后臺任務(wù)資源互斥問題,但仍需考慮前后臺之間的資源互斥問題。
- 前后臺程序的結(jié)構(gòu)靈活,實(shí)現(xiàn)形式與實(shí)現(xiàn)手段多樣,是使用最廣的程序結(jié)構(gòu),但缺乏架構(gòu)標(biāo)準(zhǔn),維護(hù)、升級、排錯都很困難。
- 必須要程序員自己來判斷和處理臨界代碼的隱患。
- 程序多任務(wù)的執(zhí)行依靠每個任務(wù)的非阻塞性來保證,是編程最大的難點(diǎn),下一節(jié)將介紹的FSM將是解決這一問題的利器!
四 FSM:狀態(tài)機(jī)建模
1、什么是狀態(tài)機(jī)?
有限狀態(tài)自動機(jī)(Finite-State Machine, FSM),簡稱狀態(tài)機(jī),是表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型。
2、為什么要引入狀態(tài)機(jī)?
流程圖的缺陷:
1、不能用于描述“任何時候”發(fā)生的事件
2、無法描述“由外部事件決定流程”的程序
3、不適合描述帶有阻塞的并發(fā)過程
4、難以描述大量的獨(dú)立事件。
需要:能夠描述并發(fā)結(jié)構(gòu)的軟件,能從行為的角度來描述軟件,且能夠根據(jù)模型生成代碼,也能夠?qū)浖M(jìn)行完整測試的新手段—狀態(tài)機(jī)模型。
3、流程圖無法描述的軟件行為舉例
(1)不能用于描述“任何時候”發(fā)生的事件
(2)不能用于描述由外部事件決定流程的事件
【例】:電子表有兩個按鍵,但按鍵順序完全由外部決定
(3)不適合描述帶有阻塞的并發(fā)過程
【例】:一個單片機(jī)同時控制2臺電動機(jī)完成運(yùn)轉(zhuǎn)時序
(4)不適合描述大量的獨(dú)立事件
【例】:投幣式自動咖啡機(jī)程序
流程圖:投幣->選咖啡->出咖啡->結(jié)束
然 而…
-
如果沒有放咖啡杯就選擇咖啡,會發(fā)生什么情況?
-
如果咖啡杯未滿之前,用戶取走了咖啡杯,會發(fā)生什么情況?
-
如果咖啡灌了一半時,用戶取走咖啡杯,再放回,能否把剩下一半繼續(xù)加滿?
-
如果咖啡灌了一半時,用戶取走咖啡杯,不再放回,剩下一半是否會加到下一用戶杯中?
-
如果咖啡杯未滿之前,用戶取走了咖啡杯,然后按退幣扭,該如何處理?
-
如果還沒有完成一次點(diǎn)單之前,用戶再次投幣,會發(fā)生什么情況?
-
如果一杯咖啡尚未加滿時,用戶又點(diǎn)了另一種咖啡,會發(fā)生什么情況?
-
如果用戶一次投入兩杯咖啡的錢,該怎樣處理?
-
如果咖啡存儲容器已空,用戶點(diǎn)單時能否正確提示?
-
如果咖啡杯未滿之前,咖啡機(jī)空了,能否給用戶退款?
…
4、引入“狀態(tài)機(jī)” 的優(yōu)勢
上面這些例子中,軟件下一步要執(zhí)行的功能不僅與外界入信息有關(guān),還與系統(tǒng)的“當(dāng)前狀態(tài)”有關(guān)。狀態(tài)機(jī)就是一種基于“狀態(tài)”與“事件”的軟件描述手段!其優(yōu)勢在于:
(1) 能夠處理并發(fā)。由于系統(tǒng)在每一時刻只能有唯一的狀態(tài),在每一個狀態(tài)下,可能發(fā)生的事件也是有限的。因此系統(tǒng)中即使存在有大量的獨(dú)立事件,軟件描述也會簡單得多。
(2) 能夠消除阻寒。真正需要CPU處理的只有系統(tǒng)狀態(tài)發(fā)生改變的那一刻,在系統(tǒng)等待事件到來的期間,是不需要CPU處理的。如果能夠用狀態(tài)與事件的形式來描述軟件,能夠?qū)PU從等待事件發(fā)生的過程中解放出來,從而生成無阻塞的代碼。
(3) 能夠降低系統(tǒng)的復(fù)雜度,提高可測性
5、狀態(tài)機(jī)的表示方法:狀態(tài)轉(zhuǎn)移圖
圓圈:狀態(tài) (有限個)
有向箭頭:狀態(tài)轉(zhuǎn)移
Event事件:事件發(fā)生時將觸發(fā)狀態(tài)轉(zhuǎn)移
Action動作:狀態(tài)轉(zhuǎn)移的同時執(zhí)行動作
6、由狀態(tài)轉(zhuǎn)移圖生成代碼
方法1、在狀態(tài)中判斷事件(事件查詢)
switch(State) //根據(jù)當(dāng)前狀態(tài)決定程序分支
{
case S0: //在s0狀態(tài)
if(Event0)
{ //如果查詢到Event0事件
Action0();
}
else if(Event1)
{ //如果查詢到Event1事件
Action1();
State=S1;
}
else if(Event2)
{ //如果查詢到Event2事件
Action3();
State=S2;
}
break;
case S1: //在s1狀態(tài)
if(Event2)
{ //如果查詢到Event2事件
Action2();
State=S2;
}
break;
......
方法2、在事件中判斷狀態(tài)(事件觸發(fā))
7、狀態(tài)機(jī)建模舉例
例1 電子表程序
====A鍵中斷====
switch(Status) /*根據(jù)當(dāng)前狀態(tài)處理A鍵所引發(fā)的狀態(tài)跳跳轉(zhuǎn)*/
{
case DISP_TIMME: Status = DISP_DATE;break://時間顯示時按A鍵,顯示日期
case DISP_DATE: Status = DISP_SEC; break;
case DISP_SEC: Status= DISP_TIME; break;
case SET_HOUR: if(++Hour>23) Hour=0; break; //小時設(shè)置時按A鍵調(diào)整小時case SET_MINUTE: if(++Min>59) Min=0; break;
case SET_MONTH: if(++Month>12) Month=1; break;
case SET_DATE: if(++Date>31) Date=0; break;
}
====B鍵中斷=====
switch (Status) /*/根據(jù)當(dāng)前狀態(tài)處理B鍵所引發(fā)的狀態(tài)跳轉(zhuǎn)/*/
{
case DISP_TIME; Status= SET_HOUR; break; //時間顯示時按B鍵,設(shè)置小時
case DISP_DATH; Status= SET_HOUR: break; //日期顯示時按B鍵,設(shè)置小時
case DISP_SEC; Second 0; break; //秒鐘顯示時按B鍵,秒歸零
case SET_HOUR; Status= SET_MINUTE; break; //小時設(shè)置時按B鍵,分鐘設(shè)置
case SET_MINUTE; Status= SET_MONTH; break; //分鐘設(shè)置時按B鍵月設(shè)置
case SET_MONTH; Status= SET_DATE; break; //月設(shè)置時按B鍵,日設(shè)置
case SET_DATE; Status= DISP_TIME; break; //日設(shè)置時按B鍵,顯示時間
}
例2 長短按鍵識別
例3 事件序列匹配
五 模塊化程序設(shè)計(jì)
1、模塊化程序的原則
- 非阻寒性 不能長時間占用CPU,更不死等待某個事件的發(fā)生,盡快地讓出CPU,供后續(xù)任務(wù)執(zhí)行。
- 硬件隔離 屏蔽硬件特征,起到硬件隔離層的作用。上層軟件將不涉及直接硬件操作。
- 模塊獨(dú)立性 各個程序庫之間沒有代碼關(guān)聯(lián)性(沒有互相調(diào)用和隸屬關(guān)系),在使用時,各個模塊文件可以任意拼接、組合、拆分。
- 時間獨(dú)立性 使用緩沖區(qū)、事件隊(duì)列等手段,對時間關(guān)聯(lián)性強(qiáng)的事件進(jìn)行斬存和緩沖,使之可以被異步處理。
- 可移植性 代碼都按照標(biāo)準(zhǔn)C的規(guī)范,很容易的移植到其他處理器上,或者其它硬件平臺上。
- 100%注釋 注釋關(guān)鍵代碼的功能或設(shè)計(jì)意圖,以及每個函數(shù)的功能.入口出口參數(shù)、說明及注意事項(xiàng),使用范例等。
- 開放性 方便日后修改、添加新的功能函數(shù)。
2、鍵盤模塊化程序
3、帶長短鍵識別的鍵盤模塊化程序
4、串口收發(fā)模塊化程序
5、數(shù)碼管顯示模塊化程序
6、時鐘和日歷程序
六 事件觸發(fā)多任務(wù)程序設(shè)計(jì)
1、什么是事件觸發(fā)程序?
任務(wù)全部在中斷內(nèi)完成,主程序休眠。
可以看做前后臺程序中,只有前臺任務(wù)。
特點(diǎn):1)實(shí)時性較好,事件響應(yīng)較快;2)低功耗
2、事件觸發(fā)程序的程序架構(gòu)
中斷:獲取原始的事件信息。
事件引擎:判斷何種事件發(fā)生,并調(diào)用相應(yīng)處理程序。
(一個中斷有多個中斷源時)
事件處理程序:只負(fù)責(zé)某個事件的處理,要求非阻塞。
3、事件觸發(fā)程序設(shè)計(jì)范例
有3個按鍵 (S1、S2、S3),按下為低電平。外部輸入電壓從ADC輸入。設(shè)計(jì)一款超低功耗的電壓表,要求用事件觸發(fā)結(jié)構(gòu)實(shí)現(xiàn)下列功能:
- 實(shí)現(xiàn)電壓測量功能,每秒刷新顯示2次電壓測量值。
每次測量值由ADC連續(xù)采樣4次求平均得到。 - 按下S1鍵時,斬停采樣與顯示刷新(保持功能)
- 按下S2鍵時,恢復(fù)采樣與刷新。
- 按下S3鍵時,將采樣數(shù)據(jù)從串口發(fā)出。
第3步:編寫5個事件處理程序,此時并不關(guān)心事件如何發(fā)生如何被檢測到,以及按什么順序發(fā)生
第4步:測試。按照預(yù)先設(shè)定的順序,依次調(diào)用5個事件處理程序(并不需要硬件上真的發(fā)生事件),模擬事件發(fā)生,即可進(jìn)行代碼測試。
第5步:編寫事件引擎,在中斷內(nèi)檢測和判判斷事件,并分別調(diào)用相應(yīng)的事件處理程序。
七 時間觸發(fā)系統(tǒng)
時間觸發(fā)系統(tǒng)可以理解為一種特殊的事件觸發(fā)系統(tǒng),但它另有自己的特點(diǎn)。
例子:一個醫(yī)生,必須在一些護(hù)理人員的幫助下,通宵照顧十個危重病人,方案可以是
● 安排護(hù)理人員在某個病人出現(xiàn)嚴(yán)重問題時喚醒他
——事件觸發(fā)
● 每小時鬧鈴,鬧鈴響時起床去探訪每個病人
——時間觸發(fā)
以每小時的間隔探訪病人,醫(yī)生能在嚴(yán)重并發(fā)癥出現(xiàn)之前探訪每個病人并安排合理的治療。另外,工作量在整個晚上平攤。于是,所有病人都能平安地度過這個夜晚。
而前一種方式可能會出現(xiàn)護(hù)理人員在喚醒醫(yī)生時,有多個病人都出現(xiàn)了嚴(yán)重并發(fā)癥,需要依次做手術(shù),后面的病人有可能來不及得到手術(shù)治療。
這個醫(yī)院的例子在事件驅(qū)動的系統(tǒng)中,即可能同時發(fā)生幾個事件。需要處理同時發(fā)生的多個事件不但增加了系統(tǒng)復(fù)雜性,而且降低了對事件觸發(fā)系統(tǒng)在所有情況下的行為做出預(yù)計(jì)的能力。
相比而言,在時間觸發(fā)的嵌入式系統(tǒng)中,設(shè)計(jì)人員能夠通過仔細(xì)安排可控的順序,保證一次只處理一個事件。
許多嵌入式系統(tǒng)并不需要睡眠,采用時間觸發(fā)方法有很多好處,有助于改善可靠性和安全性(如廣泛應(yīng)用于航空航天工業(yè)和汽車工業(yè)),主要原因在于系統(tǒng)的行為可以預(yù)計(jì)。
時間觸發(fā)方法還能降低CPU的負(fù)荷,并減少存儲器的使用量。
嵌入式系統(tǒng)需要執(zhí)行的任務(wù)分為兩種:
● **周期性任務(wù)**,比如每100ms執(zhí)行一次
● **單次任務(wù)**,如在50ms的延遲后執(zhí)行一次
考慮方案1:
void main(void)
{
Init_System();
while(1)
{
X(); // 執(zhí)行任務(wù)(耗時10ms)
Delay_90ms(); // 延遲90ms
}
}
需要知道任務(wù)X的精確運(yùn)行時間
這個運(yùn)行時間永不變化—— 不可行
考慮方案2:
基于定時器中斷,在一定的時刻調(diào)用函數(shù)
如果要支持多個任務(wù)(這些任務(wù)一般具有不同的運(yùn)行時間并以不同的時間間隔運(yùn)行),可以每個任務(wù)都使用一個定時器。
但:浪費(fèi)硬件資源(或者不夠用)、硬件的維護(hù)增加、會同時產(chǎn)生多個定時器中斷。——不合理
解決方案:使用調(diào)度器
● 調(diào)度器可以看作是一個簡單的操作系統(tǒng),允許以周期性或單次方式來調(diào)用任務(wù)。
● 從底層的角度來看,調(diào)度器可以看作是一個由許多不同任務(wù)共享的定時器中斷服務(wù)程序。
用調(diào)度器來調(diào)度三個任務(wù)的執(zhí)行:
void main(void)
{
SCH_Init(); // 設(shè)置調(diào)度器一次
/*---- 增加各任務(wù)至任務(wù)隊(duì)列(時間分辨率為1ms)----*/
// Function_A將每隔2ms運(yùn)行一次
SCH_Add_Task(Function_A, 0, 2);
// Function_B將每隔10ms運(yùn)行一次
SCH_Add_Task(Function_B, 1, 10);
// Function_C將每隔15ms運(yùn)行一次
SCH_Add_Task(Function_C, 3, 15);
SCH_Start(); // 啟動調(diào)度
while(1)
{
// 按調(diào)度算法執(zhí)行任務(wù)隊(duì)列中各任務(wù)
SCH_Dispatch_Tasks();
}
}
調(diào)度器的分類
● 合作式調(diào)度器
● 搶占式調(diào)度器
合作式調(diào)度器:
● 任務(wù)在特定的時刻被調(diào)度運(yùn)行(以周期性或單次方式)
● 當(dāng)任務(wù)需要運(yùn)行時,被添加到等待隊(duì)列
● 當(dāng)CPU空閑時,運(yùn)行等待任務(wù)中的下一個(如果有的話)
● 前一任務(wù)運(yùn)行直到完成,才輪到下一個等待任務(wù)
● 簡單,用少量代碼即可實(shí)現(xiàn)
● 一次只為一個任務(wù)分配存儲器
● 通常完全由高級語言如C實(shí)現(xiàn)
● 小心設(shè)計(jì)可以實(shí)現(xiàn)快速響應(yīng)外部事件
● 簡單、可預(yù)測、可靠并且安全
搶占式調(diào)度器:
● 任務(wù)在特定的時刻被調(diào)度運(yùn)行(以周期性或單次方式)
● 當(dāng)任務(wù)需要運(yùn)行時,被添加到等待隊(duì)列
● 等待的任務(wù)運(yùn)行一段固定的時間,如果沒有完成,將被暫停并放回到等待隊(duì)列。然后下一個等待任務(wù)(如果有的話)將運(yùn)行一段固定的時間。
● 高優(yōu)先級的任務(wù)可以搶占低優(yōu)先級任務(wù)優(yōu)先運(yùn)行
● 復(fù)雜,“并行處理的”任務(wù)試圖訪問公用資源時需避免沖突等
● 必須為被搶占任務(wù)的所有中間狀態(tài)分配存儲器
● 通常(至少是部分)由匯編語言編寫
● 對外部事件響應(yīng)快
● 與合作式調(diào)度比,通常認(rèn)為其更不可預(yù)測、并且可靠性較低
混合式調(diào)度器:
● 支持多個合作式調(diào)度的任務(wù)文章來源:http://www.zghlxwxcb.cn/news/detail-740066.html
● 支持一個搶占式任務(wù)(可以“中斷”合作式任務(wù))文章來源地址http://www.zghlxwxcb.cn/news/detail-740066.html
到了這里,關(guān)于【小黑嵌入式系統(tǒng)第六課】嵌入式系統(tǒng)軟件設(shè)計(jì)基礎(chǔ)——C語言簡述、程序涉及規(guī)范、多任務(wù)程序設(shè)計(jì)、狀態(tài)機(jī)建模(FSM)、模塊化設(shè)計(jì)、事件觸發(fā)、時間觸發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!