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个文件夹,分别是EvalBoards、uC-CPU、uC-LIB、uCOS-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函数实现如下:

1 CPU_INT32U  BSP_CPU_ClkFreq (void)
2 {
3   CPU_INT32U hclk_freq;
4  
5   hclk_freq=HAL_RCC_GetHCLKFreq();
6  
7   return hclk_freq;
8 }

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

1 static OS_TCB AppTaskStartTCB;
2 static CPU_STK AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];
3 static OS_TCB AppTaskUpdateTCB;
4 static CPU_STK AppTaskUpdateStk[APP_CFG_TASK_UPDATE_STK_SIZE];
5 static OS_TCB AppTaskCOMTCB;
6 static CPU_STK AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE];
7 static OS_TCB AppTaskUserIFTCB;
8 static CPU_STK AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE];

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

 1 //生成启动任务
 2   OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
 3               (CPU_CHAR *)"App Task Start",
 4               (OS_TASK_PTR )AppTaskStart,
 5               (void *)0,
 6               (OS_PRIO )APP_CFG_TASK_START_PRIO,
 7               (CPU_STK *)&AppTaskStartStk[0],
 8               (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE / 10,
 9               (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE,
10               (OS_MSG_QTY )0,
11               (OS_TICK )0,
12               (void *)0,
13               (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
14               (OS_ERR *)&err);
15  
16   OSStart(&err); //启动任取调度

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

 1 static void  AppTaskStart (void *p_arg)
 2 {
 3   OS_ERR err;
 4  
 5   (void)p_arg;
 6  
 7   CPU_Init();
 8  
 9 #if OS_CFG_STAT_TASK_EN > 0u
10   OSStatTaskCPUUsageInit(&err);  
11 #endif
12  
13 #ifdef CPU_CFG_INT_DIS_MEAS_EN
14   CPU_IntDisMeasMaxCurReset();
15 #endif
16                                        
17   OSTaskCreate((OS_TCB       *)&AppTaskUpdateTCB,            
18                (CPU_CHAR     *)"App Task Update",
19                (OS_TASK_PTR   )AppTaskGUIUpdate,
20                (void         *)0,
21                (OS_PRIO       )APP_CFG_TASK_UPDATE_PRIO,
22                (CPU_STK      *)&AppTaskUpdateStk[0],
23                (CPU_STK_SIZE  )APP_CFG_TASK_UPDATE_STK_SIZE / 10,
24                (CPU_STK_SIZE  )APP_CFG_TASK_UPDATE_STK_SIZE,
25                (OS_MSG_QTY    )1,
26                (OS_TICK       )0,
27                (void         *)0,
28                (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
29                (OS_ERR       *)&err);
30       
31   OSTaskCreate((OS_TCB       *)&AppTaskCOMTCB,           
32                (CPU_CHAR     *)"App Task COM",
33                (OS_TASK_PTR   )AppTaskCOM,
34                (void         *)0,
35                (OS_PRIO       )APP_CFG_TASK_COM_PRIO,
36                (CPU_STK      *)&AppTaskCOMStk[0],
37                (CPU_STK_SIZE  )APP_CFG_TASK_COM_STK_SIZE / 10,
38                (CPU_STK_SIZE  )APP_CFG_TASK_COM_STK_SIZE,
39                (OS_MSG_QTY    )2,
40                (OS_TICK       )0,
41                (void         *)0,
42                (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
43                (OS_ERR       *)&err);
44       
45   OSTaskCreate((OS_TCB       *)&AppTaskUserIFTCB,            
46                (CPU_CHAR     *)"App Task UserIF",
47                (OS_TASK_PTR   )AppTaskUserIF,
48                (void         *)0,
49                (OS_PRIO       )APP_CFG_TASK_USER_IF_PRIO,
50                (CPU_STK      *)&AppTaskUserIFStk[0],
51                (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE / 10,
52                (CPU_STK_SIZE  )APP_CFG_TASK_USER_IF_STK_SIZE,
53                (OS_MSG_QTY    )0,
54                (OS_TICK       )0,
55                (void         *)0,
56                (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
57                (OS_ERR       *)&err);
58  
59   OSTaskDel(&AppTaskStartTCB,&err);
60   while (1)
61   {                                        
62     OSTimeDly(100, OS_OPT_TIME_DLY, &err);
63   }
64 }

  编译运行没有错误,至此我们将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函数是弱定义。

欢迎关注:

 

posted @ 2020-07-12 21:42  Moonan  阅读(2775)  评论(0编辑  收藏  举报