久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

uC/OS II 學(xué)習(xí)筆記

作者:佚名   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年08月18日   【字體:

 uC/OS II 提供給用戶通用接口函數(shù)都在Ucos_ii.h中【uC/GUI 提供給用戶通用接口函數(shù)都在INC包含的各個(gè)頭文件中,使用時(shí)參考官方的手冊(cè)用就好了,有中文版的】;

 
INT8U  const  OSUnMapTbl[256] = {
    0u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    7u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    6u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    5u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
    4u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u 
}
【這個(gè)表的通俗用法就是 給出 給任意一個(gè)長(zhǎng)度不超過(guò)8位的二進(jìn)制值a, 將這個(gè)a做為該數(shù)組的索引, OSUnMapTb[a]就表示二進(jìn)制值a中第一個(gè)位1出現(xiàn)的位置】
 
這個(gè)數(shù)組 索引值  0~255
即通過(guò)這個(gè)數(shù)組 可以直接獲取0~255各值的二進(jìn)制形式從右到左第一次出現(xiàn)1的位置
 
Ucosii 中任務(wù)的優(yōu)先級(jí)管理方法(假設(shè)最多64個(gè)任務(wù)):
因?yàn)?/span>OSUnMapTbl256個(gè)元素,也就是索引是8位的二進(jìn)制值,這個(gè)索引的每一位的0 1 值代表的是對(duì)應(yīng)的任務(wù)是否就緒;
因此管理任務(wù)的最小單位為INT8U(也就是8個(gè)任務(wù)用8個(gè)位來(lái)組成一個(gè)INT8U);
依次類推:可用一個(gè)INT8U來(lái)表示某個(gè)最小單元中是否有就緒態(tài)的任務(wù)(即該INT8U是否為0
這樣就是 8X8 = 64個(gè)任務(wù);
依次往上類推,8X8X….X8,理論上在空間足夠的情況下可以管理無(wú)限個(gè)任務(wù);
具體的優(yōu)先級(jí)值的算法就是:
  y = OSUnMapTbl[OSRdyGrp];
  OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);
其實(shí)Ucosii 任務(wù)數(shù)大于64個(gè)時(shí),他是16個(gè)任務(wù)為一組,組成INT16U來(lái)管理的
同樣往上推,也是16組來(lái)管理的
16X16
if ((*ptbl & 0xFFu) != 0u) {
     //如果低8位不為0,都不用考慮高8位了,直接在低8位中去尋找第一次出現(xiàn)1的地方
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]);
} else {
//如果低8位為0,直接在高8位中去尋找第一次出現(xiàn)1的地方,然后加8 就表示整個(gè)16位的INT16U中第一次出現(xiàn)1的地方
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u);
    }

一個(gè)任意長(zhǎng)度的二進(jìn)制值(n位),我們都可以將這個(gè)n位化成m個(gè)段,用一個(gè)2的m次方個(gè)成員的數(shù)組 去存放他的特征值。代碼中可以以m位為單位求得特征值。
編程技巧,比如在用一個(gè)int(32位)的整數(shù)的30位的各個(gè)位的置位來(lái)表示對(duì)于的消息到來(lái),且0-30位,優(yōu)先級(jí)一次降低...
假如某個(gè)時(shí)刻同時(shí)來(lái)了很多個(gè)消息,很多位置1,那么怎么來(lái)獲取這時(shí)優(yōu)先級(jí)最高的捏?
就用上面的方法舉一反三
我們可以一次處理 用一個(gè)16個(gè)單元的數(shù)組,
a[16] = {}; 來(lái)存放 4位 二進(jìn)制能表示的16個(gè)數(shù)字 中 各數(shù)第一位出現(xiàn)1的位置,
每4位 4位依次處理, 就可以利用該數(shù)組快速獲取最高優(yōu)先級(jí)的消息....
 
//這里用了一個(gè)很小的數(shù)組,來(lái)處理
//這里GetOnePos 的算法 對(duì)于 很多位的大數(shù)值來(lái)說(shuō),可能效率不高,但是對(duì)于 只有4位的值來(lái)說(shuō),就是很快了
//其實(shí)這里只是一個(gè)簡(jiǎn)單的例子而已,ucos中用的是8 位  也就是256個(gè)值的數(shù)組,
//這個(gè)就看你的需求,你來(lái)選擇了具體的數(shù)組的大小了, 看具體的情況來(lái) 用時(shí)間 換 空間, 或用空間換時(shí)間
unsigned int g_unHighPrio[16] = 
{
0u, 0u, 1u, 0u, 2u, 0u, 1u, 0u, 3u, 0u, 1u, 0u, 2u, 0u, 1u, 0u,
};
 
char GetOnePos(int data)
{
if(data & 0x0000000F)
{
return(0 + g_unHighPrio[(data & 0x0000000F)>>0]);
else if(data & 0x000000F0)
{
return(4 + g_unHighPrio[(data & 0x000000F0)>>4]);
}
else if(data & 0x00000F00)
{
return(8 + g_unHighPrio[(data & 0x00000F00)>>8]);
}
else if(data & 0x0000F000)
{
return(12 + g_unHighPrio[(data & 0x0000F000)>>12]);
}
else if(data & 0x000F0000)
{
return(16 + g_unHighPrio[(data & 0x000F0000)>>16]);
}
else if(data & 0x00F00000)
{
return(20 + g_unHighPrio[(data & 0x00F00000)>>20]);
}
else if(data & 0x0F000000)
{
return(24 + g_unHighPrio[(data & 0x0F000000)>>24]);
}
else if(data & 0xF0000000)
{
return(28 + g_unHighPrio[(data & 0xF0000000)>>28]);
}
else
{
return 0;
}
}
 
int main(void)
{
unsigned int nTst = 0;
int npos = 0; 
while(1)
{
nTst = 0;
printf("Input Tst = ");
scanf("%u",&nTst);
printf("The First 1 position is %d\n",GetOnePos(nTst));
getchar();
}
}
 
 
 
實(shí)時(shí)操作系統(tǒng)RTOS
實(shí)時(shí)操作系統(tǒng)包括軟實(shí)時(shí)與硬實(shí)時(shí),軟實(shí)時(shí)要求各個(gè)任務(wù)盡快地運(yùn)行,而不要求限定某一個(gè)任務(wù)在多長(zhǎng)的時(shí)間內(nèi)完成,而硬實(shí)時(shí)系統(tǒng)不僅須執(zhí)行無(wú)誤而且要做到準(zhǔn)時(shí),需要在規(guī)定的時(shí)間內(nèi)完成相關(guān)操作
大多數(shù)實(shí)時(shí)系統(tǒng)是兩者的綜合;
非實(shí)時(shí)操作系統(tǒng)指操作系統(tǒng)無(wú)法保證哪怕是最高優(yōu)先級(jí)任務(wù)開(kāi)始執(zhí)行的最后時(shí)限。軟實(shí)時(shí)操作系統(tǒng)指的是操作系統(tǒng)只能保證在xx時(shí)間內(nèi)執(zhí)行最高優(yōu)先級(jí)的用戶代碼,但用戶軟件是否能及時(shí)完成操作,操作系統(tǒng)不管!
RTlinux就是linux的硬實(shí)時(shí)操作系統(tǒng),它能夠創(chuàng)建精確運(yùn)行的符合POSIX.1B標(biāo)準(zhǔn)的實(shí)時(shí)進(jìn)程;
 
并非所有的嵌入式系統(tǒng)都需要實(shí)時(shí)操作系統(tǒng),只有在一些特定的場(chǎng)合,對(duì)時(shí)間比較敏感的應(yīng)用才會(huì)使用實(shí)時(shí)操作系統(tǒng)。實(shí)時(shí)操作系統(tǒng)必須及時(shí)響應(yīng)所要求的任務(wù),在限定時(shí)間內(nèi)完成任務(wù)。非實(shí)時(shí)的操作系統(tǒng),多時(shí)間不是很敏感,對(duì)所要求的任務(wù)只是會(huì)保證完成,但在什么時(shí)候完成,或用多長(zhǎng)的時(shí)間完成就不一定了。例如:手機(jī)它不需要實(shí)時(shí)性。我們發(fā)短信時(shí),系統(tǒng)對(duì)它的處理早1秒或者晚1秒都不會(huì)影響到我們的使用。而對(duì)于導(dǎo)彈這樣的應(yīng)用必須具有實(shí)時(shí)性。導(dǎo)彈被發(fā)射出去鎖定目標(biāo)后要不斷修正飛行方向,以保證擊中目標(biāo),如果它的實(shí)時(shí)性不好的話,從傳感器傳來(lái)的信號(hào)沒(méi)有及時(shí)響應(yīng),即使完了1毫秒的時(shí)間,那誤差就會(huì)很大。用這樣的導(dǎo)彈攻打敵方目標(biāo)的話,目標(biāo)很可能沒(méi)有擊中,美國(guó)大使館倒是有可能被炸掉。
另外一般linux不具有實(shí)時(shí)性,它是分時(shí)操作系統(tǒng)一般是面向用戶的,但是因?yàn)樗脑创a是公開(kāi)的,它是可以改造成實(shí)時(shí)系統(tǒng)的,但即使是這樣它的實(shí)時(shí)性也不會(huì)很好,畢竟它最初的設(shè)計(jì)并不是為了實(shí)時(shí)性。我們?cè)贚inux上面同時(shí)運(yùn)行好幾個(gè)程序,它們會(huì)被并發(fā)的執(zhí)行。我們會(huì)發(fā)現(xiàn)同時(shí)多運(yùn)行幾個(gè)程序可能會(huì)比只允許一個(gè)程序慢,這是因?yàn)椴僮飨到y(tǒng)把處理器按時(shí)間片分給了每一個(gè)程序。自然會(huì)慢一些。而實(shí)時(shí)操作系統(tǒng),一般不同的任務(wù)會(huì)有不同的優(yōu)先級(jí),他會(huì)把擁有最高的優(yōu)先級(jí)的程序一次性執(zhí)行完畢。然后再執(zhí)行次一級(jí)的程序。這樣的系統(tǒng)只適用于控制,不適合一般的應(yīng)用。
 
