本篇目標(biāo):從搭建工程開始,一步步在 STM32F407ZGT6 上移植 ucos_ii 操作系統(tǒng)
材料準(zhǔn)備:
stm32庫文件:stm32f4官方庫函數(shù)文件(stm32f4官網(wǎng)庫函數(shù)資料)ucos_ii源文件:ucos_ii操作系統(tǒng)官方源代碼文件(ucos_ii官網(wǎng)資料)移植工程:stm32f4移植ucos_II最終工程(stm32f4移植ucos_ii工程)建立如下文件夾,方便整理和拷貝: 
解壓stm32庫函數(shù)包,進行文件的拷貝: (1)將 STM32F4xx_DSP_StdPeriph_Lib_V1.7.1/Libraries/STM32F4xx_ StdPeriph_Driver 文件夾下的兩個文件夾拷貝到fwlib文件夾; (2)將 Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/arm 文件夾下的 startup_stm32f40_41xxx.s 拷貝到startup文件夾; (3)將 Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates 文件夾下的 system_stm32f4xx.c 拷貝到misis文件夾; (4)將 Libraries/CMSIS/Device/ST/STM32F4xx/Include 文件夾下的兩個文件拷貝到misis文件夾; (5)將 Libraries/CMSIS/Include 文件夾下的 core_cm4.h 、core_cmFunc.h 、core_cmInstr.h 、core_cmSimd.h 拷貝到misis文件夾; (6)在 PRoject/STM32F4xx_StdPeriph_Examples 文件夾下隨便找一個工程例子,將其中的 main.c 、stm32f4xx_conf.h 、stm32f4xx_it.c 、stm32f4xx_it.h 拷貝到user文件夾;
建立keil工程如圖: 
keil工程修改: (1)刪除main.c所有內(nèi)容,只寫一個main函數(shù); (2)刪除stm32f4xx.h中的包含頭文件#inlcude”main.h”; (3)打開配置工程頁面;在output中勾上creat hex file;在C/C++中Define處輸入 STM32F40_41xxx,USE_STDPERIPH_DRIVER ;在C/C++中inlucde paths處添加所有頭文件的路徑,如圖; 
編譯,通過即可;
在ucos_II文件下建立Ports和Source文件夾
解壓ucos_ii源代碼文件: (1)將 Micrium/Software/uCOS-II/Source 文件夾下的所有文件拷貝到Source文件夾; (2)將 Micrium/Software/uCOS-II/Ports/ARM-Cortex-M4/Generic/ RealView 文件夾下的所有文件拷貝到Ports文件夾; (3)將 Micrium/Examples/ST/STM3240G-EVAL/OS2 文件夾下的app_cfg.h 、os_cfg.h拷貝到user文件夾; (4)在user文件夾下創(chuàng)建sys_cfg.c 、sys_cfg.h新文件;
將文件添加進keil工程里面如圖: 
接下來開始修改ucos_ii源碼
注釋 app_cfg.h中的 #include “cpu.h”和 void App_SerPrintf (CPU_CHAR *format, …);(136-137行)
注釋 os_cpu.h 中的 void OS_CPU_SysTickHandler (void); 和 void OS_CPU_ SysTickInit (INT32U cnts);(185-186行)
打開文件 os_cfg.h ,修改 OS_APP_HOOKS_EN 的定義值為0(30行);修改 OS_TICKS_PER_SEC 的定義值為 1000(51行);修改 OS_MEM_EN 的定義值為1(98行);修改 OS_TMR_EN 的定義值為 1(139行);
打開文件os_cpu_c.c ,注釋 #include “l(fā)ib_def.h”(53行);注釋 #if (OS_CPU_ARM_FP_EN == DEF_ENABLED) 與 #endif之間的所有內(nèi)容(317-354行);注釋 OS_CPU_SysTickHandler 整個函數(shù)內(nèi)容(461-473行);注釋 OS_CPU_SysTickInit 整個函數(shù)內(nèi)容(488-507行);
打開文件startup_stm32f40_41xxx.s 文件,將所有的 PendSV_Handler 替換成 OS_CPU_PendSVHandler (共3處,替換前需要將文件的只讀屬性去掉才能夠修改文件);
打開stm32f4xx_it.c文件,添加頭文件 #include “ucos_ii.h”;找到 SysTick_Handler 函數(shù)(146行),添加以下程序:
void SysTick_Handler(void){ OSIntEnter(); OSTimeTick(); OSIntExit();}打開 sys_cfg.c 和 sys_cfg.h,編寫一些函數(shù):sys_cfg.c:
#include "stm32f4xx.h"#include "os_cfg.h"#include "sys_cfg.h"/*** * 函數(shù)名稱 : OS_CPU_SysTickInit(); * * 函數(shù)描述 : 滴答定時器設(shè)定; * * 傳遞值 : 無; * * 返回值 : 無; * **/void OS_CPU_SysTickInit(void){ RCC_ClocksTypeDef rcc_clocks; /* 獲取系統(tǒng)時鐘 */ RCC_GetClocksFreq(&rcc_clocks); /* 設(shè)置滴答定時器溢出計數(shù)值 */ SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC);}void Sys_Config(void){}sys_cfg.h:
#ifndef SYS_CFG_H#define SYS_CFG_Hvoid OS_CPU_SysTickInit(void);void Sys_Config(void);#endif至此為止,ucos_ii的源碼修改結(jié)束,接下來就是ucos_ii初始化和任務(wù)的創(chuàng)建;
task_start.c:
#include "app_cfg.h"#include "sys_cfg.h"#include "ucos_ii.h"#include "stm32f4xx.h"#include "task_led.h"#define APP_TASK_USER_GREEN_PRIO 6u#define APP_TASK_USER_RED_PRIO 8u#define APP_TASK_USER_STK_SIZE 128ustatic OS_STK App_TaskGreenStk[APP_TASK_USER_STK_SIZE];static OS_STK App_TaskRedStk[APP_TASK_USER_STK_SIZE];static void APP_TASK_GREEN (void *p_arg);static void APP_TASK_RED (void *p_arg);/*** * 函數(shù)名稱 : APP_TASK_START(); * * 函數(shù)描述 : ucos_ii 初始化任務(wù); * * 傳遞值 : 無; * * 返回值 : 無; * **/void APP_TASK_START(void *p_arg){ OS_CPU_SR cpu_sr; (void)p_arg; /* 配置滴答定時器,此函數(shù)調(diào)用位置為第一個創(chuàng)建任務(wù)開頭 */ OS_CPU_SysTickInit(); /* 關(guān)中斷 */ OS_ENTER_CRITICAL(); /* 創(chuàng)建綠燈任務(wù) */ OSTaskCreateExt(APP_TASK_GREEN, (void *)0, (OS_STK *)&App_TaskGreenStk [APP_TASK_USER_STK_SIZE - 1], (INT8U )APP_TASK_USER_GREEN_PRIO, (INT16U )APP_TASK_USER_GREEN_PRIO, (OS_STK *)&App_TaskGreenStk[0], (INT32U )APP_TASK_USER_STK_SIZE, (void *)0, (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); /* 創(chuàng)建紅燈任務(wù) */ OSTaskCreateExt(APP_TASK_RED, (void *)0, (OS_STK *)&App_TaskRedStk [APP_TASK_USER_STK_SIZE - 1], (INT8U )APP_TASK_USER_RED_PRIO, (INT16U )APP_TASK_USER_RED_PRIO, (OS_STK *)&App_TaskRedStk[0], (INT32U )APP_TASK_USER_STK_SIZE, (void *)0, (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); /* 刪除任務(wù)自身 */ OSTaskDel(OS_PRIO_SELF); /* 關(guān)中斷 */ OS_EXIT_CRITICAL();}task_start.h:
#ifndef TASK_START_H#define TASK_START_Hvoid APP_TASK_START(void *p_arg);#endiftask_led.c:
#include "stm32f4xx.h"#include "ucos_ii.h"#define LED_RED_OFF GPIO_ResetBits(GPIOD,GPIO_Pin_7);#define LED_RED_ON GPIO_SetBits(GPIOD,GPIO_Pin_7);#define LED_GREEN_OFF GPIO_ResetBits(GPIOG,GPIO_Pin_9);#define LED_GREEN_ON GPIO_SetBits(GPIOG,GPIO_Pin_9);/*** * 函數(shù)名稱 : APP_TASK_GREEN(); * * 函數(shù)描述 : 綠燈任務(wù); * * 傳遞值 : 無; * * 返回值 : 無; * **/void APP_TASK_GREEN(void *p_arg){ for (;;) { /* 紅燈亮 */ LED_GREEN_ON; /* 延時0.5s,并任務(wù)切換 */ OSTimeDly(500); /* 紅燈滅 */ LED_GREEN_OFF; /* 延時0.5s,并任務(wù)切換 */ OSTimeDly(500); }}/*** * 函數(shù)名稱 : APP_TASK_RED(); * * 函數(shù)描述 : 紅燈任務(wù); * * 傳遞值 : 無; * * 返回值 : 無; * **/void APP_TASK_RED(void *p_arg){ for (;;) { /* 紅燈亮 */ LED_RED_ON; /* 延時0.25s,并任務(wù)切換 */ OSTimeDly(250); /* 紅燈滅 */ LED_RED_OFF; /* 延時0.25s,并任務(wù)切換 */ OSTimeDly(250); }}task_led.h:
#ifndef TASK_LED_H#define TASK_LED_Hvoid APP_TASK_GREEN (void *p_arg);void APP_TASK_RED (void *p_arg);#endif至此,移植工作全部完成,編譯,下載;成功后會發(fā)現(xiàn)兩個led閃爍,就相當(dāng)于兩個led燈的任務(wù)相互交替進行,互不影響;
小結(jié):每個裸板移植 ucos_ii 方法都是想通的,整理覺得移植ucos_ii比較重要的幾個點:
滴答定時器的配置,包括滴答定時器的初始化配置其計數(shù)值,以及滴答定時器溢出中斷中函數(shù)的調(diào)用;任務(wù)調(diào)度,在每個創(chuàng)建的任務(wù)中必須使用延時函數(shù)、掛起函數(shù)或者刪除函數(shù),才能使多個任務(wù)進行相互切換,調(diào)用的以上函數(shù)最終都會調(diào)用用匯編寫的任務(wù)切換函數(shù) OSCtxSw() ,所以任務(wù)切換相關(guān)代碼也是重要的一部分;總結(jié):從移植 ucos_ii 到移植 lwip 經(jīng)過了很漫長的過程,終于也算移植成功了,所以先寫了對 ucos_ii 的移植,之后再在此基礎(chǔ)上再寫 lwip 的移植,共勉
新聞熱點
疑難解答