【二代示波器教程】第14章 uCOS-III操作系統版本二代示波器實現

来源:https://www.cnblogs.com/armfly/archive/2018/07/11/9295129.html
-Advertisement-
Play Games

第14章 uCOS-III操作系統版本二代示波器實現 本章教程為大家講解uCOS-III操作系統版本的二代示波器實現。主要講解RTOS設計框架,即各個任務實現的功能,任務間的通信方案選擇,任務棧,系統棧以及全局變數共用問題。同時,工程調試方法也專門做了說明。 14.1 註意事項(重要必讀) 14.2 ...


第14章      uCOS-III操作系統版本二代示波器實現

本章教程為大家講解uCOS-III操作系統版本的二代示波器實現。主要講解RTOS設計框架,即各個任務實現的功能,任務間的通信方案選擇,任務棧,系統棧以及全局變數共用問題。同時,工程調試方法也專門做了說明。

14.1  註意事項(重要必讀)

14.2  任務功能劃分

14.3  用戶任務優先順序設置

14.4  全局變數分配,系統堆棧和任務堆棧

14.5  任務間通信和全局變數共用問題

14.6  uCOS-III系統調試

14.7  MDK優化等級

14.8  總結

 

 

14.1  註意事項(重要必讀)

1、學習本章節前,務必保證已經學習完畢前面章節。另外,工程代碼註釋已經比較詳細,瞭解了框架後,直接看源碼即可。

2、僅支持800*480解析度顯示屏,如果是電容屏,無需校準。如果是電阻屏,需要校準,按下按鍵K1即可進入校準界面。

3、由於按鍵不夠用,K1按鍵的消息處理做了三個條件編譯,詳情見本章14.6小節。預設K1按鍵執行觸摸校準,也可以選擇執行截圖或者串口列印任務執行情況。另外,不管當前處於任何界面都可以進行觸摸校準,僅電阻屏需要校準,電容屏無需校準。

4、STemWin5.40版本的截圖功能有bug,詳情看此貼:

http://forum.armfly.com/forum.php?mod=viewthread&tid=82445

當前用的5.32版本,也是來自STemWin軟體包。

5、Micrium官方曾經發佈過一個非常棒的文檔,如何發揮uCOS-III最高性能之重要提示和項目應用建議,推薦大家看看:http://forum.armfly.com/forum.php?mod=viewthread&tid=31634

6、uCOS-III工程的文件系統是採用的FatFS,當前開啟了MDK最高等級優化和時間優化。如果大家要使用FatFS功能,請務必關閉時間優化,因為FatFS在時間優化下會工作異常。詳情見本章14.7小節。

7、工程編譯支持MDK4.7X和MDK5。另外不支持MDK發佈的MDK5.24及其以上版本,因為這個版本不支持MDK4創建的工程轉換為MDK5了,所以要使用這個最新的版本,需要給MDK5安裝MDK4的相容包。

 

14.2  任務功能劃分

前面第三章已經將任務功能劃分好:

根據這個功能劃分,創建所需要的任務。

 

14.2.1 主函數創建

在main.c文件實現:

/*

*********************************************************************************************************

*    函 數 名: main

*    功能說明: 標準c程式入口。

*    形    參: 無

*    返 回 值: 無

*********************************************************************************************************

*/

int main(void)

{

    OS_ERR  err; 

    

     /* 動態記憶體分配 */

     MallocInit();

    

     /* 初始化uC/OS-III 內核 */

    OSInit(&err); 

 

     /* 創建一個啟動任務(也就是主任務)。啟動任務會創建所有的應用程式任務 */

     OSTaskCreate((OS_TCB       *)AppTaskStartTCB,   /* 任務控制塊地址 */           

                 (CPU_CHAR     *)"App Task Start",  /* 任務名 */

                 (OS_TASK_PTR   )AppTaskStart,      /* 啟動任務函數地址 */

                 (void         *)0,                 /* 傳遞給任務的參數 */

                 (OS_PRIO       )APP_CFG_TASK_START_PRIO, /* 任務優先順序 */

                 (CPU_STK      *)&AppTaskStartStk[0],     /* 堆棧基地址 */

                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE / 10, /* 堆棧監測區,這裡表示後10%作為監測區 */

                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,      /* 堆棧空間大小 */

                 (OS_MSG_QTY    )0,  /* 本任務支持接受的最大消息數 */

                 (OS_TICK       )0,  /* 設置時間片 */

                 (void         *)0,  /* 堆棧空間大小 */ 

                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),

        

                    /*  定義如下:

                       OS_OPT_TASK_STK_CHK      使能檢測任務棧,統計任務棧已用的和未用的

                       OS_OPT_TASK_STK_CLR      在創建任務時,清零任務棧

                       OS_OPT_TASK_SAVE_FP      如果CPU有浮點寄存器,則在任務切換時保存浮點寄存器的內容

                    */ 

                 (OS_ERR       *)&err);

 

     /* 啟動多任務系統,控制權交給uC/OS-III */

    OSStart(&err);                                              

   

    (void)&err;

   

    return (0);

}

