基于stm32f103C8T6移植uc/OS-III实时操作系统
实时操作系统(RTOS)通常由实时内核与其他高级服务两部分构成,其中高级服务涵盖文件管理、协议栈、图形用户界面(GUI)及其他辅助组件,且多数附加服务的功能实现均围绕输入/输出(I/O)设备展开。实时内核是负责管理微处理器、微控制器或数字信号处理器(DSP)的时间分配与硬件资源调度的核心软件。在设计实时应用程序时,需先将整体工作拆解为若干独立任务,每个任务仅承担特定部分的功能。这些任务(又称线程)
一、任务要求
学习嵌入式实时操作系统(RTOS),以uc/OS为例,将其移植到stm32F03上。
task1:以1s周期对LED等进行点亮-熄灭的控制。
task2:以3s周期对LED等进行点亮-熄灭的控制。
task3:以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!。记录详细的移植过程。
二、系统原理介绍
1.RTOS实时操作系统
实时操作系统(RTOS)通常由实时内核与其他高级服务两部分构成,其中高级服务涵盖文件管理、协议栈、图形用户界面(GUI)及其他辅助组件,且多数附加服务的功能实现均围绕输入/输出(I/O)设备展开。 实时内核是负责管理微处理器、微控制器或数字信号处理器(DSP)的时间分配与硬件资源调度的核心软件。在设计实时应用程序时,需先将整体工作拆解为若干独立任务,每个任务仅承担特定部分的功能。这些任务(又称线程)本质上是一段简化程序,在逻辑层面可认为自身独占中央处理器(CPU)。不过在单CPU硬件环境中,任意时刻实际上仅能有一个任务处于执行状态,且任务通常会被设计为无限循环的运行模式,以确保功能的持续响应。 内核的核心职责之一是对任务进行统一管理,这一过程被称为多任务处理。具体而言,多任务处理是指在多个任务间合理调度CPU资源、实现任务切换的动态过程——CPU会在不同任务间交替分配处理时间,从而营造出“拥有多个CPU”的运行错觉。这种机制不仅能最大限度提升CPU的资源利用率,还能帮助开发者构建模块化的应用程序架构;更重要的是,它能有效降低实时应用程序固有的设计复杂度,让应用程序的开发设计与后期维护变得更简便。 在实时操作系统中,任务切换通常通过“时间片”机制实现:系统借助中断触发任务切换,使CPU跳转到不同任务中执行;通过调整时间片的长度,可直接控制任务切换的频率。为确保任务切换后能恢复到之前的执行状态,每个任务都拥有独立的堆栈区,同时配备对应的寄存器用于记录任务当前的执行上下文(如指令地址、数据状态等)——当系统从其他任务切换回该任务时,只需通过寄存器恢复上下文,即可从断点处继续执行代码,这是保障RTOS实时性的关键设计之一。此外,RTOS中的任务还划分有不同优先级(如低级任务、高级任务),系统可通过控制中断服务程序(ISR)来调节任务的调度顺序,进一步优化实时响应性能。
2.uc/OS-III操作系统
(1)特性和功能
µC/OS 是一款源代码公开免费、内核结构精简且具备可剥夺式实时内核的实时操作系统,主要分为 µC/OS-II 和 µC/OS-III 两个版本。 其中,µC/OS-II 作为实时操作系统内核,仅集成任务调度、任务管理、时间管理、内存管理以及任务间通信与同步等基础功能。 而 µC/OS-III 是一款可升级、可固化的基于优先级的实时内核,它不受任务数量限制,还支持现代实时内核所需的大部分功能,如资源管理、同步机制及任务间通信等。 此外,µC/OS-III 具备高度可移植性、可ROM固化、可扩展性,是一款采用抢占式调度的实时、确定性多任务处理内核,适用于微处理器、微控制器和数字信号处理器(DSP)等多种硬件平台。
- 注释:任务调度与中断处理流程: (1)低优先级任务处于运行状态。 (2)中断触发后,CPU立即切换至对应设备的中断服务程序(ISR)执行。 (3)ISR仅完成中断设备的基础服务工作(通常操作极少),其核心作用是向更高优先级任务发送信号或消息,由后者负责中断设备的主要处理工作。例如,若中断来自以太网控制器,ISR仅需向特定任务发出信号,该任务会进一步处理接收到的数据包。 (4)ISR执行完毕后,μC/OS-III会检测到有更高优先级的就绪任务,此时不会返回被中断的低优先级任务,而是直接执行上下文切换,跳转至更高优先级任务。 (5)高优先级任务响应中断设备并执行必要的处理操作。 (6)高优先级任务完成工作后,会循环返回至任务代码起始处,并调用μC/OS-III的相关函数,等待设备的下一次中断。 (7)低优先级任务从中断处恢复执行,整个过程对其完全透明。 ### μC/OS-III的核心功能特性: **源代码**:以ANSI-C源代码形式提供,代码风格简洁规范、一致性强,是Micriμm企业文化中"代码清洁度"的体现。与多数商业内核相比,其代码严格遵循编码标准,并配有完整文档和示例,便于开发者使用。 **直观的应用程序编程接口(API):设计直观且遵循一致的编码约定,易于预测函数调用方式及参数类型。例如,指向对象的指针始终作为第一个参数,指向错误代码的指针始终作为最后一个参数。 **抢占式多任务处理**:作为抢占式内核,μC/OS-III始终确保优先级最高的就绪任务获得CPU执行权。 **同优先级任务循环调度**:支持多个同优先级任务运行,当该优先级为系统最高时,内核会按用户定义的"时间量子"为每个任务分配执行时间。任务可自定义时间量子,若无需完整时间量子,也可主动将CPU让渡给同优先级其他任务。 **低中断禁用时间**:针对需原子访问的内部数据结构和变量,内核通过锁定调度程序而非禁用中断来保护关键区域,因此中断禁用时间极短,确保能响应高速中断源。 **确定性**:中断响应具有确定性,且多数服务的执行时间可预测。 **可扩展性**:可根据应用需求调整代码和数据占用空间,通过约60个编译时宏定义(os_cfg.h)添加或删除功能。内核会对服务参数执行运行时检查(如验证空指针、调用环境合法性等),这些检查可在编译时禁用以进一步缩减代码体积、提升性能,使其适用于各类应用场景。 **可移植性**:可移植到多种CPU架构,多数μC/OS-II的移植版本仅需少量修改即可适配μC/OS-III,受益于μC/OS-II已支持的45种以上CPU架构。 **可ROM固化**:专为嵌入式系统设计,可与应用程序代码一同固化到ROM中。 **运行时可配置**:支持运行时配置内核,所有内核对象(任务、堆栈、信号量、事件标志组等)均由用户在运行时分配,避免编译时资源过度分配。 **无任务数量限制**:理论上支持无限任务,实际受处理器内存(代码和数据空间)限制。每个任务需独立堆栈空间,内核提供堆栈增长监视功能;任务堆栈大小仅受CPU最小需求限制,无上限约束。 **无优先级数量限制**:理论上支持无限优先级,实际配置为32-256个优先级即可满足多数应用需求。 **无内核对象数量限制**:允许创建任意数量的任务、信号量、互斥体等内核对象,均由用户在运行时分配。 **丰富的服务支持**:提供高端实时内核所需的全部服务,包括任务管理、时间管理、信号量、事件标志、互斥体、消息队列、软件定时器、固定大小内存池等。 - **互斥信号量**:用于资源管理,具备内置优先级继承机制,可消除无限制优先级反转;支持嵌套访问(最多250次),释放次数需与获取次数一致。 - **嵌套任务挂起**:允许任务挂起自身或其他任务(挂起后需由其他任务恢复才能执行),最多支持250层嵌套,恢复次数需与挂起次数一致。 - **软件计时器**:支持创建任意数量的"一次性"或"周期性"计时器,本质为倒计时计数器,计数至0时执行用户定义操作;周期性计时器会自动重载并重复执行操作,每个计时器可独立定义操作逻辑。 - **任务信号与消息**:允许ISR或任务直接向目标任务发送信号或消息,无需创建中间内核对象(如信号量),提升处理性能。 - **任务寄存器**:每个任务可配置用户自定义数量的任务寄存器(区别于CPU寄存器),可用于存储错误码、ID、中断禁用时间等任务专属信息。 - **错误检查**:验证参数合法性(如空指针、调用环境、参数范围等),所有API函数均返回与调用结果相关的错误代码。 - **内置性能测量**:可测量任务执行时间、堆栈使用情况、执行次数、CPU使用率、响应时间、列表峰值条目数等性能指标。 - **内置跟踪点**:代码中集成跟踪点,支持主流跟踪分析工具(如Percepio TraceAlyzer、SEGGER SystemView)实时记录内核事件和中断。 - **易于优化**:设计便于基于CPU架构优化,多数数据类型可调整以适配CPU自然字长;优先级解析算法可通过汇编语言实现,利用位操作、计数前导零等特殊指令提升效率。 - **死锁预防**:所有"挂起"服务均包含超时机制,有效避免死锁。 - **任务级节拍处理**:时钟节拍管理通过ISR触发的任务实现,减少中断延迟;采用散列增量列表机制,降低任务延迟和超时处理的开销。 - **用户可定义钩子函数**:允许端口和应用程序员定义钩子函数,由内核在特定事件(如上下文切换、任务创建/删除)时调用,扩展内核功能。 - **时间戳**:依赖16位或32位自由运行计数器实现时间测量,可记录事件时间(如消息发布时刻),接收者通过对比当前时间戳可计算消息传递延迟。 - **内核感知调试器支持**:支持内核感知调试器以友好方式显示变量和数据结构,可配合μC/Probe在运行时展示相关信息。 - **对象名称**:所有内核对象(任务、信号量等)可关联ASCII名称(以NUL结尾,长度不限),便于识别对象用途和分配情况。
(2)系统架构