任務(wù)劃分
目標(biāo):
    滿足實(shí)時(shí)性要求;
    任務(wù)數(shù)目合理;-->合理使用系統(tǒng)的軟硬件資源
    簡(jiǎn)化軟件系統(tǒng);-->合理規(guī)劃任務(wù),降低對(duì)操作系統(tǒng)的服務(wù)要求,使操作系統(tǒng)功能得到裁剪,簡(jiǎn)化系統(tǒng)
    降低資源需求;
   目前,各功能單獨(dú)成立為一個(gè)任務(wù),比如顯示功能成為顯示任務(wù),文件系統(tǒng)通過(guò)一個(gè)任務(wù)來(lái)管理,這樣文件系統(tǒng)任務(wù)要顯示時(shí),就向顯示任務(wù)的消息隊(duì)列里面發(fā)送顯示消息,而不是直接在本任務(wù)中調(diào)用顯示函數(shù)。
0:設(shè)備依賴性任務(wù)的劃分
從系統(tǒng)的結(jié)構(gòu)框圖中,我們可以看到系統(tǒng)的輸入輸出各個(gè)設(shè)備。并發(fā)性是任務(wù)的基本特性,而控制輸出、輸出的設(shè)備的程序具有先天的并發(fā)性,把他們分別封裝為不同的任務(wù)是合理的,這樣就可以劃分出第一批任務(wù),鍵盤(pán)任務(wù),顯示任務(wù),數(shù)據(jù)采集任務(wù),控制輸出任務(wù)和通信任務(wù)。
1:系統(tǒng)關(guān)鍵任務(wù)劃分:關(guān)鍵是指某種功能在應(yīng)用系統(tǒng)中的重要性,如果該功能不能正常實(shí)現(xiàn),則將造成重大影響,甚至引發(fā)災(zāi)難性的后果;包含該關(guān)鍵功能的任務(wù)為關(guān)鍵任務(wù),關(guān)鍵任務(wù)必須得到運(yùn)行機(jī)會(huì)即使遺漏一次也不行; 對(duì)于關(guān)鍵功能,必須盡可能與其他的功能剝離,獨(dú)立成為一個(gè)任務(wù),通過(guò)通信的方式再觸發(fā)其他的任務(wù),完成后續(xù)操作。例如:火災(zāi)檢測(cè)系統(tǒng)中,煙霧傳感器的檢測(cè)功能就是一個(gè)關(guān)鍵功能,必須將其與其他的報(bào)警、滅火等功能剝離。OSMboxPostOpt()消息發(fā)送函數(shù),具有廣播功能:  O在uC/OS II的較新版本中,消息發(fā)送函數(shù)OSMboxPostOpt()具有廣播功能,發(fā)送一條消息就可以使所有等待該消息的任務(wù)進(jìn)入就緒狀態(tài)。
2:緊迫任務(wù)劃分:某種功能必須在規(guī)定的時(shí)間內(nèi)得到運(yùn)行權(quán)(及時(shí)運(yùn)行),并在規(guī)定的時(shí)刻前執(zhí)行完畢(按時(shí)完成),這類功能有嚴(yán)格的實(shí)時(shí)性要求。大多數(shù)的緊迫任務(wù)是通過(guò)異步事件來(lái)觸發(fā),這些異步事件一般能夠引發(fā)某種中斷。在這種情況下,將緊迫任務(wù)安排在相應(yīng)的ISR中是最有效的辦法,如果不能安排在中斷任務(wù)中,那么可竟盡可能提高優(yōu)先級(jí)來(lái)解決“及時(shí)性”。對(duì)于按時(shí)完成,需要對(duì)緊迫任務(wù)進(jìn)行瘦身,盡可能剝離不太緊迫的操作,只剩下必須立刻做的操作,被剝離的不太緊迫的操作另外封裝成一個(gè)任務(wù)。例如:能譜分析儀,緊迫任務(wù)放在外部中斷服務(wù)程序中,完成對(duì)脈沖峰值的采樣,并將采樣結(jié)果放入消息隊(duì)列中。緊迫任務(wù)不一定是關(guān)鍵任務(wù),所以遺漏一兩次執(zhí)行會(huì)導(dǎo)致工作品質(zhì)下降,但是不會(huì)造成嚴(yán)重后果。
3:數(shù)據(jù)處理任務(wù)劃分:用戶程序中消耗時(shí)間最多的是各種數(shù)據(jù)處理程序單元,這些單元不止一個(gè),且分別為不同的功能服務(wù);所以需要將他們劃分出來(lái),分別包裝為不同的任務(wù),因?yàn)樗麄兊奶幚磔^耗時(shí),所以他們的優(yōu)先級(jí)須安排低,這樣讓他們使用其他任務(wù)的剩余時(shí)間來(lái)進(jìn)行數(shù)據(jù)處理(如果有時(shí)間片輪轉(zhuǎn),可以安排他們?yōu)橥粌?yōu)先級(jí),利用時(shí)間片來(lái)輪轉(zhuǎn)他們)。模擬時(shí)間片輪轉(zhuǎn):假如有3個(gè)數(shù)據(jù)處理任務(wù)A、B、C;我們可以將他們細(xì)分為A1、A2、A3,B1、B2、B3,C1、C2、C3,再交叉安排優(yōu)先級(jí)就可以了。A1->1,B1->2,C1->3,A2->4,B2->5...
4:功能聚合任務(wù)劃分:將關(guān)系密切的若干功能組合為一個(gè)任務(wù),達(dá)到功能聚合的效果,關(guān)系密切:數(shù)據(jù)關(guān)聯(lián)和時(shí)序關(guān)聯(lián),如果他們分開(kāi),有可能會(huì)使用大量的通信資源,造成較大的負(fù)擔(dān)。
5:觸發(fā)條件相同的任務(wù)劃分
如果若干個(gè)功能由相同的事件觸發(fā),則可以將這些功能組合成為一個(gè)任務(wù),從而免除將事件分發(fā)給多個(gè)任務(wù)的工作量。這樣做的條件是:當(dāng)以某順序執(zhí)行這些功能時(shí),各個(gè)功能的實(shí)時(shí)性要求仍然可以得到滿足,且各個(gè)功能在執(zhí)行過(guò)程中不會(huì)出現(xiàn)問(wèn)題,例如:火警檢測(cè)系統(tǒng)中,撥打電話、啟動(dòng)噴淋滅火系統(tǒng)、保持火警記錄,這些任務(wù)是不能合在一起做為一個(gè)任務(wù)的,否則其中一些功能有誤其他的任務(wù)就會(huì)被耽擱。
符合本類任務(wù)的通常是內(nèi)部事件,例如通過(guò)運(yùn)算處理產(chǎn)生某個(gè)結(jié)果,根據(jù)這個(gè)結(jié)果需要執(zhí)行若干功能,這些功能可組合為一個(gè)任務(wù)。
6:運(yùn)行周期相同的任務(wù)劃分
絕大多數(shù)功能都需要不停的重復(fù)執(zhí)行,如果重復(fù)執(zhí)行的條件是固定的時(shí)間間隔,則這個(gè)功能具有周期性。將周期相同的功能組合在一起封裝為一個(gè)任務(wù),就可以避免一個(gè)時(shí)間事件觸發(fā)幾個(gè)任務(wù),省去事件分發(fā)操作和他們的之間的通信。
7:順序操作任務(wù)劃分
如果若干個(gè)功能按固定的順序運(yùn)行流水作業(yè),相互之間完全沒(méi)有并發(fā)現(xiàn),則應(yīng)該將這個(gè)功能組合為一個(gè)任務(wù)。