在主函數中,首先是初始化任務所需的棧空間以及部分全局變數所需的空間,通過函數MallocInit實現(詳情看本章節14.4小節)。然後就是創建一個啟動任務,其它外設初始化,任務創建,任務消息創建等,都是在啟動任務裡面實現。

 

14.2.2 啟動任務(觸摸和按鍵)

啟動任務實現的功能比較簡單,主要是按鍵掃描和觸摸掃描:

/*

*********************************************************************************************************

*    函 數 名: AppTaskStart

*    功能說明: 這是一個啟動任務,在多任務系統啟動後,必須初始化滴答計數器。本任務主要實現按鍵和觸摸檢測。

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

     優 先 級: 3

*********************************************************************************************************

*/

static void AppTaskStart (void *p_arg)

{

     OS_ERR      err;

     uint8_t  ucCount = 0;

    

    /* 僅用於避免編譯器告警,編譯器不會產生任何目標代碼 */  

    (void)p_arg; 

    

     /* BSP 初始化。 BSP = Board Support Package 板級支持包,可以理解為底層驅動。*/

     CPU_Init();  /* 此函數要優先調用,因為外設驅動中使用的us和ms延遲是基於此函數的 */

     bsp_Init();      

     BSP_Tick_Init(); 

    

#if OS_CFG_STAT_TASK_EN > 0u

     OSStatTaskCPUUsageInit(&err);  

#endif

 

#ifdef CPU_CFG_INT_DIS_MEAS_EN

    CPU_IntDisMeasMaxCurReset();

#endif

 

     /* 創建任務通信 */

     AppObjCreate();

    

     /* 創建應用程式的任務 */

     AppTaskCreate();

    

    while(1)

    {

         /* 1ms一次觸摸掃描,電阻觸摸屏 */

         if(g_tTP.Enable == 1)

         {

              TOUCH_Scan();

             

              /* 按鍵掃描 */

              ucCount++;

              if(ucCount == 10)

              {

                   ucCount = 0;

                   bsp_KeyScan();

              }

             OSTimeDly(1, OS_OPT_TIME_DLY, &err);          

         }

        

          /* 10ms一次觸摸掃描,電容觸摸屏GT811 */

         if(g_GT811.Enable == 1)

         {

              bsp_KeyScan();

              GT811_OnePiontScan();

             OSTimeDly(10, OS_OPT_TIME_DLY, &err);     

         }

        

         /* 10ms一次觸摸掃描,電容觸摸屏FT5X06 */

         if(g_tFT5X06.Enable == 1)

         {

              bsp_KeyScan();

              FT5X06_OnePiontScan();

             OSTimeDly(10, OS_OPT_TIME_DLY, &err);

         }

    }    

}

在啟動任務里,首先做了硬體外設初始化,任務間通信創建和任務創建。然後是觸摸和按鍵掃描。

 

知識點拓展

新版emWin教程第4章或者第5章,對觸摸的實現做了詳細講解:

http://forum.armfly.com/forum.php?mod=viewthread&tid=19834

 

硬體外設的初始化函數bsp_Init是在 bsp.c 文件實現:

/*

*********************************************************************************************************

*    函 數 名: bsp_Init

*    功能說明: 初始化所有的硬體設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變數。只需要調用一次

*    形    參:無

*    返 回 值: 無

*********************************************************************************************************

*/

void bsp_Init(void)