注释:
(1)应用代码由项目或产品相关文件构成。为便于说明,此处简称为app.c和app.h,但实际应用程序可包含任意数量的文件,且文件名不必以app.*命名。应用程序代码中通常会包含main()函数。 (2)半导体制造商通常以源代码形式提供库函数,用于访问其CPU或MCU上的外设。这些库实用性强,能节省大量开发时间。由于这类文件并无统一命名规范,此处暂以.c和.h作为后缀示例。 (3)µC/OS-III所需的板级支持包(BSP)代码通常较为简单,一般而言,µC/OS-III仅需初始化一个用于时间延迟和超时处理的周期性中断源。该功能应封装在os_bsp.c文件中,并配有相应的头文件bsp_os.h。 (4)这部分是与µC/OS-III处理器无关的代码,采用高度可移植的ANSI C编写。 (5)这部分是适配特定CPU架构的µC/OS-III代码,称为端口。µC/OS-III源于µC/OS-II,因此能够复用µC/OS-II已有的约45个端口中的大部分,但µC/OS-II的端口需经过少量修改才能与µC/OS-III兼容。 (6)在Micriμm,我们对CPU功能进行了封装。这些文件定义了中断禁用与启用函数、独立于具体CPU和编译器的CPU_???数据类型,以及其他相关函数。 (7)µC/LIB是一组源文件,提供内存复制、字符串及ASCII相关函数等常用功能。有时会用它们替代编译器提供的stdlib函数。提供这些文件是为了确保其在不同应用程序间,尤其是不同编译器间具有完全可移植性。µC/OS-III不直接使用这些文件,但µC/CPU会用到。 (8)可选模块:部分编译器提供线程本地存储(Thread-local Storage)扩展,该扩展提供一个变量区域,线程可在其中存储自身状态,从而提高多线程环境的安全性。这些功能的适配工作在os_tls.c文件中完成,该文件位于uCOS-III\TLS<tool>文件夹下,其中<tool>为工具制造商名称或工具名称。 (9)可选模块:µC/OS-III在代码中内置了跟踪点,可配合主流跟踪分析工具(如Percepio的TraceAlyzer和SEGGER的SystemView)实时记录所有内核事件和中断。这些跟踪调用默认处于禁用状态,仅可在编译时通过将os_cfg.h中的配置常量OS_CFG_TRACE_EN设置为DEF_ENABLED来启用。这些跟踪函数定义于uCOS-III\Trace<tool>文件夹下的多个文件中,其中<tool>为跟踪工具名称。 (10)配置文件用于:通过os_cfg.h定义应用程序中需包含的µC/OS-III功能;通过os_cfg_app.h指定µC/OS-III所需的某些变量和数据结构的大小(如空闲任务堆栈大小、时钟节拍频率、消息池大小等);通过cpu_cfg.h配置应用程序员可用的µC/CPU功能;以及通过lib_cfg.h配置µC/LIB选项。
三、实验过程
(1)选择芯片
STM32F103C8T6
(2)配置RCC

