uC/OS-III在STM32F103上的移植与实践:构建多任务LED控制系统
分别将PendSV_Handler和Systick_Handler改为OS_CPU_PendSVHandler和OS_CPU_SysTickHandler。通过本次实践,我们成功验证了uC/OS-III在STM32平台上的稳定性和实用性,为更复杂的嵌入式应用开发奠定了坚实基础。本文将详细介绍如何将uC/OS-III移植到STM32F103C8T6微控制器,并构建一个包含三个任务的多任务系统。该处宏
uC/OS-III在STM32F103上的移植与实践:构建多任务LED控制系统
引言
在嵌入式系统开发中,实时操作系统(RTOS)扮演着至关重要的角色。uC/OS-III作为一款成熟可靠的实时内核,具有以下显著优势:
硬实时性能:确保关键任务在指定时间内完成
可抢占式调度:高优先级任务可立即获得CPU控制权
资源管理:提供信号量、消息队列等机制避免资源冲突
可移植性:高度模块化设计,便于移植到不同硬件平台
商业认证:已通过多种安全认证,适合工业级应用
本文将详细介绍如何将uC/OS-III移植到STM32F103C8T6微控制器,并构建一个包含三个任务的多任务系统。
一、开发环境准备
1.1 硬件要求
STM32F103C8T6最小系统板
USB转TTL串口模块
LED灯 x 2(PA6和PA3)
杜邦线若干
1.2 软件工具
STM32CubeMX
Keil MDK-ARM
uC/OS-III源码
串口调试助手(SSCOM)
二、STM32CubeMX工程配置
2.1 创建新工程
- 打开STM32CubeMX,选择STM32F103C8T6
- 配置系统核心:
SYS: Debug → Serial Wire
RCC: HSE → Crystal/Ceramic Resonator
- 时钟配置
HSE: 8MHz
PLL Source: HSE
PLL Mul: ×9
System Clock: 72MHz
AHB Prescaler: /1
APB1 Prescaler: /2
APB2 Prescaler: /1
- GPIO配置
PA6: GPIO_Output → LED1(1秒周期)
PA3: GPIO_Output → LED2(3秒周期)
推挽输出模式,初始电平高
- 串口配置
USART1: Asynchronous Mode
Baud Rate: 115200
Word Length: 8 Bits
Parity: None
Stop Bits: 1
- 工程配置


三、uC/OS-III源码移植
3.1 uC/OS-III源码
链接:https://pan.baidu.com/s/1bg7K34vgNuw2AR8qmb81hQ
提取码:1234
3.2 添加uC/OS-III文件
打开刚刚下载的源码文件
将以下文件复制
粘贴到工程文件中MDK-ARM下
3.3 修改工程结构
在Keil中添加文件组:
在每个分组下添加对应的文件
①CPU


②LIB


③PORT

④SOURCE

⑤CONFIG

⑥BSP

接下来导入头文件路径

四、代码修改与添加
4.1 代码修改
①打开启动文件
分别将PendSV_Handler和Systick_Handler改为OS_CPU_PendSVHandler和OS_CPU_SysTickHandler

