uCOS-III应用开发笔记之一:uCOS-III在STM32的移植

uCOS-III实时操作系统在MCU平台被广泛使用,在这里我们将简单的记录如何将uCOS-III实时操作系统移植到目标平台上并运行。

1、必要的准备

在开始uCOS-III实时操作系统的移植前,我们还需要做一些必要的准备,如确定目标板、准备目标工程及uCOS-III实时操作系统源码等。

1.1、获取uCOS-III源码

在移植uCOS-III之前,首先要获取它的源码。其源码可以从Micrium 的官方网站:www.micrium.com得到。为了方便移植,我们建议直接下载Micrium移植好的基于目标平台的例子。例如我们就下载了uCOS-III V3.0.4基于STM32F4的实例。

解压下载得到的压缩包,我们可以发现4个文件夹,分别是EvalBoardsuC-CPUuC-LIBuCOS-III,如下图所示:

其中EvalBoards文件夹下是基于该评估版的应用层实现,在我们的移植中有部分文件可以移过来使用。当然

uC-CPU文件夹这是和 CPU 紧密相关的文件,里面的一些文件很重要,都是我们需要使用的。

uC-LIB文件夹,Micrium 公司提供的官方库,诸如字符串操作、内存操作等接口,可用可不用。一般能用于代替标准库中的一些函数,使得在嵌入式中应用更加方便安全。

uCOS-III文件夹,是操作系统内核文件夹,都是系统核心文件。这些文件是我们全部需要的,移植时将这些拷贝过去就可以。

1.2、建立目标项目

在这里我们的目标MCU选用的是STM32F407ZG,所以在移植之前我们需要建立一个面向STM32F407ZG的裸机工程。当然方法有多种,我们使用STM32CubeMX工具配置硬件然后生成一个基础的项目。

2uCOS-III的移植

我们此次移植基于STM32F407平台,使用HAL库,并使用IAR开发工具来完成。首先,我们创建一个空项目,并添加必要的HAL库函数,以及启动文件,主函数等。总之是一个可以运行的干净的项目即可。

接下来就是移植uCOS-III的过程。移植的过程并不复杂,先将必要的文件复制到我们的项目中来。一是将uC-CPU、uC-LIB、uCOS-III三个文件夹全部复制到我们的项目中。

并将EvalBoards文件夹下的EvalBoards\ST\STM32F429II-SK\uCOS-III目录下的一些文件拷贝到我们的项目中。具体如下图红框中所示:

一般来说我们可以拷贝这8个文件直接使用就可以,但并不说明这8个文件是必须的。其中一些配置文件在系统中会引用到,所以文件名称不要改,而且配置参数按需设定。其他文件实际上可以根据我们的意愿修改。为简便起见,我们还可以复制两个文件,在EvalBoards\ST\STM32F429II-SK\BSP目录之下的bsp文件:

其实,这两个文件与具体硬件联系紧密,一般需要自己编写,不过因为我们知识移植,所以有几个函数我们可以直接拿过来使用,我们将其复制过来加以修改。

文件已经准备好了,接下来就是将其移植到我们的项目中,将uCOS-III下的核心代码添加到项目中,如下:

同时将uC-CPU和uC-LIB文件夹下的内容添加到项目中,具体如下:

然后,将我们从例程中复制的相关文件也添加到项目中,具体如下:

然后修改项目属性中的文件引用路径:

到这了,工程项目就已经创建完成了,但并不可用,此时若编译会出现许多错误。因为例程使用的是标准库,而我们使用了HAL库,据此首先要将bsp.h文件中的#include <stm32f4xx_conf.h>修改为:#include <stm32f4xx_hal.h>。根据需要修改bsp.c文件中的具体驱动代码。

还有一个重要的修改,那就是PendSV中断处理,在STM32F4的启动文件startup_stm32f407xx.s中定义了该中断的中断处理函数PendSV_Handler。同时uCOS-III在os_cpu_a.asm文件中也定义了该中断的中断处理函数OS_CPU_PendSVHandler。所以我们我们需要让他们统一起来,怎么办呢?可以修改startup_stm32f407xx.s文件,也可以修改os_cpu_a.asm文件。在这里我们是修改了startup_stm32f407xx.s文件。不过通常情况下,我们不建议修改别人写好的文件,事实上,原厂例程中提供的一个方法是编写一段汇编程序使用PendSV_Handler调用OS_CPU_PendSVHandler达到相应的目的。不管采用哪种方式都需要在stm32f4xx_it.c文件中注释掉PendSV_Handler函数的实现。

同样的,SysTick_Handler中断处理函数需要做类式的处理。但是由于HAL库本身也是需要使用该中断的,而且在uCOS-III中OS_CPU_SysTickHandler函数是以C代码实现的,所以我们可在stm32f4xx_it.c文件中的SysTick_Handler函数中直接调用。

到这里移植工作基本就完不成了,编译也没有错,但需要跑起来,我们还需要编写相应的多任务处理代码。

3、移植测试

