欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試

 更新時(shí)間:2022年04月08日 09:41:40   作者:zhzht19861011  
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

前言

用RTOS編程,為每個(gè)任務(wù)分配多大的堆??臻g就成了一項(xiàng)技術(shù)活:分配多了浪費(fèi)系統(tǒng)資源,分配少了又恐怕會(huì)發(fā)生堆棧溢出。由于中斷和搶占式調(diào)度器的存在,我們要估算出一個(gè)任務(wù)需要多少堆棧是非常困難的,今天我們就介紹一種方法,來獲取每個(gè)任務(wù)的剩余堆??臻g。本文以NXP LPC177x_8x系列微控制器為例。

我們將這個(gè)功能做成一個(gè)命令,添加到FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器一文介紹的命令解釋列表中。當(dāng)程序運(yùn)行一段時(shí)間后,我們?cè)赟ecureCRT軟件中輸入命令“task”后回車,能看到如圖1-1所示的任務(wù)信息。這里只有兩個(gè)任務(wù),其中堆棧一列中的數(shù)字,代表對(duì)應(yīng)任務(wù)剩余的堆??臻g,單位是StackType_t類型,這個(gè)類型在移植層定義,一般定義為4字節(jié)。

圖1-1:任務(wù)信息

1.使能可視化追蹤和運(yùn)行時(shí)間統(tǒng)計(jì)功能

如圖1-1所示,要實(shí)現(xiàn)堆棧使用量信息以及CPU使用率信息,必須將FreeRTOSConfig.h文件中的兩個(gè)宏設(shè)置為1:

         #define configUSE_TRACE_FACILITY          1      
         #define configGENERATE_RUN_TIME_STATS 1

第一個(gè)宏用來使能可視化追蹤功能,第二個(gè)宏用來使能運(yùn)行時(shí)間統(tǒng)計(jì)功能。如果第二個(gè)宏設(shè)置為1,則下面兩個(gè)宏必須被定義:

portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():

用戶程序需要提供一個(gè)基準(zhǔn)時(shí)鐘函數(shù),函數(shù)完成初始化基準(zhǔn)時(shí)鐘功能,這個(gè)函數(shù)要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。

這是因?yàn)檫\(yùn)行時(shí)間統(tǒng)計(jì)需要一個(gè)比系統(tǒng)節(jié)拍中斷頻率還要高分辨率的基準(zhǔn)定時(shí)器,否則,統(tǒng)計(jì)可能不精確。

基準(zhǔn)定時(shí)器中斷頻率要比統(tǒng)節(jié)拍中斷快10~100倍?;鶞?zhǔn)定時(shí)器中斷頻率越快,統(tǒng)計(jì)越精準(zhǔn),但能統(tǒng)計(jì)的運(yùn)行時(shí)間也越短(比如,基準(zhǔn)定時(shí)器10ms中斷一次,8位無符號(hào)整形變量可以計(jì)到2.55秒,但如果是1秒中斷一次,8位無符號(hào)整形變量可以統(tǒng)計(jì)到255秒)。

portGET_RUN_TIME_COUNTER_VALUE():

用戶程序需要提供一個(gè)返回基準(zhǔn)時(shí)鐘當(dāng)前“時(shí)間”的函數(shù),這個(gè)函數(shù)要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。

我們使用定時(shí)器1來產(chǎn)生基準(zhǔn)時(shí)鐘,定時(shí)器1初始化函數(shù)為:

/**
* 初始化計(jì)時(shí)定時(shí)器1,用于OS任務(wù)運(yùn)行時(shí)間統(tǒng)計(jì)
*/
void init_timer1_for_runtime_state(void)
{
    TIM_TIMERCFG_Type Timer0CfgType;
    Timer0CfgType.PrescaleOption=TIM_PRESCALE_USVAL;        //預(yù)分頻的單位是微秒
    Timer0CfgType.PrescaleValue=500;                        //預(yù)分頻后為500微秒,
    TIM_Init(LPC_TIM1,TIM_TIMER_MODE,&Timer0CfgType);
    LPC_TIM1->TCR=0x01;
}

