ucosII 信號量的原理及應用

#include "INCLUDES.h"

 

#define  TASK_STK_SIZE        512                 

   

char *s1="MyTask";

char *s2="YouTask";

INT8U err;   //定義一個錯誤信息

INT8U y=0;

OS_EVENT *Fun_Semp;    //聲明信號量  是事件控制塊ECB類型的

//注意,前面有一個例子定義了互斥信號量,定義如下

//BOOLEAN   ac_key;   //信號量,互斥信號量 實質上就是一個標誌位,是一個全局變量,來標誌共享資源的訪問情況

//這樣,當已經有任務訪問共享資源時,其他的任務就不能訪問,知道該資源未被訪問,其他的任務纔可以進行訪問

//注意這兩個信號量的區別和使用情況

 

 

 

 

OS_STK        StartTaskStk[TASK_STK_SIZE];   //定義任務堆棧區

OS_STK        MyTaskStk[TASK_STK_SIZE];

OS_STK        YouTaskStk[TASK_STK_SIZE];

 

void  Fun(INT8U x,INT8U y);

 

void  StartTask(void *data);

void  MyTask(void *data);                  

void  YouTask(void *data);

 

 

void  main (void)

{

Fun_Semp=OSSemCreate(1); //在主函數中創建信號量 返回值爲創建的信號量指針,參數是信號量的計數器的值

//用該參數對信號量計數器OSEventCnt進行初始化

//1即代表只創建一個信號量,代表信號量用於對共享資源的訪問(例如,把它當做二值信號量使用)

 

    OSInit();                                              

    PC_DOSSaveReturn();                                    

    PC_VectSet(uCOS, OSCtxSw);                             

    

    OSTaskCreate(StartTask,(void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0); //創建起始函數

    

    OSStart();      

}

 

void  StartTask(void *pdata)

{

#if OS_CRITICAL_METHOD == 3        

    OS_CPU_SR  cpu_sr;

#endif

    INT16S        key;             

    pdata = pdata;        

    OS_ENTER_CRITICAL();

    PC_VectSet(0x08, OSTickISR);                           

    PC_SetTickRate(OS_TICKS_PER_SEC);                      

    OS_EXIT_CRITICAL();

    OSStatInit();                                          

    

    OSTaskCreate(MyTask,(void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 1); //創建任務函數

OSTaskCreate(YouTask,(void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 2); //創建任務函數

 

for (;;)

    {

     //如果恩下ESC鍵,則退出UC/OS-II

        if (PC_GetKey(&key) == TRUE)

         {                     

            if (key == 0x1B) 

            {                             

                PC_DOSReturn();                            

            }

        }

        OSTimeDlyHMSM(0,0,3,0);                         

    }

}

 

//MyTask的函數代碼

void  MyTask(void *pdata)

{

#if OS_CRITICAL_METHOD == 3        

    OS_CPU_SR  cpu_sr;

#endif

   

    pdata = pdata;    

    for (;;)

    {

     OSSemPend(Fun_Semp,0,&err);   //請求信號量 參數Fun_Semp是信號量指針  0那一項是等待時限timeout0表示無限等待

     //err表示錯誤信息

    

PC_DispStr(0,++y,s1,DISP_BGND_BLACK+DISP_FGND_WHITE);  //顯示MyTask字符串

 

Fun(7,y);  //調用Fun函數

 

OSSemPost(Fun_Semp);    //發送信號量 釋放信號量,函數的參數Fun_Semp代表信號量的指針

 

        OSTimeDlyHMSM(0,0,1,0);  

    }

}

 

void  YouTask(void *pdata)

{

#if OS_CRITICAL_METHOD == 3        //Allocate storage for CPU status register 

    OS_CPU_SR  cpu_sr;

#endif

 

pdata=pdata;

for (;;)

{

OSSemPend(Fun_Semp,0,&err);    //請求信號量

PC_DispStr(0,++y,s2,DISP_BGND_BLACK+DISP_FGND_WHITE);

Fun(7,y);   //調用FUN函數

OSSemPost(Fun_Semp);   //釋放信號量

 

        OSTimeDlyHMSM(0,0,2,0);    //等待2s               

    }

}

 

//公共的函數Fun的代碼

void Fun(INT8U x,INT8U y)

{

PC_DispStr(x,y,"  Calling FUN()",DISP_BGND_BLACK+DISP_FGND_WHITE); //顯示字符串,表示調用了Fun函數

}

 

創建信號量時,用的參數爲1,即Fun_Semp=OSSemCreate(1); 只創建了一個信號量,這種情況一般是信號量用於對

共享資源的訪問(例如,可以把它當做二值信號量使用)

 

在上面的程序中,當MyTask運行時,先請求獲得了信號量,對共享資源Fun函數進行訪問,由於只創建了一個信號量,

所以在MyTask的訪問期間,即使任務YouTask也進行申請信號量,此時OSEventCnt是值已經爲0了,所以會把任務

YouTask列入任務等代表OSEventTbl[]中,使任務處於等待狀態。

只有等MyTaskFun函數訪問完成了,調用OSSemPost(Fun_Semp);釋放了信號量,該釋放信號量的函數會先檢查任務等待

表中是否還有等待信號量的任務,如果有,則使任務進入就緒態後,調用調度器OS_Sched()引發一次任務調度,去運行等待

任務列表中優先級最高的任務。如果沒有,則就把信號量計數器OSSemCnt1.

所以任務YouTask要想訪問Fun()函數,必須等到任務MyTaskFun訪問完畢,釋放了信號量之後,才能訪問,反之亦然

所以由上面可以看出,只創建一個信號量,即OSSemCreate(1);,作用就相當於使用一個二值信號量,標誌共享資源是否正在

被訪問。

看懂了上面的分析,也就可以解釋實驗現象了,由於YouTask等待2sMyTask等待1s,所以有可能在MyTask訪問Fan函數期間,YouTask也來訪問(也有可能是反過來),但是由於信號量已經被MyTask佔用了,所YouTask只好等待,MyTask使用完了,釋放了信號量,YouTask才能正常使用Fun函數,這樣也就解決了多任務對共享資源的使用的問題,使任務之間得到了同步

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章