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 新建工程并选择芯片

  1. 打开STM32CubeMX,点击 “File” -> “New Project”,在MCU选择器中搜索 “STM32F103C8T6”,双击选中芯片。

2.2 配置时钟(RCC)

  1. 选择 “System Core” -> “RCC”

    High Speed Clock (HSE):选择 “Crystal/Ceramic Resonator”(外部晶振模式)

    Low Speed Clock (LSE):保持默认 “Crystal/Ceramic Resonato”

    在这里插入图片描述

  2. 配置时钟树:

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

在这里插入图片描述

2.3 配置系统核心(SYS)

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

在这里插入图片描述

2.4 配置GPIO(LED引脚)

需配置2个LED引脚,分别对应1s和3s周期任务:

  1. 选择 “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周期发送字符串):

  1. 选择 “Connectivity” -> “USART1”

    • Mode:选择 “Asynchronous”(异步模式)
    • Hardware Flow Control:选择 “Disable”(禁用硬件流控)
    • 点击右侧引脚分配,确认USART1_TX对应PA9,USART1_RX对应PA10
  2. 配置串口参数(在"Parameter Settings"中):

    • Baud Rate:115200 Bits/s
    • Word Length:8 Bits
    • Parity:None
    • Stop Bits:1 Bit
      在这里插入图片描述

    一定要勾!!!
    在这里插入图片描述

2.6 生成Keil工程

  1. 点击顶部 “Project Manager”,配置工程信息:
    • Project Name:输入工程名(如uCOS-III_LED_USART
    • Project Location:选择工程保存路径(建议英文路径)
    • Toolchain/IDE:选择 “MDK-ARM”,版本选择 “V5”
  2. 点击左侧 “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”(重新生成代码时保留用户代码)
  3. 点击 “GENERATE CODE”,生成Keil工程,生成完成后点击 “Open Project” 直接打开Keil MDK。

在这里插入图片描述
在这里插入图片描述

三、移植uC/OS-III到Keil工程

2.2 源码文件整理

  1. 百度网盘下载后得到

    在这里插入图片描述

3.1 复制uC/OS-III源码到工程目录

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

在这里插入图片描述

3.2 在Keil中添加工程分组与文件

  1. 打开Keil工程,点击左侧 “Manage Project Items”(小箱子图标),在弹出窗口中新建4个分组:

    • BSP:板级支持包文件

    • CPU:uC-CPU相关文件

    • LIB:uC-LIB库文件

    • PORT:uC/OS-III CPU适配文件

  2. 向各分组添加对应文件:

    分组 文件路径与选择的文件
    BSP uC-BSP文件夹下的bsp.cbsp.h
    CPU 1. uC-CPU:选择cpu_core.ccpu_core.hcpu_def.h
    2. uC-CPU\ARM-Cortex-M3\RealView:选择cpu.hcpu_a.asmcpu_c.c
    LIB 1. uC-LIB:选择lib_ascii.clib_ascii.hlib_def.hlib_math.clib_math.hlib_mem.clib_mem.hlib_str.clib_str.h
    2. uC-LIB\Ports\ARM-Cortex-M3\RealView:选择lib_mem_a.asm
    PORT uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView:选择os_cpu.hos_cpu_a.sos_cpu_c.c

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 添加头文件路径

  1. 点击Keil工具栏 “Options for Target”(魔术棒图标),选择 “C/C++” 选项卡:

  2. 点击 “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中断服务函数:

  1. 在Keil工程中找到Application/MDK-ARM分组下的startup_stm32f103xb.s,双击打开。
  2. 搜索并修改以下两处(约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(应用配置)
  1. 打开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(头文件汇总)
  1. 打开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"
      
4.3.3 lib_cfg.h(内存配置)
  1. 打开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 下载程序到硬件

  1. 硬件连接:

    • USB转TTL模块 -> STM32F103C8T6:
      • TX -> PA10(USART1_RX)
      • RX -> PA9(USART1_TX)
      • GND -> GND
      • VCC -> 3.3V(不可接5V,避免烧毁芯片)
  2. 配置:

    • 点击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 串口任务效果

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

在这里插入图片描述

八、常见问题与解决方法

  1. 编译报错"no space in execution regions"

    • 原因:堆内存配置过大(LIB_MEM_CFG_HEAP_SIZE),超出STM32F103C8T6的20KB RAM。
    • 解决:在lib_cfg.h中减小堆大小(如改为5KB)。
  2. 程序下载后LED不闪烁、串口无输出

    • 检查启动文件是否正确修改(PendSV_HandlerSysTick_Handler是否替换为OS_CPU_xxx)。
    • 检查BSP_Init函数是否调用MX_GPIO_Init(),确保GPIO初始化生效。
    • 检查串口接线是否正确(TX/RX是否交叉连接,GND是否共地)。
  3. uC/OS-III初始化失败(OSInit返回错误)

    • 原因:配置文件(如os_cfg.h)中关键宏未启用,或头文件路径未添加完整。
    • 解决:确认os_cfg.hOS_CFG_TASK_EN等宏为DEF_ENABLED,头文件路径包含所有uC/OS相关文件夹。

九、总结

本次移植完成了uC/OS-III在STM32F103C8T6上的部署,并实现了3个独立任务:

  1. 1s周期LED闪烁任务(PC13)
  2. 3s周期LED闪烁任务(PA3)
  3. 2s周期串口发送任务

核心步骤包括:HAL库工程创建、uC/OS-III源码移植与配置、任务创建与调度。通过本实验可掌握RTOS的多任务并发执行原理,为后续复杂嵌入式项目开发奠定基础。

F103C8T6的20KB RAM。

  • 解决:在lib_cfg.h中减小堆大小(如改为5KB)。
  1. 程序下载后LED不闪烁、串口无输出

    • 检查启动文件是否正确修改(PendSV_HandlerSysTick_Handler是否替换为OS_CPU_xxx)。
    • 检查BSP_Init函数是否调用MX_GPIO_Init(),确保GPIO初始化生效。
    • 检查串口接线是否正确(TX/RX是否交叉连接,GND是否共地)。
  2. uC/OS-III初始化失败(OSInit返回错误)

    • 原因:配置文件(如os_cfg.h)中关键宏未启用,或头文件路径未添加完整。
    • 解决:确认os_cfg.hOS_CFG_TASK_EN等宏为DEF_ENABLED,头文件路径包含所有uC/OS相关文件夹。

九、总结

本次移植完成了uC/OS-III在STM32F103C8T6上的部署,并实现了3个独立任务:

  1. 1s周期LED闪烁任务(PC13)
  2. 3s周期LED闪烁任务(PA3)
  3. 2s周期串口发送任务

核心步骤包括:HAL库工程创建、uC/OS-III源码移植与配置、任务创建与调度。通过本实验可掌握RTOS的多任务并发执行原理,为后续复杂嵌入式项目开发奠定基础。

视频展示:
在这里插入图片描述

Logo

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

更多推荐