{

     /*

         由於ST固件庫的啟動文件已經執行了CPU系統時鐘的初始化,所以不必再次重覆配置系統時鐘。

         啟動文件配置了CPU主時鐘頻率、內部Flash訪問速度和可選的外部SRAM FSMC初始化。

 

         系統時鐘預設配置為168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件

     */

     /* 使能CRC 因為使用STemWin前必須要使能 */

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);

    

     /* 優先順序分組設置為4,可配置0-15級搶占式優先順序,0級子優先順序,即不存在子優先順序。*/

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    

     SystemCoreClockUpdate();    /* 根據PLL配置更新系統時鐘頻率變數 SystemCoreClock */

 

     bsp_InitUart();    /* 初始化串口 */

     bsp_InitKey();          /* 初始化按鍵變數(必須在 bsp_InitTimer() 之前調用) */

    

     bsp_InitI2C();          /* 配置I2C匯流排 */

    

     bsp_InitExtSDRAM();  /* 初始化SDRAM */

     bsp_DetectLcdType(); /* 檢測觸摸板和LCD面板型號, 結果存在全局變數 g_TouchType, g_LcdType */

    

     TOUCH_InitHard();  /* 初始化配置觸摸晶元 */

     LCD_ConfigLTDC();    /* 初始化配置LTDC */

    

     DSO_ConfigCtrlGPIO();   /* 初始化示波器模塊的引腳配置 */ 

    

     bsp_InitADC();          /* 初始化ADC1,ADC2和ADC3 */

     bsp_InitDAC1();         /* 初始化DAC1 */

    

     g_DAC1.ucDuty = 50;     /* 初始化DAC配置,用於信號發生器 */

     g_DAC1.ucWaveType = 0;

     g_DAC1.ulAMP = 4095;

     g_DAC1.ulFreq = 10000;

     dac1_SetSinWave(g_DAC1.ulAMP, g_DAC1.ulFreq);

 

     MountSD();               /* 掛載SD卡 */

        

     TIM8_MeasureTrigConfig(); /* 初始化TIM8用於記錄一段波形 */

}

任務間的通信創建如下:

/*

*********************************************************************************************************

*    函 數 名: AppObjCreate

*    功能說明: 創建任務通訊

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

*********************************************************************************************************

*/

static  void  AppObjCreate (void)

{

     OS_ERR      err;

 

     /*

        創建信號量數值為1的時候可以實現互斥功能,也就是只有一個資源可以使用

        本常式是將串口1的列印函數作為保護的資源。防止串口列印的時候被其它任務搶占

        造成串口列印錯亂。

     */

     OSSemCreate((OS_SEM    *)&AppPrintfSemp,

                   (CPU_CHAR  *)"AppPrintfSemp",

                   (OS_SEM_CTR )1,

                   (OS_ERR    *)&err);   

    

     /* 創建計數值為0,用於實現任務同步功能 */

     OSSemCreate((OS_SEM    *)&SEM_SYNCH,

                   (CPU_CHAR  *)"SEM_SYNCH",

                   (OS_SEM_CTR )0,

                   (OS_ERR    *)&err);

}

任務創建如下:

/*

*********************************************************************************************************

*    函 數 名: AppTaskCreate

*    功能說明: 創建應用任務

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

*********************************************************************************************************

*/

static  void  AppTaskCreate (void)