②app_cfg.h
第一处修改:
修改前
#define APP_CFG_SERIAL_EN DEF_ENABLED
修改后
#define APP_CFG_SERIAL_EN DEF_DISABLED
第二处修改:
修改前
#define APP_TRACE BSP_Ser_Printf
修改后
#define APP_TRACE (void)
③ includes.h
第一处修改: 添加相关头文件
修改前
#include <bsp.h>
修改后
#include <bsp.h>
#include “gpio.h”
#include “app_cfg.h”
第二处修改: 添加HAL 库
修改前
#include <stm32f10x_lib.h>
修改后
#include “stm32f1xx_hal.h”
④lib_cfg.h
该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点,这里改为了5。
4.2 代码添加
①bsp.c
// bsp.c
#include "includes.h"
#define DWT_CR *(CPU_REG32 *)0xE0001000
#define DWT_CYCCNT *(CPU_REG32 *)0xE0001004
#define DEM_CR *(CPU_REG32 *)0xE000EDFC
#define DBGMCU_CR *(CPU_REG32 *)0xE0042004
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
CPU_INT32U BSP_CPU_ClkFreq (void)
{
return HAL_RCC_GetHCLKFreq();
}
void BSP_Tick_Init(void)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
cpu_clk_freq = BSP_CPU_ClkFreq();
#if(OS_VERSION>=3000u)
cnts = cpu_clk_freq/(CPU_INT32U)OSCfg_TickRate_Hz;
#else
cnts = cpu_clk_freq/(CPU_INT32U)OS_TICKS_PER_SEC;
#endif
OS_CPU_SysTickInit(cnts);
}
void BSP_Init(void)
{
BSP_Tick_Init();
MX_GPIO_Init();
}
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void CPU_TS_TmrInit (void)
{
CPU_INT32U cpu_clk_freq_hz;
DEM_CR |= (CPU_INT32U)DEM_CR_TRCENA; /* Enable Cortex-M3's DWT CYCCNT reg. */
DWT_CYCCNT = (CPU_INT32U)0u;
DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA;
cpu_clk_freq_hz = BSP_CPU_ClkFreq();
CPU_TS_TmrFreqSet(cpu_clk_freq_hz);
}
#endif
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
CPU_TS_TMR CPU_TS_TmrRd (void)
{
return ((CPU_TS_TMR)DWT_CYCCNT);
}
#endif
#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = BSP_CPU_ClkFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = BSP_CPU_ClkFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
②bsp.h
// bsp.h
#ifndef __BSP_H__
#define __BSP_H__
#include "stm32f1xx_hal.h"
void BSP_Init(void);
#endif
五、多任务代码实现
5.1 主函数(main.c)
其中两个task分别以1s和3s周期对LED等进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。
#include "main.h"
#include "gpio.h"
#include "usart.h"
#include <includes.h>
#include <stdio.h>
/* 任务优先级定义 */
#define START_TASK_PRIO 3
#define LED1_TASK_PRIO 4
#define MSG_TASK_PRIO 5
#define LED2_TASK_PRIO 6
/* 任务堆栈定义 */
CPU_STK START_TASK_STK[256];
CPU_STK LED1_TASK_STK[128];
CPU_STK LED2_TASK_STK[128];
CPU_STK MSG_TASK_STK[128];
/* 任务控制块 */
OS_TCB StartTaskTCB, Led1TaskTCB, Led2TaskTCB, MsgTaskTCB;
int main(void)
{
OS_ERR err;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 初始化LED状态 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
OSInit(&err);
/* 创建启动任务 */
OSTaskCreate(&StartTaskTCB, "start task", start_task, 0,
START_TASK_PRIO, START_TASK_STK, 256/10, 256,
5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
OSStart(&err);
}
5.2 启动任务
void start_task(void *p_arg)
{
OS_ERR err;
(void)p_arg;
/* 创建LED1任务 - PA6, 1秒周期 */
OSTaskCreate(&Led1TaskTCB, "led_pa6", led_pa6, 0,
LED1_TASK_PRIO, LED1_TASK_STK, 128/10, 128,
5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
/* 创建LED2任务 - PA3, 3秒周期 */
OSTaskCreate(&Led2TaskTCB, "led_pa3", led_pa3, 0,
LED2_TASK_PRIO, LED2_TASK_STK, 128/10, 128,
5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
/* 创建消息任务 - 2秒周期 */
OSTaskCreate(&MsgTaskTCB, "send_msg", send_msg, 0,
MSG_TASK_PRIO, MSG_TASK_STK, 128/10, 128,
5, 0, 0, OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, &err);
OSTaskDel((OS_TCB*)0, &err);
}
5.3 LED控制任务
/* PA6 LED任务 - 1秒周期 */
static void led_pa6(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 亮
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // 灭
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/* PA3 LED任务 - 3秒周期 */
static void led_pa3(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); // 亮
OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); // 灭
OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
5.4 串口消息任务
/* 串口输出重定向 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
/* 消息发送任务 - 2秒周期 */
static void send_msg(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE) {
printf("hello uc/OS! 欢迎来到RTOS多任务环境!\r\n");
OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
5.5 完整代码
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include <stdio.h>
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 任务优先级 */
#define START_TASK_PRIO 3
#define LED0_TASK_PRIO 4
#define LED1_TASK_PRIO 5
#define MSG_TASK_PRIO 6
/* 任务堆栈大小 */
#define START_STK_SIZE 256
#define LED0_STK_SIZE 128
#define LED1_STK_SIZE 128
#define MSG_STK_SIZE 128
/* 任务栈 */
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
CPU_STK MSG_TASK_STK[MSG_STK_SIZE];
/* 任务控制块 */
OS_TCB StartTaskTCB;
OS_TCB Led0TaskTCB;
OS_TCB Led1TaskTCB;
OS_TCB MsgTaskTCB;
/* USER CODE END PD */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 重定向printf到串口 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
/* 任务函数定义 */
void start_task(void *p_arg);
static void led_pa6(void *p_arg);
static void led_pa3(void *p_arg);
static void send_msg(void *p_arg);
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
OS_ERR err;
HAL_Init();
SystemClock_Config();
/* 初始化外设 */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 初始化LED为默认状态(灭) */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // PA6灭
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); // PA3灭
/* 初始化uC/OS-III */
OSInit(&err);
if (err != OS_ERR_NONE) {
Error_Handler();
}
/* 创建启动任务 */
OSTaskCreate((OS_TCB *)&StartTaskTCB,
(CPU_CHAR *)"start task",
(OS_TASK_PTR )start_task,
(void *)0,
(OS_PRIO )START_TASK_PRIO,
(CPU_STK *)&START_TASK_STK[0],
(CPU_STK_SIZE)START_STK_SIZE/10,
(CPU_STK_SIZE)START_STK_SIZE,
(OS_MSG_QTY )5,
(OS_TICK )0,
(void *)0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
if (err != OS_ERR_NONE) {
Error_Handler();
}
/* 启动多任务系统 */
OSStart(&err);
}
/**
* @brief 启动任务
*/
void start_task(void *p_arg)
{
OS_ERR err;
(void)p_arg;
/* 创建LED0任务 - PA6, 1s周期 */
OSTaskCreate((OS_TCB *)&Led0TaskTCB,
(CPU_CHAR *)"led_pa6",
(OS_TASK_PTR)led_pa6,
(void *)0,
(OS_PRIO)LED0_TASK_PRIO,
(CPU_STK *)&LED0_TASK_STK[0],
(CPU_STK_SIZE)LED0_STK_SIZE/10,
(CPU_STK_SIZE)LED0_STK_SIZE,
(OS_MSG_QTY)5,
(OS_TICK)0,
(void *)0,
(OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR *)&err);
/* 创建LED1任务 - PA3, 3s周期 */
OSTaskCreate((OS_TCB *)&Led1TaskTCB,
(CPU_CHAR *)"led_pa3",
(OS_TASK_PTR)led_pa3,
(void *)0,
(OS_PRIO)LED1_TASK_PRIO,
(CPU_STK *)&LED1_TASK_STK[0],
(CPU_STK_SIZE)LED1_STK_SIZE/10,
(CPU_STK_SIZE)LED1_STK_SIZE,
(OS_MSG_QTY)5,
(OS_TICK)0,
(void *)0,
(OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR *)&err);
/* 创建消息发送任务 - 2s周期 */
OSTaskCreate((OS_TCB *)&MsgTaskTCB,
(CPU_CHAR *)"send_msg",
(OS_TASK_PTR)send_msg,
(void *)0,
(OS_PRIO)MSG_TASK_PRIO,
(CPU_STK *)&MSG_TASK_STK[0],
(CPU_STK_SIZE)MSG_STK_SIZE/10,
(CPU_STK_SIZE)MSG_STK_SIZE,
(OS_MSG_QTY)5,
(OS_TICK)0,
(void *)0,
(OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR *)&err);
/* 删除启动任务 */
OSTaskDel((OS_TCB *)0, &err);
}
/**
* @brief LED PA6任务 - 1s周期闪烁 (亮0.5s + 灭0.5s)
*/
static void led_pa6(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
/* LED亮 - 0.5秒 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
/* LED灭 - 0.5秒 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/**
* @brief LED PA3任务 - 3s周期闪烁 (亮1.5s + 灭1.5s)
*/
static void led_pa3(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
/* LED亮 - 1.5秒 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
/* LED灭 - 1.5秒 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
OSTimeDlyHMSM(0, 0, 1, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/**
* @brief 消息发送任务 - 2s周期发送消息
*/
static void send_msg(void *p_arg)
{
OS_ERR err;
(void)p_arg;
while (DEF_TRUE)
{
printf("hello uc/OS!欢迎来到RTOS多任务环境!\r\n");
OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/* USER CODE BEGIN 4 */
// 这里可以添加其他应用代码
/* USER CODE END 4 */
/**
* @brief 错误处理函数
*/
void Error_Handler(void)
{
/* 错误指示:使用PA6快速闪烁 */
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
HAL_Delay(100);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %ld\r\n", file, line);
}
#endif
六、实验结果与分析
- 实验现象
PA6 LED:以精确的1秒周期闪烁(亮0.5s + 灭0.5s)
PA3 LED:以精确的3秒周期闪烁(亮1.5s + 灭1.5s)
串口输出:每2秒接收到"hello uc/OS! 欢迎来到RTOS多任务环境!" - 系统性能分析
通过uC/OS-III的内置统计功能,可以观察到:
CPU利用率稳定在5%以下
各任务按时序精确执行
无任务阻塞或优先级反转现象 - 实验视频展示
uCOS
视频内容展示:
两个LED不同频率的同步闪烁
串口调试助手实时显示消息
系统稳定运行状态
本视频中用到了野火的串口调试助手
因为sscom显示我的中文是乱码,但是sscom可以看到接收信息时间及间隔
这里放图:
七、应用拓展建议
基于此基础框架,可进一步实现:
① 添加传感器数据采集任务
② 实现任务间通信(消息队列)
③ 加入看门狗任务提高系统可靠性
④ 移植文件系统实现数据存储
通过本次实践,我们成功验证了uC/OS-III在STM32平台上的稳定性和实用性,为更复杂的嵌入式应用开发奠定了坚实基础。
本次的分享就到这里啦!
参考:
超详细教程:
https://blog.csdn.net/weixin_43116606/article/details/105532222
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)