STM32F4移植ucos_II

本篇目标:从搭建工程开始,一步步在 STM32F407ZGT6 上移植 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_H

void 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                128u

static 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       128u

static 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_H

void 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_H

void APP_TASK_GREEN (void *p_arg);
void APP_TASK_RED   (void *p_arg);

#endif

至此,移植工作全部完成,编译,下载;成功后会发现两个led闪烁,就相当于两个led灯的任务相互交替进行,互不影响;

小结:每个裸板移植 ucos_ii 方法都是想通的,整理觉得移植ucos_ii比较重要的几个点:

  1. 滴答定时器的配置,包括滴答定时器的初始化配置其计数值,以及滴答定时器溢出中断中函数的调用;
  2. 任务调度,在每个创建的任务中必须使用延时函数、挂起函数或者删除函数,才能使多个任务进行相互切换,调用的以上函数最终都会调用用汇编写的任务切换函数 OSCtxSw() ,所以任务切换相关代码也是重要的一部分;

总结:从移植 ucos_ii 到移植 lwip 经过了很漫长的过程,终于也算移植成功了,所以先写了对 ucos_ii 的移植,之后再在此基础上再写 lwip 的移植,共勉

猜你喜欢

转载自blog.csdn.net/q361750389/article/details/54880714