定時(shí)器1被配置成每隔500微秒,TC寄存器值增一。我們將定時(shí)器1的 TC寄存器值作為基準(zhǔn)時(shí)鐘當(dāng)前時(shí)間。當(dāng)TC寄存器值溢出時(shí),大概要經(jīng)過24.8天,這對(duì)于我們這個(gè)應(yīng)用是足夠的。

在FreeRTOSConfig.h中,定義初始化基準(zhǔn)定時(shí)器宏和獲取當(dāng)前時(shí)間宏:

extern void init_timer1_for_runtime_state(void);
#define TIMER1_TC         ( * ( ( volatile uint32_t * )0x40008008 ) )
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() init_timer1_for_runtime_state()
#define portGET_RUN_TIME_COUNTER_VALUE() TIMER1_TC

2.獲取任務(wù)信息并格式化

獲取每個(gè)任務(wù)的狀態(tài)信息使用的是API函數(shù)uxTaskGetSystemState(),該函數(shù)定義為:

UBaseType_tuxTaskGetSystemState(
                       TaskStatus_t * constpxTaskStatusArray,
                       const UBaseType_tuxArraySize,
                       unsigned long * constpulTotalRunTime );

函數(shù)uxTaskGetSystemState()向TaskStatus_t結(jié)構(gòu)體填充相關(guān)信息,系統(tǒng)中每一個(gè)任務(wù)的信息都可以填充到TaskStatus_t結(jié)構(gòu)體數(shù)組中,數(shù)組大小由uxArraySize指定。結(jié)構(gòu)體TaskStatus_t定義如下:

typedef struct xTASK_STATUS
{
   /* 任務(wù)句柄*/
   TaskHandle_t xHandle;
   /* 指針,指向任務(wù)名*/
   const signed char *pcTaskName;
   /*任務(wù)ID,是一個(gè)獨(dú)一無二的數(shù)字*/
   UBaseType_t xTaskNumber;
   /*填充結(jié)構(gòu)體時(shí),任務(wù)當(dāng)前的狀態(tài)(運(yùn)行、就緒、掛起等等)*/
   eTaskState eCurrentState;
   /*填充結(jié)構(gòu)體時(shí),任務(wù)運(yùn)行(或繼承)的優(yōu)先級(jí)。*/
   UBaseType_t uxCurrentPriority;
   /* 當(dāng)任務(wù)因繼承而改變優(yōu)先級(jí)時(shí),該變量保存任務(wù)最初的優(yōu)先級(jí)。僅當(dāng)configUSE_MUTEXES定義為1有效。*/
   UBaseType_t uxBasePriority;
   /* 分配給任務(wù)的總運(yùn)行時(shí)間。僅當(dāng)宏configGENERATE_RUN_TIME_STATS為1時(shí)有效。*/
   unsigned long ulRunTimeCounter;
   /* 從任務(wù)創(chuàng)建起,堆棧剩余的最小數(shù)量,這個(gè)值越接近0,堆棧溢出的可能越大。 */
   unsigned short usStackHighWaterMark;
}TaskStatus_t;

注意,這個(gè)函數(shù)僅用來調(diào)試用,調(diào)用此函數(shù)會(huì)掛起所有任務(wù),直到函數(shù)結(jié)束后才恢復(fù)掛起的任務(wù),因此任務(wù)可能被掛起很長時(shí)間。在文件FreeRTOSConfig.h中,宏configUSE_TRACE_FACILITY必須設(shè)置為1,此函數(shù)才有效。

由于我們不使用動(dòng)態(tài)內(nèi)存分配策略,所以實(shí)現(xiàn)定義了最大任務(wù)個(gè)數(shù)并預(yù)先分配好了存儲(chǔ)任務(wù)狀態(tài)信息的數(shù)組:

