版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
《嵌入式系統(tǒng)設(shè)計(jì)原理》嵌入式操作系統(tǒng)原理與實(shí)踐μC/OS-III通信機(jī)制主講人:賴(lài)樹(shù)明東莞理工學(xué)院05事件標(biāo)志組01通信機(jī)制概述02信號(hào)量03互斥信號(hào)量04消息隊(duì)列01通信機(jī)制概述通信機(jī)制概述01使用實(shí)時(shí)操作系統(tǒng),相對(duì)于裸機(jī)程序的一個(gè)優(yōu)勢(shì)是可以把復(fù)雜的功能劃分到不同的任務(wù)中,但這些任務(wù)的數(shù)據(jù)以及邏輯功能是存在密切的聯(lián)系的,因此需要有一種機(jī)制可以實(shí)現(xiàn)任務(wù)之間的通信,以便于使用這些獨(dú)立的任務(wù)可以按我們的設(shè)想?yún)f(xié)調(diào)運(yùn)行起來(lái),uc/OS-III操作系統(tǒng)提供了豐富的任務(wù)間通信的機(jī)制,可以讓我們根據(jù)使用場(chǎng)景,選擇不同的通信方式。概述A信號(hào)量B互斥信號(hào)量C消息隊(duì)列D事件標(biāo)志組E任務(wù)信號(hào)量F任務(wù)消息隊(duì)列概述02信號(hào)量信號(hào)量介紹API函數(shù)接口任務(wù)同步示例任務(wù)互斥示例信號(hào)量02信號(hào)量(Semaphore)是一種實(shí)現(xiàn)任務(wù)間通信的機(jī)制,用于任務(wù)之間同步或臨界資源的互斥訪問(wèn)。通俗理解:信號(hào)量是一個(gè)正值變量,表示資源的可申請(qǐng)數(shù),當(dāng)任務(wù)申請(qǐng)信號(hào)量時(shí),變量值減1,任務(wù)使用完成后,再釋放信號(hào)量,效果是變量值
加1;信號(hào)量為0時(shí),申請(qǐng)信號(hào)號(hào)的任務(wù)則無(wú)法獲得信號(hào),表現(xiàn)為退出或者等待掛起,直到有其他任務(wù)釋放了信號(hào)量,這些等待的任務(wù)會(huì)按照優(yōu)先級(jí)來(lái)獲取信號(hào)量,繼續(xù)執(zhí)行其代碼。概念信號(hào)量介紹信號(hào)量可以細(xì)分為兩種類(lèi)型:二進(jìn)制信號(hào)量和計(jì)數(shù)信號(hào)量。二進(jìn)制信號(hào)量只能取兩個(gè)值:0或者1,在開(kāi)發(fā)中使用最多的還是是二值信號(hào)量這種情形;計(jì)數(shù)信號(hào)量允許的值介于0~255/65535/4294967295之間,具體取決于信號(hào)量機(jī)制是使用8位、16位,還是32位數(shù)據(jù)類(lèi)型實(shí)現(xiàn)的。對(duì)于μC/OS-III,信號(hào)量的最大值由數(shù)據(jù)類(lèi)型OS_SEM_CTR(見(jiàn)os_type.h)決定,可以根據(jù)需要更改其他類(lèi)似。特征信號(hào)量的使用流程有三個(gè)必需的步驟,分別是創(chuàng)建信號(hào)量、申請(qǐng)信號(hào)量、發(fā)送信號(hào)量,其他可選操作有刪除信號(hào)量、中止等待信號(hào)量、修改信號(hào)值等。使用流程表4.1信號(hào)量函數(shù)序號(hào)函數(shù)名功能描述備注1OSSemCreate()創(chuàng)建一個(gè)信號(hào)量必須調(diào)用2OSSemDel()刪除一個(gè)信號(hào)量必須調(diào)用3OSSemPend()等待信號(hào)量必須調(diào)用4OSSemPendAbort()中止對(duì)信號(hào)量的等待可選調(diào)用5OSSemPost()發(fā)送或發(fā)出信號(hào)量信號(hào)可選調(diào)用6OSSemSet()強(qiáng)制信號(hào)量計(jì)數(shù)為所需值可選調(diào)用信號(hào)量02API函數(shù)接口μC/OS-III系統(tǒng)使用OS_SEM結(jié)構(gòu)來(lái)表示一個(gè)信號(hào)量,創(chuàng)建信號(hào)量,只需要調(diào)用系統(tǒng)提供的OSSemCreate函數(shù),根據(jù)需要傳遞必須參數(shù)即可創(chuàng)建信號(hào)量原型:voidOSSemCreate(OS_SEM*p_sem,CPU_CHAR*p_name,OS_SEM_CTRcnt,RTOS_ERR*p_err)功能:創(chuàng)建信號(hào)量參數(shù):p_sem:指向要初始化的信號(hào)量的指針,一般傳遞OS_SEM類(lèi)型變量地址。p_name:指向要分配給信號(hào)量名稱(chēng)的指針。cnt:信號(hào)量的初始值,如果用于共享資源,則應(yīng)初始化為可用資源數(shù);如用于表示事件的發(fā)生,則應(yīng)初始化為0。p_err:指向存放錯(cuò)誤代碼變量的地址,函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:OS_ERR_NONE:無(wú)錯(cuò)誤,指示信號(hào)量創(chuàng)建成功;OS_ERR_CREATE_ISR:在中斷服務(wù)程序中調(diào)用了此函數(shù);OS_ERR_ILLEGAL_CREATE_RUN_TIME:在調(diào)用OSSafetyCriticalStart()后嘗試創(chuàng)建信號(hào)量。OS_ERR_NAME:如果'p_name'是一個(gè)NULL指針OS_ERR_OBJ_CREATED:如果信號(hào)量已經(jīng)創(chuàng)建,即p_sem前面已經(jīng)被創(chuàng)建過(guò)了。OS_ERR_OBJ_PTR_NULL:如果'p_sem'是一個(gè)NULL指針OS_ERR_OBJ_TYPE:p_sem類(lèi)型不是OS_SEM*;信號(hào)量02API函數(shù)接口示例代碼OS_SEMmy_sem_test;
//定義信號(hào)量全局變量,用于任務(wù)同步。//創(chuàng)建一個(gè)信號(hào)量OSSemCreate((OS_SEM*)&my_sem_test,(CPU_CHAR*)"MySemTest",(OS_SEM_CTR)0,(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){ while(1){;}}信號(hào)量02API函數(shù)接口調(diào)用OSSemPend函數(shù)申請(qǐng)指定的信號(hào)量,如果所申請(qǐng)的信號(hào)量其信號(hào)值大于0,則馬上獲得信號(hào)量,同時(shí)把信號(hào)值減去1,繼續(xù)執(zhí)行后面的代碼。如果當(dāng)前信號(hào)值是0,則表示當(dāng)前信號(hào)量不可用,此時(shí)任務(wù)可以選擇繼續(xù)往下運(yùn)行或者進(jìn)入掛起狀態(tài)等待信號(hào)量變成正數(shù)。申請(qǐng)信號(hào)量函數(shù)原型:OS_SEM_CTROSSemPend(OS_SEM*p_sem,OS_TICKtimeout,
OS_OPTopt,CPU_TS*p_ts,OS_ERR*p_err)函數(shù)功能:申請(qǐng)信號(hào)量,申請(qǐng)成功任務(wù)繼續(xù)往下運(yùn)行,信號(hào)量不可用時(shí),任務(wù)掛起或者返回錯(cuò)誤碼后繼續(xù)往下運(yùn)行(具體哪一種情況由調(diào)用函數(shù)時(shí)給opt參數(shù)傳遞的值決定)。函數(shù)參數(shù):p_sem:是指向信號(hào)量的指針,一般傳遞OS_SEM類(lèi)型變量地址;
timeout:超時(shí)時(shí)間(以時(shí)鐘節(jié)拍為單位)。當(dāng)opt參數(shù)傳遞為OS_OPT_PEND_BLOCKING,timeout值為大于0時(shí),表示信號(hào)量任務(wù)掛起的最長(zhǎng)等待時(shí)間,如超過(guò)在該參數(shù)指定的時(shí)長(zhǎng),信號(hào)量還不可用,則任務(wù)恢復(fù)運(yùn)行,并且將p_err指向的錯(cuò)誤碼變量值設(shè)置為OS_ERR_TIMEOUT。當(dāng)值為0時(shí),表示任務(wù)將永久掛起,直到等待的信號(hào)量變成可用,然后獲得信號(hào)量恢復(fù)運(yùn)行。
opt:OS_OPT_PEND_BLOCKING:任務(wù)會(huì)阻塞;OS_OPT_PEND_NON_BLOCKING:任務(wù)不會(huì)阻塞.
p_ts:用于存放信號(hào)量釋放/掛起中止/信號(hào)量刪除時(shí)的時(shí)間戳。如不需要時(shí)間戳,傳NULL。
p_err:指向存放錯(cuò)誤代碼變量的地址,函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:
OS_ERR_NONE:指示成功獲得信號(hào)量;.......
OS_ERR_PEND_ISR:指示從ISR調(diào)用此函數(shù),結(jié)果將導(dǎo)致掛起;
OS_ERR_TIMEOUT:指示在指定的超時(shí)時(shí)間內(nèi)未收到信號(hào)量。函數(shù)返回值:信號(hào)量計(jì)數(shù)器的當(dāng)前值,值為0表示當(dāng)前信號(hào)量不可用。一般是通過(guò)p_err指向的錯(cuò)誤碼來(lái)判斷申請(qǐng)結(jié)果。信號(hào)量02API函數(shù)接口示例代碼函數(shù)示例:假設(shè)當(dāng)前信號(hào)量my_sem_test已經(jīng)創(chuàng)建好了。OS_ERRerr;//存放函數(shù)調(diào)用錯(cuò)誤碼//沒(méi)有獲得信號(hào)量會(huì)掛起任務(wù)OSSemPend(&my_sem_test,0,OS_OPT_PEND_BLOCKING,0,&err);//請(qǐng)求信號(hào)量//判斷申請(qǐng)信號(hào)量是否成功if(err!=OS_ERR_NONE){//在以下編寫(xiě)沒(méi)有正確獲得信號(hào)量但是函數(shù)返回時(shí)的處理代碼……//根據(jù)實(shí)際情況編寫(xiě)出錯(cuò)處理代碼}
信號(hào)量02API函數(shù)接口本示例是使用信號(hào)量實(shí)現(xiàn)兩個(gè)任務(wù)同步,演示通過(guò)信號(hào)量實(shí)現(xiàn)任務(wù)間通信的方法。任務(wù)1負(fù)責(zé)檢測(cè)按鍵1是否按下,按下了則發(fā)送信號(hào)量;任務(wù)2負(fù)責(zé)申請(qǐng)信號(hào)量,等待任務(wù)1發(fā)送信號(hào)量后,往下執(zhí)行代碼,控制開(kāi)發(fā)板上的LED。實(shí)驗(yàn)的效果是每按下按鍵1一次,開(kāi)發(fā)板上的LED就會(huì)反轉(zhuǎn)一次。發(fā)送信號(hào)量信號(hào)量02任務(wù)同步示例主函數(shù)OS_SEMkey_sem;//定義一個(gè)信號(hào)量,用于任務(wù)同步intmain(void){OS_ERRerr;CPU_SR_ALLOC();......OSInit(&err);//初始化μC/OS-III//創(chuàng)建一個(gè)信號(hào)量OSSemCreate((OS_SEM*)&key_sem,(CPU_CHAR*)"key_sem",(OS_SEM_CTR)0,//信號(hào)值初始值設(shè)置為0(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){while(1){;}}OS_CRITICAL_ENTER();//進(jìn)入臨界區(qū)//創(chuàng)建開(kāi)始任務(wù).......//調(diào)用OSTaskCreate創(chuàng)建啟動(dòng)任務(wù)OS_CRITICAL_EXIT();//退出臨界區(qū)OSStart(&err);//開(kāi)啟μC/OS-III}信號(hào)量02任務(wù)同步示例主函數(shù)OS_SEMkey_sem;//定義一個(gè)信號(hào)量,用于任務(wù)同步intmain(void){OS_ERRerr;CPU_SR_ALLOC();......OSInit(&err);//初始化μC/OS-III//創(chuàng)建一個(gè)信號(hào)量OSSemCreate((OS_SEM*)&key_sem,(CPU_CHAR*)"key_sem",(OS_SEM_CTR)0,//信號(hào)值初始值設(shè)置為0(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){while(1){;}}OS_CRITICAL_ENTER();//進(jìn)入臨界區(qū)//創(chuàng)建開(kāi)始任務(wù).......//調(diào)用OSTaskCreate創(chuàng)建啟動(dòng)任務(wù)OS_CRITICAL_EXIT();//退出臨界區(qū)OSStart(&err);//開(kāi)啟μC/OS-III}信號(hào)量02任務(wù)同步示例任務(wù)1函數(shù)//任務(wù)1的任務(wù)函數(shù)voidtask1_task(void*p_arg){
u8key;
OS_ERRerr;
while(1)
{ key=KEY_Scan(0);
//掃描按鍵 if(key==KEY1_PRES)
//如果按下開(kāi)發(fā)板按鍵1 { printf("Task1:發(fā)送一個(gè)信號(hào)量\r\n");
//輸出發(fā)送信號(hào)量提示 OSSemPost(&key_sem,OS_OPT_POST_1,&err);
//發(fā)送信號(hào)量 printf("當(dāng)前信號(hào)值:%u\r\n",key_sem.Ctr); } OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);//延時(shí)10ms
}}信號(hào)量02任務(wù)同步示例任務(wù)1函數(shù)voidtask2_task(void*p_arg){u8num;OS_ERRerr;while(1){//沒(méi)有獲得信號(hào)量會(huì)掛起任務(wù)OSSemPend(&key_sem,0,OS_OPT_PEND_BLOCKING,0,&err);//請(qǐng)求信號(hào)量//判斷申請(qǐng)信號(hào)量是否成功if(err!=OS_ERR_NONE){//在以下編寫(xiě)沒(méi)有正確獲得信號(hào)量但是函數(shù)返回時(shí)的處理代碼//......}LED1_Toglge();//翻轉(zhuǎn)LED1狀態(tài)}}信號(hào)量02任務(wù)同步示例本示例是使用信號(hào)量實(shí)現(xiàn)對(duì)共享資源的互斥訪問(wèn),演示通過(guò)信號(hào)量實(shí)現(xiàn)任務(wù)間通信的另一種使用場(chǎng)景。任務(wù)1和任務(wù)2都需要訪問(wèn)一個(gè)共享資源,即一塊數(shù)據(jù)緩沖區(qū),程序中可表示為一個(gè)數(shù)組,其中任務(wù)1對(duì)這塊數(shù)組進(jìn)行寫(xiě)操作,任務(wù)2負(fù)責(zé)讀取出任務(wù)1寫(xiě)入的數(shù)據(jù)。為了保證任務(wù)2每次都可以完整讀取任務(wù)1的一次完成寫(xiě)操作數(shù)據(jù),保證數(shù)據(jù)不會(huì)混亂,則任務(wù)1和任務(wù)2在訪問(wèn)這塊共享的內(nèi)存(數(shù)組)時(shí)都需要申請(qǐng)同一個(gè)信號(hào)量,如果信號(hào)量被其中一個(gè)持有了,則需要等待對(duì)方訪問(wèn)完共享資源,然后發(fā)送信號(hào)量,才可以訪問(wèn)共享資源,從而保證了共享資源的互斥訪問(wèn)。功能說(shuō)明信號(hào)量02任務(wù)互斥示例示例框圖信號(hào)量02任務(wù)互斥示例主函數(shù)OS_SEMshare_mem_sem;//定義一個(gè)信號(hào)量,用于保護(hù)共享資訪問(wèn)。intmain(void){OS_ERRerr;CPU_SR_ALLOC();......OSInit(&err);//初始化μC/OS-III//創(chuàng)建一個(gè)信號(hào)量share_mem_semOSSemCreate((OS_SEM*)&share_mem_sem,(CPU_CHAR*)"share_mem_sem",(OS_SEM_CTR)1,//注意本示例初始值不能為0(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){while(1){;}}OS_CRITICAL_ENTER();//進(jìn)入臨界區(qū)……//調(diào)用OSTaskCreate創(chuàng)建啟動(dòng)任務(wù)。OS_CRITICAL_EXIT();//退出臨界區(qū)OSStart(&err);//開(kāi)啟μC/OS-III}信號(hào)量02任務(wù)互斥示例主函數(shù)voidtask1_task(void*p_arg){ OS_ERRerr; uint32_tcnt=1;//記錄寫(xiě)入數(shù)據(jù)的次數(shù) while(1) { OSSemPend(&share_mem_sem,0,OS_OPT_PEND_BLOCKING,0,&err);//請(qǐng)求信號(hào)量 //判斷申請(qǐng)信號(hào)量是否成功 if(err!=OS_ERR_NONE){ //在以下編寫(xiě)沒(méi)有正確獲得信號(hào)量但是函數(shù)返回時(shí)的處理代碼 } //以下開(kāi)始訪問(wèn)共享資源,往array_buf數(shù)組中寫(xiě)入數(shù)據(jù) sprintf(array_buf,"cnt:%05d",cnt);//開(kāi)始訪問(wèn)共享資源 printf("第%d次寫(xiě)入數(shù)據(jù):%s\r\n",cnt,array_buf);//輸出寫(xiě)入內(nèi)容提示 cnt++;//寫(xiě)入次數(shù)增加 OSSemPost(&share_mem_sem,OS_OPT_POST_1,&err);//釋放信號(hào)量 OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);//延時(shí)1s }}信號(hào)量02任務(wù)互斥示例任務(wù)1函數(shù)//任務(wù)1的任務(wù)函數(shù)voidtask1_task(void*p_arg){
u8key;
OS_ERRerr;
while(1)
{ key=KEY_Scan(0);
//掃描按鍵 if(key==KEY1_PRES)
//如果按下開(kāi)發(fā)板按鍵1 { printf("Task1:發(fā)送一個(gè)信號(hào)量\r\n");
//輸出發(fā)送信號(hào)量提示 OSSemPost(&key_sem,OS_OPT_POST_1,&err);
//發(fā)送信號(hào)量 printf("當(dāng)前信號(hào)值:%u\r\n",key_sem.Ctr); } OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);//延時(shí)10ms
}}信號(hào)量02任務(wù)互斥示例任務(wù)2函數(shù)voidtask2_task(void*p_arg){OS_ERRerr;charread_buf[50]={0};//用于存放臨時(shí)數(shù)據(jù)uint32_tcnt=1;
//記錄讀取數(shù)據(jù)的次數(shù)while(1){
//沒(méi)有獲得信號(hào)量會(huì)掛起任務(wù)OSSemPend(&share_mem_sem,0,OS_OPT_PEND_BLOCKING,0,&err);if(err!=OS_ERR_NONE){//在以下編寫(xiě)沒(méi)有正確獲得信號(hào)量但是函數(shù)返回時(shí)的處理代碼....}//以下開(kāi)始訪問(wèn)共享資源,把a(bǔ)rray_buf數(shù)組中的字符串復(fù)制到read_buf中strcpy(read_buf,array_buf);//開(kāi)始訪問(wèn)共享資源//輸出讀取到的內(nèi)容提示,寫(xiě)入次數(shù)增加printf("第%d次讀取數(shù)據(jù):%s\r\n",cnt++,read_buf);OSSemPost(&share_mem_sem,OS_OPT_POST_1,&err);//釋放信號(hào)量OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);}}信號(hào)量02任務(wù)互斥示例03互斥信號(hào)量互斥信號(hào)量介紹API函數(shù)接口任務(wù)互斥示例----------優(yōu)先級(jí)反轉(zhuǎn),是指某個(gè)共享資源被較低優(yōu)先級(jí)的任務(wù)所持有,較高優(yōu)先級(jí)的任務(wù)任務(wù)申請(qǐng)?jiān)摴蚕碣Y源無(wú)法獲得,導(dǎo)致較高優(yōu)先級(jí)任務(wù)反而被更低優(yōu)先級(jí)的任務(wù)推遲被調(diào)度執(zhí)行的現(xiàn)象。互斥信號(hào)量03互斥信號(hào)量介紹優(yōu)先級(jí)反轉(zhuǎn)概念μC/OS-III支持一種特殊類(lèi)型的二值互斥信號(hào)量,稱(chēng)為互斥信號(hào)量(也稱(chēng)為互斥體),相對(duì)于前面學(xué)習(xí)過(guò)普通二值互斥信號(hào)量,它解決了優(yōu)先級(jí)反轉(zhuǎn)的問(wèn)題。接下來(lái)的先來(lái)學(xué)習(xí)什么是什么級(jí)轉(zhuǎn)換,才可以更好理解互斥信號(hào)量的作用?;コ庑盘?hào)量概念右圖展示一個(gè)優(yōu)先級(jí)反轉(zhuǎn)的示例:系統(tǒng)中有高(TaskH),中(TaskM),低(TaskL)三個(gè)級(jí)別優(yōu)先級(jí)任務(wù),某一時(shí)刻低TaskL任務(wù)持有信號(hào)量S,此時(shí)TaskH就緒搶占TaskL,然后申請(qǐng)信號(hào)量S,但是此時(shí)信號(hào)量被TaskL持有,因此TaskH掛起,放棄CPU。然后TaskL恢復(fù)運(yùn)行,運(yùn)行過(guò)程中TaskM就緒搶占TaskL,TaskM沒(méi)有申請(qǐng)信號(hào)量S,因此它可以長(zhǎng)時(shí)間持有CPU,這樣就導(dǎo)致了TaskH反而被比它低的任務(wù)TaskM推遲調(diào)度,因?yàn)橹挥蠺askM釋放CPU,TaskL才可以繼續(xù)運(yùn)行,從而釋放信號(hào)量,Task才有機(jī)會(huì)運(yùn)行,這現(xiàn)象就是優(yōu)先級(jí)反轉(zhuǎn)?;コ庑盘?hào)量03互斥信號(hào)量介紹優(yōu)先級(jí)反轉(zhuǎn)示例互斥信號(hào)量的使用流程很簡(jiǎn)單:創(chuàng)建互斥信號(hào)量、申請(qǐng)互斥信號(hào)量、釋放互斥信號(hào)量三個(gè)必需的步驟,其他可選操作有刪除互斥信號(hào)量、中止等待互斥信號(hào)量?;コ庑盘?hào)量接口互斥信號(hào)量03API函數(shù)接口
互斥信號(hào)量函數(shù)序號(hào)函數(shù)名功能描述備注1OSMutexCreate()創(chuàng)建一個(gè)互斥信號(hào)量必須調(diào)用2OSMutexDel()刪除一個(gè)互斥信號(hào)量必須調(diào)用3OSMutexPend()等待互斥信號(hào)量必須調(diào)用4OSMutexPendAbort()中止對(duì)互斥信號(hào)量的等待可選調(diào)用5OSMutexPost()釋放互斥信號(hào)量可選調(diào)用μC/OS-III系統(tǒng)使用OS_MUTEX結(jié)構(gòu)來(lái)表示一個(gè)互斥信號(hào)量,要?jiǎng)?chuàng)建互斥信號(hào)量,我們只需要調(diào)用系統(tǒng)提供的OSMutexCreateAPI函數(shù),根據(jù)需要傳遞必須參數(shù)即可創(chuàng)建互斥信號(hào)量互斥信號(hào)量03API函數(shù)接口函數(shù)原型:voidOSMutexCreate(OS_MUTEX*p_mutex,CPU_CHAR*p_name,OS_ERR*p_err)函數(shù)功能:創(chuàng)建互斥信號(hào)量函數(shù)參數(shù):p_mutex:指向要初始化的互斥信號(hào)量的指針,一般是傳遞OS_MUTEX類(lèi)型的變量地址。
p_name:指向要分配給互斥信號(hào)量的名稱(chēng)的指針
p_err:指向存放錯(cuò)誤代碼變量的指針,函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:
OS_ERR_NONE:指示互斥信號(hào)量創(chuàng)建成功;
OS_ERR_CREATE_ISR:指示在中斷服務(wù)程序中調(diào)用了此函數(shù);
OS_ERR_NAME:指令'p_name'是一個(gè)NULL指針;
OS_ERR_OBJ_CREATED:指示p_mutex已經(jīng)創(chuàng)建過(guò)了;
OS_ERR_OBJ_PTR_NULL:指示'p_mutex'是一個(gè)NULL指針;示例代碼函數(shù)示例:OS_MUTEXmy_mutex_test;//定義互斥信號(hào)量全局變量,用于共享資源保護(hù)。OSMutexCreate((OS_MUTEX*)&my_mutex_test,(CPU_CHAR*)"my_mutex_test",(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){ while(1){;}}示例說(shuō)明:①使用互斥信號(hào)量時(shí),互斥信號(hào)量變量需要定義為全局變量,否則其他任務(wù)不能使用;②不要在中斷服務(wù)程序中去創(chuàng)建互斥信號(hào)量;備注:函數(shù)提供的錯(cuò)誤碼比較多,寫(xiě)代碼時(shí)一般判斷錯(cuò)誤碼值是否等于OS_ERR_NONE,如果不等于該值表示函數(shù)調(diào)用出錯(cuò)了,如果需要分析具體哪一種錯(cuò)誤,再使用單步調(diào)試的方法來(lái)觀察函數(shù)返回的錯(cuò)誤碼?;コ庑盘?hào)量03API函數(shù)接口調(diào)用OSMutexPend函數(shù)申請(qǐng)指定的互斥信號(hào)量,如果持有互斥信號(hào)量的任務(wù)優(yōu)先級(jí)比當(dāng)前申請(qǐng)互斥信號(hào)量的任務(wù)優(yōu)先級(jí)低,則會(huì)把持有互斥信號(hào)量的任務(wù)的優(yōu)先級(jí)臨時(shí)提升到和當(dāng)前申請(qǐng)互斥信號(hào)量的任務(wù)優(yōu)先級(jí)一樣。然后,當(dāng)前任務(wù)進(jìn)入掛起狀態(tài),把CPU歸還給原來(lái)持有互斥信號(hào)量的任務(wù),讓持有互斥信號(hào)量的任務(wù)繼續(xù)運(yùn)行。當(dāng)持有該互斥信號(hào)量的任務(wù)釋放掉互斥信號(hào)量后,其優(yōu)先級(jí)重新恢復(fù)到原來(lái)的優(yōu)先級(jí)?;コ庑盘?hào)量03API函數(shù)接口申請(qǐng)互斥信號(hào)量函數(shù)原型:voidOSMutexPend(OS_MUTEX*p_mutex,OS_TICKtimeout,OS_OPTopt,CPU_TS*p_ts,OS_ERR*p_err)函數(shù)功能:申請(qǐng)指定的互斥信號(hào)量,函數(shù)形參:p_sem:指向互斥信號(hào)量的指針;timeout:超時(shí)時(shí)間(以時(shí)鐘節(jié)拍為單位),用法和作用和申請(qǐng)信號(hào)量函數(shù)時(shí)一樣。opt:用法和作用和申請(qǐng)信號(hào)量函數(shù)時(shí)一樣。。p_ts:用于保存互斥信號(hào)量發(fā)布或掛起中止或互斥信號(hào)量刪除時(shí)的時(shí)間戳。不需要時(shí)間戳,可傳NULL。p_err:指向存放錯(cuò)誤代碼變量的指針,函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:
OS_ERR_NONE:指示成功獲得互斥信號(hào)量
OS_ERR_PEND_ISR:指示在中斷服務(wù)程序中調(diào)用了此函數(shù),結(jié)果將導(dǎo)致掛起。
OS_ERR_TIMEOUT:指示在指定的超時(shí)時(shí)間內(nèi)未能成功獲得互斥信號(hào)量
.......示例代碼函數(shù)示例:假設(shè)當(dāng)前互斥信號(hào)量my_mutex_test已經(jīng)創(chuàng)建好。OS_ERRerr;//存放函數(shù)調(diào)用錯(cuò)誤碼//沒(méi)有獲得互斥信號(hào)量會(huì)掛起任務(wù)OSMutexPend(&my_mutex_test,0,OS_OPT_PEND_BLOCKING,0,&err);//請(qǐng)求互斥信號(hào)量//判斷互斥信號(hào)量是否成功獲得if(err!=OS_ERR_NONE){ //在以下編寫(xiě)沒(méi)有正確獲得互斥信號(hào)量但是函數(shù)返回時(shí)的處理代碼 ......//根據(jù)實(shí)際情況編寫(xiě)出錯(cuò)處理代碼}互斥信號(hào)量03API函數(shù)接口調(diào)用OSMutexPost函數(shù)可以釋放互斥信號(hào)量,如果有等待該互斥信號(hào)量的任務(wù)就緒,并比當(dāng)前任務(wù)有更高的優(yōu)先級(jí),則執(zhí)行任務(wù)調(diào)度,CPU執(zhí)行切換到新任務(wù)執(zhí)行。否則,原任務(wù)在釋放互斥信號(hào)量之后繼續(xù)執(zhí)行后面代碼。函數(shù)原型:voidOSMutexPost(OS_MUTEX*p_mutex,OS_OPTopt,OS_ERR*p_err)函數(shù)功能:釋放互斥信號(hào)量,如果有等待此互斥信號(hào)量的高優(yōu)先級(jí)任務(wù),則馬上發(fā)生任務(wù)切換,否則繼續(xù)運(yùn)行當(dāng)前任務(wù)后面的代碼。函數(shù)形參:p_sem:是指向互斥信號(hào)量的指針
opt:確定執(zhí)行的POST類(lèi)型
OS_OPT_POST_NONE:表示未選擇特殊選項(xiàng)
OS_OPT_POST_NO_SCHED:表示如果你不希望在釋放互斥信號(hào)量后開(kāi)始調(diào)度程序p_err:指向存放錯(cuò)誤代碼變量的指針。函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:
OS_ERR_NONE:指示調(diào)用成功釋放互斥信號(hào)量;
OS_ERR_MUTEX_NESTING:指示互斥鎖擁有者嵌套了它對(duì)互斥鎖的使用;
OS_ERR_MUTEX_NOT_OWNER:指示釋放互斥信號(hào)量的任務(wù)不是互斥鎖所有者;
OS_ERR_OBJ_PTR_NULL:指示'p_mutex'是一個(gè)NULL指針;
OS_ERR_OBJ_TYPE:指示'p_mutex'沒(méi)有指向OS_MUTEX類(lèi)型變量;
OS_ERR_POST_ISR:指示在中斷服務(wù)程序中釋放互斥信號(hào)量?;コ庑盘?hào)量03API函數(shù)接口釋放互斥信號(hào)量示例代碼函數(shù)示例:假設(shè)當(dāng)前互斥信號(hào)量my_mutex_test已經(jīng)創(chuàng)建好了。OS_ERRerr;//存放函數(shù)調(diào)用錯(cuò)誤碼OSMutexPost(&my_mutex_test,OS_OPT_POST_NONE,&err);//發(fā)送互斥信號(hào)量//判斷互斥信號(hào)量是否成功發(fā)送,發(fā)送一般都不會(huì)出錯(cuò),以下判斷代碼也可以不寫(xiě)if(err!=OS_ERR_NONE){ //在以下編寫(xiě)沒(méi)有成功發(fā)送互斥信號(hào)量時(shí)的處理代碼,一般情況不用寫(xiě)。 ……//}互斥信號(hào)量03API函數(shù)接口本示例是使用互斥信號(hào)量實(shí)現(xiàn)對(duì)共享資源的互斥訪問(wèn)。任務(wù)1和任務(wù)2都需要訪問(wèn)一個(gè)共享資源,即一塊數(shù)據(jù)緩沖區(qū),程序中可表示為一個(gè)數(shù)組,其中任務(wù)1對(duì)這塊數(shù)組進(jìn)行寫(xiě)操作,任務(wù)2負(fù)責(zé)讀取出數(shù)據(jù)緩沖區(qū)任務(wù)1寫(xiě)入的數(shù)據(jù)。為了保證任務(wù)2每次都可以完整讀取任務(wù)1的一次完成寫(xiě)操作,保證數(shù)據(jù)不會(huì)混亂,則任務(wù)1和任務(wù)2在訪問(wèn)這塊共享的內(nèi)存(數(shù)組)時(shí)都需要申請(qǐng)同一個(gè)互斥信號(hào)量,如果互斥信號(hào)量被其中一個(gè)任務(wù)持有了,則需要等待對(duì)方訪問(wèn)完共享資源,然后互斥信號(hào)量才可以訪問(wèn)共享資源,從而保證了共享資源的互斥訪問(wèn)。功能說(shuō)明互斥信號(hào)量03任務(wù)互斥示例示例框圖互斥信號(hào)量03任務(wù)互斥示例主函數(shù)OS_MUTEXshare_mem_mutex;//定義一個(gè)互斥信號(hào)量,用于保護(hù)共享資訪問(wèn)intmain(void){OS_ERRerr;CPU_SR_ALLOC();......OSInit(&err);//初始化μC/OS-III//創(chuàng)建一個(gè)互斥信號(hào)量OSMutexCreate((OS_MUTEX*)&share_mem_mutex,(CPU_CHAR*)"share_mem_mutex",(OS_ERR*)&err);//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題if(err!=OS_ERR_NONE){while(1){;}}OS_CRITICAL_ENTER();//進(jìn)入臨界區(qū)//調(diào)用OSTaskCreate創(chuàng)建啟動(dòng)任務(wù),和前面講解的代碼相同,此時(shí)省略......OS_CRITICAL_EXIT();//退出臨界區(qū)OSStart(&err);//開(kāi)啟μC/OS-III}互斥信號(hào)量03任務(wù)互斥示例主函數(shù)voidtask1_task(void*p_arg){ OS_ERRerr; uint32_tcnt=1;//記錄寫(xiě)入數(shù)據(jù)的次數(shù) while(1) { OSSemPend(&share_mem_sem,0,OS_OPT_PEND_BLOCKING,0,&err);//請(qǐng)求信號(hào)量 //判斷申請(qǐng)信號(hào)量是否成功 if(err!=OS_ERR_NONE){ //在以下編寫(xiě)沒(méi)有正確獲得信號(hào)量但是函數(shù)返回時(shí)的處理代碼 } //以下開(kāi)始訪問(wèn)共享資源,往array_buf數(shù)組中寫(xiě)入數(shù)據(jù) sprintf(array_buf,"cnt:%05d",cnt);//開(kāi)始訪問(wèn)共享資源 printf("第%d次寫(xiě)入數(shù)據(jù):%s\r\n",cnt,array_buf);//輸出寫(xiě)入內(nèi)容提示 cnt++;//寫(xiě)入次數(shù)增加 OSSemPost(&share_mem_sem,OS_OPT_POST_1,&err);//釋放信號(hào)量 OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);//延時(shí)1s }}互斥信號(hào)量03任務(wù)互斥示例任務(wù)1函數(shù)voidtask1_task(void*p_arg){OS_ERRerr;uint32_tcnt=1;//記錄寫(xiě)入數(shù)據(jù)的次數(shù)while(1){
//請(qǐng)求互斥信號(hào)量OSMutexPend(&share_mem_mutex,0,OS_OPT_PEND_BLOCKING,0,&err);
if(err!=OS_ERR_NONE){//在以下編寫(xiě)沒(méi)有正確獲得互斥信號(hào)量但是函數(shù)返回時(shí)的處理代碼//……} //以下開(kāi)始訪問(wèn)共享資源,往array_buf數(shù)組中寫(xiě)入數(shù)據(jù)sprintf(array_buf,"cnt:%05d",cnt);//開(kāi)始訪問(wèn)共享資源printf("第%d次寫(xiě)入數(shù)據(jù):%s\r\n",cnt++,array_buf);//輸出寫(xiě)入內(nèi)容提示,寫(xiě)入次數(shù)增加OSMutexPost(&share_mem_mutex,OS_OPT_POST_NONE,&err);//釋放互斥信號(hào)量OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);//延時(shí)1s}}互斥信號(hào)量03任務(wù)互斥示例任務(wù)2函數(shù)voidtask2_task(void*p_arg){OS_ERRerr;charread_buf[50]={0};//用于存放臨時(shí)數(shù)據(jù)uint32_tcnt=1;
//記錄讀取數(shù)據(jù)的次數(shù)while(1){//請(qǐng)求互斥信號(hào)量,沒(méi)有獲得互斥信號(hào)量會(huì)掛起任務(wù)OSMutexPend(&share_mem_mutex,0,OS_OPT_PEND_BLOCKING,0,&err);if(err!=OS_ERR_NONE){//判斷申請(qǐng)互斥信號(hào)量是否成功//在以下編寫(xiě)沒(méi)有正確獲得互斥信號(hào)量但是函數(shù)返回時(shí)的處理代碼}//以下開(kāi)始訪問(wèn)共享資源,把a(bǔ)rray_buf數(shù)組中的字符串復(fù)制到read_buf中strcpy(read_buf,array_buf);//開(kāi)始訪問(wèn)共享資源printf("第%d次讀取數(shù)據(jù):%s\r\n",cnt++,read_buf);//輸出讀取到的內(nèi)容提示OSMutexPost(&share_mem_mutex,OS_OPT_POST_NONE,&err);//釋放互斥信號(hào)量OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);//延時(shí)0.5s}}互斥信號(hào)量03任務(wù)互斥示例04消息隊(duì)列量消息隊(duì)列介紹API函數(shù)接口任務(wù)同步示例μC/OS-III提供的信號(hào)量和互斥信號(hào)量,它們可以實(shí)現(xiàn)任務(wù)間的通信和中斷與任務(wù)之間的通信,但是它們還是有缺陷的,它們不支持在任務(wù)間傳遞用戶自定義的數(shù)據(jù),僅僅是由系統(tǒng)報(bào)告了一個(gè)事件的發(fā)生而已。在實(shí)現(xiàn)編程中,很多場(chǎng)景需要在任務(wù)間或中斷與任務(wù)間傳輸自定義的數(shù)據(jù)。比如,有鍵盤(pán)掃描任務(wù)和動(dòng)作執(zhí)行任務(wù),鍵盤(pán)掃描任務(wù)負(fù)責(zé)掃描用戶按下了哪個(gè)按鍵,然后把按鍵碼發(fā)送給動(dòng)作執(zhí)行任務(wù)。動(dòng)作執(zhí)行任務(wù)接收鍵盤(pán)掃描任務(wù)發(fā)來(lái)的按鍵碼,根據(jù)不同的按鍵碼執(zhí)行不同的控制動(dòng)作。要實(shí)現(xiàn)這樣的功能,就需要使用到μC/OS-III提供的消息隊(duì)列功能了。消息隊(duì)列04消息隊(duì)列介紹消除隊(duì)列特征消息隊(duì)列也是任務(wù)間通信的一種機(jī)制,可以看成一個(gè)容器,可存放多條消息。一條消息由指向具體數(shù)據(jù)的指針、存放指向數(shù)據(jù)大小的變量和指示消息發(fā)送時(shí)間的時(shí)間戳組成。數(shù)據(jù)的指針可以指向任何用戶自定義的數(shù)據(jù)區(qū),甚至可以指向一個(gè)函數(shù)。消息隊(duì)列概念消息隊(duì)列04消息隊(duì)列介紹消息內(nèi)容在消息發(fā)出后,在被任務(wù)接收前,必須保持靜態(tài),中途不能改變它的值,因?yàn)閿?shù)據(jù)是通過(guò)發(fā)送其內(nèi)存地址而不是通過(guò)值發(fā)送的。換句話說(shuō),發(fā)送的數(shù)據(jù)不會(huì)被復(fù)制,或者,傳遞指向全局變量、全局?jǐn)?shù)據(jù)結(jié)構(gòu)、全局?jǐn)?shù)組或函數(shù)等的指針。μC/OS-III中消息隊(duì)列是用戶創(chuàng)建的內(nèi)核對(duì)象,只有內(nèi)存資源足夠大,數(shù)量沒(méi)有限制。下圖展示了對(duì)消息隊(duì)列進(jìn)行的操作有數(shù)據(jù)流程。認(rèn)識(shí)消息隊(duì)列消息隊(duì)列04消息隊(duì)列介紹消息隊(duì)列默認(rèn)是使用先進(jìn)先出管道(FIFO)的方式,即先進(jìn)入隊(duì)列的消息也是先被取出來(lái)。在μC/OS-III中,還可以按后進(jìn)先出順序(LIFO)發(fā)布消息。當(dāng)任務(wù)或中斷服務(wù)程序必須向任務(wù)發(fā)送“緊急”消息時(shí),LIFO機(jī)制很有用。往任務(wù)中發(fā)送消息是通過(guò)調(diào)用OSQPost()函數(shù)來(lái)實(shí)現(xiàn),至于使用FIFO,還是LIFO方式,則由傳遞給OSQPost()函數(shù)的參數(shù)來(lái)決定。認(rèn)識(shí)消息隊(duì)列消息隊(duì)列使用OSQPend()函數(shù)來(lái)接收消息,接收消息的任務(wù)旁邊的小沙漏表示任務(wù)可以指定一個(gè)超時(shí)等待時(shí)間,如果任務(wù)指定的時(shí)間內(nèi)沒(méi)有收到消息,則會(huì)超時(shí)喚醒任務(wù),并且返回錯(cuò)誤碼指示當(dāng)前任務(wù)是因?yàn)榻邮障⒊瑫r(shí)而被喚醒的,不是正確接收到消息被喚醒。如果指定超時(shí)時(shí)間為0,任務(wù)就會(huì)永遠(yuǎn)等待下去,直到接收到消息為止。消息隊(duì)列04消息隊(duì)列介紹消息隊(duì)列還包含一個(gè)等待消息發(fā)送到消息隊(duì)列的任務(wù)列表。多個(gè)任務(wù)可以在一個(gè)消息隊(duì)列上等待,如右圖所示。當(dāng)消息發(fā)送到消息隊(duì)列時(shí),等待消息隊(duì)列的最高優(yōu)先級(jí)任務(wù)接收該消息,還可以向所有在消息隊(duì)列上等待的任務(wù)廣播發(fā)送一條消息,從廣播中接收到消息的任務(wù),只要它們的優(yōu)先級(jí)高于發(fā)送消息的任務(wù),或者如果任務(wù)是被中斷打斷,消息是在中斷服務(wù)程序中發(fā)送,μC/OS-III都會(huì)發(fā)生任務(wù)調(diào)度,μC/OS-III將運(yùn)行這些處于就緒狀態(tài)優(yōu)先級(jí)最高的任務(wù)。認(rèn)識(shí)消息隊(duì)列消息隊(duì)列的使用流程很簡(jiǎn)單:創(chuàng)建消息郵箱、讀取消息、發(fā)送消息三個(gè)必需的步驟,其他可選操作有刪除等待消息、中止等待消息。消息隊(duì)列接口消息隊(duì)列04API函數(shù)接口消息隊(duì)列函數(shù)序號(hào)函數(shù)名功能描述備注1OSQCreate()創(chuàng)建消息隊(duì)列必須調(diào)用2OSQPend()等待接收消息必須調(diào)用3OSQPost()發(fā)送消息到消息隊(duì)列中必須調(diào)用4OSQDel()刪除消息隊(duì)列可選調(diào)用5OSQFlush()清空消息隊(duì)列可選調(diào)用6OSQPendAbort()取消等待消除隊(duì)列可選調(diào)用μC/OS-III系統(tǒng)使用OS_Q結(jié)構(gòu)來(lái)表示一個(gè)消息隊(duì)列,創(chuàng)建消息隊(duì)列,只需要調(diào)用系統(tǒng)提供的OSQCreateAPI函數(shù),根據(jù)需要傳遞必需的參數(shù)即可。創(chuàng)建消息隊(duì)列函數(shù)原型:voidOSQCreate(OS_Q*p_q,CPU_CHAR*p_name,OS_MSG_QTYmax_qty,OS_ERR*p_err)函數(shù)功能:創(chuàng)建消息隊(duì)列函數(shù)形參:p_q:指向消息隊(duì)列的指針,傳遞OS_Q類(lèi)型變量的地址;p_name:一個(gè)字符串指針,用于給消息隊(duì)列命名;max_qty:表示消息隊(duì)列的大?。ū仨毞橇悖?,即消息隊(duì)列中可以容納消息的數(shù)量;p_err:一個(gè)指向存放錯(cuò)誤碼變量的指針,該變量將包含此函數(shù)返回的錯(cuò)誤代碼,可取錯(cuò)誤碼有:OS_ERR_NONE:成功創(chuàng)建消息隊(duì)列OS_ERR_CREATE_ISR:指示不能從ISR創(chuàng)建OS_ERR_NAME:指示'p_name'是一個(gè)NULL指針OS_ERR_Q_SIZE:指示max_qty指定的大小為0。.......消息隊(duì)列04API函數(shù)接口示例代碼函數(shù)示例:創(chuàng)建消息隊(duì)列key_msg_qOSQCreate((OS_Q*)&key_msg_q,//消息隊(duì)列(CPU_CHAR*)"key_msg_q",
//消息隊(duì)列名稱(chēng)(OS_MSG_QTY)10,
//消息隊(duì)列長(zhǎng)度,這里設(shè)置為10。(OS_ERR*)&err);
//錯(cuò)誤碼//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題。if(err!=OS_ERR_NONE){while(1){;}}消息隊(duì)列04API函數(shù)接口當(dāng)一個(gè)任務(wù)要獲得其他任務(wù)或中斷程序發(fā)來(lái)的消息,然后執(zhí)行某些操作時(shí),通過(guò)用OSQPend函數(shù)接收消息,如果當(dāng)前沒(méi)有消息可接收,任務(wù)會(huì)進(jìn)入掛起狀態(tài)或直接返回(具體行為和調(diào)用時(shí)傳遞的參數(shù)有關(guān)),并且在參數(shù)中攜帶返回錯(cuò)誤碼.從隊(duì)列獲取消息函數(shù)原型:void*OSQPend(OS_Q*p_q,OS_TICKtimeout,OS_OPTopt,OS_MSG_SIZE*p_msg_size,CPU_TS*p_ts,OS_ERR*p_err)函數(shù)功能:等待接收消息,如果成功在消息隊(duì)列中接收到消息。函數(shù)形參:p_q:是指向消息隊(duì)列的指針,傳遞OS_Q類(lèi)型變量的地址;timeout:超時(shí)時(shí)間(以時(shí)鐘節(jié)拍為單位),和信號(hào)量函數(shù)中的timeout參數(shù)相同。opt:指示在接收消息時(shí),和信號(hào)量函數(shù)中的opt參數(shù)相同。p_ts:存放消息接收、掛起中止或消息隊(duì)列刪除時(shí)的時(shí)間戳。不需要時(shí)間戳?xí)r,傳遞NULL;p_err該變量將包含此函數(shù)返回的錯(cuò)誤代碼。函數(shù)調(diào)用可能產(chǎn)生的錯(cuò)誤碼如下:OS_ERR_NONE:指示成功接收到消息。OS_ERR_PEND_ISR:指示在中斷服務(wù)程序中調(diào)用此函數(shù)OS_ERR_TIMEOUT:指示在指定的時(shí)間內(nèi)未收到消息導(dǎo)致超時(shí)返回....函數(shù)返回值:非NULL:指向接收到的消息指針
消息隊(duì)列04API函數(shù)接口示例代碼函數(shù)示例:假設(shè)當(dāng)前消息隊(duì)列key_msg_q已經(jīng)創(chuàng)建好了OS_ERRerr;//存放函數(shù)調(diào)用的錯(cuò)誤碼CPU_TSts;//保存時(shí)間戳uint32_tkey_code;//保存消息傳遞來(lái)的按鍵碼//假設(shè)OSQPost發(fā)送來(lái)的消息是uint32_t類(lèi)型按鍵碼,因此接收到后需要轉(zhuǎn)換為原來(lái)數(shù)據(jù)類(lèi)型。key_code=(uint32_t)OSQPend((OS_Q*)&key_msg_q,
(OS_TICK)0,
OS_OPT_PEND_BLOCKING,
(OS_MSG_SIZE*)&key_code,
(CPU_TS*)&ts,(OS_ERR*)&err);消息隊(duì)列04API函數(shù)接口調(diào)用OSQPost函數(shù)可以發(fā)送一條消息到消息隊(duì)列中,如果有在此消息隊(duì)列上等待接收消息,并比當(dāng)前任務(wù)有更高優(yōu)先級(jí)的任務(wù),則執(zhí)行任務(wù)調(diào)度,CPU執(zhí)行切換到新任務(wù)中執(zhí)行。函數(shù)原型:voidOSQPost(OS_Q*p_q,void*p_void,OS_MSG_SIZEmsg_size,OS_OPTopt,OS_ERR*p_err)函數(shù)功能:向消息隊(duì)列中發(fā)送一條消息函數(shù)形參:p_q:是指向消息隊(duì)列的指針,傳遞OS_Q類(lèi)型變量的地址;opt:確定執(zhí)行的POST類(lèi)型,可取值有:
OS_OPT_POST_ALL:表示POST到隊(duì)列中等待的所有任務(wù)。該選項(xiàng)可以添加到OS_OPT_POST_FIFO或OS_OPT_POST_LIFO上。
OS_OPT_POST_FIFOPOST:表示消息到隊(duì)列末尾(FIFO)并喚醒單個(gè)等待任務(wù)。
OS_OPT_POST_LIFOPOST:表示消息到隊(duì)列前面的LIFO)并喚醒單個(gè)等待任務(wù)。
OS_OPT_POST_NO_SCHED:表示發(fā)送消息到消息隊(duì)列上后,不調(diào)用調(diào)度器。
可能出現(xiàn)的選項(xiàng)組合:
OS_OPT_POST_FIFO、OS_OPT_POST_LIFO、OS_OPT_POST_FIFO+OS_OPT_POST_ALL、
OS_OPT_POST_LIFO+OS_OPT_POST_ALL、
OS_OPT_POST_FIFO+OS_OPT_POST_NO_SCHED
、OS_OPT_POST_LIFO+OS_OPT_POST_NO_SCHED、
OS_OPT_POST_FIFO+OS_OPT_POST_ALL+OS_OPT_POST_NO_SCHED、OS_OPT_POST_LIFO+OS_OPT_POST_ALL+OS_OPT_POST_NO_SCHEDp_err:指向存放錯(cuò)誤代碼的變量的指針,可能產(chǎn)生的錯(cuò)誤碼如下:OS_ERR_NONE:指示成功發(fā)送消息到消息隊(duì)列上;........發(fā)送消息到隊(duì)列消息隊(duì)列04API函數(shù)接口示例代碼函數(shù)示例:假設(shè)當(dāng)前消息隊(duì)列key_msg_q已經(jīng)創(chuàng)建好OS_ERRerr;uint32_tkey=0x01;//注意類(lèi)型是uint32_t,后面接收到需要轉(zhuǎn)換回來(lái)//發(fā)送key的值到消息隊(duì)列中OSQPost((OS_Q*)&key_msg_q,
(void*)key,
//注意:把按鍵碼強(qiáng)制轉(zhuǎn)換為Void
(OS_MSG_SIZE)sizeof(key),
//消息內(nèi)存占用的字節(jié)數(shù)量
(OS_OPT)OS_OPT_POST_FIFO,
//使用先進(jìn)先出的方式發(fā)送消息
(OS_ERR*)&err);
//接收函數(shù)的錯(cuò)誤碼消息隊(duì)列04API函數(shù)接口本示例是使用消息隊(duì)列實(shí)現(xiàn)任務(wù)間通信的方法。任務(wù)1負(fù)責(zé)檢測(cè)按鍵1~按鍵4是否按下,檢測(cè)到有鍵按下了,則把按鍵碼當(dāng)成消息內(nèi)容發(fā)送到消息隊(duì)列上;任務(wù)2負(fù)責(zé)接收消息,并且根據(jù)消息內(nèi)容執(zhí)行不同的代碼。實(shí)驗(yàn)的效果是開(kāi)發(fā)板上KEY1~KEY4,每按下一個(gè)按鍵,開(kāi)發(fā)板上的對(duì)應(yīng)的LED1~LED4狀態(tài)就會(huì)翻轉(zhuǎn)一次。功能說(shuō)明消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例示例框圖消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例主函數(shù)OS_Qkey_msg_q;//定義一個(gè)消息隊(duì)列變量intmain(void){OS_ERRerr;CPU_SR_ALLOC();......OSInit(&err);//初始化μC/OS-III//創(chuàng)建消息隊(duì)列key_msg_qOSQCreate((OS_Q*)&key_msg_q,//消息隊(duì)列(CPU_CHAR*)"key_msg_q",
//消息隊(duì)列名稱(chēng)(OS_MSG_QTY)10,
//消息隊(duì)列長(zhǎng)度,這里設(shè)置為10(OS_ERR*)&err);
//錯(cuò)誤碼if(err!=OS_ERR_NONE){//創(chuàng)建失敗,讓程序進(jìn)入死循環(huán),這樣在開(kāi)發(fā)階段方便發(fā)現(xiàn)問(wèn)題while(1){;}}OS_CRITICAL_ENTER();
//進(jìn)入臨界區(qū)//調(diào)用OSTaskCreate創(chuàng)建啟動(dòng)任務(wù),和前面講解的代碼相同,此時(shí)省略......OS_CRITICAL_EXIT();
//退出臨界區(qū)OSStart(&err);
//開(kāi)啟μC/OS-III}消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例主函數(shù)voidtask1_task(void*p_arg){uint32_tkey;OS_ERRerr;while(1){key=KEY_Scan(0);//掃描按鍵if(key){//如果檢測(cè)到有鍵按下//發(fā)送按鍵碼OSQPost((OS_Q*)&key_msg_q,(void*)key,//注意:把按鍵碼強(qiáng)制轉(zhuǎn)換為void*(OS_MSG_SIZE)sizeof(key),//消息內(nèi)存占用的字節(jié)數(shù)量(OS_OPT)OS_OPT_POST_FIFO,//使用先進(jìn)先出的方式發(fā)送消息(OS_ERR*)&err);//接收函數(shù)的錯(cuò)誤碼OSTimeDlyHMSM(0,0,0,50,OS_OPT_TIME_PERIODIC,&err);//延時(shí)50ms}}}消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例任務(wù)1函數(shù)voidtask1_task(void*p_arg){OS_ERRerr;uint32_tcnt=1;//記錄寫(xiě)入數(shù)據(jù)的次數(shù)while(1){
//請(qǐng)求互斥信號(hào)量OSMutexPend(&share_mem_mutex,0,OS_OPT_PEND_BLOCKING,0,&err);
if(err!=OS_ERR_NONE){//在以下編寫(xiě)沒(méi)有正確獲得互斥信號(hào)量但是函數(shù)返回時(shí)的處理代碼//……} //以下開(kāi)始訪問(wèn)共享資源,往array_buf數(shù)組中寫(xiě)入數(shù)據(jù)sprintf(array_buf,"cnt:%05d",cnt);//開(kāi)始訪問(wèn)共享資源printf("第%d次寫(xiě)入數(shù)據(jù):%s\r\n",cnt++,array_buf);//輸出寫(xiě)入內(nèi)容提示,寫(xiě)入次數(shù)增加OSMutexPost(&share_mem_mutex,OS_OPT_POST_NONE,&err);//釋放互斥信號(hào)量OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);//延時(shí)1s}}消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例voidtask2_task(void*p_arg){OS_ERRerr;CPU_TSts;//保存時(shí)間戳uint32_tkey_code;//保存消息傳遞來(lái)的按鍵碼while(1){//沒(méi)有接收到消息會(huì)掛起任務(wù)//OSQPend發(fā)送來(lái)的消息是uint32_t類(lèi)型按鍵碼,因此接收到后還原原來(lái)的數(shù)據(jù)類(lèi)型。key_code=(uint32_t)OSQPend(
(OS_Q*)&key_msg_q,
(OS_TICK)0,
(OS_OPT)OS_OPT_PEND_BLOCKING,
(OS_MSG_SIZE*)&key_code,
(CPU_TS*)&ts,
(OS_ERR*)&err);if(err!=OS_ERR_NONE){//沒(méi)有正確獲得消息但是函數(shù)返回時(shí)的處理代碼}消息隊(duì)列04任務(wù)間傳遞數(shù)據(jù)示例//根據(jù)接收到的按鍵碼執(zhí)行不同的操作:這里分別改變LED1~LED4狀態(tài)switch(key_code){caseKEY1_PRES://按鍵1按下LED1_Toglge();//翻轉(zhuǎn)LED1狀態(tài)break;caseKEY2_PRES://按鍵2按下LED2_Toglge();//翻轉(zhuǎn)LED1狀態(tài)break;caseKEY3_PRES://按鍵3按下LED3_Toglge();//翻轉(zhuǎn)LED3狀態(tài)break;caseKEY4_PRES://按鍵4按下LED4_Toglge();//翻轉(zhuǎn)LED4狀態(tài)break;}OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);//延時(shí)0.5s}}任務(wù)2函數(shù)總結(jié)與信號(hào)量和互斥信號(hào)量不同,它們并不能攜帶用戶自定義的數(shù)據(jù)給其他任務(wù),消息隊(duì)列設(shè)計(jì)可以用于任務(wù)間或中斷與任務(wù)間傳遞數(shù)據(jù),消息隊(duì)列可以容納多條消息,可以用作事件的緩沖區(qū),暫時(shí)存儲(chǔ)當(dāng)前沒(méi)有及時(shí)處理的事件,不會(huì)因?yàn)橄到y(tǒng)當(dāng)前工作負(fù)載過(guò)重,無(wú)法及時(shí)處理導(dǎo)致的事件丟失。使用消息隊(duì)列時(shí),不能在中斷程序中調(diào)用OSQPend,以阻塞從消息隊(duì)列中等待接收消息。往消息隊(duì)列發(fā)送消息支持FIFO和FILO方式,對(duì)于后面發(fā)生的要緊急處理的消息,可以通過(guò)指定FILO方式來(lái)實(shí)現(xiàn)接收者優(yōu)先處理的效果。消息隊(duì)列04小結(jié)05事件標(biāo)志組事件標(biāo)志組介紹API函數(shù)接口任務(wù)同步示例事件標(biāo)志組05事件標(biāo)志組介紹事件標(biāo)志組是μC/OS-III系統(tǒng)提供的一種用于任務(wù)間通信的同步機(jī)制,它和信號(hào)量類(lèi)似,都可以實(shí)現(xiàn)任務(wù)等待某個(gè)事件的發(fā)生再繼續(xù)往下運(yùn)行。但事件標(biāo)志組在任務(wù)同步方面比信號(hào)量功能更強(qiáng)大,使用更靈活。一個(gè)事件標(biāo)志組同步等待多個(gè)事件發(fā)生或者等待多個(gè)事件中任何一個(gè)事件的發(fā)生。從專(zhuān)業(yè)術(shù)語(yǔ)角度描述,即多個(gè)事件的“邏輯與”和多個(gè)事件的“邏輯或”。“邏輯與”:等待所有事件都發(fā)生時(shí),條件才成立,任務(wù)恢復(fù)運(yùn)行;“邏輯或”:等待所有的事件的中任意一個(gè)事件發(fā)生,條件成立,任務(wù)恢復(fù)運(yùn)行;事件標(biāo)志組概念051.μC/OS-III“事件標(biāo)志組”使用OS_FLAG_GRP類(lèi)型來(lái)表示,也是一個(gè)內(nèi)核對(duì)象,由一系列位(8位/16位/32位,由源碼中的OS_FLAGS定義的數(shù)據(jù)類(lèi)型決定)組成,可以簡(jiǎn)單理解為一個(gè)二進(jìn)制位表示一個(gè)等待的事件,即圖中間的多個(gè)小方格。創(chuàng)建事件標(biāo)志組通過(guò)OSFlagCreate()函數(shù)創(chuàng)建,創(chuàng)建成功后就可以在任務(wù)/中斷服務(wù)程序中使用它了;2.任務(wù)或中斷服務(wù)程序可通過(guò)OSFlagPost()函數(shù)發(fā)布事件標(biāo)志。注意:只有任務(wù)可以創(chuàng)建、刪除和取消其他任務(wù)在事件標(biāo)志組上掛起狀態(tài),不能在中斷服務(wù)程序中執(zhí)行這幾種操作;認(rèn)識(shí)事件標(biāo)志組事件標(biāo)志組事件標(biāo)志組介紹053.調(diào)用OSFlagPend()函數(shù),任務(wù)可以等待(掛起)事件標(biāo)志組(所有位的子集)中任意數(shù)量的位(一個(gè)二進(jìn)制位就是一個(gè)事件)發(fā)生期望的事件(邏輯與、邏輯或)。和前面學(xué)習(xí)過(guò)的信號(hào)量、消息隊(duì)列的掛起一樣,在調(diào)用OSFlagPend()可指定最長(zhǎng)的等待超時(shí)值,如在指定的時(shí)間量(以時(shí)鐘節(jié)拍為單位)內(nèi)未發(fā)生期望的事件,則掛起的任務(wù)將恢復(fù)并返回超時(shí)錯(cuò)誤碼。認(rèn)識(shí)事件標(biāo)志組事件標(biāo)志組事件標(biāo)志組介紹054.調(diào)用OSFlagPend()函數(shù)時(shí)可以通過(guò)參數(shù)決定等待的方式是采用邏輯與還是邏輯或、等待目標(biāo)事件位是清零還是置位。這樣就出現(xiàn)了四種等級(jí)組合:①等待所有位集合邏輯“與”置位事件;
②等待所有位集合邏輯“與”清零事件;③等待所有位集合邏輯“或”置位事件;④等待所有位集合邏輯“或”清零事件認(rèn)識(shí)事件標(biāo)志組事件標(biāo)志組事件標(biāo)志組介紹事件標(biāo)志組的使用流程很簡(jiǎn)單:創(chuàng)建事件標(biāo)志組、等待事件標(biāo)志、發(fā)送事件標(biāo)志三個(gè)必需的步驟,其他可選操作有刪除事件標(biāo)志組、中止等待事件標(biāo)志。事件標(biāo)志組接口事件標(biāo)志組05API函數(shù)接口事件標(biāo)志組函數(shù)序號(hào)函數(shù)名功能描述備注1OSFlagCreate()創(chuàng)建事件標(biāo)志組必須調(diào)用2OSFlagPend()等待事件標(biāo)志發(fā)布必須調(diào)用3OSFlagPost()發(fā)布事件標(biāo)志到事件標(biāo)志組必須調(diào)用4OSFlagPendAbort()取消等待事件標(biāo)志組可選調(diào)用5OSFlagDel()刪除事件標(biāo)志組可選調(diào)用6OSFl
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五版牧業(yè)養(yǎng)殖技術(shù)引進(jìn)與推廣合同3篇
- 二零二五年鋼結(jié)構(gòu)工程居間驗(yàn)收服務(wù)合同3篇
- 2025年校園熱泵熱水設(shè)備供應(yīng)合同樣本2篇
- 2025版學(xué)校圖書(shū)采購(gòu)與配送服務(wù)承包合同3篇
- 2025版宣傳片制作與宣傳合同3篇
- 2025版塔吊租賃、安裝與安全維護(hù)服務(wù)合同3篇
- 全新二零二五年度廣告制作與發(fā)布合同6篇
- 家用紡織品智能溫控技術(shù)考核試卷
- 個(gè)人職業(yè)規(guī)劃社群考核試卷
- 2025版學(xué)校校園安全防范系統(tǒng)建設(shè)承包合同3篇
- 2024年山東省泰安市高考物理一模試卷(含詳細(xì)答案解析)
- 腫瘤患者管理
- 2025春夏運(yùn)動(dòng)戶外行業(yè)趨勢(shì)白皮書(shū)
- 《法制宣傳之盜竊罪》課件
- 通信工程單位勞動(dòng)合同
- 2024年醫(yī)療器械經(jīng)營(yíng)質(zhì)量管理規(guī)范培訓(xùn)課件
- 高低壓配電柜產(chǎn)品營(yíng)銷(xiāo)計(jì)劃書(shū)
- 2024年4月自考02202傳感器與檢測(cè)技術(shù)試題
- 新入職員工培訓(xùn)考試附有答案
- 互聯(lián)網(wǎng)的發(fā)展歷程
- 外觀質(zhì)量評(píng)定報(bào)告
評(píng)論
0/150
提交評(píng)論