ucosiii淺析內核對象-軟件定時器


內核對象和各種內核機制的函數接口都在os.h里聲明,實現在各自的.c文件,比如os_tmr.cos_time.c

C語言全局變量一般會默認初始化;局部變量如若不初始化,會分配垃圾數據的;建議使用時都手動初始化。

其實使用內核對象時,就類似與使用任務,只不過在創建對象之前,要先聲明一個內核對象。

好了,上面閑聊了幾句,今天來說說ucosiii的幾個內核對象。

首先說“軟件定時器”,其實單純的講就是定時作用,這里我們要注意的就是,使用它方法和使用任務類似;那么我們就先來分析分析任務的執行過程:

  1. main會初始化ucos;調用一個起始任務創建函數(它的參數就是就是任務的工作模式,任務信息,任務函數指針)來創建任務;啟動多任務管理。
  2. 任務函數指針指向起始任務函數會初始化操作系統;調用若干普通任務創建函數(與上一致)來創建任務;刪除起始任務本身。
  3. 任務函數就會完成具體的操作。

那繼續說軟件定時器,在上面的3里任務函數會聲明一個定時器對象,然后調用一個定時器創建函數(它的參數為定時器信息,工作模式,回調函數指針等)來創建任務,回調函數完成一些自定義的操作(每次定時完成會調用此回調函數),最后調用OSTmrStart()啟動軟件定時器;接下來就可以使用它了。

 

 

我們可以知道,用OSTimeDly是將任務置為等待態,CPU的使用權暫時被剝奪,開啟定時器之后,該任務還是可以使用CPU

通過debug我們也可以發現,運行完OSTimeDly之后(也可以說定時了指定時間之后),會完成一次回調函數里面的操作。也就驗證了這個結論“定時完成之后會調用回調函數”。

下面我們就具體看一下源碼,聲明:這是秉火例程里的代碼,我只是做了稍加修改。

 

#include <includes.h>

CPU_TS             ts_start;       //時間戳變量
CPU_TS             ts_end; 

static  OS_TCB   AppTaskStartTCB;                                //任務控制塊

static  OS_TCB   AppTaskTmrTCB;



static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];       //任務堆棧

static  CPU_STK  AppTaskTmrStk [ APP_TASK_TMR_STK_SIZE ];


static  void  AppTaskStart  (void *p_arg);                       //任務函數聲明

static  void  AppTaskTmr  ( void * p_arg );


int  main (void)
{
    OS_ERR  err;


    OSInit(&err);                                                           //初始化 uC/OS-III

      /* 創建起始任務 */
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                            //任務控制塊地址
                 (CPU_CHAR   *)"App Task Start",                            //任務名稱
                 (OS_TASK_PTR ) AppTaskStart,                               //任務函數
                 (void       *) 0,                                          //傳遞給任務函數(形參p_arg)的實參
                 (OS_PRIO     ) APP_TASK_START_PRIO,                        //任務的優先級
                 (CPU_STK    *)&AppTaskStartStk[0],                         //任務堆棧的基地址
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,               //任務堆棧空間剩下1/10時限制其增長
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,                    //任務堆棧空間(單位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任務可接收的最大消息數
                 (OS_TICK     ) 0u,                                         //任務的時間片節拍數(0表默認值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任務擴展(0表不擴展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任務選項
                 (OS_ERR     *)&err);                                       //返回錯誤類型

    OSStart(&err);                                                          //啟動多任務管理(交由uC/OS-III控制)
        
        
}

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


   (void)p_arg;

    BSP_Init();                                                 //板級初始化
    CPU_Init();                                                 //初始化 CPU 組件(時間戳、關中斷時間測量和主機名)

    cpu_clk_freq = BSP_CPU_ClkFreq();                           //獲取 CPU 內核時鍾頻率(SysTick 工作時鍾)
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        //根據用戶設定的時鍾節拍頻率計算 SysTick 定時器的計數值
    OS_CPU_SysTickInit(cnts);                                   //調用 SysTick 初始化函數,設置定時器計數值和啟動定時器

    Mem_Init();                                                 //初始化內存管理組件(堆內存池和內存池表)

#if OS_CFG_STAT_TASK_EN > 0u                                    //如果使能(默認使能)了統計任務
    OSStatTaskCPUUsageInit(&err);                               //計算沒有應用任務(只有空閑任務)運行時 CPU 的(最大)
