嵌入式实时操作系统(RTOS)移植与实践:将 uc/OS 移植到 STM32F103
通过上述步骤,我们成功地将 uc/OS 移植到了 STM32F103 上,并实现了三个任务的功能。这个过程涉及到了硬件初始化、中断配置、任务调度器的启动等多个方面。在实际开发中,可以根据项目需求进一步优化和扩展 uc/OS 的功能。希望本文能为嵌入式开发人员提供一个清晰的 uc/OS 移植指南。如果有任何问题或建议,欢迎在评论区留言。
嵌入式实时操作系统(RTOS)移植与实践:将 uc/OS 移植到 STM32F103
在嵌入式系统开发中,实时操作系统(RTOS)的应用越来越广泛。uc/OS 是一款经典的开源实时操作系统,具有高效、可靠、可裁剪等优点。本文将详细介绍如何将 uc/OS 移植到 STM32F103 上,并构建三个任务来实现对 LED 的控制和通过串口发送消息的功能。
一、开发环境准备
在开始移植之前,需要准备好以下开发环境:
- 硬件环境:STM32F103C8T6 开发板。
- 软件环境:
- Keil uVision 5(或其他支持 STM32 的 IDE)。
- STM32 HAL 库。
- uc/OS 源码。
二、uc/OS 移植步骤
1. 创建工程
- 打开 Keil uVision 5,创建一个新的 STM32 工程。
- 添加 STM32 HAL 库文件到工程中。
- 将 uc/OS 源码文件夹(如
ucos-ii)添加到工程中。











4.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)
3. includes.h
第一处修改: 添加相关头文件
修改前
#include <bsp.h>
修改后
#include <bsp.h>
#include “gpio.h”
#include “app_cfg.h”
#include “app.h”
第二处修改: 添加HAL 库
修改前
#include <stm32f10x_lib.h>
修改后
#include “stm32f1xx_hal.h”
————————————————
版权声明:本文为CSDN博主「带火星的小木头」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43116606/article/details/105532222
2. 配置时钟
uc/OS 需要一个定时器来提供时钟中断。STM32F103 提供了多个定时器,可以选择其中一个作为系统时钟。
#include "stm32f1xx_hal.h"
TIM_HandleTypeDef htim1;
void TIM1_UP_Init(void)
{
__HAL_RCC_TIM1_CLK_ENABLE();
htim1.Instance = TIM1;
htim1.Init.Prescaler = (uint16_t)(SystemCoreClock / 1000) - 1; // 设置时钟频率为 1kHz
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1000 - 1; // 设置定时周期为 1ms
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim1);
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 0, 0); // 设置中断优先级
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn); // 使能中断
HAL_TIM_Base_Start_IT(&htim1); // 启动定时器
}
!](https://i-blog.csdnimg.cn/direct/029be6cf9c4e4ba8879db21468f0dae5.png)
3. 配置中断服务例程
uc/OS 需要一个中断服务例程(ISR)来处理时钟中断。在 stm32f1xx_it.c 文件中添加以下代码:
extern void OSTickISR(void);
void TIM1_UP_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
OSTickISR(); // 调用 uc/OS 的时钟中断处理函数
}
}
}
4. 配置任务调度器
在 main.c 文件中初始化 uc/OS 并启动任务调度器:
#include "ucos_ii.h"
#include "stm32f1xx_hal.h"
#define LED1_PIN GPIO_PIN_5
#define LED1_GPIO_PORT GPIOA
#define LED2_PIN GPIO_PIN_6
#define LED2_GPIO_PORT GPIOA
OS_TCB Task1TCB, Task2TCB, Task3TCB;
OS_STK Task1Stk[128], Task2Stk[128], Task3Stk[128];
void Task1(void *p_arg)
{
while (1)
{
HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_PIN);
OSTimeDlyHMSM(0, 0, 1, 0); // 延时 1 秒
}
}
void Task2(void *p_arg)
{
while (1)
{
HAL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_PIN);
OSTimeDlyHMSM(0, 0, 3, 0); // 延时 3 秒
}
}
void Task3(void *p_arg)
{
char *msg = "hello uc/OS! 欢迎来到RTOS多任务环境!\r\n";
while (1)
{
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
OSTimeDlyHMSM(0, 0, 2, 0); // 延时 2 秒
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
TIM1_UP_Init();
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = LED1_PIN | LED2_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);
OSInit(); // 初始化 uc/OS
OSTaskCreate(Task1, NULL, &Task1Stk[128 - 1], 1);
OSTaskCreate(Task2, NULL, &Task2Stk[128 - 1], 2);
OSTaskCreate(Task3, NULL, &Task3Stk[128 - 1], 3);
OSStart(); // 启动任务调度器
while (1)
{
}
}
三、调试与测试
- 硬件连接:将 LED 连接到 STM32F103 的 PA5 和 PA6 引脚,将串口连接到调试助手。
- 编译与下载:编译工程并下载到开发板。
- 观察结果:
- LED1 每秒闪烁一次。
- LED2 每 3 秒闪烁一次。
- 串口每 2 秒发送一次消息:“hello uc/OS! 欢迎来到RTOS多任务环境!”
四、总结
通过上述步骤,我们成功地将 uc/OS 移植到了 STM32F103 上,并实现了三个任务的功能。这个过程涉及到了硬件初始化、中断配置、任务调度器的启动等多个方面。在实际开发中,可以根据项目需求进一步优化和扩展 uc/OS 的功能。
希望本文能为嵌入式开发人员提供一个清晰的 uc/OS 移植指南。如果有任何问题或建议,欢迎在评论区留言。
参考资料
更多推荐



所有评论(0)