任務(wù)設(shè)計(jì)
任務(wù)函數(shù)結(jié)構(gòu)
所設(shè)計(jì)的任務(wù)函數(shù)至少有一次對(duì)操作系統(tǒng)服務(wù)函數(shù)的調(diào)用,這樣才能讓低優(yōu)先級(jí)的任務(wù)得到執(zhí)行。
1:?jiǎn)未螆?zhí)行的任務(wù)
任務(wù)創(chuàng)建后,得到執(zhí)行,執(zhí)行完畢后自我刪除;任務(wù)基本分為三大部分:1:準(zhǔn)備工作代碼(定義變量以及初始化工作)2:任務(wù)實(shí)體代碼(完成具體的功能,一般都可以被中斷)3:調(diào)用刪除函數(shù)。例如啟動(dòng)任務(wù)(如果采用啟動(dòng)任務(wù)去啟動(dòng)各個(gè)任務(wù),那啟動(dòng)任務(wù)的優(yōu)先級(jí)需要比它創(chuàng)建的任務(wù)的優(yōu)先級(jí)高,一般系統(tǒng)中通常將啟動(dòng)任務(wù)所做的事情交給系統(tǒng)的一個(gè)實(shí)質(zhì)任務(wù)去做,節(jié)省資源);
采用“創(chuàng)建任務(wù)”的方式來(lái)啟動(dòng)任務(wù),不僅可以省去通常的通信手段激活任務(wù)的麻煩,還可以通過(guò)*pdata來(lái)傳遞參數(shù),是沒(méi)有啟動(dòng)具有不同的工作狀態(tài)(比如串口波特率),但是這樣的話實(shí)時(shí)性會(huì)比較差,每一次任務(wù)的啟動(dòng)都需要?jiǎng)?chuàng)建,發(fā)費(fèi)較多的時(shí)間,還有可能在刪除時(shí)引起不必要的后遺癥(如共享資源釋放、任務(wù)關(guān)聯(lián));
所以通過(guò)“創(chuàng)建任務(wù)”來(lái)啟動(dòng)的任務(wù)一般是孤立的任務(wù),他們不和其他的任務(wù)進(jìn)行通信(ISR除外),只使用共享資源來(lái)獲取信息和輸出信息。
2:周期性執(zhí)行的任務(wù) 
周期性執(zhí)行的任務(wù),通常在代碼中調(diào)用系統(tǒng)延時(shí)函數(shù),OSTimeDly或OSTimeDlyHMSM來(lái)調(diào)整執(zhí)行周期。但是這兩個(gè)函數(shù)有延時(shí)誤差,至少有一個(gè)或小于一個(gè)時(shí)鐘節(jié)拍的誤差,如需精確的定時(shí)需采用獨(dú)立的定時(shí)器。
3:事件觸發(fā)執(zhí)行的任務(wù)
任務(wù)的實(shí)體代碼的執(zhí)行需要等待某種事件的發(fā)生,在相關(guān)事件發(fā)生之前,任務(wù)被掛起,相關(guān)事件發(fā)生一次,任務(wù)執(zhí)行一次。當(dāng)觸發(fā)條件是“時(shí)間間隔”(定時(shí)器觸發(fā))時(shí),它既是周期任務(wù)。
如觸發(fā)條件是某個(gè)信號(hào)(信號(hào)量等),那么這個(gè)觸發(fā)條件僅僅是觸發(fā)任務(wù)的執(zhí)行。
如觸發(fā)條件是某個(gè)信息(郵箱等),那么這個(gè)觸發(fā)條件除了啟動(dòng)該任務(wù)外,還為任務(wù)提供原始數(shù)據(jù)和資料。
任務(wù)優(yōu)先級(jí)安排
uC/OS II共有64個(gè)優(yōu)先級(jí):0~63。在OS_CFG.h中設(shè)置OS_LOWEST_PRIO來(lái)確定系統(tǒng)實(shí)際使用的優(yōu)先級(jí)范圍,#define OS_LOWEST_PRIO  18 ->系統(tǒng)裁剪到只有19個(gè)優(yōu)先級(jí),節(jié)省資源開(kāi)銷。
OS_LOWEST_PRIO-->空閑任務(wù);     OS_LOWEST_PRIO-1-->統(tǒng)計(jì)任務(wù);
OS_LOWEST_PRIO-2-->系統(tǒng)保留;   OS_LOWEST_PRIO-3-->系統(tǒng)保留;
系統(tǒng)最高的4個(gè)優(yōu)先級(jí)(0、1、2、3)保留。
任務(wù)優(yōu)先級(jí)安排原則
中斷關(guān)聯(lián)性、緊迫性、關(guān)鍵性、頻繁性、快捷性、傳遞性
 