{

     OS_ERR      err;

    

     /**************創建MsgPro任務*********************/

     OSTaskCreate((OS_TCB       *)AppTaskMsgProTCB,            

                 (CPU_CHAR     *)"App Task MsgPro",

                 (OS_TASK_PTR   )AppTaskMsgPro,

                 (void         *)0,

                 (OS_PRIO       )APP_CFG_TASK_MsgPro_PRIO,

                 (CPU_STK      *)&AppTaskMsgProStk[0],

                 (CPU_STK_SIZE  )APP_CFG_TASK_MsgPro_STK_SIZE / 10,

                 (CPU_STK_SIZE  )APP_CFG_TASK_MsgPro_STK_SIZE,

                 (OS_MSG_QTY    )0,

                 (OS_TICK       )0,

                 (void         *)0,

                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),

                 (OS_ERR       *)&err);

                    

     /**************創建USER IF任務*********************/

     OSTaskCreate((OS_TCB       *)AppTaskUserIFTCB,            

                 (CPU_CHAR     *)"App Task UserIF",

                 (OS_TASK_PTR   )AppTaskUserIF,

                 (void         *)0,

                 (OS_PRIO       )APP_CFG_TASK_USER_IF_PRIO,

                 (CPU_STK      *)&AppTaskUserIFStk[0],

                 (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE / 10,

                 (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE,

                 (OS_MSG_QTY    )0,

                 (OS_TICK       )0,

                 (void         *)0,

                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),

                 (OS_ERR       *)&err);

 

     /**************創建GUI任務*********************/           

     OSTaskCreate((OS_TCB       *)AppTaskGUITCB,             

                 (CPU_CHAR     *)"App Task GUI",

                 (OS_TASK_PTR   )AppTaskGUI,

                 (void         *)0,

                 (OS_PRIO       )APP_CFG_TASK_GUI_PRIO,

                 (CPU_STK      *)&AppTaskGUIStk[0],

                 (CPU_STK_SIZE  )APP_CFG_TASK_GUI_STK_SIZE / 10,

                 (CPU_STK_SIZE  )APP_CFG_TASK_GUI_STK_SIZE,

                 (OS_MSG_QTY    )0,

                 (OS_TICK       )0,

                 (void         *)0,

                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),

                 (OS_ERR       *)&err);  

 

     /**************創建DSO任務*********************/           

     OSTaskCreate((OS_TCB       *)AppTaskDsoTCB,             

                 (CPU_CHAR     *)"App Task DSO",

                 (OS_TASK_PTR   )AppTaskDSO,

                 (void         *)0,

                 (OS_PRIO       )APP_CFG_TASK_DSO_PRIO,

                 (CPU_STK      *)&AppTaskDsoStk[0],

                 (CPU_STK_SIZE  )APP_CFG_TASK_DSO_STK_SIZE / 10,

                 (CPU_STK_SIZE  )APP_CFG_TASK_DSO_STK_SIZE,

                 (OS_MSG_QTY    )5,

                 (OS_TICK       )0,

                 (void         *)0,

                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_SAVE_FP),

                 (OS_ERR       *)&err);                     

}

 

14.2.3 信號處理任務

信號處理任務的實現如下:

/*

*********************************************************************************************************

*    函 數 名: AppTaskDSO

*    功能說明: 雙通道示波器數據處理任務。

*    形    參: 無

*    返 回 值: 無

*   優 先 級: 2 

*********************************************************************************************************

*/

static void AppTaskDSO (void *p_arg)

{

     OS_ERR      err;

     CPU_TS       ts;

     void     *p_msg;

     OS_MSG_SIZE   msg_size;

     uint32_t *ucReceive,

    

     /* 實數序列FFT長度 */

     fftSize = 2048;

    

     /* 正變換 */

    ifftFlag = 0;

    

     /* 初始化結構體S中的參數 */

     arm_rfft_fast_init_f32(&S, fftSize);

    

    while(1)

    {

         /* 接受數據 */

         p_msg = OSTaskQPend(0,

                             OS_OPT_PEND_BLOCKING,

                             &msg_size,   /* 此參數是接收到數據個數 */

                             &ts,

                             &err);

        

         if(err == OS_ERR_NONE)

         {

              ucReceive = (uint32_t *)p_msg;

             

              switch (*ucReceive)

            {

                   /* 雙通道波形處理 */

                   case DspFFT2048Pro_15:

                       /* 讀取的是ADC3的位置 */

                       g_DSO1->usCurPos = 10240 - DMA2_Stream1->NDTR;

                  

                        /* 讀取的是ADC1的位置 */

                       g_DSO2->usCurPos = 10240 - DMA2_Stream0->NDTR;

                  

                       DSO2_WaveTrig(g_DSO2->usCurPos);

                       DSO1_WaveTrig(g_DSO1->usCurPos);

                       DSO2_WaveProcess();

                       DSO1_WaveProcess();

                       break;

 

                   /* 用於簡單的ADC數據採集 */

                   case DspMultiMeterPro_14:

                       g_uiAdcAvgSample = ADC_GetSampleAvgN();

                       break;

                  

                   /* 僅用於調試目的,列印任務的執行情況,預設不使用 */

                   case DspTaskInfo_13:

                       DispTaskInfo();

                       break;

                  

                   /* 其它位暫未使用 */

                   default:

                       App_Printf("*ucReceive = %x\r\n", *ucReceive);

                       break;

            }

         }

    }

}

根據接收到的不同任務消息來處理不同的功能,要處理的消息分為三類:

1、雙通道波形數據處理

主要實現軟體觸發,計算FFT ,FIR ,RMS,最大值,最小值,平均值和峰峰值。兩個通道都進行了處理。具體實現方法已經在前面章節為大家做了講解。

2、簡單電壓測量處理

這個功能比較簡單,就是獲取一組ADC數值,然後求平均。

3、列印任務執行情況

