標題:
uCOS-III學習筆記
[打印本頁]
作者:
wxs732
時間:
2021-2-19 20:43
標題:
uCOS-III學習筆記
為什么要學習這個ucos ii
在單片機的世界里翱翔了好多年,
一直覺得無所不能、無所不會鄙視一些應用層的開發(fā),
輕示一些軟硬都好搞一點的過去,
直到遇見你 ucosii 或你的好兄弟iii 我從沒有如此卑微的如此靠近過。
你是來團結(jié)這些”地方武裝勢力的”真真為社會主義事業(yè)而奮斗終身的。
崇拜了無數(shù)大嬸,還是俺叔給我說 “ 算法” 才是 ----葵花寶典
但有天碰到一個“事情”需要兩個或三個或更多個家庭來合力完成一項工作的情況下;
比如“苦逼的程序員終于要結(jié)婚了”這就需要二個最最重要的兩個高級任務你和你老婆、
兩個稍低一點的有可能存在“翻轉(zhuǎn)任務優(yōu)先級”的情況影響你和你老婆的任務執(zhí)行的”任務” ,
�。ㄆ鋵嵨蚁胝f的是彩禮可能把好好的任務給攪黃,相當于最高級別的優(yōu)先級丈母娘,一票否決權(quán)
�。∪绻钤缒阍谶M行任務留有debug 的話,這些都是小菜---你懂的)
還需要一些處理各種額外的功能任務。
如果是單片機的“世界中”這樣的情況下需要先初始化了
老婆的“包括找到老婆+熟悉老婆各種配件+熟悉她的各種關(guān)系”,
初始化娶老婆的各種條件”買車+買房+買家具+++++”,
初始化婚禮的各種瑣事,初始化她父母+你父母的各種要求;
最后的循環(huán)執(zhí)行就是你和你老婆結(jié)婚+重復瑣事+賺錢+養(yǎng)育孩子+照顧父母+孩子結(jié)婚+自己老去,
最后你的主函數(shù)終于運行完畢。
這里可能有些初始化條件不合適還有可能會出現(xiàn)#if………#else………. //重新選擇老婆
也可能會出現(xiàn)
Do{………..}while(條件) //試婚
也可能會出現(xiàn)
Delay(10year); // //延時
也可能會出現(xiàn)
While(各種可能情況)
{…………..}; //這里就是一個牢籠直至…………
最危險的不能進入“迭代的” 的循環(huán)中,
一旦進入后果無法設想
思想指針可以來回游走
可別忘記自己的類型和安全返回
否則很容易帶回的是錯誤的數(shù)據(jù)和丟失自己,
損壞主函數(shù)的生命周期
“忒復雜了為了結(jié)一個婚這大工程還是給了系統(tǒng)好把”
系統(tǒng)是如何來處理
建立幾個任務
任務一負責各種婚前準備
任務二負責老婆家各種需要準備工作
任務三負責各種意外情況處理
任務四負責……..
任務五負責……….
任務六…………
這樣是不是稍微輕松一下,但是也不是最輕松的
系統(tǒng)給設定好了各種格式
現(xiàn)在的社會你只需要有錢就可以了
Ucos ii ----- iii 也一樣
感覺好幸福
有中馬上見到美麗賢惠聰明可愛的 新娘子
流會兒口水了
作者:
wxs732
時間:
2021-2-19 21:57
首先,第一個要解決的問題是,
為什么我們需要uCos?就像最開始學C編程時,師傅告訴我們,指針很重要,那時你肯定有一個大的疑問,指針到底有什么好?
心里一直犯嘀咕著:不用指針不一樣把程序編出來了? 現(xiàn)在想想看c語言沒了指針,是不是寸步難行呢�;氐秸},我們到底為什么需要uCos?
一般的簡單的嵌入式設備的編程思路是下面這樣的:
int main ()
{ //初始化各種外設
//初始化各種時鐘
//初始化IO 口
while(1)
{
{處理事務1};
{處理事務2};
{處理事務3};
.......
{處理事務N};
}
}
void shijian1 ()
{}
void shijian2()
{}
void shijian3()
{}
isr_server
{
{處理中斷};
}
這也是我們在51、 STM32、AVR、stm8 中最常用的形式
這是最一般的思路,對于簡單的系統(tǒng)當然是夠用了,
但這樣的系統(tǒng)實時性是很差的,
比如“事務1”如果是一個用戶輸入的檢測(掃描按鍵是否有按下),
當用戶輸入時,
如果程序正在處理事務1下面的那些事務,
也就是在處理任務2 后任務3 后任務4。
那么這次用戶輸入將失效,
用戶的體驗是“這個按鍵不靈敏,
這個機器很慢”,
而我們?nèi)绻咽聞辗诺街袛嗬锶ヌ幚?我們把按鍵掃描放在中斷函數(shù)里面),
雖然改善了實時性但會導致另外一個問題,
有可能會引發(fā)中斷丟失,
(這里我沒有想明白 按鍵掃描在中斷里丟失 是不是順序掃描0-9個按鍵
當掃描到按鍵8 ,而這個時候 我 按得失2,
如果中斷掃描足夠快的話,應該也很快就可以掃描到
)
這個后果有時候比“慢一點”更加嚴重和惡劣!
又比如事務2是一個只需要1s鐘處理一次的任務,
那么顯然事務2會白白浪費CPU的時間。
通篇想說就是 “實時性不夠好”
作者:
wxs732
時間:
2021-2-20 16:28
下面不是重點
有些書會介紹(前后臺系統(tǒng) + 實時內(nèi)核)都是用于處理實際工業(yè)具體問題的軟件編程方法,
前后臺系統(tǒng)結(jié)構(gòu): 就是一個死循環(huán)和若干個中斷服務程序
中斷用于處理系統(tǒng)的異步事件(前臺)
相應函數(shù)完成相應的操作(后臺)
這其實和我們平常寫的一樣,主函數(shù)+應用函數(shù)+中斷,只不過我們沒有給他起名字而已。
這樣做的有一個弊端也是書上說的,后來我想想也對啊
如果中斷時前臺―――
為了保證任務得到及時處理,
哪些本該在任務中執(zhí)行的關(guān)鍵代碼必須放在,中斷里執(zhí)行。
�。ň褪菫榱说玫郊皶r的響應)
想想中斷到可以及時處理特定的數(shù)據(jù)并且更新
而任務或應用程序是不是能立刻更新吶???
這個真未必能夠及時執(zhí)行。
比如:
一個項目是這樣的定時開燈或關(guān)燈+WIFI 通信�。r間屏幕顯示
更新時間功能我們放在中斷里
當進行WIFI 通訊 時
即時我讀取到了時間改變了,但是現(xiàn)在沒有切換到
屏幕時間顯示,是不是也不會更新顯示時間數(shù)組
(這個說法有些澀)
生活的例子:
現(xiàn)在需要燒水(設定一個時間)+看閨女
看閨女就是中斷里的代碼
燒水開了沒有開,只有看2分閨女――― 去看看時間或水―――
燒水時間是一值在走并且水一直在升溫
而作為主循環(huán)中每走幾分鐘才查看一回,而且這個查看時間還不固定
閨女哭了、閨女不讓走、閨女要吃奶粉
這些在中斷中都需要立即執(zhí)行的
中斷里――只有聽見水壺鳴叫或時間到
才去處理燒開水灌進水壺里的動作
有個說法 “任務級響應延遲”
實時內(nèi)核:(ucos)
用于管理控制器、微處理器的時間及硬件資源的軟件代碼。
忒重要了這句話,就是通過管理控制器的時間來控制硬件資源的軟件代碼;
通過把一個大的項目分解成為幾個小的任務或叫線程
分配單片機的時間來間隔運行任務�。�、2、3、4、5
每個任務都是的
while(1) { ;;;}這樣的死循環(huán)
實時內(nèi)核--- 相當于家長來負責管理這些任務的運行時間、運行順序;
作者:
wxs732
時間:
2021-2-20 16:54
重點一句話: ucos是用約70多個新函數(shù)形式為應用程序代碼提供服務的。 這句話也是書上的,相當于學習“c 語言中的 頭文件函數(shù)”; 我們想 用 vc6.0 在屏幕上輸出 字符 是不是要用到printf() , 而用到這個函數(shù)是不是需要 #include <stdio.h> 想輸出時間 是不是需要 #include <ctime.h> 學習細節(jié)---( 時刻把握整體 我們 wifi.c + LED.C + KEY.C 都寫好了,并且放在一個工程中了, 調(diào)用一下系統(tǒng)函數(shù) 來協(xié)調(diào)外設給我老實工作否則, 在現(xiàn)在的 while(1) {} 死循環(huán)中,一樣也能干掉你這個線程) 不畏懼困難。 還有這個線程就是任務就是一個函數(shù)實現(xiàn)一個功能。
作者:
wxs732
時間:
2021-2-25 16:23
從總體上理解一個事物
從總體上看待一個人
從總體上學習一個技能
這個總體很重要,比如學習ucos iii 或 ii
其實如果從總體上說沒啥大的區(qū)別
可也不能說沒有區(qū)別
先學會一個在說 III 和 II 都是個浮云
先白話幾句
下面都是聊天
如果計劃作一件事情是不是先在腦子里思考一下這個事情的大概,
如果有老婆的話是不是需要和老婆商量一下,如果商量好了或自己決定了這件事情;
就相當于 建立了 “任務” 現(xiàn)在建立了任務
這個任務可能是一個 “看電視的閑任務”
也可能會遇到更緊急的任務 “只好刪除這個任務” ( 更緊急的任務是優(yōu)先級)
還有可能 “在開始操作這個任務的時候先掛起這個任務”(就是先記下來不執(zhí)行)
頂下來的無論學習任務還是找老婆的任務一旦定下來就必須要有回應
哪怕是 個“空任務”什么也不做; 也要對他有定義有設置。
人生就和這個很類似
china main() //中國出生 也就是建立了任務
{
father_init(); // 父親初始化
mother_init(); // 母親初始化
house_init(); //房子初始化
while(1)
{
幼兒() ; //
小學 (); //
中學 (); //
高中 () ; //
大學 (); //
工作 (); //
組合家庭 () ; //
生活 (); //
孕育新生命 (); // ------------------ china main()
50_year(); // { ;;;;;;;;
60_year(); // }
70_year(); //
80_year(); //
90_year(); //
over_game(); //
// 刪除任務本身 (); //
// 每個人沒有 return
//
}
}
-----------------------------------------------
china main()
{
//
OSInit(&err); // 各種適齡婚前的必要條件
OSTaskCreate("new_family"); // 創(chuàng)建一個新任務 創(chuàng)建新的家庭
OSStart(&err); //這個開始任務有些 “農(nóng)村分家的意思”
}
static void new_family()
{
//各種初始化兩個人新家的準備
//各種初始化條件
OS_CPU_SystickInit(); //時鐘 控制一個家庭的節(jié)奏
Mem_Init(); //初始化家庭的內(nèi)存空間
CPU_IntDisMeasMaxCurReset(); //復位清 零當前最大 夫妻吵架互相不搭理的 最大隔閡時間
//其實這里 不寫函數(shù)名字好一些
//提前給大家提高了 困難 指數(shù)
// ( 只看注釋也可以)
OSTaskCreate( " father_taks"); //
OSTaskCreate( " mother_task"); //
OSTaskCreate(" girl_task"); //
OSTaskCreate(" son_task"); //
OSTaskDel("&newfamily ,&err"); //刪除開始任務
}
void father_task1()
{ }
void mother_task2()
{ }
void girl_task()
{ }
void son_task()
{ }
主要任務就是這四個方面還有別的比如 :
給父母養(yǎng)老_task (); // 其實這個也是應該添加在任務里的
在往后的 幾十年里 這四個任務會 按照一定的 "cnts" 或 Systick 系統(tǒng)時鐘穩(wěn)定運行
我們是生活在一個連環(huán)的任務中,我們是父母的任務也是自己的孩子的任務,
這要在C++ 上是繼承和被繼承的關(guān)系是類和派生類的關(guān)系
在 代碼中我們就是一個任務,一個家庭是一個大任務;
丈夫_apptask();
妻子_apptask();
孩子_apptask();
閨女_apptask();
分工不同,需要完成的任務也不同
但是在 社會這個大循環(huán)中個體所賦予的任務大同小異
分工不同造成實際需要完成的工作也不同
比如:father_init() ; 這個初始化函數(shù)中就必須表現(xiàn)出掙錢的特征,
或者說以這個為主要任務
//其實也就是下面的 括號里的 具體名字 ,叫法不同 我覺得來表示人生還是很像的
( III 將學習 任務 --- 任務時間片運行 --- 閑任務和阻塞延時 --- 時間戳 --- 臨界段
--- 就緒列表 --- 優(yōu)先級 --- 時基列表 --- 時間片 --- 任務掛起和恢復 --- 任務刪除
)
作者:
wxs732
時間:
2021-3-1 21:40
下面繼續(xù)閑聊,
經(jīng)過幾個片斷聊天理解ucos 也是不現(xiàn)實的。
如果是趙大爺?shù)脑捑褪?“話療”,
通過談話的 方式來理解明白我們需要掌握的東西.
剛開始學習ucos 時也是膽戰(zhàn)心驚苦悶無比,
搞不懂為什么有些通俗易懂的知識非要寫的那么高大上
難以理解。
現(xiàn)實社會這個大循環(huán)中,人們是圍繞 “錢” 在轉(zhuǎn),
無論多少個家庭、個人都無法離開這個 最基本的 生存需求,
不圍繞錢來 轉(zhuǎn)的 我只能想到 “佛” “道” 界,
這些如果在 ucos 系統(tǒng)中,我理解應該就屬于 "空閑任務" 沒有這些任務是不行的。
( 社會需要這些精神上的知識)
既然 社會 是圍繞 "錢" 這個最基本的目標在運作,
那么 在ucos 中 有沒有 也有一個也圍繞 “靶點”而運行?
通過學習 知道是有的;
這個 點就是 “時鐘”--- Systick --- 類似---心跳--
在ucos 系統(tǒng)中也是圍繞這個和錢類似的 "點" ,
讓任務來有條不紊的運行, 沒有他行不行,萬萬不行。
在學習單片機的時候也有 51、avr 、stm8、stm32、PIC。
這些都是需要時鐘的;
現(xiàn)在32 特別火 就已32 來說吧!
下面不是閑聊需要理解的
stm32 中有一個SysTick定時器 他是一個24位倒計定時器,當計數(shù)到 0 時,
則從reload 寄存器中自動重新裝載定時器的初值,并開始新一輪的計數(shù)。
這個定時器是24位
這個定時器是倒計時(比如 從1000減到0 , 1000 就是初值 )
當遞減到0 時就有從 reload 寄存器中重新加載初值
這個初值最大是多少 24位 = 0xffffff = 0b1111 1111 1111 1111 1111 1111
2^24 = 等于多大的數(shù)值 = 16777215
一般我們也沒有用這么大的,這是可以加載的最大數(shù)值
也就是數(shù) 數(shù)字來 cpu 也要倒序 減 - - ;
在 ucos 中使用systick 來計數(shù),作為 “系統(tǒng)時鐘節(jié)拍”
一般這個節(jié)拍是固定的用 OS_TICKS_PER_SEC 這個標志來定義了
OS_TICKS_PER_SEC = 200 也有的 = 500
理解大概意思就行,知道有這個標志
為什么 ???
下面是 delay_init();
delay_ms();
兩個函數(shù) ,第一個初始化 系統(tǒng)時鐘 開啟SYSTICK
第二就是在有個別任務中需要用到的延時函數(shù)
//初始化延遲函數(shù)
//當使用OS的時候,此函數(shù)會初始化OS的時鐘節(jié)拍
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統(tǒng)時鐘
/***********************
要說清楚還需要進入這個延時函數(shù)初始化中來
這個函數(shù)最重要的功能是給
fac_ms fac_us賦值
如果是ucos 話進入這個函數(shù)
而且這個函數(shù)還必須在沒有進入中斷中來初始化
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
//選擇外部時鐘 HCLK/8
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//這里選擇外部時鐘原 也就是外部的 8Mhz
//經(jīng)過倍頻后 時鐘 = 72mhz = 72000 000
fac_us=SystemCoreClock/8000000;
//這里計算 出 延時 微秒的倍乘數(shù)值
//為系統(tǒng)時鐘的1/8
// fac_us = 72000 000 /8000 000
//fac_us = 9
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
//72000000/8000000 = 9
reload=SystemCoreClock/8000000; //每秒鐘的計數(shù)次數(shù) 單位為K
// = 72000 000 /8000 000
// reload = 9;
//--------------------------------------------
// = 1000 000 /200
// = 1000 0 /2 =5000
reload*=1000000/delay_ostickspersec; //根據(jù)delay_ostickspersec設定溢出時間
//reload = reload * 1000 000 /200
// reload = 9 * 5000
// reload = 45000
// 設定LOAD 寄存器的最大值
//就是從45000 開始遞減
//reload為24位寄存器,最大值:16777216,在72M下,約合1.86s左右
//--------------------------------------------------------
fac_ms=1000/delay_ostickspersec; //代表OS可以延時的最少單位
// fac_ms = 1000 /200
// fac_ms = 5
//設定 延時毫秒 倍 乘值
//+++++++++++++++++++++++++++++++++++++++++++++++
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //開啟SYSTICK中斷
SysTick->LOAD=reload; //每1/delay_ostickspersec秒中斷一次
//這里 LOAD = 45000
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK
// 啟動嘀嗒定時器
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每個ms需要的systick時鐘數(shù)
// 9*1000 = 9000
#endif
}
********************/
我貼過來這個delay_Init(); 延時函數(shù)初始化是因為在有些任務中,
需要用到 delay_ms(); delay_us();
//延時nus
//nus為要延時的us數(shù).
//比如
void delay_us(u32 nus)
{
int ticks;
int told,tnow,tcnt=0;
int reload=SysTick->LOAD; //LOAD的值
// reload = 45000
ticks=nus*fac_us; //需要的節(jié)拍數(shù)
//這里假設 nus = 10
//ticks = 10*9
//這就是需要減 90 次
//也就是 要從45000減到
// 44910 就到了延時時間
// 90 = 0x5A;
// 90 就是 從 45000 減 到 44910
tcnt=0;
delay_osschedlock(); //阻止OS調(diào)度,防止打斷us延時
told=SysTick->VAL; //剛進入時的計數(shù)器值
// 這是剛進入ucos 的最大值
//
while(1)
{
tnow=SysTick->VAL;
//得到現(xiàn)在的的嘀嗒時鐘的計數(shù) 值
//如果現(xiàn)在的值不等于 最初進入的計數(shù)值
//
if(tnow!=told) //進行比較
{
//這里注意一下SYSTICK是一個遞減的計數(shù)器就可以了.
if(tnow<told)
//如果現(xiàn)在的計數(shù)值 < 剛進入的計數(shù)值
tcnt+=told-tnow; //微秒延時使用這個來計數(shù)判斷
//tcnt = tcnt+told-tnow
// 1000 = 1000 +2000-2000
// 7998 < 8000
// 0 = 0 + 8000 - 7998
else
tcnt+=reload-tnow+told; //ms 延時使用這個來計數(shù)
// tcnt = tcnt +(reload-tnow+told)
// 0 = 0 + ( 45000 - 1000 +2000 )
told=tnow;
if(tcnt>=ticks)break; //時間超過/等于要延遲的時間,則退出.
}
};
//這個 while(); 等待函數(shù)
//就是經(jīng)過 不停的
//tnow = tnow -0x14
//每次循環(huán)一次就減20 個計數(shù)
//直道tcnt = 6D
//這個時候 大于 6D> 5A
//就直接退出了定時
//這里還有個發(fā)現(xiàn)就是 實際上定時 us= 10
//多計數(shù)了 19 個計數(shù)
delay_osschedunlock(); //恢復OS調(diào)度
}
//通過不斷的循環(huán)仿真還是有好處的
//特別對初始化函數(shù) ucos 啟動可以很好的理解
//啟動是如何運行的
//這個是有些復雜的啟動嘀嗒時鐘情況
//在有的代碼中只是啟動了 systicks 使能了一下
//這里復雜就是有 延時函數(shù) 并且是不允許中斷的延時
//還有就是 延時是有范圍
//以前可能沒有注意到這些
//在就是 野火的代碼在 啟動嘀嗒定時器的函數(shù)中是有錯誤的
//SystICK->CTRL| = 0X07; 在實際代碼中不是這樣寫的
//但是 他計算后的情況和上面類似
//這就造成有些位設置不對
//會出現(xiàn)設置過后不能起到作用
//我也是看到有網(wǎng)友碰到了這種情況
//
作者:
xunzhaod
時間:
2021-3-2 15:22
很好的文章
作者:
wxs732
時間:
2021-3-4 20:21
xunzhaod 發(fā)表于 2021-3-2 15:22
很好的文章
謝謝鼓勵
delay_ms();
delay_us();
delay_Init();
這三個函數(shù) 感覺沒有 說明白
這幾天一直在 想如何在 補充一下
我的想說的 是
1 ucos 中的時鐘節(jié)拍 是如何 算出來的
2 在任務中如果要使用 delay_ms(); 是如何使用的 他是如何工作的
2 -1 還有就是 本來 備案中有 程序一步一步是如何 運行的 可 想 不好 最好的表達方式
作者:
wxs732
時間:
2021-3-16 21:22
ucos 的任務想了好幾天
也寫了些稿子,總覺的都不夠能清楚簡單明了的說明這個任務
任務在書上說了很多,包括一些視頻分了好幾段來說明
而我又想不依靠書上了語言來說書上的知識
這就造成好些“歪理邪說”很有可能誤導一些知識點的解釋
還是開始吧
任務可以理解 --- 生活中的一項任務比如燒水
比如洗菜
比如 炒菜、比如洗衣服、比如吃飯、比如收拾屋子都是在家庭內(nèi)
圍繞特定固定地址 的活動
這些活動 可以允許 顛倒 順序
這些活動 也可以 根據(jù)需要切換 先后
這些活動 也 有 必須立即執(zhí)行的 中斷任務
比如 水開了
比如 12點了 必須中斷一切別的活動 先 吃飯在說
這些活動也 可以 同步一起做
比如洗衣機洗衣服的時間內(nèi)可以做飯
洗衣服的時間內(nèi)可以拖地
這好像任務同步了是不是???
這些活動是誰來安排先后順序?
一般有一個當家的老婆媳婦女朋友來安排
如果是一個沒有返回的單身漢就好比一個
一家總要有一個說話算數(shù)的
一家總要有一個來協(xié)調(diào)安排先做啥在做啥的
一家總要有一個 “總管” 的
void main("有繼承沒有子類的函數(shù)")
{
//0
//1
//20
......
//110
......
//活夠了
}
//想想就悲哀
這些活動 還有一些 比如需要燒水 但是現(xiàn)在水瓶內(nèi)還是滿的
比如每天需要拖地 但是現(xiàn)在地板還很干凈
比如需要做飯 但是你或你和媳婦都不餓
這是不是就相當于 有需求 但是先掛了起來不執(zhí)行
先說 一家的 “ 總管” 吧!
她 --- 是如何管理你和你的家的
她 --- 是如何給你分配干活的工具的
她 --- 是如何給你分配先干啥后干啥的
她 --- 是如何給你劃的道道的
在實際應用程序設計中,通常需要把握完成的工作分成多個任務
每個任務只負責一項工作
一個任務是一個 “線程”(計算機離不開叫線程的)
實際上早期只有一個CPU
某刻只能做一個任務
ucos 支持多任務管理
允許有無數(shù)個任務
但是一般受限CPu 和存儲器的容量
多任務其實就是多個任務間的切換和調(diào)度
在任務相繼執(zhí)行過程中
CPU 的使用權(quán)在任務間切換
創(chuàng)建后的任務函數(shù)是這樣的
void Task_task1(void* p_arg)
這里我想說的是
void *p_arg
這和在普通函數(shù)的形參一樣
這個參數(shù)是 void 型指針
該指針是一個通用的指針變量
可以向任務傳遞一個 “變量地址”
傳遞一個結(jié)構(gòu)體
甚至 傳遞一個函數(shù)入口地址
生活中我們處理一個大問題的時候通常都是將這個問題“分而治之”,
把大問題分成多個小問題,
小問題被逐步的解決掉,
大問題也就隨之解決了。
那么這些小問題就可以看成是很多個小任務。
在我們設計復雜、大型程序的時候也是一樣的,
將這些負責的程序分割成許多個簡單的小程序,
這些小程序就是單個的任務,
所有的小任務融洽的工作,
最終完成復雜的功能。
在操作系統(tǒng)中這些小任務可以并發(fā)執(zhí)行,
從而提高CPU的使用效率。
UCOSIII就是一個可剝奪的多任務系統(tǒng),
我們使用UCOSIII的一個重要 的原因就是它的多任務處理能力。
(
任務說白了就是一個大的工作分若干個人來共同完成
每個人就相當于與一個獨立的任務
最后在系統(tǒng)的協(xié)調(diào)下
共同完成這項工作
)
作者:
jjwangxu2008
時間:
2021-3-17 08:40
這么好的文章 。。
作者:
wxs732
時間:
2021-3-18 20:15
/***********************************************
感謝版主不辭辛苦的給予的“黑幣”獎金鼓勵
感謝各位老師給予的夸獎評價
在學習的路上不敢驕傲
在項目的路上老板
表揚的好似只有 0 回和 1回
更多的是
來 小X 這個需求在改改
小X 這個功能能不能在添加一個新的創(chuàng)意
小X 這個邏輯有些菜
小X 這個項目進展有些慢
小X 這個設備怎么設計的有bug
...........
...........
第一年我羨慕大佬
第二年我羨慕老板
第三年我羨慕搬磚
第四年 ......搬磚
........ 搬磚
........搬磚
........ 搬磚
.........搬磚
(還想寫,但是咱是來學習的)
后來想想就是個菜鳥
適合搬磚
其實想想
無論多么牛逼
都是個打工的
在別人眼里都是個工具
除非達到前幾年
航天行業(yè)的那個兄弟
自己走了
那幫人玩不轉(zhuǎn)
************************************/
//一直想從整體上說任務
//分開了說
//老忘記前面學的啥 (比較笨)
任務是以何種面貌存在的呢?
在UCOSIII中任務就是程序?qū)嶓w,
每個任務就是一個 void main(); 函數(shù)
UCOSIII能夠管理和調(diào)度這些小任務(程序)。
任務的設計也是整個軟件代碼的基礎(chǔ)
其他設計工作都是圍繞一個個小任務來展開的
在不看書本的知識情況下想一想
做飯吃飯這類任務
是不是 ----是個重復的或說周期類執(zhí)行的任務
下館子這類任務
是不是 ----是個事件觸發(fā)類事物
{
//女朋友生日、老婆生日、朋友想你了陪他喝會兒
//都是在受到外部刺激了
//或受到外部觸發(fā)了
//才產(chǎn)生一次)
}
老婆給你買衣服這類任務
是不是 ----是不是個單次執(zhí)行類任務
{
//小姑娘可以一月買兩件或三件衣服
//大老爺們你一月買三件試試
//大部分是一對鞋破了直接扔掉買對新的
//衣服爛了小了在買一套替換
}
周期類或重復任務---- 比如做飯
{
準備好菜
洗好米
和好面
--------這都是準備的 狀態(tài)
炒菜、蒸米、下面
------- 這是執(zhí)行的狀態(tài)
蒸米需要10分鐘
炒菜需要5分鐘
面熟需要8分鐘
--------這是等待狀態(tài)
(這里一定別小看 等待的 狀態(tài)這個狀態(tài)忒有必要了)
/***
為什么這里等待很有必要
其實等待的時間就是讓CPU來
切換不同的任務
否則 一個任務寫個 while(1) { ......}
一直運行不出來?
咋運行別的任務
這里也是系統(tǒng)的最好的地方
系統(tǒng)內(nèi)怎么切換的
暫時不管它
****/
}
//下面繼續(xù)偽代碼
/**單次執(zhí)行類任務-----就是女朋友給你買衣服******/
鞋破了衣服爛了
給當家的匯報---------這是創(chuàng)建任務
通過了同意了
給錢了,并且買到了----這是運行了任務
{
這也有可能
給錢了同意了
但是現(xiàn)在不同意去購買去執(zhí)行
}
買到了試試合適
還想要一個“機械鍵盤”的可愛要求
---- 直接刪除這個任務3
void my_Task_clothing(void *pdata)
{
//進行準備工作 定義和初始化變量
//任務實體 完成衣服具體購買
//任務刪除 將這月買衣服的任務刪除
}
/***周期類任務 做飯吃飯************************/
void my_Task_have_a_meal(void *pdata)
{
//進行準備工作
//食材
while(1)
{
//做飯
//吃飯
//等待延時 沒到飯點,沒有餓的需求。
}
}
/***觸發(fā)類任務 有約去外吃飯**********************/
void my_Task_eat(void *pdata)
{
//進行準備工作
//準備穿的衣服
//準備好酒
//化妝
while(1)
{
//等待朋友發(fā)的位置
//或給朋友發(fā)吃飯的位置
//也就是獲取別人的請求
//接受到消息后
//開始一起吃飯
//聊天
//等待下一次彼此聚餐
}
}
作者:
wxs732
時間:
2021-3-19 17:48
繼續(xù)說說和書上沒有關(guān)系的白話
這么多任務
有是單任務、
有是觸發(fā)類任務、
又是周期類或重復類任務
又是出外吃飯、又是買衣服、又是在家做飯吃飯
這些任務應該怎么安排?
安排不好就是-----生活的雞飛狗跳
這就出現(xiàn)一個問題----先后順序
那個任務應該安排在最靠前?
那個任務可以安排的次一些?
那個任務可以安排的靠后一些?
哪些任務可以協(xié)調(diào)為有需求在執(zhí)行的觸發(fā)性任務?
哪些任務可以安排為臨時性或突發(fā)性任務?
如何安排先后順序--- 優(yōu)先級 ----???
無論幾個任務這個中心非常重要
如果不能安排好就會造成系統(tǒng)不能協(xié)調(diào)工作
1---首先要滿足這個項目對"實時性"的要求,這也是ucos吹的地方。
2---在就是多少個任務系統(tǒng)協(xié)調(diào)起來最合適,想想是不是任務
數(shù)目越少越好,要是就兩個或三個四個任務
系統(tǒng)跑起來都不是事
3---在就是適當簡化或屏蔽掉一些系統(tǒng)的多余的用不到的功能
這個暫時理解即可,知道在ucos中可以屏蔽一些功能
4---任務和中斷、任務和任務、重復類和單次任務之間
聯(lián)系適當或合理簡化數(shù)據(jù)的同步和通信需求
從而降低或減少對系統(tǒng)資源的時間上的影響
當然,合適不合適跑跑就知道了
實踐--- 實踐 ----- 實踐
缺一不可類任務或關(guān)鍵類任務
任務優(yōu)先級安排越高越好,必須保障其執(zhí)行機會
周期性頻繁類任務
任務優(yōu)先級安排也要高,一般這類任務都執(zhí)行時間都不會長
在寫的時也要保證這類任務盡量簡短
快速響應類實際環(huán)境中的傳感器更新數(shù)據(jù)類任務
任務優(yōu)先級安排也要高,以確保數(shù)據(jù)的實時性
---交換性或上下任務通信數(shù)據(jù)傳遞、信號數(shù)據(jù)處理類
任務優(yōu)先級安排低于快速響應類
致命性危險性緊迫性破壞性非常嚴重性任務
任務一般采用與中斷有聯(lián)系
這么多都要求優(yōu)先級高
確實不好處理
舉一個例子吧
中國保護動物共分為三個級別。
一級保護動物:金絲猴、雪豹、中華白海豚、西藏野驢、梅花鹿、野牦牛藏羚羊等。
二級保護動物:短尾猴、獼猴、藏酋猴、穿山甲、豺、黑熊、棕熊、石貂、水獺等。
三級保護動物:黃鼬、青鼬、中華竹鼠、銀星竹鼠等。
這雖然不是一個行業(yè)的
但是動物保護分級能很好說明就是這樣的一個意思
在國家保護動物中分1、2、3的優(yōu)先性
這也是在任務分配中各個任務的優(yōu)先級
前面蒸米煮面條需要等待為什么很有必要???
答: 這是因為ucos 是完全基于優(yōu)先級的操作系統(tǒng)
所以一定條件下必須出讓cpu占有權(quán)以便比自己優(yōu)先級更低的任務
能夠運行
這是通過調(diào)用部分系統(tǒng)函數(shù)來實現(xiàn)的
這些函數(shù)如下表---
一般的任務必須調(diào)用至少一個表里的函數(shù)
只有一種情況除外
就是單次執(zhí)行的任務
因為任務刪除后肯定出讓CPU
所以可以不調(diào)用表中的函數(shù)
(看看就行不用記住)
OSFlagPend --- 等待事件標志組的事件標志位
(類似手機里APP的屏幕通知)
OSQPend --- 等待消息隊列中的消息
(類似 QQ 中別人給你打字你看到別人正在輸入)
OSSemPend --- 等待一個信號量
(類似摩斯密碼
等待前線發(fā)送過來,
指揮所根據(jù)發(fā)送的字符
了解前線情況
還有些信號量有廣播的功能)
OSTimeDly --- 延時
OSMutexPend --- 等待一個互斥信號量
(類似對講機 每次只能一個人說話另外一個人聽)
這些只是生活中的比喻,有些不恰當
OSQPend --- 等待消息隊列中的消息
OSTaskSuspend -- 掛起任務
OSTimeDlyHMSM -- 延時
上面這幾個函數(shù)都能引起任務函數(shù)的時間等待
任務由三部分組成:
任務堆棧、任務控制塊、任務函數(shù)。
任務由這三部分組成都是啥意思啊?
答:任務堆棧 --- 理解為倉庫
任務控制塊 - 理解為倉庫管理員
任務函數(shù) --- 理解為物流司機
現(xiàn)在網(wǎng)絡購物方便實惠
我們下單子后是給商家---這就是發(fā)送了一個請求信號量 (這里注意了)
商家接收到下的單子也就是信號量開始對單子處理
或?qū)δ阗徺I的東西進行確認
(商家需要和賣家知道彼此說的是啥)
開始備貨 (這是不是就是創(chuàng)建了一個任務)
開始對任務進行具體操作
貨物現(xiàn)在需要在倉庫里有個存儲空間 (這就是任務堆棧了)
貨物在倉庫中有進出關(guān)系
ucos 系統(tǒng)在處理任務堆棧也有進出關(guān)系
(這個和實際ucos 中一樣也有先進先出或后進先出規(guī)則)
別管是啥進出規(guī)則
這個堆棧里或倉庫里保存了這件商品的基本信息
倉庫管理員來管理這個商品是發(fā)給誰 (這就是任務控制塊)
倉庫管理員好牛啊
控制管理層大小是個領(lǐng)導
庫管決定后通知任務函數(shù)
任務函數(shù)來規(guī)劃是發(fā)到北京還是宇宙
是走路地還是航空
(這就是憑本事吃飯了自己發(fā)揮了只要能完成給客戶的商品發(fā)送)
任務其實就是個干具體工作的
完成具體任務
是個苦逼的打工仔
作者:
wxs732
時間:
2021-3-21 22:07
下面這幾句話也是在網(wǎng)絡上看到,感覺寫的很通俗易懂供參考:
任務狀態(tài)
簡單分為運行態(tài),就緒態(tài),阻塞態(tài)。
運行態(tài):萬事俱備,不欠東風(獲得CPU控制權(quán));
就緒態(tài):萬事俱備,只欠東風(缺少CPU控制權(quán));
阻塞態(tài):萬事不俱備(等事件或信號),還欠東風(缺少CPU控制權(quán));
(運行態(tài):老板簽過字、銀行正常上班有錢------可以正常發(fā)薪水)
(就緒態(tài):老板沒簽字、銀行正常上班有錢 ----- 還需要等待)
(阻塞態(tài):老板沒簽字、銀行正常上班沒錢 ----- 還需要等待)
每個任務基本上都會游離于這三種狀態(tài)。
運行到阻塞,就緒到運行稱為任務切換過程。
從用戶的角度看,UCOSIII的任務一共有5種狀態(tài):
1、休眠態(tài):
任務已經(jīng)在CPU的flash中了,
但是還不受UCOSIII管理。
2、就緒態(tài):
系統(tǒng)為任務分配了任務控制塊,
并且任務已經(jīng)在就緒表中登記,
這時這個任務就具有了運行的條件,
但是沒有獲得CPU 的使用權(quán)
此時任務的狀態(tài)就是就緒態(tài)。
3、運行態(tài):
任務獲得CPU的使用權(quán),正在運行。
4、等待態(tài):
正在運行的任務需要等待一段時間,
或者等待某個事件,
這個任務就進入了等待態(tài),
此時系統(tǒng)就會把CPU使用權(quán)轉(zhuǎn)交給別的任務。
5、中斷服務態(tài):
當發(fā)送中斷,
當前正在運行的任務會被掛起,
CPU轉(zhuǎn)而去執(zhí)行中斷服務函數(shù),此時任務的任務狀態(tài)叫做中斷服務態(tài)。
白話任務堆棧、任務控制塊、任務函數(shù)
在多任務操作系統(tǒng)中創(chuàng)建任務時,都需要指定該任務的堆棧大小,
那么這個堆棧的作用時什么呢?
什么情況下需要用到堆棧,以及大小不夠時會產(chǎn)生什么異常呢?
任務堆棧的作用:
1 任務處于運行狀態(tài):
當任務在運行時,
一般都會調(diào)用各式各樣的函數(shù),
而函數(shù)的局部變量,參數(shù),返回值是存在于函數(shù)棧幀里的,
每個函數(shù)都擁有獨立的棧幀,
各個棧幀使用的空間就是任務堆棧的空間。
所以任務堆棧的作用是用于保存函數(shù)在運行/調(diào)用過程中的參數(shù)/局部變量。
(理解堆棧就是個倉庫倉庫里各種各樣的商品也就是各種功能不同函數(shù))
2 任務處于切換
當運行的任務被切換時,需要保護現(xiàn)場(CPU中寄存器的值),
以便于下次恢復數(shù)據(jù)。
所以任務堆棧的作用是用于保存CPU中寄存器的值。
3
任務(低優(yōu)先級的)在運行過程中,
隨時可能被切換,
所以CPU中寄存器的值入棧的棧位置是不確定的,
這取決于當前任務的執(zhí)行情況。
4 堆棧溢出
若堆棧的空間設置太大,會浪費內(nèi)存資源。
而設置得太小,則會出現(xiàn)堆棧溢出,在沒有MMU功能的操作系統(tǒng)中,
可能會導致系統(tǒng)奔潰。
所以,
需要根據(jù)任務的情況設置合適的堆棧大小。
同時,應避免使用遞歸調(diào)用函數(shù),
函數(shù)中局部變量的分配空間不能太大。
任務堆棧是任務的重要部分,
堆棧是在RAM中按照“先進先出(FIFO)”的原則
組織的一塊連續(xù)的存儲空間。
為了滿足任務切換和響應中斷時保存CPU寄存器中的內(nèi)容及
任務調(diào)用其它函數(shù)時的需要,
每個任務都應該有自己的堆棧。
一般是這樣定義的
#define START_STK_SIZE 512 //堆棧大小
CPU_STK START_TASK_STK[START_STK_SIZE];//定義一個數(shù)組來作為任務堆棧
一般就是這樣定義的,
明白就行不能有壓力。
任務堆棧的大小是多少呢?
CPU_STK為 CPU_INT32U類型,
也就是 unsigned int類型,
為4字節(jié)的,
那么任務堆棧
START_TASK_STK的大小就為:512 X 4=2048字節(jié)!
任務如何才能切換回上一個任務
并且還能接著從上次被中斷的地方開始運行?
這一點很重要系統(tǒng)是如何來切換任務的?
它是怎么知道某一個任務運行到了那里?
它是怎么來記錄任務運行過程中產(chǎn)生的數(shù)據(jù)?
這就是任務堆棧初始化的工作
這里是不是和剛學習單片機c51有些類似
org 0x0300
ljmp main
main: mov r0,r1
.....
.....
.....
.....
ajmp main
道理是一樣的
只不過在C 中我們直接定義了幾個大的ROM
每個ROM有是連續(xù)的存儲空間
好似這樣的結(jié)構(gòu)
................
. c51 .
. .
. .
. void main() .
. .
. .
. .
................
........................................................
. stm32 . .
. ucos - iii . .
........................................................
. void main() . . . .
. .void main() . . .
. . .void main() . .
. . . . void main() .
........................................................
51 的ROM 空間有過2K 、16K、64K 的
STM32 的空間就大的多了
這樣利用ucos iii 的組織能力就能在其內(nèi)部分割出來
相同或不相同的 void main(); 來
這其實就是任務堆棧的原型了。
至于在單片機內(nèi)部是如何分配的就不知道了。
知道堆棧的大概了那么
恢復現(xiàn)場就是重新讀取保存下來的CPU的內(nèi)部各個寄存器數(shù)據(jù)。
因此在創(chuàng)建一個新任務時,
必須把系統(tǒng)啟動這個任務時所需的CPU各個寄存器初始值事先存放在任務堆棧中。
這樣當任務獲得CPU使用權(quán)時,
就把任務堆棧的內(nèi)容復制到CPU的各個寄存器,
從而可以任務順利地啟動并運行。
把任務初始數(shù)據(jù)存放到任務堆棧的工作就叫做任務堆棧的初始化,
UCOSIII 提供了完成堆棧初始化的函數(shù):
OSTaskStkInit()。
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
用戶一般不會直接操作堆棧初始化函數(shù),
任務堆棧初始化函數(shù)由任務創(chuàng)建函數(shù)OSTaskCreate()調(diào)用。
不同的CPU對于的寄存器和對堆棧的操作方式不同,
因此在移植UCOSIII的時候需要
用戶根據(jù)各自所選的CPU來編寫任務堆棧初始化函數(shù)。
前面我們創(chuàng)建了一個任務堆棧,怎么使用這個任務堆棧?
作為任務創(chuàng)建函數(shù)OSTaskCreate()的參數(shù),
函數(shù)OSTaskCreate()如下:
void OSTaskCreate (OS_TCB *p_tcb,
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base, //任務堆�;刂�
CPU_STK_SIZE stk_limit, //任務堆棧棧深
CPU_STK_SIZE stk_size, //任務堆棧大小
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
其實看著有些復雜,其實很多參數(shù)都是一定的;
學習過后就理解
基礎(chǔ)東西很重要
特別是C 語言的基礎(chǔ)知識和算法
因為基礎(chǔ)的都是實際來處理具體問題的
即便上了系統(tǒng)
系統(tǒng)也只是起到一個調(diào)度的作用
平衡各個任務之間的運行
函數(shù)OSTaskCreate()中的參數(shù)p_stk_base如何確定?
根據(jù)堆棧的增長方式,
堆棧有兩種增長方式:
向上增長:堆棧的增長方向從低地址向高地址增長。
向下增長:堆棧的增長方向從高地址向低地址增長
函數(shù)OSTaskCreate()中的參數(shù)p_stk_base是任務堆棧基地址,
那么如果CPU的堆棧是向上增長的話
那么基地址就&START_TASK_STK[0],
如果CPU堆棧是向下增長的話
基地址就是&START_TASK_STK[START_STK_SIZE-1]
STM32的堆棧是向下增長的!
寫了很多廢話,只是 為了了解任務堆棧
也寫的沒有趣味性了
失敗
作者:
wxs732
時間:
2021-3-24 13:35
任務堆棧: 就是上下文切換的時候用來保存任務的工作環(huán)境,
若是使用STM32的話用來保存內(nèi)部寄存器值,
無論是中斷還是任務切換都要產(chǎn)生需要保存的
能維持任務中斷或任務切換過后的正常運行的數(shù)據(jù)。
2 任務控制塊
是任務的抽象類型,用于描述其屬性和方法
任務控制塊好似讓做飯這項任務的基礎(chǔ)包
做啥飯
都有啥蔬菜
油鹽醬醋
包括盛菜的盤子
這就是任務的基礎(chǔ)包
里面有完成任務的必要材料
以及去倉庫拿這些食材
廚師好似任務控制塊,控制做出的飯菜味道營養(yǎng)
(那么做出的菜就好比任務函數(shù),送到不同的餐桌,起不同的功能)
用來記錄任務的堆棧指針、任務的當前狀態(tài)、任務的優(yōu)先級別
等一些與任務管理有關(guān)的屬性的表稱為任務控制塊
用來記錄倉庫里商品的存放位置、倉庫有多少商品、商品的價格
等一些商品的屬性就是任務控制塊也就是 庫管。
而且在倉庫里任務控制塊制作一個excel表就是一個表格
一般倉庫都是一格一格這樣擺放的
也就是說只要使用這個倉庫
這樣的空格子就是連續(xù)的
對應ucos就是一條空任務鏈表
既然有空的肯定有實的任務列表
實的就是我們實際創(chuàng)建任務產(chǎn)生的任務控制塊
也就是在倉庫里擺放了 100件
實際存在的商品
(在ucos III中規(guī)定了47個這樣的參數(shù)來說明內(nèi)部的消息)
任務控制塊是用來記錄與任務相關(guān)的信息的數(shù)據(jù)結(jié)構(gòu),
每個任務都要有自己的任務控制塊。
任務控制塊由用戶自行創(chuàng)建,
如下代碼為創(chuàng)建一個任務控制塊:
OS_TCB StartTaskTCB; //創(chuàng)建一個任務控制塊
OS_TCB為一個結(jié)構(gòu)體,
描述了任務控制塊,
任務控制塊中的成員變量用戶不能直接訪問,
更不可能改變他們。
OS_TCB為一個結(jié)構(gòu)體,其中有些成員采用了條件編譯的方式來確定
任務控制塊初始化函數(shù):
OSTCBInit()
下面是ucos ii中的任務控制塊初始化函數(shù)
INT8U OSTCBInit(
INT8U prio, //任務的優(yōu)先級別
OS_STK *ptos, //任務堆棧棧頂指針
OS_STK *pbos, //任務堆棧低指針
INT16U id, //任務的標識符
INT16U stk_size, //任務堆棧的長度
void *pext, //任務控制塊的擴展指針
INT16U opt); //任務控制塊的選擇項
(這里III 對任務控制塊參數(shù)達到47個忒復雜了怕一下嚇懵了,
知道大概有哪些東西就行)
INT8U OSTCBInit(
//商品的價格
//商品的最多的數(shù)目
//商品最少的數(shù)目
//商品的標志
//倉庫對該商品分配的存儲空間大小
//該商品如果在規(guī)定存儲空間放不下如何在新空間來標志
//商品的其他選擇項目
);
該函數(shù)啥作用?
-- 對創(chuàng)建該商品放入整個倉庫的商品目錄中
-- 為商品進行說明
-- 為該商品在倉庫存放(堆棧內(nèi))指定位置
II 和 III 任務控制塊里所包含的參數(shù)不一樣
III 的參數(shù)多多了
作者:
空野
時間:
2021-4-6 12:50
謝謝樓主的發(fā)帖,我正在學習ucosII ,感覺你讓我受到了很大的啟發(fā)
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1