从 0 到 1!STM32F103C8T6+HAL 库实战 uC/OS-III 移植,多任务控灯 + 串口通信全实现

一、uC/OS-III 简单介绍

uC/OS-III(Micro-Controller Operating System Version III)是 Micrium 公司推出的第三代实时操作系统(RTOS),核心定位是服务嵌入式系统。它主打 “轻量 + 强功能”,专门适配微控制器(MCU)、数字信号处理器(DSP)等硬件资源受限的设备,同时继承了 uC/OS-II 的稳定架构,并在多任务、实时性等关键能力上完成增强与优化。

1、核心特性解析

(1)高可移植性:跨平台适配无压力

uC/OS-III 对主流硬件架构兼容性极强,已支持 ARM、MIPS、PowerPC、AVR 等多种微控制器架构,开发者无需大幅修改代码,即可在不同硬件平台间迁移使用。

(2)多任务管理:灵活调度高并发

  • 基础能力:覆盖任务创建、调度、终止全流程,满足多任务并发需求。
  • 核心调度:采用 优先级抢占式调度算法,能确保高优先级任务优先执行;同时支持动态优先级调整,可根据业务需求灵活修改任务优先级。

(3)时间管理:精准控制时序

提供毫秒级精度的系统时钟管理,支持两种核心定时场景:

  • 单次延时任务:实现任务的精准延时等待。
  • 周期性定时任务:满足周期性执行的业务需求(如数据定时采集)。

(4)内存管理:安全且高效

  • 分配方式:同时支持静态内存分配(适合确定性要求高的场景)和动态内存分配(适合灵活使用内存的场景),并通过内存池机制统一管理内存资源。
  • 安全保障:自带内存保护机制,可有效防止内存泄漏、非法访问等问题,提升系统稳定性。

(5)任务同步与通信:多任务协作无阻碍

内置 4 类核心同步通信组件,覆盖多任务交互的所有常见场景:

  • 信号量(Semaphore):解决任务间的同步问题(如资源占用、步骤协同)。
  • 消息队列(Message Queue):实现多任务间的批量数据传递。
  • 邮件箱(Mailbox):用于单个消息的快速传递,适合轻量数据交互。
  • 事件标志组(Event Flags):支持多任务间的事件通知(如 “等待多个事件触发后执行”)。

(6)高效中断处理:快速响应硬件请求

  • 响应速度:支持高效的中断管理机制,能快速响应硬件中断,减少中断延迟。
  • 优先级关联:允许中断服务例程(ISR)与任务优先级关联,确保中断处理不影响核心任务执行。

(7)可配置性:按需裁剪轻量运行

uC/OS-III 采用模块化设计,所有功能(如内存管理、事件标志组)均可按需开启或关闭。通过裁剪不必要的模块,能将系统代码量和内存占用压缩到极小,完美适配资源受限的嵌入式设备。

(8)强实时性:满足严苛时序要求

核心设计围绕 “实时响应” 展开,任务切换时间、中断延迟均为可预测值,能满足工业控制、医疗设备等对延迟和响应时间要求极高的场景。

(9)调试支持:降低开发难度

提供完善的调试接口,可与 JTAG 等主流调试工具无缝配合,方便开发者定位代码 bug、分析系统性能(如任务执行时间、CPU 占用率),提升开发效率。

2、uC/OS-III 的架构:模块化设计解析

uC/OS-III 采用模块化架构,核心模块分工明确且相互协同,既保证了功能的完整性,也为 “按需裁剪” 提供了基础。整体可拆解为 5 个核心模块,各模块的定位与功能如下:
请添加图片描述

(1)内核(Kernel):系统的 “中枢大脑”

内核是 uC/OS-III 的核心控制模块,承担 “统筹调度” 角色,直接管理其他所有功能模块。其核心职责包括:

  • 统一协调 任务管理、时间管理、内存管理 等模块的运行;
  • 封装同步与通信组件(如信号量、消息队列),为多任务交互提供底层支持;
  • 作为硬件与上层任务的中间层,屏蔽硬件差异,保障系统稳定运行。

(2)任务管理:多任务的 “生命周期管家”