uC/OS II通信機(jī)制
uC/OS II通信機(jī)制包括有信號(hào)量(計(jì)數(shù))、互斥信號(hào)量(可以高低優(yōu)先級(jí)翻轉(zhuǎn))、事件標(biāo)志組、郵箱、消息隊(duì)列;
所有的通信機(jī)制都有5種功能函數(shù):創(chuàng)建、刪除、查詢、發(fā)送、(掛起式)獲取、(不掛起、不等待式)獲取;
且一旦某個(gè)通信制作被使用,其創(chuàng)建、發(fā)送、(掛起式)獲取功能是不能被裁剪的;
中斷函數(shù)需要盡可能短,實(shí)時(shí)性高,在中斷中,可以發(fā)送信號(hào),其他的不要用。
除了事件標(biāo)志組用OS_FLAG_GRP結(jié)構(gòu)體表示外,其余的通信方式都使用OS_EVENT結(jié)構(gòu)體表示;
typedef struct os_event {
    INT8U    OSEventType;                    //通信事件的類型
    void    *OSEventPtr;                     //郵箱或消息隊(duì)列中指向消息實(shí)體的指針
    INT16U   OSEventCnt;                     //計(jì)數(shù)單元
    INT8U    OSEventGrp;                     //等待該通信事件的任務(wù)所在的組
    INT8U    OSEventTbl[OS_EVENT_TBL_SIZE];  //等待該通信事件的任務(wù)列表
} OS_EVENT;
1:信號(hào)量(計(jì)數(shù)型)sem
信號(hào)量是一個(gè)可被多個(gè)進(jìn)程共享的數(shù)據(jù)結(jié)構(gòu),主要用于任  
務(wù)間少量的信息通信。信號(hào)量通常是在多個(gè)任務(wù)訪問(wèn)一個(gè)共同的但
非共享的資源的情況下,用于同步各個(gè)任務(wù)之間的操作。
OS_EVENT *pevnt;
pevnt = OSSemCreate(int cnt);//創(chuàng)建并賦初值
OSsemPost(pevnt );
OSEventCnt>0表示該信號(hào)有效(且表示事件發(fā)生的次數(shù)),OSEventCnt==0表示該信號(hào)無(wú)效;
任務(wù)調(diào)用OSsemPost(pevnt),表示計(jì)數(shù)型信號(hào)量事件的OS_EVENT結(jié)構(gòu)體中的OSEventCnt++;
任務(wù)調(diào)用OSSemPend(pevnt),如果此時(shí)OSEventCnt>0,則OSEventCnt--,且該任務(wù)接著繼續(xù)往下執(zhí)行;否則該任務(wù)掛起(再進(jìn)行一次任務(wù)切換),直到該事件發(fā)生(OSEventCnt>0)且此時(shí)系統(tǒng)中該任務(wù)的優(yōu)先級(jí)最高方可得到運(yùn)行;
任務(wù)調(diào)用OSSemAccept(pevnt),如果此時(shí)OSEventCnt>0,則OSEventCnt--,且不論OSEventCnt的值是多少,該函數(shù)直接返回OSEventCnt的值,return(cnt);
任務(wù)調(diào)用OSSemQuery(OS_EVENT *, OS_SEM_DATA),OS_SEM_DATA是一個(gè)精簡(jiǎn)的OS_EVENT結(jié)構(gòu)體,用來(lái)記錄被查詢信號(hào)量的計(jì)數(shù)值、任務(wù)等待列表等;
任務(wù)調(diào)用OSSemDel(pevnt )刪除信號(hào)量;起初分配的OS_EVENT結(jié)構(gòu)體被釋放到空閑事件鏈表中;
2:互斥信號(hào)量mutex
在訪問(wèn)比較耗時(shí)的共享資源時(shí),如果采用關(guān)中斷的方法(系統(tǒng)此時(shí)不能被中斷、任務(wù)不能被切換)來(lái)實(shí)現(xiàn)訪問(wèn)沖突,這對(duì)中斷的響應(yīng)是很不好的,所以這時(shí)采用互斥型信號(hào)量就可以很好的解決問(wèn)題,同時(shí)可以響應(yīng)中斷。
互斥鎖用來(lái)實(shí)現(xiàn)任務(wù)之間的簡(jiǎn)單同步,一個(gè)互斥鎖是一個(gè)  
二元信號(hào)量,它的狀態(tài)只能是0(允許,開(kāi)鎖)和1(禁止,上鎖)。
   
在互斥鎖范圍內(nèi),任何一個(gè)任務(wù)都可以對(duì)互斥負(fù)上鎖,但只有鎖住
   
該信號(hào)的任務(wù)才能開(kāi)鎖從而實(shí)現(xiàn)了任務(wù)同步。
mutex不同于sem,mutex是一個(gè)互斥型信號(hào)量,它可以通過(guò)在應(yīng)用程序中翻轉(zhuǎn)任務(wù)的優(yōu)先級(jí)來(lái)解決資源互鎖的問(wèn)題;
舉例:首先給一塊共享資源配備一個(gè)互斥型信號(hào)量Mutex,系統(tǒng)中有兩個(gè)任務(wù)A、B,他們的優(yōu)先級(jí)分別為5,6;
假設(shè)B先運(yùn)行,并通過(guò)OSMutexPend申請(qǐng)到了Mutex,那么它就會(huì)使用該共享資源繼續(xù)運(yùn)行,在某個(gè)時(shí)刻,任務(wù)A搶占了任務(wù)B,同時(shí)也通過(guò)OSMutexPend申請(qǐng)Mutex,由于資源已經(jīng)被B占用,那么OSMutexPend會(huì)將B任務(wù)的優(yōu)先級(jí)調(diào)高到4(假設(shè)),這時(shí)任務(wù)B得意繼續(xù)運(yùn)行,資源使用完畢后釋放mutex。OSMutexPost注意到原來(lái)占有這個(gè)mutex的任務(wù)的優(yōu)先級(jí)被調(diào)高了,于是將B的優(yōu)先級(jí)調(diào)低,同時(shí)注意到A在申請(qǐng),于是將mutex給A,做任務(wù)切換后A得以執(zhí)行。
由于互斥型信號(hào)量的特性,互斥型信號(hào)量只能由于任務(wù)中(包括發(fā)送功能);
OS_EVENT *ResourceMutex;
ResourceMutex= OSMutexCreate(INT8U prio,&err);//在上述情況中 任務(wù)可以被調(diào)高到prio指定的優(yōu)先級(jí)
OS_EVENT中,pevent->OSEventCnt = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE(0xff);
高八位:PIP;低八位:占用該互斥信號(hào)量的任務(wù)的優(yōu)先級(jí)(若為0xff表示無(wú)任務(wù)占用該信號(hào)量);
OSMutexPend(ResourceMutex,..,..):在訪問(wèn)共享資源時(shí),先通過(guò)該函數(shù)獲取互斥型信號(hào)量,如果互斥型信號(hào)量是有效的(沒(méi)有被占用),則該Mutex的OSEventCnt的低八位為0xff,如果已被占用,則低八位為占用該信號(hào)量的任務(wù)的優(yōu)先級(jí);如果占用該信號(hào)量的任務(wù)的優(yōu)先級(jí)比調(diào)用該申請(qǐng)函數(shù)的任務(wù)的信號(hào)量的優(yōu)先級(jí)低,此時(shí)低優(yōu)先級(jí)的任務(wù)占用共享資源,且已被高優(yōu)先級(jí)的任務(wù)搶占了CPU,此時(shí)高優(yōu)先級(jí)的任務(wù)再調(diào)用OSMutexPend申請(qǐng)互斥量,OSMutexPend內(nèi)部會(huì)將占用mutex的低優(yōu)先級(jí)的任務(wù)的優(yōu)先級(jí)調(diào)高到信號(hào)量指定的PIP,這樣來(lái)讓低優(yōu)先級(jí)的任務(wù)變?yōu)楦邇?yōu)先級(jí),盡快釋放資源;
3:事件標(biāo)志組event flag
typedef struct os_flag_grp {                
    INT8U         OSFlagType;               //事件類型
    void         *OSFlagWaitList;           //等待該事件標(biāo)志組的任務(wù)列表
    OS_FLAGS      OSFlagFlags;              //事件標(biāo)志組標(biāo)志位
} OS_FLAG_GRP;
事件標(biāo)志組用于實(shí)現(xiàn)多個(gè)任務(wù)(包括ISR)協(xié)同控制一個(gè)任務(wù),當(dāng)各個(gè)相關(guān)任務(wù)(ISR)先后發(fā)出自己的信號(hào)后(使事件標(biāo)志組的對(duì)應(yīng)標(biāo)志位有效),預(yù)定的邏輯運(yùn)算結(jié)果有效,這時(shí)將觸發(fā)被控制的任務(wù)(使其進(jìn)去就緒態(tài))。
事件標(biāo)志組可以選擇標(biāo)志位1有效或0有效,邏輯關(guān)系可以為“邏輯與”或“邏輯或”,這樣有效定義與邏輯定義有4種組合,同時(shí)也可以設(shè)定只選擇使用所有標(biāo)志位中的其中幾位;
OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags,INT8U *err);
flags為事件標(biāo)志組中各個(gè)標(biāo)志的初始值(1有效時(shí),初始值為0);
發(fā)送標(biāo)志到事件標(biāo)志組:
OS_FLAGS  OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *perr)
pgrp:事件標(biāo)志組指針;flags:指明待發(fā)送標(biāo)志在事件標(biāo)志組中的位置(0x1表示bit0);opt:選擇操作的方式,OS_FLAG_SET(對(duì)標(biāo)志位置1),OS_FLAG_CLR(對(duì)標(biāo)志位置0);perr:執(zhí)行結(jié)果;
等待事件標(biāo)志組:
OS_FLAGS  OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *perr)
pgrp:事件標(biāo)志組指針;flags:指明哪些標(biāo)志位用來(lái)等待,0x03(bit0、1),0x1d(bit0、2、3、4)opt:指明對(duì)這些等待的位采用的邏輯運(yùn)算perr:執(zhí)行結(jié)果;
opt如下:
OS_FLAG_WAIT_CLR_ALL:所以標(biāo)志位為0時(shí),將等待任務(wù)就緒;
OS_FLAG_WAIT_CLR_ANY任何一個(gè)標(biāo)志位清0時(shí),將等待任務(wù)就緒;
OS_FLAG_WAIT_SET_ALL:所以標(biāo)志位為1時(shí),將等待任務(wù)就緒;
OS_FLAG_WAIT_SET_ANY:任何一個(gè)標(biāo)志位為1時(shí),將等待任務(wù)就緒;
OS_FLAG_CONSUME:清除標(biāo)志位(OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME
4:消息郵箱box
郵箱是μC/OS-II中另一種通訊機(jī)制,它可以使一個(gè)任務(wù)或者中斷服務(wù)子程序向另一個(gè)任務(wù)發(fā)送一個(gè)指針型的變量。該指針指向一個(gè)包含了特定“消息”的數(shù)據(jù)結(jié)構(gòu)。
用信號(hào)量進(jìn)行行為同步時(shí),只能提供同步的時(shí)刻信息,不能提供內(nèi)容信息;
當(dāng)控制方在對(duì)被控制方進(jìn)行控制的同時(shí),還需要向被控制方提供內(nèi)容信息時(shí),消息郵箱是一個(gè)有效的方案;
由于消息郵箱中只能存儲(chǔ)一條消息,在用消息郵箱進(jìn)行同步控制時(shí),必須滿足一個(gè)前提:任何時(shí)候消息的生產(chǎn)速度都比消息的消費(fèi)速度慢,即被控制的任務(wù)總是在等待消息;否則就會(huì)有消息丟失;
消息郵箱中可以放入任何類型的信息,通常用空郵箱(void * 0)表示事件沒(méi)有發(fā)生;用非空郵箱(void * 1)表示事件已發(fā)生;因此郵箱也可以用來(lái)做二值信號(hào)量(注意與互斥信號(hào)量的區(qū)別);
郵箱用OS_EVENT結(jié)構(gòu)體中的OSEventPtr指向消息實(shí)體;
OS_EVENT *pbox;
pbox= OSMBoxCreate(void *msg);//void * 0表示空郵箱
INT8U OSMboxPost(pbox, void * msg);//向郵箱中發(fā)送一條消息
INT8U OSMboxPostOpt(pbox,void * msg, INT8U opt)//分發(fā)消息,將消息分發(fā)給所有正在等待該消息的任務(wù),讓他們都處于就緒態(tài)
void *OSMboxPend(pbox,timeout,INT8U *err)//等待消息 當(dāng)郵箱中的指針為空時(shí),調(diào)用等待消息函數(shù)后就會(huì)被系統(tǒng)掛起。
5:消息隊(duì)列
將要通信的信息放置在一個(gè)預(yù)定義的消息結(jié)構(gòu)中,任務(wù)生成的消息指定了消息的類型,并把它放在一個(gè)由系統(tǒng)負(fù)責(zé)維護(hù)的消息隊(duì)列中,而訪問(wèn)消息隊(duì)列的任務(wù)可以根據(jù)消息類型,有選擇地從隊(duì)列中按FIFO的方式讀取特定類型的消息。消息隊(duì)列為用戶提供了從多個(gè)生產(chǎn)者中獲得多元信息的一種手段。
相當(dāng)于一個(gè)郵箱隊(duì)列,消息隊(duì)列可以存放多個(gè)消息,能夠有效解決消息的臨時(shí)堆積問(wèn)題。和計(jì)數(shù)信號(hào)量的情況類似,消息隊(duì)列的使用仍然需要滿足:消費(fèi)速度比生產(chǎn)速度快,否則再大的隊(duì)列也會(huì)滿,從而溢出;
void *MyArrayOfMsg[SIZE];
OS_EVNT *pQ;
pQ=OSQCreate(MyArrayOfMsg,SIZE); 
INT8U OSQPost(pQ,void *Msg)//發(fā)送一條消息
void *OSQPend(pQ,0,&err)//當(dāng)消息隊(duì)列為空時(shí) 掛起


【各個(gè)通信機(jī)制都要無(wú)等待式獲取相關(guān)的信號(hào),均可用在中斷中,中斷中決不能用等待的方式】



 
 
相關(guān)函數(shù)使用說(shuō)明:
創(chuàng)建任務(wù):
INT8U  OSTaskCreateExt (void   (*task)(void *p_arg),//被創(chuàng)建的任務(wù)函數(shù)指針
                        void    *p_arg,               //傳遞給任務(wù)的參數(shù)的指針
                        OS_STK  *ptos,                //分配給任務(wù)的堆棧的棧頂指針
                        INT8U    prio,                //被創(chuàng)建任務(wù)的優(yōu)先級(jí)
                        INT16U   id,                  //為創(chuàng)建的任務(wù)創(chuàng)建一個(gè)特殊的標(biāo)識(shí)符,暫沒(méi)用
                        OS_STK  *pbos,                //指向任務(wù)的堆棧棧底的指針(用于堆棧檢驗(yàn))
                        INT32U   stk_size,            //堆棧的容量
                        void    *pext,                //指向用戶附件的數(shù)據(jù)域的指針
                        INT16U   opt)                 //指定是否卞堆棧檢驗(yàn),是否將堆棧清0,任務(wù)是否需要進(jìn)行浮點(diǎn)操作
OSTaskCreate中還調(diào)用了OSTaskStkInit函數(shù),調(diào)用該函數(shù)的目標(biāo)是初始化任務(wù)的堆棧,使其看起來(lái)像發(fā)生過(guò)中斷一樣。OSTaskStkInit是需要移植的函數(shù)。
 
修改任務(wù)屬性:
調(diào)用OSTaskChangePrio()函數(shù)可以動(dòng)態(tài)地改變某一個(gè)任務(wù)的優(yōu)先級(jí),調(diào)用OSTaskNameGet()函數(shù)可以獲取某一個(gè)任務(wù)的名稱,調(diào)用OSTaskNameSet()函數(shù)可以設(shè)置一個(gè)任務(wù)的名稱。
INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio);
INT8U OSTaskNameGet INT8U   prio,INT8U  *pname,INT8U  *perr);
void  OSTaskNameSet (INT8U prio, INT8U *pname, INT8U *perr)
任務(wù)的名稱保存在任務(wù)對(duì)應(yīng)的任務(wù)控制塊中的成員:OSTCBTaskName[OS_TASK_NAME_SIZE]中;
直接掛起任務(wù)的函數(shù):
有時(shí)將任務(wù)掛起是很有用的,掛起任務(wù)的函數(shù)可以通過(guò)INT8U  OSTaskSuspend(INT8U prio)來(lái)實(shí)現(xiàn),且被掛起的任務(wù)只能通過(guò)調(diào)用INT8U  OSTaskResume (INT8U prio)來(lái)恢復(fù)。任務(wù)可以掛起自己或者其他的任務(wù)。
舉例:在一些設(shè)計(jì)中,在main函數(shù)中只有簡(jiǎn)單的幾行,在其中創(chuàng)建了一個(gè)啟動(dòng)任務(wù):用于啟動(dòng)其他的任務(wù)與初始化系統(tǒng),啟動(dòng)任務(wù)的優(yōu)先級(jí)比它要?jiǎng)?chuàng)建的任務(wù)都要高,初始化成功與創(chuàng)建完相關(guān)任務(wù)之后,一般自己將自己掛起。
堆棧檢驗(yàn)函數(shù):
如果要使用堆棧檢驗(yàn)函數(shù),那么在任務(wù)的建立需要使用OSTaskCreateExt()來(lái)建立任務(wù),且需要指定入口參數(shù):opt(OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);
OS_TASK_OPT_STK_CHK:指示任務(wù)需要使用堆棧校驗(yàn)功能
OS_TASK_OPT_STK_CLR:將任務(wù)的堆棧RAM清0(因?yàn)槎褩z驗(yàn)是從棧底開(kāi)始計(jì)算為0(空閑)的空間大小)
在任務(wù)創(chuàng)建時(shí)指定棧頂、棧底,在任務(wù)運(yùn)行一段時(shí)間后,一般需在堆棧使用最充分后才去檢驗(yàn)較為準(zhǔn)確;任務(wù)可以檢查自己或者其他任務(wù)的堆棧使用情況,堆棧檢驗(yàn)函數(shù)確定堆棧的實(shí)際空間字節(jié)數(shù)和已被占用的字節(jié)數(shù),放在入口參數(shù)OS_STK_DATA數(shù)據(jù)結(jié)構(gòu)中;
[可以閱讀 嵌入式ARM系統(tǒng)原理與實(shí)例開(kāi)發(fā)(楊宗德)的第八章,里面對(duì)該系統(tǒng)包含的大部分函數(shù)簡(jiǎn)要說(shuō)明以及移植時(shí)的相關(guān)函數(shù)說(shuō)明]

任務(wù)切換過(guò)程分析
1:任務(wù)之間搶占式切換(高優(yōu)先級(jí)的任務(wù)就緒后立即搶占正在運(yùn)行的低優(yōu)先級(jí)的任務(wù))
系統(tǒng)在任何響應(yīng)后,都需要進(jìn)行任務(wù)調(diào)度,確保系統(tǒng)中優(yōu)先級(jí)最高的任務(wù)被執(zhí)行,那么系統(tǒng)采用的任務(wù)調(diào)度切換函數(shù)就是void  OS_Sched(void);
void  OS_Sched(void)
    OS_ENTER_CRITICAL();   //進(jìn)入臨界區(qū) 關(guān)中斷 
    if(OSIntNesting==0) {  //目前系統(tǒng)不處于中斷態(tài)                         
        if(OSLockNesting==0) { //系統(tǒng)調(diào)度功能使能                    
            OS_SchedNew();   //計(jì)算出目前系統(tǒng)中最高的優(yōu)先級(jí),保存在INT8U OSPrioHighRdy中
            if(OSPrioHighRdy!=OSPrioCur) { //判斷當(dāng)前正運(yùn)行的任務(wù)是不是最高優(yōu)先級(jí) 否則就不用切換
                 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//將最高優(yōu)先級(jí)任務(wù)的控制塊的指針?lè)?                                                            //入任務(wù)控制塊指針變量OSTCBHighRdy
                 #if OS_TASK_PROFILE_EN > 0
                    OSTCBHighRdy->OSTCBCtxSwCtr++; //目前優(yōu)先級(jí)最高的任務(wù)切換次數(shù)統(tǒng)計(jì)        
                 #endif
                 OSCtxSwCtr++; //系統(tǒng)任務(wù)切換的總次數(shù)統(tǒng)計(jì)
                 OS_TASK_SW(); //實(shí)現(xiàn)任務(wù)切換
            }
        }
     }
     OS_EXIT_CRITICAL(); //恢復(fù)全局中斷標(biāo)志 退出臨界區(qū)
 
在任務(wù)調(diào)度前,OS_SchedNew()計(jì)算出目前系統(tǒng)中最高的優(yōu)先級(jí),保存在INT8U OSPrioHighRdy中
#define  OS_TASK_SW()         OSCtxSw()
OSCtxSw //懸起PSV異常
    LDR     R0, =NVIC_INT_CTRL  //NVIC_INT_CTRL為SCB中的中斷控制寄存器(ICSR)的地址數(shù)值 0xE000ED04
    LDR     R1, =NVIC_PENDSVSET //NVIC_PENDSVSET 為設(shè)置ICSR的值(0x10000000
    STR     R1, [R0]            //設(shè)置ICSR = NVIC_PENDSVSET  即將觸發(fā)PendSV中斷
    BX      LR                  //因?yàn)樵贠S_Sched中調(diào)用OSCtxSw時(shí),是在臨界區(qū),中斷是關(guān)閉的,所以這里通過(guò)BX LR返回OS_Sched,等退出臨界區(qū)后,觸發(fā)PendSV中斷【任務(wù)切換時(shí)必須關(guān)中斷”的原則
