網上基於MDK的移植數不勝數,但是基於IAR的移植幾乎沒有,因爲官方的例程就是基於IAR的,所以移植起來很簡單,沒人介紹,但還是得小心謹慎,一不小心就出錯,對於新手來說,查找錯誤可不是那麼容易的。IAR建立工程,這裏就不介紹。
以下紅色部分需要與MCU型號對應
(1)在官網下載適合自己STM32的uCOS-II庫,連接如下,我用的MCU是STM32F103VCT6,屬於大容量的,所以選擇的庫是STMicroelectronics STM32F103ZE。
(2)下載下來的是(.exe)文件,雙擊解壓得到名稱爲Micrium的文件夾。
(3)在自己的工程中建立文件夾ucosii,裏面包含3個子文件夾,分別是config,port,source,文件夾名稱隨意。
(4)將文件夾Micrium\Software\uCOS-II\Ports\ARM-Cortex-M3\Generic\IAR中的文件全部複製到port文件夾中。
將文件夾Micrium\Software\uCOS-II\Source中的文件全部複製到source文件夾中。
將文件夾Micrium\Software\EvalBoards\ST\STM3210E-EVAL\IAR\OS-Probe中的app_cfg.h和os_cfg.h複製到config文件夾中。
(STM3210E-EVAL此目錄根據STM型號而定,型號不相符是否有影響,未測試)
(5)爲了防止修改錯誤,這裏暫時可以將port和source這兩個文件夾中的文件設置爲只讀,以後用的時候再取消。
(6)修改os_cfg.h中的第一個宏定義爲#define OS_APP_HOOKS_EN 0 (取消鉤子函數)。
(7)將啓動程序startup_stm32f10x_hd.s中所有PendSV_Handler替換成OS_CPU_PendSVHandler,SysTick_Handler替換成OS_CPU_SysTickHandler。
注意:下面這種註釋是錯誤的,會導致進入硬件錯位中斷,害的我浪費了好幾天時間。
PUBWEAK OS_CPU_PendSVHandler;PendSV_Handler
SECTION .text:CODE:REORDER(1)
OS_CPU_PendSVHandler;PendSV_Handler
B OS_CPU_PendSVHandler;PendSV_Handler
PUBWEAK OS_CPU_SysTickHandler;SysTick_Handler
SECTION .text:CODE:REORDER(1)
OS_CPU_SysTickHandler;SysTick_Handler
B OS_CPU_SysTickHandler;SysTick_Handler
(8)打開Micrium\Software\EvalBoards\ST\STM3210E-EVAL\IAR\BSP\bsp.c文件,複製函數CPU_INT32U BSP_CPU_ClkFreq (void)和INT32U OS_CPU_SysTickClkFreq (void)到main.c中。
(注意將所有CPU_INT32U修改爲INT32U,不然會報錯)
(9)在main.c中創建任務。
#include "ucos_ii.h" #include "os_cpu.h" #include "stm32f10x.h" #define STARTUP_TASK_PRIO 10 #define STARTUP_TASK_STK_SIZE 64 OS_STK startup_task_stk[STARTUP_TASK_STK_SIZE]; //LED1任務 //設置任務優先級 #define LED1_TASK_PRIO 5 //設置任務堆棧大小 #define LED1_STK_SIZE 64 //創建任務堆棧空間 OS_STK LED1_TASK_STK[LED1_STK_SIZE]; //LED2任務 //設置任務優先級 #define LED2_TASK_PRIO 6 //設置任務堆棧大小 #define LED2_STK_SIZE 64 //創建任務堆棧空間 OS_STK LED2_TASK_STK[LED2_STK_SIZE]; void led1_task(void *p_arg); void led2_task(void *p_arg); INT32U OS_CPU_SysTickClkFreq (void) { INT32U freq; RCC_ClocksTypeDef rcc_clocks; RCC_GetClocksFreq(&rcc_clocks); freq = (INT32U)rcc_clocks.HCLK_Frequency; return (freq); } void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); //使能PB,PE端口時鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED0-->PA.2 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推輓輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度爲50MHz GPIO_Init(GPIOA, &GPIO_InitStructure); //根據設定參數初始化GPIOA.2 GPIO_ResetBits(GPIOA,GPIO_Pin_2); //PA.2 輸出高 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //LED1-->PB.12 端口配置, 推輓輸出 GPIO_Init(GPIOB, &GPIO_InitStructure); //推輓輸出 ,IO口速度爲50MHz GPIO_ResetBits(GPIOB,GPIO_Pin_12); //PB.12 輸出高 } static void startup_task(void *p_arg) { INT8U err; OS_CPU_SR cpu_sr=0; OS_CPU_SysTickInit(); #if (OS_TASK_STAT_EN > 0) OSStatInit(); #endif OS_ENTER_CRITICAL(); //進入臨界區(無法被中斷打斷) err = OSTaskCreate(led1_task, (void *)0, (OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1], LED1_TASK_PRIO); err = OSTaskCreate(led2_task, (void *)0, (OS_STK*)&LED2_TASK_STK[LED2_STK_SIZE-1], LED2_TASK_PRIO); OSTaskSuspend(STARTUP_TASK_PRIO); //掛起起始任務. OS_EXIT_CRITICAL(); //退出臨界區(可以被中斷打斷) if (OS_ERR_NONE != err) while(1); OSTaskDel(OS_PRIO_SELF); } int main(void) { LED_Init(); OSInit(); OSTaskCreate(startup_task, (void *)0, (OS_STK*)&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO); OSStart(); return 0; } //LED1任務 void led1_task(void *p_arg) { while(1) { GPIO_ResetBits(GPIOA,GPIO_Pin_2); OSTimeDly(500); GPIO_SetBits(GPIOA,GPIO_Pin_2); OSTimeDly(500); } } //LED2任務 void led2_task(void *p_arg) { while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_12); OSTimeDly(500); GPIO_SetBits(GPIOB,GPIO_Pin_12); OSTimeDly(500); } }