#endif                                                          //容量(決定 OS_Stat_IdleCtrMax 的值,為后面計算 CPU 
                                                                //使用率使用)。
    CPU_IntDisMeasMaxCurReset();                                //復位(清零)當前最大關中斷時間

    
        /* 創建 AppTaskTmr 任務 */
    OSTaskCreate((OS_TCB     *)&AppTaskTmrTCB,                             //任務控制塊地址
                 (CPU_CHAR   *)"App Task Tmr",                             //任務名稱
                 (OS_TASK_PTR ) AppTaskTmr,                                //任務函數
                 (void       *) 0,                                          //傳遞給任務函數(形參p_arg)的實參
                 (OS_PRIO     ) APP_TASK_TMR_PRIO,                         //任務的優先級
                 (CPU_STK    *)&AppTaskTmrStk[0],                          //任務堆棧的基地址
                 (CPU_STK_SIZE) APP_TASK_TMR_STK_SIZE / 10,                //任務堆棧空間剩下1/10時限制其增長
                 (CPU_STK_SIZE) APP_TASK_TMR_STK_SIZE,                     //任務堆棧空間(單位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任務可接收的最大消息數
                 (OS_TICK     ) 0u,                                         //任務的時間片節拍數(0表默認值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任務擴展(0表不擴展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任務選項
                 (OS_ERR     *)&err);                                       //返回錯誤類型
                                 
        OSTaskDel ( & AppTaskStartTCB, & err );                     //刪除起始任務本身,該任務不再運行
        
        
}


/*
*********************************************************************************************************
*                                          TMR TASK
*********************************************************************************************************
*/
void TmrCallback (OS_TMR *p_tmr, void *p_arg) //軟件定時器MyTmr的回調函數
{
    CPU_INT32U       cpu_clk_freq;    
    CPU_SR_ALLOC();      //使用到臨界段(在關/開中斷時)時必需該宏,該宏聲明和定義一個局部變
                                             //量,用於保存關中斷前的 CPU 狀態寄存器 SR(臨界段關中斷只需保存SR)
                                             //,開中斷時將該值還原。  
  printf ( "%s", ( char * ) p_arg );
    
    cpu_clk_freq = BSP_CPU_ClkFreq();                   //獲取CPU時鍾,時間戳是以該時鍾計數
    
    macLED1_TOGGLE (); 
    
  ts_end = OS_TS_GET() - ts_start;     //獲取定時后的時間戳(以CPU時鍾進行計數的一個計數值)
                                         //,並計算定時時間。
    OS_CRITICAL_ENTER();                 //進入臨界段,不希望下面串口打印遭到中斷
    
    printf ( "\r\n定時1s,通過時間戳測得定時 %07d us,即 %04d ms。\r\n", 
                        ts_end / ( cpu_clk_freq / 1000000 ),     //將定時時間折算成 us 
                        ts_end / ( cpu_clk_freq / 1000 ) );      //將定時時間折算成 ms 
    
    OS_CRITICAL_EXIT();                               

    ts_start = OS_TS_GET();                            //獲取定時前時間戳
    
}


static  void  AppTaskTmr ( void * p_arg )
{
    OS_ERR      err;
    OS_TMR      my_tmr;   //聲明軟件定時器對象

    
    (void)p_arg;


  /* 創建軟件定時器 */
  OSTmrCreate ((OS_TMR              *)&my_tmr,             //軟件定時器對象
               (CPU_CHAR            *)"MySoftTimer",       //命名軟件定時器
               (OS_TICK              )10,                  //定時器初始值,依10Hz時基計算,即為1s
               (OS_TICK              )10,                  //定時器周期重載值,依10Hz時基計算,即為1s
               (OS_OPT               )OS_OPT_TMR_PERIODIC, //周期性定時
               (OS_TMR_CALLBACK_PTR  )TmrCallback,         //回調函數
               (void                *)"Timer Over!",       //傳遞實參給回調函數
               (OS_ERR              *)err);                //返回錯誤類型
                             
    /* 啟動軟件定時器 */                         
  OSTmrStart ((OS_TMR   *)&my_tmr, //軟件定時器對象
              (OS_ERR   *)err);    //返回錯誤類型
                     
    ts_start = OS_TS_GET();                       //獲取定時前時間戳
                             
    while (DEF_TRUE) {                            //任務體,通常寫成一個死循環DEF_TRUE
        printf("將任務置為等待態1s");
        OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); //給任務提供定時 

    }
    
}

 

那再啰嗦一下回調函數,上面這個回調函數的類型聲明如下:

typedef  void                      (*OS_TMR_CALLBACK_PTR)(void *p_tmr, void *p_arg);

顯而易見的是,我們自定義的回調函數的返回類型OS_TMR_CALLBACK_PTR其實就是一個void指針(而這個指針是一個函數指針),為了避免晦澀的基礎類型,所以typedef一下,便於理解。

 那再說一下void

1.當函數返回為空或參數列表為空使用。

2.void*指向任何類型,只不過使用時要轉換成具體類型,才能操作。(上面的回調函數的實現有應用到)。

仔細將這些話與代碼對應起來體會,很有意思的。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM