STM32F103移植uC/OS-III实时操作系统实战:构建多任务应用前言
在嵌入式系统开发中,实时操作系统(RTOS)能够有效管理多个任务,提供任务调度、同步通信等功能。本文将详细介绍如何将uC/OS-III移植到STM32F103微控制器上,并创建三个周期性任务,分别控制LED闪烁和串口通信。
一、环境准备
1. 硬件准备
-
STM32F103C8T6最小系统板(蓝色pill板)
-
LED灯 x2
-
USB-TTL串口模块(CH340/CP2102等)
-
杜邦线若干

2. 软件准备
-
STM32CubeMX v6.x
-
Keil MDK-ARM v5.x
-
uC/OS-III源码(可从Micrium官网获取)
二、STM32CubeMX工程配置
1. 创建新工程
打开STM32CubeMX,选择STM32F103C8T6芯片:

2. 系统配置
在"Pinout & Configuration"标签页中进行以下配置:
SYS设置:
-
Debug: Serial Wire(用于ST-Link调试)

RCC设置:
-
High Speed Clock (HSE): Crystal/Ceramic Resonator

3. 时钟配置
进入Clock Configuration标签页,配置系统时钟为72MHz:

配置步骤:
-
选择HSE作为时钟源
-
设置PLL倍频为9倍
-
系统时钟设置为72MHz
-
APB1总线时钟为36MHz
-
APB2总线时钟为72MHz
4. GPIO配置
LED1:
-
选择PC13引脚
-
模式: GPIO_Output
-
标签: LED1
LED2:
-
选择PA0引脚
-
模式: GPIO_Output
-
标签: LED2

5. 串口配置
USART1:
-
模式: Asynchronous
-
波特率: 115200
-
数据位: 8
-
停止位: 1
-
校验位: None
6. 添加uC/OS-III
在"Middleware"部分选择μC/OS-III:
-
Version: 3.07.03
-
模板: 默认配置
7. 生成代码
点击"Generate Code"生成工程代码,选择MDK-ARM作为工具链。
三、uC/OS-III配置与移植
1. 修改os_cfg.h配置文件
在Core/uC-OS-III/inc/os_cfg.h中修改关键配置:
/* 系统配置 */ #define OS_CFG_TICK_RATE_HZ 1000u /* 系统时钟频率1kHz */ #define OS_CFG_PRIO_MAX 64u /* 最大优先级数量 */ #define OS_CFG_SCHED_ROUND_ROBIN_EN 1u /* 启用时间片轮转调度 */ /* 任务配置 */ #define OS_CFG_TASK_EN 1u /* 启用任务功能 */ #define OS_CFG_TASK_STK_REDZONE_EN 0u /* 禁用堆栈警戒区 */ /* 时间管理配置 */ #define OS_CFG_TIME_DLY_HMSM_EN 1u /* 启用时分秒毫秒延时 */
2. 修改app.c应用程序文件
在Core/Src/app.c中添加我们的任务代码:
#include "main.h" #include "stdio.h" /* 外部引用 */ extern UART_HandleTypeDef huart1; /* 定义任务堆栈大小 */ #define TASK_STK_SIZE 128 /* 任务堆栈定义 */ static CPU_STK AppTaskStartStk[TASK_STK_SIZE]; static CPU_STK Task1Stk[TASK_STK_SIZE]; static CPU_STK Task2Stk[TASK_STK_SIZE]; static CPU_STK Task3Stk[TASK_STK_SIZE]; /* 任务控制块定义 */ static OS_TCB AppTaskStartTCB; static OS_TCB Task1TCB; static OS_TCB Task2TCB; static OS_TCB Task3TCB; /* 函数声明 */ static void AppTaskStart(void *p_arg); static void Task1(void *p_arg); static void Task2(void *p_arg); static void Task3(void *p_arg); void BSP_Init(void);
四、任务实现
1. 启动任务实现
启动任务负责硬件初始化和创建其他任务:
c void AppTaskStart(void *p_arg) { OS_ERR err; (void)p_arg; /* 初始化板级支持包 */ BSP_Init(); /* 创建任务1 - 1秒周期LED闪烁 */ OSTaskCreate(&Task1TCB, "Task 1", Task1, (void *)0, 2, /* 优先级2 */ &Task1Stk[0], TASK_STK_SIZE/10, /* 堆栈水线限制 */ TASK_STK_SIZE, /* 堆栈大小 */ 0, 0, (void *)0, OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err); /* 检查任务创建是否成功 */ if (err != OS_ERR_NONE) { /* 处理错误 */ while(1); } /* 创建任务2 - 3秒周期LED闪烁 */ OSTaskCreate(&Task2TCB, "Task 2", Task2, (void *)0, 3, /* 优先级3 */ &Task2Stk[0], TASK_STK_SIZE/10, TASK_STK_SIZE, 0, 0, (void *)0, OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err); /* 创建任务3 - 2秒周期串口发送 */ OSTaskCreate(&Task3TCB, "Task 3", Task3, (void *)0, 4, /* 优先级4 */ &Task3Stk[0], TASK_STK_SIZE/10, TASK_STK_SIZE, 0, 0, (void *)0, OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err); /* 启动任务创建完成,删除自身 */ OSTaskDel(&AppTaskStartTCB, &err); }
2. 任务1 - 1秒LED闪烁
/* 任务1:1秒周期控制LED1闪烁 */
static void Task1(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while(1) {
/* 翻转LED1状态 */
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
/* 延时1秒 */
OSTimeDlyHMSM(0, 0, 1, 0,
OS_OPT_TIME_HMSM_STRICT,
&err);
}
}
3. 任务2 - 3秒LED闪烁
/* 任务2:3秒周期控制LED2闪烁 */
static void Task2(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while(1) {
/* 翻转LED2状态 */
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
/* 延时3秒 */
OSTimeDlyHMSM(0, 0, 3, 0,
OS_OPT_TIME_HMSM_STRICT,
&err);
}
}
4. 任务3 - 2秒串口通信
/* 任务3:2秒周期通过串口发送消息 */
static void Task3(void *p_arg)
{
OS_ERR err;
char tx_buf[64];
uint16_t len;
(void)p_arg;
while(1) {
/* 格式化要发送的字符串 */
len = sprintf(tx_buf, "hello uc/OS! 欢迎来到RTOS多任务环境!\r\n");
/* 通过串口发送数据 */
HAL_UART_Transmit(&huart1,
(uint8_t*)tx_buf,
len,
1000); /* 超时时间1秒 */
/* 延时2秒 */
OSTimeDlyHMSM(0, 0, 2, 0,
OS_OPT_TIME_HMSM_STRICT,
&err);
}
}
5. 硬件初始化函数
/* 板级支持包初始化 */
void BSP_Init(void)
{
/* 初始化LED为关闭状态 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); /* LED1 off */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); /* LED2 off */
/* 可以在这里添加其他外设初始化代码 */
/* 例如:ADC、SPI、I2C等 */
}