在前面我们已经完成了uCOS-III移植的基本工作。接下来我们实现多任务的测试代码。在开始任务编写前,我们需要修改bsp.c文件的内容。除了具体的应用驱动外,需要实现几个与时钟相关的函数:BSP_CPU_ClkFreq、CPU_TS_TmrInit、CPU_TS_TmrRd、CPU_TS32_to_uSec和CPU_TS64_to_uSec。在我们拷贝来的实例中,其实都有,除BSP_CPU_ClkFreq外,其他都不需要修改。BSP_CPU_ClkFreq函数实现如下:

CPU_INT32U  BSP_CPU_ClkFreq (void)
{
  CPU_INT32U hclk_freq;
 
  hclk_freq=HAL_RCC_GetHCLKFreq();
 
  return hclk_freq;
}

然后我们就可以开始具体任务的实现,在这里我们实现1个启动任务和3个普通任务,当然这些任务都非常简单,我们先声明任务控制块和任务栈如下:

static OS_TCB AppTaskStartTCB;
static CPU_STK AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];
static OS_TCB AppTaskUpdateTCB;
static CPU_STK AppTaskUpdateStk[APP_CFG_TASK_UPDATE_STK_SIZE];
static OS_TCB AppTaskCOMTCB;
static CPU_STK AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE];
static OS_TCB AppTaskUserIFTCB;
static CPU_STK AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE];

接着我们在主函数中创建启动任务,并启动任务调度。这时操作系统已经开始任务调度。

//生成启动任务
  OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
              (CPU_CHAR *)"App Task Start",
              (OS_TASK_PTR )AppTaskStart,
              (void *)0,
              (OS_PRIO )APP_CFG_TASK_START_PRIO,
              (CPU_STK *)&AppTaskStartStk[0],
              (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE / 10,
              (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE,
              (OS_MSG_QTY )0,
              (OS_TICK )0,
              (void *)0,
              (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
              (OS_ERR *)&err);
 
  OSStart(&err); //启动任取调度

在启动任务的任务函数中我们创建3个具体业务处理的任务,这三个任务创建后,启动任务将自己删除掉。

static void  AppTaskStart (void *p_arg)
{
  OS_ERR err;

  (void)p_arg;

  CPU_Init();

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);  
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
  CPU_IntDisMeasMaxCurReset();
#endif
                                       
  OSTaskCreate((OS_TCB       *)&AppTaskUpdateTCB,            
               (CPU_CHAR     *)"App Task Update",
               (OS_TASK_PTR   )AppTaskGUIUpdate,
               (void         *)0,
               (OS_PRIO       )APP_CFG_TASK_UPDATE_PRIO,
               (CPU_STK      *)&AppTaskUpdateStk[0],
               (CPU_STK_SIZE  )APP_CFG_TASK_UPDATE_STK_SIZE / 10,
               (CPU_STK_SIZE  )APP_CFG_TASK_UPDATE_STK_SIZE,
               (OS_MSG_QTY    )1,
               (OS_TICK       )0,
               (void         *)0,
               (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
               (OS_ERR       *)&err);
      
  OSTaskCreate((OS_TCB       *)&AppTaskCOMTCB,           
               (CPU_CHAR     *)"App Task COM",
               (OS_TASK_PTR   )AppTaskCOM,
               (void         *)0,
               (OS_PRIO       )APP_CFG_TASK_COM_PRIO,
               (CPU_STK      *)&AppTaskCOMStk[0],
               (CPU_STK_SIZE  )APP_CFG_TASK_COM_STK_SIZE / 10,
               (CPU_STK_SIZE  )APP_CFG_TASK_COM_STK_SIZE,
               (OS_MSG_QTY    )2,
               (OS_TICK       )0,
               (void         *)0,
               (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
               (OS_ERR       *)&err);
      
  OSTaskCreate((OS_TCB       *)&AppTaskUserIFTCB,            
               (CPU_CHAR     *)"App Task UserIF",
               (OS_TASK_PTR   )AppTaskUserIF,
               (void         *)0,
               (OS_PRIO       )APP_CFG_TASK_USER_IF_PRIO,
               (CPU_STK      *)&AppTaskUserIFStk[0],
               (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE / 10,
               (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE,
               (OS_MSG_QTY    )0,
               (OS_TICK       )0,
               (void         *)0,
               (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
               (OS_ERR       *)&err);
 
  OSTaskDel(&AppTaskStartTCB,&err);
  while (1)
  {                                        
    OSTimeDly(100, OS_OPT_TIME_DLY, &err);
  }
}

编译运行没有错误,至此我们将uCOS-III移植到目标MCU平台的工作就完成了。

4、小结

本篇中我们简单的介绍了uCOS-III移植到目标MCU平台的过程,并对移植后的系统进行了简单的测试。系统的运行与我们预期的一致,移植本身没有问题。

在本篇中我们对PendSV和SysTick中断处理,采用的是修改启动文件startup_stm32f407xx.s来实现的。事实上我们觉得更好的方式是编写一段汇编程序,在PendSV_Handler和SysTick_Handler中断处理函数中调用OS_CPU_PendSVHandler和OS_CPU_SysTickHandler,这样就不用修改startup_stm32f407xx.s和os_cpu_a.asm这两个文件了。当然之所以能如此操作,是因为在startup_stm32f407xx.s文件中PendSV_Handler和SysTick_Handler函数是弱定义。

欢迎关注:

猜你喜欢

转载自blog.csdn.net/foxclever/article/details/107304904