本篇目标:从搭建工程开始,一步步在 STM32F407ZGT6 上移植 ucos_ii 操作系统
材料准备:
stm32库文件:stm32f4官方库函数文件(stm32f4官网库函数资料)ucos_ii源文件:ucos_ii操作系统官方源代码文件(ucos_ii官网资料)移植工程:stm32f4移植ucos_II最终工程(stm32f4移植ucos_ii工程)建立如下文件夹,方便整理和拷贝:
解压stm32库函数包,进行文件的拷贝: (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所有内容,只写一个main函数; (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文件夹下创建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 “lib_def.h”(53行);注释 #if (OS_CPU_ARM_FP_EN == DEF_ENABLED) 与 #endif之间的所有内容(317-354行);注释 OS_CPU_SysTickHandler 整个函数内容(461-473行);注释 OS_CPU_SysTickInit 整个函数内容(488-507行);
打开文件startup_stm32f40_41xxx.s 文件,将所有的 PendSV_Handler 替换成 OS_CPU_PendSVHandler (共3处,替换前需要将文件的只读属性去掉才能够修改文件);
打开stm32f4xx_it.c文件,添加头文件 #include “ucos_ii.h”;找到 SysTick_Handler 函数(146行),添加以下程序:
void SysTick_Handler(void){ OSIntEnter(); OSTimeTick(); OSIntExit();}打开 sys_cfg.c 和 sys_cfg.h,编写一些函数:sys_cfg.c:
#include "stm32f4xx.h"#include "os_cfg.h"#include "sys_cfg.h"/*** * 函数名称 : OS_CPU_SysTickInit(); * * 函数描述 : 滴答定时器设定; * * 传递值 : 无; * * 返回值 : 无; * **/void OS_CPU_SysTickInit(void){ RCC_ClocksTypeDef rcc_clocks; /* 获取系统时钟 */ RCC_GetClocksFreq(&rcc_clocks); /* 设置滴答定时器溢出计数值 */ 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的源码修改结束,接下来就是ucos_ii初始化和任务的创建;
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);/*** * 函数名称 : APP_TASK_START(); * * 函数描述 : ucos_ii 初始化任务; * * 传递值 : 无; * * 返回值 : 无; * **/void APP_TASK_START(void *p_arg){ OS_CPU_SR cpu_sr; (void)p_arg; /* 配置滴答定时器,此函数调用位置为第一个创建任务开头 */ OS_CPU_SysTickInit(); /* 关中断 */ OS_ENTER_CRITICAL(); /* 创建绿灯任务 */ 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)); /* 创建红灯任务 */ 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)); /* 删除任务自身 */ OSTaskDel(OS_PRIO_SELF); /* 关中断 */ 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);/*** * 函数名称 : APP_TASK_GREEN(); * * 函数描述 : 绿灯任务; * * 传递值 : 无; * * 返回值 : 无; * **/void APP_TASK_GREEN(void *p_arg){ for (;;) { /* 红灯亮 */ LED_GREEN_ON; /* 延时0.5s,并任务切换 */ OSTimeDly(500); /* 红灯灭 */ LED_GREEN_OFF; /* 延时0.5s,并任务切换 */ OSTimeDly(500); }}/*** * 函数名称 : APP_TASK_RED(); * * 函数描述 : 红灯任务; * * 传递值 : 无; * * 返回值 : 无; * **/void APP_TASK_RED(void *p_arg){ for (;;) { /* 红灯亮 */ LED_RED_ON; /* 延时0.25s,并任务切换 */ OSTimeDly(250); /* 红灯灭 */ LED_RED_OFF; /* 延时0.25s,并任务切换 */ 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至此,移植工作全部完成,编译,下载;成功后会发现两个led闪烁,就相当于两个led灯的任务相互交替进行,互不影响;
小结:每个裸板移植 ucos_ii 方法都是想通的,整理觉得移植ucos_ii比较重要的几个点:
滴答定时器的配置,包括滴答定时器的初始化配置其计数值,以及滴答定时器溢出中断中函数的调用;任务调度,在每个创建的任务中必须使用延时函数、挂起函数或者删除函数,才能使多个任务进行相互切换,调用的以上函数最终都会调用用汇编写的任务切换函数 OSCtxSw() ,所以任务切换相关代码也是重要的一部分;总结:从移植 ucos_ii 到移植 lwip 经过了很漫长的过程,终于也算移植成功了,所以先写了对 ucos_ii 的移植,之后再在此基础上再写 lwip 的移植,共勉
新闻热点
疑难解答