STM32F103C8T6移植uCOS-III及多任务实现
STM32F103C8T6移植uC/OS-III及多任务实现
一、前期准备
1.1 硬件与软件环境
| 类别 | 具体说明 |
|---|---|
| 硬件 | STM32F103C8T6最小系统板、USB转TTL模块、LED灯(1个)、杜邦线 |
| 软件 | STM32CubeMX 、Keil MDK-ARM V5、CH340驱动、串口调试助手 |
| 源码资源 | uC/OS-III源码(官网链接:http://micrium.com/downloadcenter/) |
二、使用STM32CubeMX创建HAL库工程
2.1 新建工程并选择芯片
- 打开STM32CubeMX,点击 “File” -> “New Project”,在MCU选择器中搜索 “STM32F103C8T6”,双击选中芯片。
2.2 配置时钟(RCC)
-
选择 “System Core” -> “RCC”:
High Speed Clock (HSE):选择 “Crystal/Ceramic Resonator”(外部晶振模式)
Low Speed Clock (LSE):保持默认 “Crystal/Ceramic Resonato”

-
配置时钟树:
- 点击顶部 “Clock Configuration”,进入时钟树配置界面
- HSE输入频率设为 8MHz(外部晶振常用值)
- PLL倍频系数选择 “PLLMUL = x9”,使SYSCLK(系统时钟)= 8MHz * 9 = 72MHz
- 确认各总线时钟:HCLK=72MHz、PCLK1=36MHz、PCLK2=72MHz

2.3 配置系统核心(SYS)
- 在左侧菜单栏选择 “System Core” -> “SYS”:
- Debug:选择 “Serial Wire”(SWD调试模式,占用PA13/PA14引脚)
- Timebase Source:选择 “SysTick”(系统滴答定时器,后续uC/OS-III会复用)

2.4 配置GPIO(LED引脚)
需配置2个LED引脚,分别对应1s和3s周期任务:
-
选择 “System Core” -> “GPIO”:
-
LED1(1s周期):选择引脚 PC13和PA3(STM32F103C8T6默认板载LED引脚和外接引脚),配置为 “GPIO_Output”
- GPIO输出电平:默认 “High”(LED初始熄灭,低电平点亮)
- 上下拉:“No pull-up and no pull-down”
- 输出速度:“Low”

-
2.5 配置串口(USART1)
用于串口发送任务(2s周期发送字符串):
-
选择 “Connectivity” -> “USART1”:
- Mode:选择 “Asynchronous”(异步模式)
- Hardware Flow Control:选择 “Disable”(禁用硬件流控)
- 点击右侧引脚分配,确认USART1_TX对应PA9,USART1_RX对应PA10
-
配置串口参数(在"Parameter Settings"中):
- Baud Rate:115200 Bits/s
- Word Length:8 Bits
- Parity:None
- Stop Bits:1 Bit

一定要勾!!!

2.6 生成Keil工程
- 点击顶部 “Project Manager”,配置工程信息:
- Project Name:输入工程名(如
uCOS-III_LED_USART) - Project Location:选择工程保存路径(建议英文路径)
- Toolchain/IDE:选择 “MDK-ARM”,版本选择 “V5”
- Project Name:输入工程名(如
- 点击左侧 “Code Generator”,勾选:
- “Copy only the necessary library files”(仅复制必要的库文件)
- “Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”(按外设生成独立的初始化文件)
- “Keep User Code when re-generating”(重新生成代码时保留用户代码)
- 点击 “GENERATE CODE”,生成Keil工程,生成完成后点击 “Open Project” 直接打开Keil MDK。


三、移植uC/OS-III到Keil工程
2.2 源码文件整理
-
百度网盘下载后得到

3.1 复制uC/OS-III源码到工程目录
打开Keil工程所在文件夹,进入MDK-ARM子目录,将准备的3个源码文件夹(uC-CPU、uC-LIB、uCOS-III)复制到此处。

3.2 在Keil中添加工程分组与文件
-
打开Keil工程,点击左侧 “Manage Project Items”(小箱子图标),在弹出窗口中新建4个分组:
-
BSP:板级支持包文件 -
CPU:uC-CPU相关文件 -
LIB:uC-LIB库文件 -
PORT:uC/OS-III CPU适配文件
-
-
向各分组添加对应文件:
分组 文件路径与选择的文件 BSP uC-BSP文件夹下的bsp.c和bsp.hCPU 1. uC-CPU:选择cpu_core.c、cpu_core.h、cpu_def.h
2.uC-CPU\ARM-Cortex-M3\RealView:选择cpu.h、cpu_a.asm、cpu_c.cLIB 1. uC-LIB:选择lib_ascii.c、lib_ascii.h、lib_def.h、lib_math.c、lib_math.h、lib_mem.c、lib_mem.h、lib_str.c、lib_str.h
2.uC-LIB\Ports\ARM-Cortex-M3\RealView:选择lib_mem_a.asmPORT uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView:选择os_cpu.h、os_cpu_a.s、os_cpu_c.c



3.3 添加头文件路径
-
点击Keil工具栏 “Options for Target”(魔术棒图标),选择 “C/C++” 选项卡:
-
点击 “Include Paths” 右侧的
...按钮,添加以下头文件路径(需根据实际工程路径调整):./uC-BSP ./uC-CPU ./uC-CPU/ARM-Cortex-M3/RealView ./uC-LIB ./uC-LIB/Ports/ARM-Cortex-M3/RealView ./uCOS-III/Ports/ARM-Cortex-M3/Generic/RealView ./Core/Inc ./Drivers/STM32F1xx_HAL_Driver/Inc ./Drivers/STM32F1xx_HAL_Driver/Inc/Legacy ./Drivers/CMSIS/Device/ST/STM32F1xx/Include ./Drivers/CMSIS/Include
四、修改关键文件代码
4.1 修改启动文件(startup_stm32f103xb.s)
uC/OS-III需替换默认的PendSV和SysTick中断服务函数:
- 在Keil工程中找到
Application/MDK-ARM分组下的startup_stm32f103xb.s,双击打开。 - 搜索并修改以下两处(约74-75行):
- 将
PendSV_Handler改为OS_CPU_PendSVHandler - 将
SysTick_Handler改为OS_CPU_SysTickHandler
; 原代码 DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; 修改后代码 DCD OS_CPU_PendSVHandler ; PendSV Handler(uC/OS-III任务切换用) DCD OS_CPU_SysTickHandler ; SysTick Handler(uC/OS-III节拍用) - 将

4.2 编写板级支持包(bsp.c和bsp.h)
4.2.1 bsp.h代码
#ifndef __BSP_H__
#define __BSP_H__
#include "stm32f1xx_hal.h"
// 函数声明
void BSP_Init(void); // 板级初始化总函数
CPU_INT32U BSP_CPU_ClkFreq(void); // 获取CPU时钟频率
void BSP_Tick_Init(void); // 滴答定时器初始化(供uC/OS-III用)
#endif

4.2.2 bsp.c代码
#include "includes.h"
// DWT寄存器定义(用于时间戳,可选)
#define DWT_CR *(CPU_REG32 *)0xE0001000
#define DWT_CYCCNT *(CPU_REG32 *)0xE0001004
#define DEM_CR *(CPU_REG32 *)0xE000EDFC
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
// 获取CPU时钟频率(HCLK)
CPU_INT32U BSP_CPU_ClkFreq(void)
{
return HAL_RCC_GetHCLKFreq();
}
// 初始化SysTick(供uC/OS-III作为时间节拍)
void BSP_Tick_Init(void)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
cpu_clk_freq = BSP_CPU_ClkFreq(); // 获取HCLK频率(72MHz)
// 计算SysTick重载值:uC/OS-III默认节拍为1ms(1000Hz)
#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); // 调用uC/OS-III的SysTick初始化函数
}
// 板级初始化总函数(初始化GPIO、SysTick等)
void BSP_Init(void)
{
BSP_Tick_Init(); // 初始化uC/OS-III节拍
MX_GPIO_Init(); // 初始化GPIO(CubeMX生成的函数)
}
// 以下为时间戳相关函数(可选,用于调试)
#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; // 使能DWT
DWT_CYCCNT = (CPU_INT32U)0u;
DWT_CR |= (CPU_INT32U)DWT_CR_CYCCNTENA; // 使能CYCCNT计数器
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
4.3 修改配置文件
4.3.1 app_cfg.h(应用配置)
- 打开
uC-CONFIG下的app_cfg.h,修改以下两处:- 禁用串口调试(避免未定义函数报错):
// 原代码 #define APP_CFG_SERIAL_EN DEF_ENABLED // 修改后 #define APP_CFG_SERIAL_EN DEF_DISABLED - 禁用APP_TRACE(避免依赖未实现的打印函数):
// 原代码 #define APP_TRACE BSP_Ser_Printf // 修改后 #define APP_TRACE (void)
- 禁用串口调试(避免未定义函数报错):
4.3.2 includes.h(头文件汇总)
- 打开
uC-CONFIG下的includes.h,修改两处:- 添加GPIO和app_cfg头文件:
#include <bsp.h> #include "gpio.h" // 新增:GPIO初始化相关 #include "app_cfg.h" // 新增:应用配置 - 替换旧库头文件为HAL库头文件:
// 原代码 #include <stm32f10x_lib.h> // 修改后 #include "stm32f1xx_hal.h"
- 添加GPIO和app_cfg头文件:
4.3.3 lib_cfg.h(内存配置)
- 打开
uC-CONFIG下的lib_cfg.h,修改堆内存大小(STM32F103C8T6总RAM为20KB,需减小堆大小避免溢出):// 原代码 #define LIB_MEM_CFG_HEAP_SIZE 27u * 1024u // 27KB(过大) // 修改后 #define LIB_MEM_CFG_HEAP_SIZE 5u * 1024u // 5KB(适配20KB RAM)
4.4 串口重定向(支持printf函数)
在Drivers/STM32F1xx_HAL_Driver/Src下的usart.c中,添加fputc函数重定向:
/* USER CODE BEGIN 1 */
#include <stdio.h> // 需包含stdio.h头文件
// 重定向fputc到USART1,使printf能通过串口发送
typedef struct __FILE FILE;
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); // 阻塞发送1字节
return ch;
}
/* USER CODE END 1 */
五、编写uC/OS-III多任务代码(main.c)
5.1 定义任务相关宏和变量
在main.c的/* USER CODE BEGIN PD */和/* USER CODE BEGIN PV */区域添加任务优先级、堆栈大小、任务栈和任务控制块:
/* USER CODE BEGIN PD */
/* 任务优先级:数字越小优先级越低,start任务优先级最低(3),LED1任务最高(6) */
#define START_TASK_PRIO 3
#define LED1_TASK_PRIO 4 // 1s周期LED任务
#define USART_TASK_PRIO 5 // 2s周期串口任务
#define LED2_TASK_PRIO 6 // 3s周期LED任务
/* 任务堆栈大小:根据任务复杂度调整,start任务需创建其他任务,堆栈稍大 */
#define START_STK_SIZE 96
#define LED1_STK_SIZE 64
#define USART_STK_SIZE 64
#define LED2_STK_SIZE 64
/* 任务栈:CPU_STK为uC/OS-III定义的堆栈类型 */
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
CPU_STK USART_TASK_STK[USART_STK_SIZE];
CPU_STK LED2_TASK_STK[LED2_STK_SIZE];
/* 任务控制块(TCB):uC/OS-III用于管理任务的数据结构 */
OS_TCB StartTaskTCB;
OS_TCB Led1TaskTCB;
OS_TCB UsartTaskTCB;
OS_TCB Led2TaskTCB;
/* USER CODE END PD */
/* USER CODE BEGIN PV */
/* 任务函数声明 */
void start_task(void *p_arg); // 启动任务(创建其他任务)
static void led1_task(void *p_arg); // 1s周期LED任务(PC13)
static void usart_task(void *p_arg); // 2s周期串口任务
static void led2_task(void *p_arg); // 3s周期LED任务(PA3)
/* USER CODE END PV */
5.2 重写main函数
替换main.c中的默认main函数,初始化uC/OS-III并创建启动任务:
int main(void)
{
OS_ERR err; // uC/OS-III函数返回的错误码
// 1. 初始化uC/OS-III内核
OSInit(&err);
if(err != OS_ERR_NONE)
{
while(1); // 内核初始化失败,死循环
}
// 2. 初始化HAL库(CubeMX生成的函数)
HAL_Init();
// 3. 配置系统时钟(CubeMX生成的函数)
SystemClock_Config();
// 4. 初始化USART1(CubeMX生成的函数,GPIO在BSP_Init中初始化)
MX_USART1_UART_Init();
// 5. 创建启动任务(start_task):所有用户任务由启动任务创建
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, // 任务栈警戒区大小(1/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); // 错误码输出
if(err != OS_ERR_NONE)
{
while(1); // 任务创建失败,死循环
}
// 6. 启动uC/OS-III多任务调度(从此处开始,内核接管CPU)
OSStart(&err);
if(err != OS_ERR_NONE)
{
while(1);
}
// 以下代码永远不会执行
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
5.3 编写启动任务(start_task)
启动任务负责初始化BSP、创建用户任务,完成后挂起自身:
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC(); // 声明CPU状态寄存器(用于临界区)
p_arg = p_arg; // 避免编译器警告
// 1. 初始化板级支持包(GPIO、SysTick等)
BSP_Init();
// 2. 初始化uC/OS-III CPU使用率统计任务(可选)
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
// 3. 使能时间片轮转调度(可选,相同优先级任务按时间片切换)
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
OSSchedRoundRobinCfg(DEF_ENABLED, 1, &err); // 时间片1ms
#endif
// 4. 进入临界区(禁止中断,避免任务创建过程被打断)
OS_CRITICAL_ENTER();
// 4.1 创建1s周期LED任务(LED1,PC13)
OSTaskCreate((OS_TCB *)&Led1TaskTCB,
(CPU_CHAR *)"LED1 Task",
(OS_TASK_PTR )led1_task,
(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);
// 4.2 创建2s周期串口任务
OSTaskCreate((OS_TCB *)&UsartTaskTCB,
(CPU_CHAR *)"USART Task",
(OS_TASK_PTR )usart_task,
(void *)0,
(OS_PRIO )USART_TASK_PRIO,
(CPU_STK *)&USART_TASK_STK[0],
(CPU_STK_SIZE)USART_STK_SIZE/10,
(CPU_STK_SIZE)USART_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);
// 4.3 创建3s周期LED任务(LED2,PA3)
OSTaskCreate((OS_TCB *)&Led2TaskTCB,
(CPU_CHAR *)"LED2 Task",
(OS_TASK_PTR )led2_task,
(void *)0,
(OS_PRIO )LED2_TASK_PRIO,
(CPU_STK *)&LED2_TASK_STK[0],
(CPU_STK_SIZE)LED2_STK_SIZE/10,
(CPU_STK_SIZE)LED2_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);
// 5. 挂起启动任务(任务创建完成,自身不再需要运行)
OSTaskSuspend((OS_TCB *)&StartTaskTCB, &err);
// 6. 退出临界区
OS_CRITICAL_EXIT();
}
5.4 编写用户任务函数
5.4.1 1s周期LED任务(led1_task)
控制PC13引脚LED每秒闪烁一次(亮1s,灭1s):
static void led1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(DEF_TRUE) // 任务循环(永不退出)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED亮(低电平)
OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err); // 延时1s
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED灭(高电平)
OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err); // 延时1s
}
}
5.4.2 3s周期LED任务(led2_task)
控制PA3引脚LED每3秒闪烁一次(亮3s,灭3s):
static void led2_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(DEF_TRUE)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); // LED亮
OSTimeDlyHMSM(0, 0, 3, 0, OS_OPT_TIME_HMSM_STRICT, &err); // 延时3s
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); // LED灭
OSTimeDlyHMSM(0, 0, 3, 0, OS_OPT_TIME_HMSM_STRICT, &err); // 延时3s
}
}
5.4.3 2s周期串口任务(usart_task)
每2秒通过USART1发送字符串“hello uc/OS! 欢迎来到RTOS多任务环境!”:
static void usart_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(DEF_TRUE)
{
printf("hello uc/OS! 欢迎来到RTOS多任务环境!\r\n"); // 串口发送
OSTimeDlyHMSM(0, 0, 2, 0, OS_OPT_TIME_HMSM_STRICT, &err); // 延时2s
}
}
六、编译与下载程序
6.1 编译工程