任务管理模块负责对用户任务的全生命周期进行管控,支持复杂的任务操作需求,核心能力包括:

  • 生命周期控制:支持任务的 创建、删除、挂起、恢复 等基础操作,满足任务动态调整需求;
  • 任务行为控制:提供 任务延时、任务通知 功能(如通过任务通知直接向目标任务发送消息,无需额外组件);
  • 与调度器协同:将任务的优先级、状态等信息同步给调度器,为调度决策提供依据。

(3)调度器(Scheduler):任务执行的 “指挥中心”

调度器是实现 “实时性” 的关键模块,负责决定 “哪个任务何时执行”,核心逻辑如下:

  • 调度算法:采用 优先级抢占式调度,系统始终优先执行当前最高优先级的就绪任务;
  • 调度触发时机:任务状态变化(如高优先级任务就绪、当前任务延时)时,自动触发调度;
  • 辅助调度:支持 时间片轮转调度(仅对同优先级任务生效),确保同优先级任务公平占用 CPU 资源。

(4)中断管理:硬件请求的 “快速响应通道”

中断管理模块负责处理硬件中断请求,保障系统对外部事件的快速响应,核心特性包括:

  • 支持 嵌套中断(高优先级中断可打断低优先级中断的执行),提升中断响应效率;
  • 低延迟设计:简化中断处理流程,缩短中断响应时间,确保实时任务不被长期阻塞;
  • 中断与任务协同:允许在中断服务例程(ISR)中触发任务调度,实现 “中断处理后立即执行关联任务”。

(5)内存管理:系统内存的 “高效分配器”

内存管理模块负责统筹系统内存资源,避免内存浪费与非法访问,核心机制包括:

  • 两种分配模式:支持 静态内存分配(编译时确定内存地址,适合确定性要求高的场景)和 动态内存分配(运行时灵活分配,适合内存需求动态变化的场景);
  • 精细化管理:通过 内存池、内存块 机制(将大块内存划分为固定大小的内存块),减少内存碎片;
  • 任务栈管理:为每个任务分配独立的栈空间,并监控栈使用情况,防止栈溢出。

总结

uC/OS-III 是一款为嵌入式场景量身打造的轻量化 RTOS,它既通过高可移植性适配多硬件架构,以优先级抢占调度、低延迟中断处理保障强实时性,又靠模块化设计实现按需裁剪,搭配内存保护、丰富同步通信组件与调试支持,兼顾了资源效率与开发便捷性;其内核统筹、任务管理、调度器、中断管理、内存管理五大模块分工协同的架构,进一步强化了 “轻量可靠、灵活适配” 的核心优势,能很好满足工业控制、汽车电子等领域对实时性与资源占用的双重需求,是嵌入式开发的优质选择。

二、cubemx配置

先建立CubeMx工程
配置RCC

51

配置SYS

52

串口配置USART1

53

然后配置GPIO口
这里我配置了PC13、PA3为output,用来接LED

54

之后设置好路径,导出工程文件

三、移植文件

获取uCOS-III源码

进入 Micrium 公司官网下载中心:http://micrium.com/downloadcenter/
选择ST系列,点击 View all STMicroelectronics,点击 STMicroelectronics STM32F107
之后按照提示注册下载即可。

1、整理文件夹

新建一个uC-BSP文件夹,将uCOS-CONFIG里的bsp.c bsp.h粘贴到uC-BSP文件夹

55

56

然后将以上文件夹粘贴到已建好的工程文件里

57

2、添加文件

之后打开工程,在里面添加文件
根据以下步骤添加

58

MDK-ARM\uC-CPU路径选择全部文件
MDK-ARM\uC-CPU\ARM-Cortex-M3\RealView路径选择全部文件

59

60

MDK-ARM\uC-LIB路径选择全部文件
MDK-ARM\uC-LIB\Ports\ARM-Cortex-M3\RealView路径选择全部文件

61

MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView路径 选择全部路径

67

MDK-ARM\uCOS-III\Source路径下选中以下全部 .c .h 文件
MDK-ARM\uC-CONFIG路径下选中全部文件

68

MDK-ARM\uC-BSP路径下选中全部文件

69

3、导入文件路径

然后导入文件路径