6. 修改main函数
int main(void)
{
OS_ERR err;
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 初始化uC/OS-III内核 */
OSInit(&err);
if (err != OS_ERR_NONE) {
/* 内核初始化失败,进入死循环 */
while(1);
}
/* 创建启动任务 */
OSTaskCreate(&AppTaskStartTCB, /* 任务控制块 */
"App Task Start", /* 任务名称 */
AppTaskStart, /* 任务函数 */
(void *)0, /* 传递给任务的参数 */
1, /* 优先级1(最高) */
&AppTaskStartStk[0], /* 堆栈基地址 */
TASK_STK_SIZE/10, /* 堆栈水线限制 */
TASK_STK_SIZE, /* 堆栈大小 */
0,
0,
(void *)0,
OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR,
&err);
/* 启动多任务调度 */
OSStart(&err);
/* 正常情况下不会执行到这里 */
while(1);
}

五、编译与调试
1. 工程配置检查
在Keil中打开工程后,需要检查以下配置:
目标选项 → Target:
-
芯片: STM32F103C8
-
时钟: 72MHz

目标选项 → Output:
-
勾选"Create HEX File"

目标选项 → C/C++:
-
预定义宏:
USE_HAL_DRIVER,STM32F103xB

2. 编译工程
点击"Build"按钮编译整个工程,确保没有错误和警告。
3. 下载程序
使用ST-Link调试器将程序下载到STM32F103开发板。
六、实验结果
1. LED闪烁观察
程序运行后,可以观察到:
-
LED1(PC13):每1秒闪烁一次
-
LED2(PA0):每3秒闪烁一次
[图片7:LED闪烁效果图]
2. 串口输出验证
使用串口助手(如Putty、SecureCRT等)连接开发板:
-
波特率: 115200
-
数据位: 8
-
停止位: 1
-
校验位: None
每2秒会收到消息:"hello uc/OS! 欢迎来到RTOS多任务环境!"
七、常见问题与解决方案
1. 编译错误
问题:找不到uC/OS-III头文件
解决:检查头文件路径是否包含正确,在Keil的"C/C++"选项中添加uC/OS-III的include路径。
2. 系统无法启动
问题:程序卡在启动任务
解决:检查系统时钟配置,确保SysTick中断正常工作。
3. 任务调度异常
问题:某些任务无法执行
解决:
-
检查任务优先级设置
-
确认堆栈大小足够
-
查看是否有任务占用CPU时间过长
4. 串口无输出
问题:串口接收不到数据
解决:
-
检查串口线连接
-
确认波特率设置正确
-
验证USART引脚配置
八、总结
通过本次实践,我们成功完成了:
-
uC/OS-III移植:将实时操作系统移植到STM32F103平台
-
多任务创建:构建了三个具有不同周期的任务
-
外设控制:实现了GPIO控制和串口通信
-
系统调试:验证了多任务调度功能
这个项目展示了RTOS在嵌入式系统中的核心优势:
-
多任务并发:多个任务独立运行,互不干扰
-
精确时序:任务能够按照精确的时间周期执行
-
资源管理:系统有效管理CPU时间和外设资源
更多推荐


所有评论(0)