一、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:
代码语言:javascript复制git clone https://github.com/SiliconLabs/uC-OS3.git
② uC-CPU:
代码语言:javascript复制git clone https://github.com/SiliconLabs/uC-CPU.git
③ uC-LIB:
代码语言:javascript复制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 文件,在头文件添加:
代码语言:javascript复制/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "os.h"
/* USER CODE END Includes */
① 处理pendSV异常,如下:
代码语言:javascript复制/**
* @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异常,如下:
代码语言:javascript复制/**
* @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头文件:
代码语言:javascript复制/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "os.h"
/* USER CODE END Includes */
② 定义任务栈、任务控制块、任务入口函数:
代码语言:javascript复制/* 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函数中定义错误值变量:
代码语言:javascript复制 /* USER CODE BEGIN 1 */
OS_ERR err;
/* USER CODE END 1 */
④ 在main函数中初始化内核、创建两个任务、启动内核:
代码语言:javascript复制/* 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!