70

71

四、更改代码

1、添加代码

另外添加两个新代码
bsp.h

#ifndef  __BSP_H__
#define  __BSP_H__

#include "stm32f1xx_hal.h"

void BSP_Init(void);

#endif

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

2、更改代码

打开startup_stm32f103xb.s文件
在以下位置处将PendSV_Handler改为OS_CPU_PendSVHandler,
SysTick_Handler改为OS_CPU_SysTickHandler

72

73

打开app_cfg.h文件
DEF_ENABLED 改为 DEF_DISABLED

74

#define APP_TRACE BSP_Ser_Printf 改为 #define APP_TRACE(void)

75

打开includes.h文件
在#include <bsp.h>下面添加 #include “gpio.h” #include “app_cfg.h”
将#include <stm32f10x_lib.h> 改为 #include “stm32f1xx_hal.h”

76

打开lib_cfg.h文件
修改为5(该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点)

77

打开usart.c文件,添加代码完成printf重定向

/* USER CODE BEGIN 1 */

typedef struct __FILE FILE;
int fputc(int ch,FILE *f){
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
	return ch;
}

/* USER CODE END 1 */

在gpio.c文件中修改代码

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);


  /*Configure GPIO pin : PC13|PA3 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

修改main.c文件

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include "stm32f1xx_hal.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 任务优先级 */
#define START_TASK_PRIO		3
#define LED0_TASK_PRIO		4
#define MSG_TASK_PRIO		5
#define LED1_TASK_PRIO		6

/* 任务堆栈大小	*/
#define START_STK_SIZE 		96
#define LED0_STK_SIZE 		64
#define MSG_STK_SIZE 		64
#define LED1_STK_SIZE 		64

/* 任务栈 */	
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
CPU_STK MSG_TASK_STK[MSG_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];

/* 任务控制块 */
OS_TCB StartTaskTCB;
OS_TCB Led0TaskTCB;
OS_TCB MsgTaskTCB;
OS_TCB Led1TaskTCB;

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */

/* 任务函数定义 */
void start_task(void *p_arg);
static  void  AppTaskCreate(void);
static  void  AppObjCreate(void);
static  void  led_pc13(void *p_arg);
static  void  send_msg(void *p_arg);
static  void  led_pa3(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 CPU, AHB and APB busses clocks 
  */
  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 busses 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;
	OSInit(&err);
  HAL_Init();
	SystemClock_Config();
	//MX_GPIO_Init(); 这个在BSP的初始化里也会初始化
  MX_USART1_UART_Init();	
	/* 创建任务 */
	OSTaskCreate((OS_TCB     *)&StartTaskTCB,                /* Create the start task                                */
				 (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  ) 0,
				 (OS_TICK     ) 0,
				 (void       *) 0,
				 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
				 (OS_ERR     *)&err);
	/* 启动多任务系统,控制权交给uC/OS-III */
	OSStart(&err);            /* Start multitasking (i.e. give control to uC/OS-III). */
               
}


void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;
	
	/* YangJie add 2021.05.20*/
  BSP_Init();                                                   /* Initialize BSP functions */
  //CPU_Init();
  //Mem_Init();                                                 /* Initialize Memory Management Module */

#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);  		//统计任务                
#endif
	
#ifdef CPU_CFG_INT_DIS_MEAS_EN			//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif

#if	OS_CFG_SCHED_ROUND_ROBIN_EN  		//当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif		
	
	OS_CRITICAL_ENTER();	//进入临界区
	/* 创建LED0任务 */
	OSTaskCreate((OS_TCB 	* )&Led0TaskTCB,		
				 (CPU_CHAR	* )"led_pc13", 		
                 (OS_TASK_PTR )led_pc13, 			
                 (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  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);		

/* 创建LED1任务 */
	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  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);										 
				 
	/* 创建MSG任务 */
	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  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,				
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, 
                 (OS_ERR 	* )&err);
				 
	OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务			 
	OS_CRITICAL_EXIT();	//进入临界区
}
/**
  * 函数功能: 启动任务函数体。
  * 输入参数: p_arg 是在创建该任务时传递的形参
  * 返 回 值: 无
  * 说    明:无
  */