通過串口列印任務棧的使用情況和各個任務的CPU利用率。     

                          

14.2.4 GUI任務

emWin任務的實現代碼如下:

/*

*********************************************************************************************************

*    函 數 名: AppTaskGUI

*    功能說明: GUI任務,最低優先順序                        

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

*   優 先 級: OS_CFG_PRIO_MAX - 4u

*********************************************************************************************************

*/

static void AppTaskGUI(void *p_arg)

{

    (void)p_arg;       /* 避免編譯器告警 */

        

     while (1)

     {

         MainTask();

     }

}

emWin的代碼都是在函數MainTask裡面實現,這樣做是方便在main.c文件裡面統一管理任務。關於GUI部分最重要的界面優化,波形刷新優化,波形瀏覽等,在前面章節已經都做了講解,我們這裡不再贅述。更詳細的實現,需要結合前面章節的講解去看源碼。

 

14.2.5 用戶介面任務

這個任務暫時未執行任何功能,保留供以後升級使用。代碼如下:

/*

*********************************************************************************************************

*    函 數 名: AppTaskUserIF

*    功能說明: 保留,暫未使用。

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

     優 先 級: 5

*********************************************************************************************************

*/

static void AppTaskUserIF(void *p_arg)

{

     OS_ERR      err;

    

     (void)p_arg;                /* 避免編譯器報警 */

    

 

     while (1)

     {       

         OSTimeDly(1000, OS_OPT_TIME_DLY, &err);

     }

}

 

14.2.6 文件系統處理任務

當前文件系統處理任務主要用來做截圖功能,將GUI界面以BMP格式存儲到SD卡裡面:

/*

*********************************************************************************************************

*    函 數 名: AppTaskMsgPro

*    功能說明: 實現截圖功能,將圖片以BMP格式保存到SD卡中

*    形    參: p_arg 是在創建該任務時傳遞的形參

*    返 回 值: 無

     優 先 級: 4

*********************************************************************************************************

*/

static void AppTaskMsgPro(void *p_arg)

{

     uint32_t ulStart, ulEnd;

     OS_ERR      err;

     uint8_t       Pic_Name = 0;

     char buf[20];

 

     (void)p_arg;

          

     while(1)

     {   

          /* 等待獲取信號量同步消息,接收到後實現截圖功能,將圖片以BMP格式保存到SD卡中 */

         OSSemPend((OS_SEM *)&SEM_SYNCH,

                     (OS_TICK )0,

                     (OS_OPT  )OS_OPT_PEND_BLOCKING,

                     (CPU_TS  )0,

                     (OS_ERR *)&err);

        

         if(err == OS_ERR_NONE)

         {   

              sprintf(buf,"0:/PicSave/%d.bmp",Pic_Name);

             

              /* 記錄截圖前起始時間 */

              ulStart = OSTimeGet(&err);

             

              /* 開啟調度鎖 */

              //OSSchedLock(&err);

             

              /* 如果SD卡中沒有PicSave文件,會進行創建 */

              result = f_mkdir("0:/PicSave");

             

              /* 創建截圖 */

              result = f_open(&file,buf, FA_WRITE|FA_CREATE_ALWAYS);

             

              /* 向SD卡繪製BMP圖片 */

              GUI_BMP_Serialize(_WriteByte2File, &file);

             

              /* 創建完成後關閉file */

             result = f_close(&file);

             

              /* 開啟調度鎖 */

              //OSSchedUnlock(&err);

             

              /* 記錄截圖後時間並獲取截圖過程耗時 */

              ulEnd = OSTimeGet(&err);

              ulEnd -= ulStart;

             

              App_Printf("截圖完成,耗時 = %dms\r\n", ulEnd);

              Pic_Name++;       

         }                                                                                                                  

     }  

}

後期這個任務將被升級,用於將波形數據以CSV文件格式存儲到SD卡裡面。

 

14.3 用戶任務優先順序設置

當前任務的優先順序安排如下(數值越小,優先順序越高):

App Task DSO任務  : 優先順序2。

DSP任務一定要是優先順序最高的,因為採集的數據要實時處理。

App Task Start任務  : 優先順序3。

App Task MsgPro任務 : 優先順序4。

啟動任務(觸摸和按鍵掃描)以及MsgPro(文件系統處理)任務的優先順序誰高誰低都沒有關係。

App Task UserIF任務 :優先順序5。

保留,未使用任務,暫且安排為這個優先順序。