PendSV中斷響應(yīng)函數(shù)OSPendSV
//Cortex-M3進(jìn)入異常服務(wù)例程時(shí),使用的是MSP指向的堆棧空間,且自動(dòng)壓入了R0-R3,R12,LR(R14,連接寄存器),PSR(程序狀態(tài)寄存器)和PC(R15),這些寄存器是任務(wù)被中斷時(shí)的現(xiàn)場(chǎng)記錄此時(shí)任務(wù)所使用的PSP的值沒(méi)有變化。
//M3處理器的控制寄存器的CONTROL[1] = 1(系統(tǒng)復(fù)位后默認(rèn)是0),表明M3的線程模式的堆棧指針SP選用PSP【handler模式只允許使用MSP】,這樣兩個(gè)模式下SP使用不同的堆棧指針,且訪問(wèn)SP時(shí),訪問(wèn)到的是當(dāng)前被使用的堆棧指針,這時(shí)另一個(gè)堆棧指針要通過(guò)MRS、MSR命令來(lái)訪問(wèn),即R13(PSP)或R13(MSP),R13是PSP還是MSP由系統(tǒng)當(dāng)前的狀態(tài)與CONTROL[1]決定,PSP是某個(gè)任務(wù)在RAM中的堆棧指針,MSP是異常模式下在RAM中的堆棧指針。
//一個(gè)任務(wù)占用CPU運(yùn)行,它的運(yùn)行現(xiàn)場(chǎng)是R0-R3,R4-R11,R12,R13(PSP/MSP),R14(LR),PSR和R15(PC),如果該任務(wù)被中斷,那么在進(jìn)中斷過(guò)程中,硬件會(huì)自動(dòng)對(duì)CPU的部分現(xiàn)場(chǎng)寄存器(R0-R3,R12,R14,PSR和R15)進(jìn)行壓棧,其他寄存器硬件不壓棧,如果CONTROL[1] = 1,那么硬件就會(huì)將相關(guān)寄存器壓入PSP(R13)指向的堆棧中(線程模式時(shí)SP為PSP),CONTROL[1] = 0,硬件就會(huì)將相關(guān)寄存器壓入MSP(R13)指向的堆棧中;CONTROL[1] = 1時(shí)如下圖所示,線程模式與handler模式的SP不一樣。
 
OSPendSV   【在進(jìn)入中斷前 R0-R3,R12,R14,PSR和R15已被壓入任務(wù)所使用的堆棧中,下面是將其他的寄            存器再壓入任務(wù)的堆棧中,以及保存該任務(wù)的堆棧棧頂?shù)闹档絇SP指向的堆棧中去,任務(wù)使用            的是PSP,異常模式下使用的是MSP
    MRS     R0, PSP   //R0<=PSP 異常模式下使用的是MSP,所以只能通過(guò)MRS讀取被中斷的任務(wù)的堆棧指針,
    CBZ     R0, OSPendSV_nosave //如果PSP==0,則跳轉(zhuǎn)到 OSPendSV_nosave ,否則往下執(zhí)行【在系統(tǒng)剛開(kāi)                                //始啟動(dòng)時(shí),OSStart()會(huì)調(diào)用OS_SchedNew()與OSStartHighRdy()來(lái)使                                 //系統(tǒng)中最高優(yōu)先級(jí)的任務(wù)運(yùn)行,在OSStartHighRdy中,PSP設(shè)置為0,因?yàn)?                                //在OSStart前還沒(méi)有任務(wù)運(yùn)行,所以進(jìn)入軟中斷后不用保存此時(shí)CPU的值,                                 //只要將最高優(yōu)先級(jí)任務(wù)的現(xiàn)場(chǎng)恢復(fù)到CPU的各寄存器就好了
    SUBS    R0, R0, #0x20   //R0(PSP)!=0,那么R0的值減去0X20,32個(gè)字節(jié)(下面保持8個(gè)32位的寄存器)
    STM     R0, {R4-R11}    //將R4~R11這8個(gè)寄存器存儲(chǔ)到PSP對(duì)應(yīng)的空間中去,這些寄存器是當(dāng)前任務(wù)被中                             //斷時(shí)的現(xiàn)場(chǎng)
    LDR     R1, __OS_TCBCur //__OS_TCBCur  DCD  OSTCBCur
                            //當(dāng)前任務(wù)(被中斷的任務(wù))的任務(wù)控制塊OSTCBCur, OSTCBCur是當(dāng)前任務(wù)控制                             //塊的首地址,也代表了它的第一個(gè)成員的地址,所以下面其實(shí)是對(duì)他的第一個(gè)                             //成員OS_STK *OSTCBStkPtr(指向任務(wù)的堆棧棧頂?shù)闹羔槪┻M(jìn)行賦值
    LDR     R1, [R1]        //將OSTCBStkPtr中保持的值賦給R1,該值指向任務(wù)的堆棧棧頂?shù)闹羔?/span>
                            //即R1存儲(chǔ)被中斷的當(dāng)前任務(wù)的堆棧棧頂?shù)闹羔?/span>
    STR     R0, [R1]        //將被中斷的當(dāng)前任務(wù)的堆棧棧頂?shù)闹羔槾娴絇SP指向的堆棧中去,即保存被中斷                             //任務(wù)所使用的堆棧棧頂?shù)闹羔?上面其他的寄存器是任務(wù)被中斷的線場(chǎng)
OSPendSV_nosave  【上面的程序執(zhí)行完后,接著繼續(xù)執(zhí)行下面的程序】
    PUSH    {R14}           //保存R14寄存器的值 壓入到MSP指向的堆棧中,該寄存器在中斷返回時(shí)大有作用
    LDR     R0, __OS_TaskSwHook //調(diào)用回調(diào)函數(shù)  鉤子函數(shù)        
    BLX     R0
    POP     {R14}           
    -------------------------------------------
    //相當(dāng)于定義指針變量:__OS_PrioCur DCD   OSPrioCur;  __OS_PrioHighRdy  DCD  OSPrioHighRdy
    LDR     R0, __OS_PrioCur     //INT8U OSPrioCur當(dāng)前任務(wù)的優(yōu)先級(jí)   
    LDR     R1, __OS_PrioHighRdy //OSPrioHighRdy系統(tǒng)中最高的優(yōu)先級(jí)  
    LDRB    R2, [R1]             //上面兩句是將變量的地址傳給了R0與R1,[R1]最高優(yōu)先級(jí)的值存入R2
    STRB    R2, [R0]             //將R2中的值存入到OSPrioCur變量中去(即接下來(lái)運(yùn)行最高優(yōu)先級(jí)任務(wù))
                                 //即實(shí)現(xiàn):OSPrioCur = OSPrioHighRdy;
    -------------------------------------------------
    //相當(dāng)于定義指針變量:__OS_TCBCur DCD   OSTCBCur;  __OS_TCBHighRdy  DCD  OSTCBHighRdy     
    LDR     R0, __OS_TCBCur      //R0=&OSTCBCur;  OS_TCB  *OSTCBCur; OS_TCB *OSTCBHighRdy;
    LDR     R1, __OS_TCBHighRdy  //R1=&OSTCBHighRdy;這四句同理上面,OSTCBCur = OSTCBHighRdy
    LDR     R2, [R1]             //R2 = *R1;  R2=OSTCBHighRdy 指向優(yōu)先級(jí)最高的任務(wù)的任務(wù)控制塊
    STR     R2, [R0]             //*R0 = R2即實(shí)現(xiàn):OSTCBCur = OSTCBHighRdy;
                                 //系統(tǒng)中用OSPrioCur   OSTCBCur 來(lái)表示正在運(yùn)行的任務(wù)
    ----------------------------------------------
   通過(guò)R2(OSTCBHighRdy)將OSTCBHighRdy->OSTCBStkPtr的值賦給R0,再通過(guò)LDM將最高優(yōu)先級(jí)任務(wù)的堆棧中保存好的R4-R11恢復(fù)到當(dāng)前CPU的R4-R11寄存器中(這個(gè)過(guò)程與上面的保存過(guò)程是相逆的),因?yàn)?/span>R0-R3,R12,R14,PSR和R15是硬件自動(dòng)壓入任務(wù)的堆棧的,在中斷中后來(lái)再保存R4-R11的(是先對(duì)SP減了32后再保存,相當(dāng)于SP的值沒(méi)有變化),且中斷退出時(shí)會(huì)自動(dòng)彈出R0-R3,R12,R14,PSR,所以下面的代碼只要恢復(fù)最高優(yōu)先級(jí)任務(wù)的R4-R11(OSTCBHighRdy->OSTCBStkPtr通過(guò)LDM自減了32,),然后將加上32, OSTCBHighRdy->OSTCBStkPtr 相當(dāng)于沒(méi)有變化,再將OSTCBHighRdy->OSTCBStkPtr賦給PSP,這樣硬件在中斷退出時(shí)會(huì)自動(dòng)恢復(fù) R0-R3,R12,R14,PSR ,這樣就完全恢復(fù)了,一運(yùn)行就是最高優(yōu)先級(jí)的任務(wù)了
    LDR     R0, [R2]             //[R2]為*OSTCBHighRdy,R2是4字節(jié)的寄存器,所以[R2]是OSTCBHighRdy                                  //指向地址的后4個(gè)字節(jié)的值,即OSTCBHighRdy->OSTCBStkPtr,  
                                 //即 R0 = OSTCBHighRdy->OSTCBStkPtr
    LDM     R0, {R4-R11}         //將 OSTCBHighRdy->OSTCBStkPtr(R0)指向的堆棧(向下生長(zhǎng))棧頂后                                  //的32個(gè)字節(jié)依次存入R4-R11(R0的值自減,后綴為!表示自增),因?yàn)槎?                                  //棧保持時(shí)是自減的,這里相當(dāng)于恢復(fù)最高優(yōu)先級(jí)任務(wù)的現(xiàn)場(chǎng))               
    ADDS    R0, R0, #0x20        //將R0的值加上0x20后賦給R0
    MSR     PSP, R0              //PSP <= R0                              
    ORR     LR, LR, #0x04    //按位或 將LR的第二位置1,這樣中斷返回時(shí),就將從進(jìn)程的堆棧中做                              //出棧操作,返回后使用PSP(否則將從主堆棧中做出棧操作,返回后                              //使用MSP)                                
    BX      LR                   //中斷返回
 
