首页 > 学院 > 开发设计 > 正文

STM32F4移植ucos_II

2019-11-14 10:02:19
字体:
来源:转载
供稿:网友

本篇目标:从搭建工程开始,一步步在 STM32F407ZGT6 上移植 ucos_ii 操作系统

材料准备:

stm32库文件:stm32f4官方库函数文件(stm32f4官网库函数资料)ucos_ii源文件:ucos_ii操作系统官方源代码文件(ucos_ii官网资料)移植工程:stm32f4移植ucos_II最终工程(stm32f4移植ucos_ii工程)

搭建stm32f4工程

建立如下文件夹,方便整理和拷贝: 建立工程1

解压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工程如图: keil1

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处添加所有头文件的路径,如图; keil2

编译,通过即可;


移植ucos_ii操作系统

在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工程里面如图: keil3

接下来开始修改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初始化和任务的创建;


ucos_ii初始化

修改main.c文件,添加相关头文件,添加任务相关宏定义,修改main函数如下:#include "app_cfg.h"#include "sys_cfg.h"#include "ucos_ii.h"#include "task_start.h"#define APP_TASK_START_PRIO 10u#define APP_TASK_START_STK_SIZE 128ustatic OS_STK App_TaskStartStk[APP_TASK_START_STK_SIZE];int main(void){ /* stm32系统初始化配置 */ Sys_Config(); /* ucos_ii初始化 */ OSInit(); /* 创建ucos_ii初始化任务 TASK_START */ OSTaskCreateExt(APP_TASK_START, (void *)0, (OS_STK *)&App_TaskStartStk [APP_TASK_START_STK_SIZE - 1], (INT8U )APP_TASK_START_PRIO, (INT16U )APP_TASK_START_PRIO, (OS_STK *)&App_TaskStartStk[0], (INT32U )APP_TASK_START_STK_SIZE, (void *)0, (INT16U)(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); /* 开始 ucos_ii */ OSStart(); return 0;}在task文件夹下创建文件 task_start.c 和 task_start.h,并添加进keil工程,打开文件添加头文件,宏定义,以及初始任务:

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);#endif

ucos_ii建立用户任务

首先需要初始化stm32的GPIO口,在sys_cfg.c中修改和添加下列函数:/*** * 函数名称 : GPIO_Configuration(); * * 函数描述 : GPIO初始化配置; * * 传递值 : 无; * * 返回值 : 无; * **/static void GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_Init(GPIOG, &GPIO_InitStructure); /* 关闭所有灯 */ GPIO_ResetBits(GPIOD,GPIO_Pin_7); GPIO_ResetBits(GPIOG,GPIO_Pin_9);}/*** * 函数名称 : Sys_Config(); * * 函数描述 : 系统初始化配置; * * 传递值 : 无; * * 返回值 : 无; * **/void Sys_Config(void){ /* 配置GPIO口 */ GPIO_Configuration();}在task文件夹下创建文件 task_led.c 和 task_led.h,并添加进keil工程,打开文件添加led任务函数:

task_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 的移植,共勉


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表