App Task GUI任務   :優先順序OS_CFG_PRIO_MAX - 4u,即32 – 4 = 28

emWin任務是除了空閑任務,統計任務以外最低優先順序的,因為emWin極其占用系統資源,而且時間長,如果這個任務設置為高優先順序,會直接影響低優先順序任務的執行。

 

知識點拓展

關於任務優先順序的安排,在我們RTX操作系統教程第8章的8.2小節有些拓展:

http://forum.armfly.com/forum.php?mod=viewthread&tid=14837

在我們FreeRTOS操作系統教程的第13章的13.2小節有些拓展:

http://forum.armfly.com/forum.php?mod=viewthread&tid=17658

 

14.4 全局變數分配,系統堆棧和任務堆棧

1、全局變數分配

示波器的設計需要很多變數進行邏輯管理,從設計之初就需要將變數分類進行結構體封裝,方便以後的維護升級。這一步至關重要,實際中差不多要定義上百個變數,如果不進行分類管理,以後的升級維護將非常麻煩。

這種方式還有一個好處是方便我們將F429的CCM RAM空間分配給這些變數使用。使用CCM RAM的好處是速度比通用RAM要快些,缺點是這部分空間不支持DMA操作。初次使用的用戶比較容易在這個地方犯錯誤。所以在使用局部變數時,切勿將局部變數用於DMA傳輸。

當前需要頻繁調用的變數已經通過動態記憶體管理分配給各個結構體變數,使用的CCM RAM空間。

uint64_t AppMallocCCM[64*1024/8] __attribute__((at(0x10000000))); /* CCM RAM動態記憶體池 */

 

/*

*********************************************************************************************************

*    函 數 名: MallocInit

*    功能說明: 用戶任務棧,用戶TCB(任務控制塊)和示波器結構體變數使用CCM RAM

*    形    參: 無

*    返 回 值: 無

*********************************************************************************************************

*/

static void MallocInit(void)

{

     /* 將內部CCM SRAM的64KB全部供動態記憶體使用 */

     rt_init_mem(AppMallocCCM, 1024*64);

 

     /* 任務棧和任務控制塊TCB的初始化,省略未寫 */

 

     /* 申請示波器通道1動態記憶體 */

    g_DSO1 = (DSO_T *)rt_alloc_mem(AppMallocCCM, sizeof(DSO_T));

    

     /* 申請示波器通道2動態記憶體 */

    g_DSO2 = (DSO_T *)rt_alloc_mem(AppMallocCCM, sizeof(DSO_T));

    

     /* 申請游標測量結構體變數動態記憶體 */

    g_Cursors = (CURSORS_T *)rt_alloc_mem(AppMallocCCM, sizeof(CURSORS_T));

 

     /* 申請標誌位結構體變數動態記憶體 */

    g_Flag = (FLAG_T *)rt_alloc_mem(AppMallocCCM, sizeof(FLAG_T));

    

     /* 申請觸髮結構體變數動態記憶體 */

    g_TrigVol = (TRIVOLTAGE_T *)rt_alloc_mem(AppMallocCCM, sizeof(TRIVOLTAGE_T));

    

     /* 申請FFT動態記憶體 */

    testInput_fft_2048 = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*2048);

    testOutput_fft_2048 = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*2048);

    

     /* 申請RMS動態記憶體 */

     g_RMSBUF = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*600);

    

     /* 申請FIR動態記憶體 */

    FirDataInput = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*FIR_LENGTH_SAMPLES);

    FirDataOutput = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*FIR_LENGTH_SAMPLES);

     firStateF32 = (float32_t *)rt_alloc_mem(AppMallocCCM, sizeof(float32_t)*FIR_StateBufSize);

}

 

2、任務棧和任務控制塊TCB

任務棧和任務控制塊TCB也是用的CCM RAM空間,具體分配如下:

uint64_t AppMallocCCM[64*1024/8] __attribute__((at(0x10000000))); /* CCM RAM動態記憶體池 */

 

/*

*********************************************************************************************************

*    函 數 名: MallocInit

*    功能說明: 用戶任務棧,用戶TCB(任務控制塊)和示波器結構體變數使用CCM RAM

*    形    參: 無

*    返 回 值: 無

*********************************************************************************************************

*/

static void MallocInit(void)