6.2 下载程序到硬件
-
硬件连接:
- USB转TTL模块 -> STM32F103C8T6:
- TX -> PA10(USART1_RX)
- RX -> PA9(USART1_TX)
- GND -> GND
- VCC -> 3.3V(不可接5V,避免烧毁芯片)
- USB转TTL模块 -> STM32F103C8T6:
-
配置:
- 点击Keil工具栏 “Options for Target” -> “Debug” -> 选择调试器(ST-Link),点击 “Settings” 确认调试连接正常。
- 点击 “Flash” -> “Download”(或按F8),将程序下载到STM32芯片。

七、实验效果验证
7.1 LED任务效果
- LED1(PC13):每秒闪烁一次(亮1s,灭1s)
- LED2(PA3):每3秒闪烁一次(亮3s,灭3s)

7.2 串口任务效果
- 打开串口调试助手(如野火多功能调试助手):
- 选择USB转TTL对应的COM口(如COM8)
- 波特率设为 115200,数据位8,校验位无,停止位1
- 点击 “打开串口”,每2秒会收到一次字符串:
hello uc/OS! 欢迎来到RTOS多任务环境!

八、常见问题与解决方法
-
编译报错"no space in execution regions":
- 原因:堆内存配置过大(
LIB_MEM_CFG_HEAP_SIZE),超出STM32F103C8T6的20KB RAM。 - 解决:在
lib_cfg.h中减小堆大小(如改为5KB)。
- 原因:堆内存配置过大(
-
程序下载后LED不闪烁、串口无输出:
- 检查启动文件是否正确修改(
PendSV_Handler和SysTick_Handler是否替换为OS_CPU_xxx)。 - 检查BSP_Init函数是否调用
MX_GPIO_Init(),确保GPIO初始化生效。 - 检查串口接线是否正确(TX/RX是否交叉连接,GND是否共地)。
- 检查启动文件是否正确修改(
-
uC/OS-III初始化失败(OSInit返回错误):
- 原因:配置文件(如
os_cfg.h)中关键宏未启用,或头文件路径未添加完整。 - 解决:确认
os_cfg.h中OS_CFG_TASK_EN等宏为DEF_ENABLED,头文件路径包含所有uC/OS相关文件夹。
- 原因:配置文件(如
九、总结
本次移植完成了uC/OS-III在STM32F103C8T6上的部署,并实现了3个独立任务:
- 1s周期LED闪烁任务(PC13)
- 3s周期LED闪烁任务(PA3)
- 2s周期串口发送任务
核心步骤包括:HAL库工程创建、uC/OS-III源码移植与配置、任务创建与调度。通过本实验可掌握RTOS的多任务并发执行原理,为后续复杂嵌入式项目开发奠定基础。
F103C8T6的20KB RAM。
- 解决:在
lib_cfg.h中减小堆大小(如改为5KB)。
-
程序下载后LED不闪烁、串口无输出:
- 检查启动文件是否正确修改(
PendSV_Handler和SysTick_Handler是否替换为OS_CPU_xxx)。 - 检查BSP_Init函数是否调用
MX_GPIO_Init(),确保GPIO初始化生效。 - 检查串口接线是否正确(TX/RX是否交叉连接,GND是否共地)。
- 检查启动文件是否正确修改(
-
uC/OS-III初始化失败(OSInit返回错误):
- 原因:配置文件(如
os_cfg.h)中关键宏未启用,或头文件路径未添加完整。 - 解决:确认
os_cfg.h中OS_CFG_TASK_EN等宏为DEF_ENABLED,头文件路径包含所有uC/OS相关文件夹。
- 原因:配置文件(如
九、总结
本次移植完成了uC/OS-III在STM32F103C8T6上的部署,并实现了3个独立任务:
- 1s周期LED闪烁任务(PC13)
- 3s周期LED闪烁任务(PA3)
- 2s周期串口发送任务
核心步骤包括:HAL库工程创建、uC/OS-III源码移植与配置、任务创建与调度。通过本实验可掌握RTOS的多任务并发执行原理,为后续复杂嵌入式项目开发奠定基础。
视频展示:
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)