xPSR、PC、LR、R12、R3、R2、R1、R0會(huì)被硬件按一定的次序壓入PSP所指向的堆棧中(同時(shí)被中斷的任務(wù)后面要恢復(fù)執(zhí)行,還需保存R4-R11,保存后一定要保證堆棧指針指向硬件自動(dòng)壓棧后的原位置,這樣硬件才能在恢復(fù)任務(wù)時(shí)硬件自動(dòng)正確出棧)
 
 
2:在中斷中實(shí)現(xiàn)任務(wù)的切換
uC/OS II  的中斷服務(wù)函數(shù)必須遵循一定的架構(gòu)來(lái)實(shí)現(xiàn),
void SysTickHandler(void)
{
    OS_CPU_SR  cpu_sr;
    OS_ENTER_CRITICAL();  //保存全局中斷標(biāo)志,關(guān)總中斷
    OSIntNesting++;
    OS_EXIT_CRITICAL();  //恢復(fù)全局中斷標(biāo)志

    OSTimeTick();    
 
    OSIntExit();  //在os_core.c文件里定義,如果有更高優(yōu)先級(jí)的任務(wù)就緒了,則執(zhí)行一次任務(wù)切換 
}

OSInit函數(shù)
系統(tǒng)初始化函數(shù)OSInit()初始化所有的變量和數(shù)據(jù)結(jié)構(gòu),同時(shí)也會(huì)建立空閑任務(wù)OS_TaskIdle(),該任務(wù)永遠(yuǎn)處于就緒態(tài),如果統(tǒng)計(jì)任務(wù)使能,那么他還要建立統(tǒng)計(jì)任務(wù)OS_TaskStat(),并使其進(jìn)入就緒態(tài)。
空閑任務(wù)
  OS_TaskIdle
uC/OS II總要建立一個(gè)空閑任務(wù),idle task,這個(gè)任務(wù)在沒(méi)有其他任務(wù)進(jìn)入就緒態(tài)時(shí)投入運(yùn)行,它的優(yōu)先級(jí)永遠(yuǎn)設(shè)為最低優(yōu)先級(jí),即OS_LOWEST_PRIO,且空閑任務(wù)是不能被應(yīng)用軟件刪除的
空閑任務(wù)不停的給一個(gè)32位的OSIdleCtr的變量加1,統(tǒng)計(jì)任務(wù)用這個(gè)計(jì)數(shù)器變量確定當(dāng)前應(yīng)用軟件實(shí)際消耗CPU的時(shí)間,計(jì)數(shù)器加1前后分別關(guān)閉打開(kāi)中斷,OS_TaskIdle可以借助OSTaskIdleHook()做CPU的睡眠等;OS_TaskIdle總是處于就緒態(tài)
統(tǒng)計(jì)任務(wù)OS_TaskStat
只要將OS_TASK_STAT_EN宏使能,那么統(tǒng)計(jì)任務(wù)就會(huì)建立,一旦運(yùn)行,它將每秒運(yùn)行一次,計(jì)算當(dāng)前CPU的利用率,將值放在OSCPUsage這個(gè)8位的變量中,用百分比表示,精度為1%.如果應(yīng)用程序打算使用統(tǒng)計(jì)任務(wù),那么必須在初始化時(shí)建立的第一個(gè)也是唯一的任務(wù)中調(diào)用統(tǒng)計(jì)任務(wù)初始化函數(shù)OSStatInit(),也就是在調(diào)用系統(tǒng)啟動(dòng)函數(shù)OSStart前,用戶初始化代碼中必須先建立一任務(wù),在這個(gè)任務(wù)中調(diào)用系統(tǒng)統(tǒng)計(jì)初始化函數(shù)OSStatInit,然后再建立應(yīng)用程序中的其他任務(wù)。它的優(yōu)先級(jí)是OS_LOWEST_PRIO-1
OSStart操作系統(tǒng)啟動(dòng)函數(shù)
uC/OS II啟動(dòng)之前,至少須建立一個(gè)應(yīng)用程序,因?yàn)槿绻鼓芙y(tǒng)計(jì)任務(wù),那么統(tǒng)計(jì)任務(wù)要求必須先建立一個(gè)也是唯一一個(gè)用戶任務(wù)后,再啟動(dòng)系統(tǒng),再創(chuàng)建其他的任務(wù),如果什么任務(wù)都沒(méi)有建立,只要空閑任務(wù),那系統(tǒng)也就一直空閑,所以需要先創(chuàng)建至少一個(gè)任務(wù)。

關(guān)閉窗口
主站蜘蛛池模板: 天天色图 | 福利视频网站 | 中文天堂在线观看 | zzzwww在线看片免费 | 欧美阿v | 一级黄色毛片免费 | 在线观看黄色 | 91在线看网站 | 激情a| 国产精品xxxx| 成人国产在线观看 | 欧美精品一区二区在线观看 | 黄色小视频入口 | 91av久久久 | 天堂素人约啪 | 成人99| 中文字幕久久精品 | 日韩电影中文字幕 | 伊人精品在线视频 | 国产99久久精品 | 国产日韩精品在线 | 日韩欧美久久精品 | 久草精品视频 | 亚洲欧美激情精品一区二区 | 天天干夜夜操 | 国产在线视频一区 | 欧美日韩高清在线一区 | 欧美国产视频一区二区 | 亚洲精品乱码久久久久久蜜桃 | 久久精品一区二区 | 国产视频一二三区 | 在线免费观看黄a | 精品久久久久久久人人人人传媒 | 成人免费精品 | 国产精品毛片一区二区在线看 | 国产高清自拍视频在线观看 | 国产黄色一级电影 | 亚洲一区视频在线 | 精品国产一区二区三区久久 | a欧美 | 91网在线观看 |