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函數實現如下:
1 CPU_INT32U BSP_CPU_ClkFreq (void) 2 { 3 CPU_INT32U hclk_freq; 4 5 hclk_freq=HAL_RCC_GetHCLKFreq(); 6 7 return hclk_freq; 8 }
然后我們就可以開始具體任務的實現,在這里我們實現1個啟動任務和3個普通任務,當然這些任務都非常簡單,我們先聲明任務控制塊和任務棧如下:
1 static OS_TCB AppTaskStartTCB; 2 static CPU_STK AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE]; 3 static OS_TCB AppTaskUpdateTCB; 4 static CPU_STK AppTaskUpdateStk[APP_CFG_TASK_UPDATE_STK_SIZE]; 5 static OS_TCB AppTaskCOMTCB; 6 static CPU_STK AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE]; 7 static OS_TCB AppTaskUserIFTCB; 8 static CPU_STK AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE];
接着我們在主函數中創建啟動任務,並啟動任務調度。這時操作系統已經開始任務調度。
1 //生成啟動任務 2 OSTaskCreate((OS_TCB *)&AppTaskStartTCB, 3 (CPU_CHAR *)"App Task Start", 4 (OS_TASK_PTR )AppTaskStart, 5 (void *)0, 6 (OS_PRIO )APP_CFG_TASK_START_PRIO, 7 (CPU_STK *)&AppTaskStartStk[0], 8 (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE / 10, 9 (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE, 10 (OS_MSG_QTY )0, 11 (OS_TICK )0, 12 (void *)0, 13 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 14 (OS_ERR *)&err); 15 16 OSStart(&err); //啟動任取調度
在啟動任務的任務函數中我們創建3個具體業務處理的任務,這三個任務創建后,啟動任務將自己刪除掉。
1 static void AppTaskStart (void *p_arg) 2 { 3 OS_ERR err; 4 5 (void)p_arg; 6 7 CPU_Init(); 8 9 #if OS_CFG_STAT_TASK_EN > 0u 10 OSStatTaskCPUUsageInit(&err); 11 #endif 12 13 #ifdef CPU_CFG_INT_DIS_MEAS_EN 14 CPU_IntDisMeasMaxCurReset(); 15 #endif 16 17 OSTaskCreate((OS_TCB *)&AppTaskUpdateTCB, 18 (CPU_CHAR *)"App Task Update", 19 (OS_TASK_PTR )AppTaskGUIUpdate, 20 (void *)0, 21 (OS_PRIO )APP_CFG_TASK_UPDATE_PRIO, 22 (CPU_STK *)&AppTaskUpdateStk[0], 23 (CPU_STK_SIZE )APP_CFG_TASK_UPDATE_STK_SIZE / 10, 24 (CPU_STK_SIZE )APP_CFG_TASK_UPDATE_STK_SIZE, 25 (OS_MSG_QTY )1, 26 (OS_TICK )0, 27 (void *)0, 28 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 29 (OS_ERR *)&err); 30 31 OSTaskCreate((OS_TCB *)&AppTaskCOMTCB, 32 (CPU_CHAR *)"App Task COM", 33 (OS_TASK_PTR )AppTaskCOM, 34 (void *)0, 35 (OS_PRIO )APP_CFG_TASK_COM_PRIO, 36 (CPU_STK *)&AppTaskCOMStk[0], 37 (CPU_STK_SIZE )APP_CFG_TASK_COM_STK_SIZE / 10, 38 (CPU_STK_SIZE )APP_CFG_TASK_COM_STK_SIZE, 39 (OS_MSG_QTY )2, 40 (OS_TICK )0, 41 (void *)0, 42 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 43 (OS_ERR *)&err); 44 45 OSTaskCreate((OS_TCB *)&AppTaskUserIFTCB, 46 (CPU_CHAR *)"App Task UserIF", 47 (OS_TASK_PTR )AppTaskUserIF, 48 (void *)0, 49 (OS_PRIO )APP_CFG_TASK_USER_IF_PRIO, 50 (CPU_STK *)&AppTaskUserIFStk[0], 51 (CPU_STK_SIZE )APP_CFG_TASK_USER_IF_STK_SIZE / 10, 52 (CPU_STK_SIZE )APP_CFG_TASK_USER_IF_STK_SIZE, 53 (OS_MSG_QTY )0, 54 (OS_TICK )0, 55 (void *)0, 56 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), 57 (OS_ERR *)&err); 58 59 OSTaskDel(&AppTaskStartTCB,&err); 60 while (1) 61 { 62 OSTimeDly(100, OS_OPT_TIME_DLY, &err); 63 } 64 }
編譯運行沒有錯誤,至此我們將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函數是弱定義。
歡迎關注: