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工具配置硬件然后生成一個基礎的項目。

2uCOS-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函數是弱定義。

歡迎關注:

 


免責聲明!

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



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