(3)配置SYS

(4)串口配置USART1

(5)GPIO口设置
设置PA3 PC13作为两个LED灯的端口,将与LED相连的两个端口PA3 PC13配置为GPIO_Output,可根据LED现象作为是否移植成功的依据。

(6)设置路径

按之前教程设置好到处keil文件即可。
2.获取uCOS-III源码
进入 Micrium 公司官网下载中心http://micrium.com/downloadcenter/
选择ST系列,点击 View all STMicroelectronics,点击 STMicroelectronics STM32F107之后按照提示注册下载即可。
3.移植前的文件准备
(1)打开下载好的源码

文件夹下的文件已经复制添加好了,如下图所示

(2)将uCOS的5个相关文件复制到cubeMX工程的MDK-ARM文件夹下

4.移植过程
打开cubeMX生成的keil文件
(1)将uCOS文件添加到项目中
点击Manage Project Items,按下图所示操作,为项目新建文件夹,在对应文件夹下添加文件。

(2)点击CPU–>Add Files…
MDK-ARM\uC-CPU路径下选中以下文件,Add添加

(3)MDK-ARM\uC-CPU\ARM-Cortex-M3\RealView路径下选中以下文件,Add添加

(4)点击PORT–>Add Files…
MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView路径下选中以下文件,Add添加

(5)点击SOURCE–>Add Files…
MDK-ARM\uCOS-III\Source路径下选中以下全部 .c .h 文件,Add添加
(6)点击CONFIG–>Add Files…
MDK-ARM\uC-CONFIG路径下选中以下全部文件,Add添加
(7)点击BSP–>Add Files…
MDK-ARM\uC-BSP路径下选中以下全部文件,Add添加,全部添加完毕后,点击OK
5.导入文件路径
按下图所示步骤操作

6.构建三个任务
(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
打开app_cfg.h文件
DEF_ENABLED 改为 DEF_DISABLED#define APP_TRACE BSP_Ser_Printf 改为 #define APP_TRACE(void)
打开includes.h文件
在#include <bsp.h>下面添加 #include “gpio.h” #include “app_cfg.h”
将#include <stm32f10x_lib.h> 改为 #include “stm32f1xx_hal.h”
打开lib_cfg.h文件
修改为5(该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点)
打开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 */
(3)初始化管脚
在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);
}
(4)撰写主函数
修改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****/
五、总结
当我们需要处理器完成的任务比较多,为了便于管理可以引入实时操作系统,这能很方便准确的将所有任务进行整合。
学习了这个操作系统为后续大作业有了很大的帮助。但是在进行移植时要仔细,否则在编译时很容易报一大堆错误。
参考博客
https://blog.csdn.net/qq_46467126/article/details/121441622
https://blog.csdn.net/sjsnsnsnsi/article/details/134612198
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)