static  void  led_pc13 (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
		OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
		OSTimeDlyHMSM(0, 0, 1, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

static  void  led_pa3 (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
		OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
		OSTimeDlyHMSM(0, 0, 3, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

static  void  send_msg (void *p_arg)
{
  OS_ERR      err;

  (void)p_arg;

  BSP_Init();                                                 /* Initialize BSP functions                             */
  CPU_Init();

  Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

  CPU_IntDisMeasMaxCurReset();

  AppTaskCreate();                                            /* Create Application Tasks                             */

  AppObjCreate();                                             /* Create Application Objects                           */

  while (DEF_TRUE)
  {
			printf("hello uc/OS \r\n");
		OSTimeDlyHMSM(0, 0, 2, 0,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}


/* USER CODE BEGIN 4 */
/**
  * 函数功能: 创建应用任务
  * 输入参数: p_arg 是在创建该任务时传递的形参
  * 返 回 值: 无
  * 说    明:无
  */
static  void  AppTaskCreate (void)
{
  
}


/**
  * 函数功能: uCOSIII内核对象创建
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
static  void  AppObjCreate (void)
{

}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

设置target

78

然后进行编译烧录

五、实验结果

两个灯,分别以1s和3s周期闪烁

效果

串口以2s周期发送“hello uc/OS!“

串口接收

六、实验心得

这次基于 HAL 库在 STM32F103C8T6 上移植 uC/OS-III,让我对 “理论到实践” 的距离有了真切体会。原本以为照着步骤复制文件、修改配置就能顺利完成,却在 CubeMX 时钟配置和源码路径导入时频频卡壳 —— 比如一开始没注意 HSE 时钟模式要选 “Crystal/Ceramic Resonator”,导致后续系统时钟初始化失败,这才意识到硬件配置与 RTOS 内核的联动远比想象中紧密。

移植过程中的 “小细节” 最磨人,也最让人成长。像是忘记将启动文件里的 SysTick_Handler 改为 OS_CPU_SysTickHandler,系统上电后直接无响应;还有没根据 STM32F103C8T6 的 20K RAM 调整 lib_cfg.h 的堆空间大小,编译时反复出现内存溢出报错。这些 “坑” 让我明白,RTOS 移植不是机械复刻,而是要结合硬件特性灵活调整,每一行代码修改都得对应底层逻辑。

当看到两个 LED 分别以 1 秒、3 秒周期稳定闪烁,串口每隔 2 秒弹出 “hello uc/OS” 时,那种成就感难以言喻。这不仅是功能的实现,更让我直观感受到了 RTOS 的优势 —— 要是用裸机开发,多个周期性任务需要靠定时器中断嵌套来协调,逻辑复杂还容易阻塞;而 uC/OS-III 的多任务调度,让每个任务独立运行又互不干扰,系统实时性和代码可读性都提升了不少。

这次实验也刷新了我对 “嵌入式开发严谨性” 的认知。比如编写 bsp.c 时,BSP_Tick_Init 函数里要根据 uC/OS-III 版本判断时钟节拍参数,少个条件编译就会导致 SysTick 初始化出错;导入文件路径时漏加 uC-LIB 的路径,就会出现一堆头文件找不到的错误。这些看似微小的疏漏,却能让整个移植功亏一篑,也让我养成了 “改代码前先想关联,改完后逐行检查” 的习惯。

这次移植不仅教会了我具体的技术方法,更打开了嵌入式开发的新思路。以前面对多任务场景总局限于裸机思维,现在知道可以借助 RTOS 高效解决问题。未来再遇到工业控制、智能硬件等复杂项目,我会更有底气用 uC/OS-III 这类 RTOS 提升开发效率,而这次 “踩坑又填坑” 的经历,也成了我嵌入式学习路上很宝贵的实践积累。

七、仓库地址

https://gitee.com/zhang-kaikaikaikai/rtos.git

八、参考博客

https://blog.csdn.net/qq_46467126/article/details/121441622
https://blog.csdn.net/junseven164/article/details/121534916
https://blog.csdn.net/weixin_43116606/article/details/105532222
https://blog.csdn.net/qq_45659777/article/details/121570886

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