移植uc/OS-III最新版到小熊派开发板(STM32L431)

时间:2022-07-25
本文章向大家介绍移植uc/OS-III最新版到小熊派开发板(STM32L431),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、uc/OS全家桶

1. Micrium Software

Micrium Software提供了 RTOS 解决方案系列,俗称ucos全家桶,其中最为出名的就是 ucOS-II 和ucOS-III,于 2016 年成为 Silicon Labs 的一部分。

2. μc/OS RTOS & stacks

ucos整条产品线非常丰富,常用的组件都有,官方叫做 μc/OS RTOS & stacks,民间叫做ucos全家桶。

作为一个上过火星的老牌RTOS,找机会体验一下还是很爽的,ucos全家桶中提供了非常丰富的内容。

目前ucos全家桶中的产品大多数已经在github开源,遵循 Apache-2.0 开源许可,开源地址在:

“https://github.com/SiliconLabs ”

3. ucos内核选择

玩全家桶之前,肯定要先把RTOS内核玩起来,关于选择ucos-II还是ucos-III是个老生长谈的问题,上图解决:

4. uc/OS-III源码下载

uc/OS-III系统分为了三个开源仓库,要分别拉取。

① uC-OS3:

git clone https://github.com/SiliconLabs/uC-OS3.git

② uC-CPU:

git clone https://github.com/SiliconLabs/uC-CPU.git

③ uC-LIB:

git clone https://github.com/SiliconLabs/uC-LIB.git

二、移植前的准备

本文中使用的开发板为小熊派IoT开发板,主控为STM32L431RCT6:

本文使用的开发工具是MDK 5.30版本,编译器版本为ARMCC5。

移植之前使用STM32CubeMX生成一份裸机工程,保证可以使用printf在串口正常打印。

三、移植uc/OS-III

1. 复制ucos内核文件到工程中

“这里我全都复制过来,后续可以将未添加到MDK中的文件删除。 ”

在工程下新建 ucOS-III 文件夹,存放ucOS-III相关文件。

① 复制ucos内核文件夹过来:

② 复制uC-CPU和uC-LIB两个文件夹过来:

2.添加文件到MDK工程

① 添加 ucos-iii/ports 分组,添加 PortsARM-Cortex-MARMv7-M 目录下的os_cpu_c.c文件,以及该目录下ARM目录下的os_cpu_a.asm文件和 os_cpu_c.c文件:

② 添加 ucos-iii/source分组,添加Source文件夹下的所有c文件(除去__dbg_uCOS-III.c):

③ 添加uC-LIB分组,添加uC-LIB文件夹下的4个c文件:

④ 添加uC-CPU分组,添加uC-CPU下的相关文件,如图:

⑤ 添加 ucos-iii/config 分组,添加配置文件,如下:

  • lib_cfg.h:uC-LIBCfgTemplate
  • os_cfg.h:CfgTemplate
  • cpu_cfg.h:uC-CPUCfgTemplate

3. 添加头文件路径到工程中

4. 修改配置文件

① 修改 cpu_cfg.h,配置本工程所使用内核中CPU的NVIC优先级位数:

② 修改 os_cfg.h,关闭系统中 APP HOOKS 功能:

5. 处理中断

RTOS中内核得以运行需要两个中断:

  • 在pendSV异常处理中进行任务切换
  • 在systick异常处理中进行内核时钟处理

首先包含进来ucos的头文件,修改 stm32l4xx_it.c 文件,在头文件添加:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "os.h"
/* USER CODE END Includes */

① 处理pendSV异常,如下:

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{
  /* USER CODE BEGIN PendSV_IRQn 0 */
   OS_CPU_PendSVHandler();

  /* USER CODE END PendSV_IRQn 0 */
  /* USER CODE BEGIN PendSV_IRQn 1 */

  /* USER CODE END PendSV_IRQn 1 */
}

② 处理Systick异常,如下:

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
 /* USER CODE BEGIN SysTick_IRQn 0 */
 
 /* USER CODE END SysTick_IRQn 0 */
 HAL_IncTick();
 /* USER CODE BEGIN SysTick_IRQn 1 */
 OS_CPU_SysTickHandler();
 
 /* USER CODE END SysTick_IRQn 1 */
}

至此,移植完成。

四、测试系统调度和延时

在main.c中按照如下过程编写测试代码。

① 引入ucos头文件:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "os.h"
/* USER CODE END Includes */

② 定义任务栈、任务控制块、任务入口函数:

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
static  OS_TCB   Task1TCB;
static  CPU_STK  Task1Stk[512];

static void Task1_entry(void *p_arg)
{
 OS_ERR  err;
    
 (void)p_arg;
    
 while(1)
 {
        printf("task1 is running...rn");
     OSTimeDly(1000, OS_OPT_TIME_DLY, &err);  
 }   
}


static  OS_TCB   Task2TCB;
static  CPU_STK  Task2Stk[512];

static void Task2_entry(void *p_arg)
{
 OS_ERR  err;
    
 (void)p_arg;
    
 while(1)
 {
        printf("task2 is running...rn");
     OSTimeDly(1000, OS_OPT_TIME_DLY, &err);  
 }   
}


/* USER CODE END PV */

③ 在main函数中定义错误值变量:

  /* USER CODE BEGIN 1 */
    OS_ERR  err;
  /* USER CODE END 1 */

④ 在main函数中初始化内核、创建两个任务、启动内核:

/* USER CODE BEGIN 2 */
printf("uc/OS-III Port On BearPi Board By Mculover666rn");

/* 初始化 uc/OS 内核 */
OSInit(&err); 

/* 创建task1 */
OSTaskCreate((OS_TCB       *)&Task1TCB,         //任务控制块指针           
             (CPU_CHAR     *)"Task 1",          //任务名称
             (OS_TASK_PTR   )Task1_entry,       //任务入口函数
             (void         *)NULL,              //任务入口函数的参数
             (OS_PRIO       )2,                 //任务优先级
             (CPU_STK      *)&Task1Stk[0],      //任务栈地址
             (CPU_STK_SIZE  )512 / 10,          //任务栈监测区大小
             (CPU_STK_SIZE  )512,               //任务栈大小
             (OS_MSG_QTY    )0,                 //任务支持接受的最大消息数
             (OS_TICK       )0,                 //时间片 */
             (void         *)0,                 //堆栈空间大小  
             (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
 /*
 OS_OPT_TASK_STK_CHK      使能检测任务栈,统计任务栈已用的和未用的
 OS_OPT_TASK_STK_CLR      在创建任务时,清零任务栈
 */  
             (OS_ERR       *)&err);

/* 创建task2 */
OSTaskCreate((OS_TCB       *)&Task2TCB,   
             (CPU_CHAR     *)"Task 2",
             (OS_TASK_PTR   )Task2_entry,
             (void         *)0,
             (OS_PRIO       )3,
             (CPU_STK      *)&Task2Stk[0],
             (CPU_STK_SIZE  )512 / 10,
             (CPU_STK_SIZE  )512,
             (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);

(void)&err;

/* USER CODE END 2 */

⑤ 编译,下载,在串口助手中查看输出:

接下来就可以愉快的去玩uc/OS-III内核啦~还可以玩玩全家桶,go go go!