zoukankan      html  css  js  c++  java
  • 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文件夹下的EvalBoardsSTSTM32F429II-SKuCOS-III目录下的一些文件拷贝到我们的项目中。具体如下图红框中所示:

     

      一般来说我们可以拷贝这8个文件直接使用就可以,但并不说明这8个文件是必须的。其中一些配置文件在系统中会引用到,所以文件名称不要改,而且配置参数按需设定。其他文件实际上可以根据我们的意愿修改。为简便起见,我们还可以复制两个文件,在EvalBoardsSTSTM32F429II-SKBSP目录之下的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函数是弱定义。

    欢迎关注:

  • 相关阅读:
    阅读笔记03
    第十三周总结
    阅读笔记02
    第十二周总结
    第十一周总结
    阅读笔记01
    阅读笔记3
    第十一周总结
    阅读笔记
    HDFS-学习总结
  • 原文地址:https://www.cnblogs.com/foxclever/p/13290074.html
Copyright © 2011-2022 走看看