在嵌入式系统开发中,实时操作系统(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:

配置步骤:

  1. 选择HSE作为时钟源

  2. 设置PLL倍频为9倍

  3. 系统时钟设置为72MHz

  4. APB1总线时钟为36MHz

  5. 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引脚配置

八、总结

通过本次实践,我们成功完成了:

  1. uC/OS-III移植:将实时操作系统移植到STM32F103平台

  2. 多任务创建:构建了三个具有不同周期的任务

  3. 外设控制:实现了GPIO控制和串口通信

  4. 系统调试:验证了多任务调度功能

这个项目展示了RTOS在嵌入式系统中的核心优势:

  • 多任务并发:多个任务独立运行,互不干扰

  • 精确时序:任务能够按照精确的时间周期执行

  • 资源管理:系统有效管理CPU时间和外设资源

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