{

     /* 將內部CCM SRAM的64KB全部供動態記憶體使用 */

     rt_init_mem(AppMallocCCM, 1024*64);

 

     /* 任務堆棧和任務控制塊是使用CCM RAM */

     AppTaskDsoTCB = (OS_TCB *)rt_alloc_mem(AppMallocCCM, sizeof(OS_TCB));

     AppTaskDsoStk = (CPU_STK *)rt_alloc_mem(AppMallocCCM,

                                             sizeof(CPU_STK)*APP_CFG_TASK_DSO_STK_SIZE);

 

     AppTaskStartTCB = (OS_TCB *)rt_alloc_mem(AppMallocCCM, sizeof(OS_TCB));

     AppTaskStartStk = (CPU_STK *)rt_alloc_mem(AppMallocCCM,

                                               sizeof(CPU_STK)*APP_CFG_TASK_START_STK_SIZE);

 

     AppTaskMsgProTCB = (OS_TCB *)rt_alloc_mem(AppMallocCCM, sizeof(OS_TCB));

     AppTaskMsgProStk = (CPU_STK *)rt_alloc_mem(AppMallocCCM,

                                                sizeof(CPU_STK)*APP_CFG_TASK_MsgPro_STK_SIZE);

 

     AppTaskUserIFTCB = (OS_TCB *)rt_alloc_mem(AppMallocCCM, sizeof(OS_TCB));

     AppTaskUserIFStk = (CPU_STK *)rt_alloc_mem(AppMallocCCM,

                                                sizeof(CPU_STK)*APP_CFG_TASK_USER_IF_STK_SIZE);

 

     AppTaskGUITCB = (OS_TCB *)rt_alloc_mem(AppMallocCCM, sizeof(OS_TCB));

     AppTaskGUIStk = (CPU_STK *)rt_alloc_mem(AppMallocCCM,

                                             sizeof(CPU_STK)*APP_CFG_TASK_GUI_STK_SIZE);

    

 

     /* 部分全局變數的初始化,省略未寫 */

 

}

 

知識點拓展

關於任務棧大小應該分配多大的問題,可以看FreeRTOS教程第11章,對於uCOS-III系統也是適用的:http://forum.armfly.com/forum.php?mod=viewthread&tid=17658

 

3、系統棧分配

系統棧的大小不是在啟動文件裡面配置,因為系統啟動過程中做了重新配置,所以啟動文件裡面配置的系統棧只在uCOS-III開啟多任務之前使用:

 

重新配置的系統棧需要在如下所示位置設置,單位4位元組,比如這裡是配置的512u,也就是2048位元組。

 

 

14.5 任務間通信和全局變數共用問題

二代示波器的雙通道ADC通過DMA方式在實時的採集數據,每個通道的緩衝大小是1024*20位元組,採集的數據經過信號處理後送給GUI任務進行波形顯示和測量值顯示。為了實現這個功能,專門測試了兩種方案。

(1)方案一

採用DMA雙緩衝,一路緩衝採集波形的時候,另一路已經採集的波形數據發給數字信號處理任務,信號處理任務再將整理好的波形數據和測量值發給emWin任務做刷新。這種方式的優點是ADC採集的數據可以實時處理。缺點是F429處理不過來,比如我們一個通道的採樣率是2Msps,緩衝大小設置為2048,將緩衝填滿需要1ms左右的時間,而我們僅做一個2048點的實數FFT就需要0.862ms,其它的FIR,RMS等都還沒有做,而且已經沒有時間發消息給emWin任務做界面刷新了。如果我們降低FFT,FIR等信號處理的點數,也就失去了實時處理的意義。也許讀者會說,加大緩衝不就好了,其實不然。如果我們加大了緩衝,我們要處理的數據也增加了,還是處理不過來,而且我們現在要處理的是雙通道。

除了F429的性能問題,這種方式還有一個比較棘手的問題需要解決,就是用戶操作界面的時候,GUI任務基本已經沒有時間去處理數字信號處理任務發來的數據,為瞭解決這個問題,大大增加了軟體設計的複雜度,特別是波形暫停和運行的切換,視窗的切換以及其它操作時,都要註意這個問題。

如果沒有複雜的界面操作,而且採樣率較低的話,方案一還是比較合適的。由於我們需要滑動操作波形,而且要實現雙通道,每個通道最高採樣率是2.8Msps,所以放棄這種方案。

(2)方案二

與方案一恰恰相反,ADC數據依然是通過DMA方式實時採集,而任務間的通信反過來進行,emWin任務需要波形數據刷新時給數字信號處理任務發消息獲取,這樣就有效地解決了方案一中F429性能不夠的問題,而且方案一中棘手的軟體問題得到了很好的解決,隨時都可以操作界面。

並且這種方式無形中解決了emWin任務和數字信號處理任務之間共同操作全局變數的問題,因為emWin是低優先順序任務,而數字信號處理任務在emWin任務發消息後才會執行,這樣就不存在搶占問題了,有效地解決了全局變數共用問題。

但是這種方式也有一個缺陷,無法實時刷新波形和測量值了,不過可以通過普通觸發來解決了,普通觸發方式實時採集了觸發值前後各1024位元組的數據,並且可以滑動瀏覽。不過工程中未對這種方式做FFT和FIR的支持。

總結,二代示波器中最終選擇了方案二。

 

14.6 uCOS-III系統調試

調試uCOS-III有兩種方法,一種是uC/Probe,還有一種是串口列印。

1、uC/Probe調試

uCOS-III的調試推薦使用uC/Probe,性能強勁。針對uC/Probe的調試,我們專門做過一個專題教程,如果沒有用過的話,務必先學習教程。

 

知識點拓展

【專題教程第2期】uC/Probe簡易使用說明,含MDK和IAR,支持F103,F407和F429開發板

http://forum.armfly.com/forum.php?mod=viewthread&tid=50280

 

另外特別註意一個問題,二代示波器的uCOS-III做了最高等級的優化和時間優化,使用uC/Probe調試需要關閉所有優化,否則無法使用,因為調試信息都被優化掉了。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、其實有現成的 先來看看Windows10進度條的兩種模式: 網上有不少介紹仿製Windows10進度條的文章,也都實現了不錯的效果。而我再開一文的原因是覺得如果在這基礎上添加一些功能,比如圓點的數量,圓點的大小等等,效果可能會更好一些。接觸過UWP的朋友應該知道,其框架中自帶了進度條控制項,以 P ...
  • 《代碼大全》的第二章:介紹隱喻(類比)的思維方式, 《經濟學原理》的第二章:介紹怎麼像經濟學家一樣思考, 《電腦的心智操作系統之哲學原理》的第一章:介紹學習操作系統的思維, 所以我也儘早地介紹我寫本系列中會經常運用的學習思維。 ...
  • 一、c#版本中添加的功能: C#2.0 泛型 部分類型 匿名方法 迭代器 可空類型 Getter / setter單獨可訪問性 方法組轉換(代表) Co- and Contra-variance for delegates 靜態類 Delegate inference 泛型 部分類型 匿名方法 迭代 ...
  • 序 在前面的文章C# 如何插入、修改、刪除Word批註一文中介紹瞭如何操作Word批註的一些方法,在本篇文章中繼續介紹操作Word批註的方法。分以下三種情況來介紹: 1. 插入圖片到Word批註 2. 讀取Word批註 3. 回覆Word批註 所需工具 Free Spire.Doc for .NET ...
  • 在一個正常的項目中,登錄註冊的密碼是密文傳輸到後臺服務端的,也就是說,首先前端js對密碼做處理,隨後再傳遞到服務端,服務端解密再加密傳出到資料庫裡面。Dotnet已經提供了RSA演算法的加解密類庫,我們只需要引用下就好,前端js也有對RSA演算法的封裝,解決了加解密演算法之後,剩下的就是要確保公私鑰的傳輸 ...
  • 一、第一步導入api 二、窗體初始化的時候,開啟剪切板切換 三、窗體關閉時,移除監聽 三、重寫窗體的WndProc方法處理監聽 運行結果: ...
  • 原先做伺服器程式, 都是部署在xx雲上, 也沒理解雲是個啥, 不就是個伺服器(虛擬機)租賃商嗎? 好吧, 其實這個是IaaS, 而接下來要學習的ServiceFabric(以下簡稱SF)是PaaS. 首先SF和Orleans類似, 都是基於actor模型, 然後編程方式也很像, 大概就是定義公開介面 ...
  • 最近學習redhat7,進行網路配置,以前都是橋接直連,然後直接組網。由於一些原因現在虛擬機做內網使用,不用上網,只能使用僅主機模式。在僅主機模式下進行虛擬機組網。 僅主機模式下各個虛擬機只能和主機通信,各個虛擬機之間也可以通信,可以搭建自己的區域網環境。 安裝虛擬機時候選擇,或者虛擬機的網路設置: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...