#defineMAX_TASK_NUM        5
TaskStatus_tpxTaskStatusArray[MAX_TASK_NUM];

正確調(diào)用函數(shù)uxTaskGetSystemState()后,任務(wù)的信息會(huì)被放在TaskStatus_t結(jié)構(gòu)體中,我們需要將這些信息格式化為容易閱讀的形式,并共通過串口打印到屏幕。完成這些功能的函數(shù)叫做get_task_state(),代碼如下所示:

/*獲取OS任務(wù)信息*/
voidget_task_state(int32_t argc,void *cmd_arg)
{
    const chartask_state[]={'r','R','B','S','D'};
    volatile UBaseType_t uxArraySize, x;
    uint32_t ulTotalRunTime,ulStatsAsPercentage;
    /* 獲取任務(wù)總數(shù)目 */
    uxArraySize = uxTaskGetNumberOfTasks();
   if(uxArraySize>MAX_TASK_NUM)
    {
        MY_DEBUGF(CMD_LINE_DEBUG,("當(dāng)前任務(wù)數(shù)量過多!\n"));
    }
    /*獲取每個(gè)任務(wù)的狀態(tài)信息 */
    uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
    #if (configGENERATE_RUN_TIME_STATS==1)
    MY_DEBUGF(CMD_LINE_DEBUG,("任務(wù)名      狀態(tài)  ID    優(yōu)先級(jí)  堆棧    CPU使用率\n"));
 
    /* 避免除零錯(cuò)誤 */
    if( ulTotalRunTime > 0 )
    {
        /* 將獲得的每一個(gè)任務(wù)狀態(tài)信息部分的轉(zhuǎn)化為程序員容易識(shí)別的字符串格式 */
        for( x = 0; x < uxArraySize; x++ )
        {
            char tmp[128];
            /* 計(jì)算任務(wù)運(yùn)行時(shí)間與總運(yùn)行時(shí)間的百分比。*/
            ulStatsAsPercentage =(uint64_t)(pxTaskStatusArray[ x ].ulRunTimeCounter)*100 / ulTotalRunTime;
            if( ulStatsAsPercentage > 0UL )
            {
               sprintf(tmp,"%-12s%-6c%-6d%-8d%-8d%d%%",pxTaskStatusArray[ x].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],
                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,
                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark,ulStatsAsPercentage);
            }
            else
            {
                /* 任務(wù)運(yùn)行時(shí)間不足總運(yùn)行時(shí)間的1%*/
                sprintf(tmp,"%-12s%-6c%-6d%-8d%-8dt<1%%",pxTaskStatusArray[x ].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],
                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,
                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark);               
            }
           MY_DEBUGF(CMD_LINE_DEBUG,("%s\n",tmp));
        }
    }
    MY_DEBUGF(CMD_LINE_DEBUG,("任務(wù)狀態(tài):   r-運(yùn)行  R-就緒  B-阻塞  S-掛起  D-刪除\n"));
    #endif //#if (configGENERATE_RUN_TIME_STATS==1)
}

3.添加到命令解釋列表

FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器一文我們講過了命令表,這里只需要將get_task_state()函數(shù)添加到命令列表中,命令設(shè)置為”task”,代碼如下所示:

/*命令表*/
const cmd_list_structcmd_list[]={
/*   命令    參數(shù)數(shù)目    處理函數(shù)        幫助信息                                  */   
    {"?",       0,     handle_help,     "?                                  -打印幫助信息"},                 
    {"reset",   0,     handle_reset,    "reset                              -重啟控制器"},
    {"arg",     8,     handle_arg,      "arg<arg1> <arg2> ...               -測(cè)試用,打印輸入的參數(shù)"},
    {"hello",   0,     printf_hello,    "hello                              -打印HelloWorld!"},
    {"task",    0,     get_task_state,  "task                               -獲取任務(wù)信息"},
};

以上就是FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS可視化追蹤調(diào)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論