uCOS-III应用开发笔记之一:uCOS-III在STM32的移植
uCOS-III實時操作系統在MCU平臺被廣泛使用,在這里我們將簡單的記錄如何將uCOS-III實時操作系統移植到目標平臺上并運行。
1、必要的準備
在開始uCOS-III實時操作系統的移植前,我們還需要做一些必要的準備,如確定目標板、準備目標工程及uCOS-III實時操作系統源碼等。
1.1、獲取uCOS-III源碼
在移植uCOS-III之前,首先要獲取它的源碼。其源碼可以從Micrium 的官方網站:www.micrium.com得到。為了方便移植,我們建議直接下載Micrium移植好的基于目標平臺的例子。例如我們就下載了uCOS-III V3.0.4基于STM32F4的實例。
解壓下載得到的壓縮包,我們可以發現4個文件夾,分別是EvalBoards、uC-CPU、uC-LIB、uCOS-III,如下圖所示:
其中EvalBoards文件夾下是基于該評估版的應用層實現,在我們的移植中有部分文件可以移過來使用。當然
uC-CPU文件夾這是和 CPU 緊密相關的文件,里面的一些文件很重要,都是我們需要使用的。
uC-LIB文件夾,Micrium 公司提供的官方庫,諸如字符串操作、內存操作等接口,可用可不用。一般能用于代替標準庫中的一些函數,使得在嵌入式中應用更加方便安全。
uCOS-III文件夾,是操作系統內核文件夾,都是系統核心文件。這些文件是我們全部需要的,移植時將這些拷貝過去就可以。
1.2、建立目標項目
在這里我們的目標MCU選用的是STM32F407ZG,所以在移植之前我們需要建立一個面向STM32F407ZG的裸機工程。當然方法有多種,我們使用STM32CubeMX工具配置硬件然后生成一個基礎的項目。
2、uCOS-III的移植
我們此次移植基于STM32F407平臺,使用HAL庫,并使用IAR開發工具來完成。首先,我們創建一個空項目,并添加必要的HAL庫函數,以及啟動文件,主函數等。總之是一個可以運行的干凈的項目即可。
接下來就是移植uCOS-III的過程。移植的過程并不復雜,先將必要的文件復制到我們的項目中來。一是將uC-CPU、uC-LIB、uCOS-III三個文件夾全部復制到我們的項目中。
并將EvalBoards文件夾下的EvalBoards\ST\STM32F429II-SK\uCOS-III目錄下的一些文件拷貝到我們的項目中。具體如下圖紅框中所示:
一般來說我們可以拷貝這8個文件直接使用就可以,但并不說明這8個文件是必須的。其中一些配置文件在系統中會引用到,所以文件名稱不要改,而且配置參數按需設定。其他文件實際上可以根據我們的意愿修改。為簡便起見,我們還可以復制兩個文件,在EvalBoards\ST\STM32F429II-SK\BSP目錄之下的bsp文件:
其實,這兩個文件與具體硬件聯系緊密,一般需要自己編寫,不過因為我們知識移植,所以有幾個函數我們可以直接拿過來使用,我們將其復制過來加以修改。
文件已經準備好了,接下來就是將其移植到我們的項目中,將uCOS-III下的核心代碼添加到項目中,如下:
同時將uC-CPU和uC-LIB文件夾下的內容添加到項目中,具體如下:
然后,將我們從例程中復制的相關文件也添加到項目中,具體如下:
然后修改項目屬性中的文件引用路徑:
到這了,工程項目就已經創建完成了,但并不可用,此時若編譯會出現許多錯誤。因為例程使用的是標準庫,而我們使用了HAL庫,據此首先要將bsp.h文件中的#include <stm32f4xx_conf.h>修改為:#include <stm32f4xx_hal.h>。根據需要修改bsp.c文件中的具體驅動代碼。
還有一個重要的修改,那就是PendSV中斷處理,在STM32F4的啟動文件startup_stm32f407xx.s中定義了該中斷的中斷處理函數PendSV_Handler。同時uCOS-III在os_cpu_a.asm文件中也定義了該中斷的中斷處理函數OS_CPU_PendSVHandler。所以我們我們需要讓他們統一起來,怎么辦呢?可以修改startup_stm32f407xx.s文件,也可以修改os_cpu_a.asm文件。在這里我們是修改了startup_stm32f407xx.s文件。不過通常情況下,我們不建議修改別人寫好的文件,事實上,原廠例程中提供的一個方法是編寫一段匯編程序使用PendSV_Handler調用OS_CPU_PendSVHandler達到相應的目的。不管采用哪種方式都需要在stm32f4xx_it.c文件中注釋掉PendSV_Handler函數的實現。
同樣的,SysTick_Handler中斷處理函數需要做類式的處理。但是由于HAL庫本身也是需要使用該中斷的,而且在uCOS-III中OS_CPU_SysTickHandler函數是以C代碼實現的,所以我們可在stm32f4xx_it.c文件中的SysTick_Handler函數中直接調用。
到這里移植工作基本就完不成了,編譯也沒有錯,但需要跑起來,我們還需要編寫相應的多任務處理代碼。
3、移植測試
在前面我們已經完成了uCOS-III移植的基本工作。接下來我們實現多任務的測試代碼。在開始任務編寫前,我們需要修改bsp.c文件的內容。除了具體的應用驅動外,需要實現幾個與時鐘相關的函數:BSP_CPU_ClkFreq、CPU_TS_TmrInit、CPU_TS_TmrRd、CPU_TS32_to_uSec和CPU_TS64_to_uSec。在我們拷貝來的實例中,其實都有,除BSP_CPU_ClkFreq外,其他都不需要修改。BSP_CPU_ClkFreq函數實現如下:
CPU_INT32U? BSP_CPU_ClkFreq (void) {CPU_INT32U hclk_freq;hclk_freq=HAL_RCC_GetHCLKFreq();return hclk_freq; }然后我們就可以開始具體任務的實現,在這里我們實現1個啟動任務和3個普通任務,當然這些任務都非常簡單,我們先聲明任務控制塊和任務棧如下:
static OS_TCB AppTaskStartTCB; static CPU_STK AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE]; static OS_TCB AppTaskUpdateTCB; static CPU_STK AppTaskUpdateStk[APP_CFG_TASK_UPDATE_STK_SIZE]; static OS_TCB AppTaskCOMTCB; static CPU_STK AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE]; static OS_TCB AppTaskUserIFTCB; static CPU_STK AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE];接著我們在主函數中創建啟動任務,并啟動任務調度。這時操作系統已經開始任務調度。
//生成啟動任務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,(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_ERR *)&err);OSStart(&err); //啟動任取調度在啟動任務的任務函數中我們創建3個具體業務處理的任務,這三個任務創建后,啟動任務將自己刪除掉。
static void? AppTaskStart (void *p_arg) {OS_ERR err;(void)p_arg;CPU_Init();#if OS_CFG_STAT_TASK_EN > 0uOSStatTaskCPUUsageInit(&err);?? #endif#ifdef CPU_CFG_INT_DIS_MEAS_ENCPU_IntDisMeasMaxCurReset(); #endifOSTaskCreate((OS_TCB?????? *)&AppTaskUpdateTCB,????????????(CPU_CHAR???? *)"App Task Update",(OS_TASK_PTR?? )AppTaskGUIUpdate,(void???????? *)0,(OS_PRIO?????? )APP_CFG_TASK_UPDATE_PRIO,(CPU_STK????? *)&AppTaskUpdateStk[0],(CPU_STK_SIZE? )APP_CFG_TASK_UPDATE_STK_SIZE / 10,(CPU_STK_SIZE? )APP_CFG_TASK_UPDATE_STK_SIZE,(OS_MSG_QTY??? )1,(OS_TICK?????? )0,(void???????? *)0,(OS_OPT??????? )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),(OS_ERR?????? *)&err);OSTaskCreate((OS_TCB?????? *)&AppTaskCOMTCB,???????????(CPU_CHAR???? *)"App Task COM",(OS_TASK_PTR?? )AppTaskCOM,(void???????? *)0,(OS_PRIO?????? )APP_CFG_TASK_COM_PRIO,(CPU_STK????? *)&AppTaskCOMStk[0],(CPU_STK_SIZE? )APP_CFG_TASK_COM_STK_SIZE / 10,(CPU_STK_SIZE? )APP_CFG_TASK_COM_STK_SIZE,(OS_MSG_QTY??? )2,(OS_TICK?????? )0,(void???????? *)0,(OS_OPT??????? )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),(OS_ERR?????? *)&err);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);OSTaskDel(&AppTaskStartTCB,&err);while (1){????????????????????????????????????????OSTimeDly(100, OS_OPT_TIME_DLY, &err);} }編譯運行沒有錯誤,至此我們將uCOS-III移植到目標MCU平臺的工作就完成了。
4、小結
本篇中我們簡單的介紹了uCOS-III移植到目標MCU平臺的過程,并對移植后的系統進行了簡單的測試。系統的運行與我們預期的一致,移植本身沒有問題。
在本篇中我們對PendSV和SysTick中斷處理,采用的是修改啟動文件startup_stm32f407xx.s來實現的。事實上我們覺得更好的方式是編寫一段匯編程序,在PendSV_Handler和SysTick_Handler中斷處理函數中調用OS_CPU_PendSVHandler和OS_CPU_SysTickHandler,這樣就不用修改startup_stm32f407xx.s和os_cpu_a.asm這兩個文件了。當然之所以能如此操作,是因為在startup_stm32f407xx.s文件中PendSV_Handler和SysTick_Handler函數是弱定義。
歡迎關注:
總結
以上是生活随笔為你收集整理的uCOS-III应用开发笔记之一:uCOS-III在STM32的移植的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinSock I/O 模型 -- WS
- 下一篇: 动态链接MFC引发的血案