前言
uC/OS-III是一款高效、可移植、可裁剪的实时嵌入式操作系统,STM32F103C8T6是基于HAL库的微控制器。实操过程中,首先需要在STM32F103C8T6上移植uC/OS-III操作系统,然后使用逻辑分析仪抓取波形进行协议分析。通过这个过程,可以深入了解uC/OS-III的操作过程,以及如何在微控制器上实现基于操作系统的开发。同时,通过逻辑分析仪抓取的波形数据,可以进一步进行协议分析,对于研究嵌入式系统的通信协议具有重要意义。
任务要求
学习嵌入式实时操作系统(RTOS),以uc/OS-III为例,将其移植到stm32F103上,构建至少3个任务(task):
其中两个task分别以1s和3s周期对LED等进行点亮-熄灭的控制;
另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。
记录详细的移植过程。
uc/OS-III介绍
UCOSIII是一款由Micrium公司开发的实时操作系统(RTOS),它提供了丰富的功能和卓越的性能,适用于各种嵌入式系统应用。UCOSIII具有可裁剪、可剥夺型的多任务内核,支持多个并发任务,并且没有任务数限制。这使得UCOSIII成为了一个强大而灵活的工具,适用于各种不同的应用场景。
UCOSIII是用C和汇编语言编写的。其中,大部分代码都是用C语言编写的,只有极少数的与处理器密切相关的部分代码是使用汇编语言编写的。这种设计使得UCOSIII具有很高的可读性和可维护性,特别适合嵌入式系统开发人员和爱好者学习和使用。
在UCOSIII中,任务(线程)是简单的程序实体。在单CPU系统中,任何时刻只能有一个任务被执行。每个任务看起来就像一个C函数,但是在大多数嵌入式系统中,任务通常是无限循环的,不能像C函数那样返回。
在UCOSIII中,任务以程序实体的形式存在。UCOSIII通过管理和调度这些小任务(程序)来实现系统的运行。每个任务都由三部分组成:任务堆栈、任务控制块和任务函数。
任务堆栈是用于保存任务执行时的上下文信息,包括各种寄存器的状态、任务的局部变量等。任务控制块则包含了任务的描述信息和控制信息,例如任务的优先级、状态等。任务函数则是任务的主体代码,它包含了任务的逻辑和功能。
UCOSIII通过任务控制块和任务堆栈来管理和调度任务。当一个任务被创建时,UCOSIII会为该任务分配一个任务控制块和一块任务堆栈。在任务执行时,UCOSIII会根据任务的优先级和状态信息来调度任务的执行。当一个任务需要等待某个事件发生时,UCOSIII会将该任务的状态设置为等待状态,并将该任务放入相应的等待队列中等待调度。当事件发生后,UCOSIII会将该任务重新放入就绪队列中等待执行。
总之,UCOSIII是一款功能强大、可读性强的RTOS,适用于各种嵌入式系统应用。通过了解UCOSIII的任务管理和调度机制,可以更好地理解和应用该系统进行开发。
UCOSIII在STM32F103上的移植
ROTS简介
物联网操作系统是控制和管理物联网设备及其连接的软件平台。以下是三种流行的物联网操作系统:华为的LiteOS、亚马逊的FreeRTOS和RT-Thread。
(1)华为的LiteOS
华为LiteOS是一种轻量级的实时操作系统,专为物联网设备设计。它具有低功耗、快速启动和实时响应的特点,适用于各种智能家居、工业物联网和智能城市应用。
(2)亚马逊的FreeRTOS
FreeRTOS是亚马逊公司推出的一款免费开源的嵌入式操作系统,专为物联网设备和其他嵌入式系统设计。它具有可移植性、可扩展性和可缩放性,支持多种编程语言和硬件平台。
(3)RT-Thread
RT-Thread是一款中国开发的开源实时操作系统,适用于各种物联网设备。它具有可剥夺性和多任务能力,能够实现高度可靠和稳定的系统运行。RT-Thread提供了丰富的中间件组件和开发工具,方便开发人员快速构建和部署应用程序。
这些物联网操作系统都具有实时性、可剥夺性和多任务能力等核心特性,能够满足不同类型物联网设备的需求。选择合适的操作系统取决于具体的应用场景、硬件平台和开发需求。
UCOSIII任务管理
任务的基本概念
在设计大型复杂程序时,我们通常会将它们分解为许多小而简单的程序,也称为任务。这些任务就像一个个独立的工作单元,它们协同工作以实现复杂的功能。通过并发执行这些小任务,可以有效地提高CPU的利用率。
UCOSIII是一种可剥夺的多任务操作系统。多任务处理能力是UCOSIII的重要优势之一,这使得我们能够同时运行多个任务,从而提高了系统的效率和响应速度。
在UCOSIII中,任务被视为程序实体,UCOSIII能够有效地管理和调度这些小型任务(或程序)。为了更好地理解任务在UCOSIII中的存在方式,我们可以将其分解为三个主要组成部分:任务堆栈、任务控制块和任务函数。
(1)任务堆栈:当进行上下文切换时,任务堆栈用于保存任务的工作环境。这实际上意味着它存储了STM32的内部寄存器值。这些寄存器通常用于保存任务的执行状态、CPU的程序计数器(PC)和堆栈指针等信息。因此,任务堆栈在任务切换时起到了关键作用,确保了任务的正确执行。
(2)任务控制块:任务控制块用于记录任务的各个属性。这包括任务的优先级、状态(就绪、等待、运行中)、相关信息等。任务控制块是UCOSIII内部用于管理和调度任务的重要结构,它为每个任务提供了一个独立的存储空间,以便系统可以轻松地访问和更新任务的属性。
(3)任务函数:这是用户编写的实际任务处理代码,它承载了任务的实质性工作。这些函数是由用户定义并实现的,可以根据具体需求编写特定的处理逻辑。在UCOSIII中,任务函数是用于执行特定任务的代码片段,它是构成任务的核心部分。
综上所述,UCOSIII中的任务由三部分组成:任务堆栈用于保存任务的工作环境,任务控制块记录任务的属性,而任务函数则是由用户编写的实际任务处理代码。这三个组成部分共同协作,使得UCOSIII能够有效地管理和调度复杂的任务,实现高效的实时操作系统的功能。
UCOSIII中以下优先级用户程序不能使用
将这些优先级分配给了UCOSIII的5个系统内部任务
优先级0:中断服务服务管理任务 OS_IntQTask()
优先级1:时钟节拍任务 OS_TickTask()
优先级2:定时任务 OS_TmrTask() 通过系统函数确定是否启用
优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
任务堆栈
原则:先进先出
定义:为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其它函数时的需要。
格式:
#define START_STK_SIZE 512 //堆栈大小
CPU_STK START_TASK_STK[START_STK_SIZE]; //定义一个数组来作为任务堆栈
使用:
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, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
(void * )0, //用户补充的存储区
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
(OS_ERR * )&err); //存放该函数错误时的返回值
任务控制块
定义:任务控制块是用来记录与任务相关的信息的数据结构,每个任务都要有自己的任务控制块。
格式:
OS_TCB StartTaskTCB; //创建一个任务控制块
任务就绪表
(1)优先级
在UCOSIII中,任务优先级的数量由宏OS_CFG_PRIO_MAX来配置。在UCOSIII中,数值越小表示优先级越高。因此,最低可用的优先级是OS_CFG_PRIO_MAX-1。这个宏定义位于os_cfg.h文件中,用于配置任务优先级的最大数量。
#define OS_CFG_PRIO_MAX 64u
(2)就绪表
组成部分:
优先级位映射表OSPrioTbl[]:该表记录了哪个优先级下存在就绪的任务。OSPrioTbl[]在os_prio.c文件中定义如下:
CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE];
如何找到已经就绪了的最高优先级的任务:OS_PrioGetHighest()函数会返回当前最高优先级的任务。
就绪任务列表OSRdyList[]:该列表记录了每一个优先级下所有就绪的任务。OSRdyList[]在os_prio.c文件中定义如下:
OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX];
结构体os_rdy_list的定义如下:
struct os_rdy_list {
OS_TCB *HeadPtr; /* 指向头Pointer to task that will run at selected priority */
OS_TCB *TailPtr; /* 指向尾Pointer to last task at selected priority */
OS_OBJ_QTY NbrEntries; /* 总数Number of entries at selected priority */
};
这个结构体描述了一个就绪任务列表,其中HeadPtr指向优先级最高的任务,TailPtr指向优先级最低的任务,NbrEntries表示该优先级下的任务数量。通过这个结构体,我们可以快速找到任何一个优先级下的就绪任务。
三个就绪的任务以链表的形式连接在一起
OS_TCB *NextPtr; /* Pointer to next TCB in the TCB list */
OS_TCB *PrevPtr; /* Pointer to previous TCB in the TCB list
同一优先级下如果有多个任务的话最先运行的永远是HeadPtr所指向的任务!
创建工程
选择芯片
配置RCC
配置SYS
串口配置USART1
设置PA3 PC13作为两个LED灯的端口
将与LED相连的两个端口PA3 PC13配置为GPIO_Output,可根据LED现象作为是否移植成功的依据。
创建并打开工程
移植前准备
进入 Micrium 公司官网下载中心:http://micrium.com/downloadcenter/
选择ST系列,点击 View all STMicroelectronics,点击 STMicroelectronics STM32F107
之后按照提示注册下载即可。
可直接下载此网盘链接内容
链接:https://pan.baidu.com/s/10RqsDRecbmVteWmDv2oUNQ
提取码:1234
打开下载好的源码,并复制以下文件
再打开创建的工程,进入将以上复制的文件复制到cubeMX工程的MDK-ARM文件夹下
移植过程
打开cubeMX生成的keil文件,点击三个小箱子,将源码引入程序
建立好以下分组,并添加文件
(1)cU-BSP文件:
MDK-ARM\uC-BSP路径下选中以下全部文件
(2)cU-CPU文件:
MDK-ARM\uC-CPU路径下选中以下文件:
MDK-ARM\uC-CPU\ARM-Cortex-M3\RealView路径下选中以下文件
(3)cU-CONFIG文件:
MDK-ARM\uC-CONFIG路径下选中以下全部文件:
(4)cU-LIB文件:
MDK-ARM\uC-LIB路径下选中下图文件
MDK-ARM\uC-LIB\Ports\ARM-Cortex-M3\RealView路径下选中下图绿框文件,Add添加
(5)SOURCE文件
MDK-ARM\uCOS-III\Source路径下选中以下全部 .c .h 文件
(6)PORT文件
MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView路径下选中以下文件
全部添加完毕后,点击OK
点击魔法棒,添加各文件路径
最终结果如下:
代码
添加代码
找到bsp.c和bsp.h文件
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
bsp.h中添加以下代码(最后一定要空一行,不然容易报错):
#ifndef __BSP_H__
#define __BSP_H__
#include "stm32f1xx_hal.h"
void BSP_Init(void);
#endif
修改代码
打开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 */
初始化管脚
在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);
}
撰写主函数
修改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****/
最后,再在魔法棒中的target中选中Use MicroLIB
编译运行
实现效果
(1)烧录结果
(2)波形观察
设置下面的“Dialog DLL”项为“DARMSTM.DLL”和“TARMSTM.DLL”;parameter项为“-pSTM32F103ZE”,用于设置支持STM32F103ZE的软硬件仿真。
因为在观测波形时发现波形卡住不动,因此进行如下设置,如果没有遇到此情况,则可忽略下面2步骤。
本文就是卡着不动了。
因此接下来采用第二种方法,观察结果如下
总结
将uc/OS-III移植到STM32F103上作为嵌入式实时操作系统是一项颇具挑战性的任务,但以下是几个关键步骤,有助于顺利完成移植和任务执行。
首先,需要熟悉uc/OS-III的体系结构和API,以及STM32F103的硬件特性。这包括对处理器寄存器的配置、中断处理程序的设计、内存管理的设置等。
其次,根据uc/OS-III的移植要求,需要定制一些硬件相关的代码。这包括编写处理器相关的启动代码、硬件抽象层代码、中断服务程序等。同时,还需要为uc/OS-III的各种任务和队列等数据结构分配适当的内存空间。
在移植过程中,需要仔细检查每个步骤和设置,确保没有遗漏或错误。这包括核对API函数调用、参数设置、文件路径等。此外,还需要进行编译和调试,确保移植的正确性和稳定性。
最后,完成移植后,可以执行任务并测试系统的性能。这包括创建任务、分配优先级、启动系统等。同时,还需要进行功能和性能测试,以确保系统符合预期并能够正确地完成任务。
总之,将uc/OS-III移植到STM32F103上是一项需要细心和耐心的任务,但通过这个过程,我们可以增强对uc/OS-III系统的理解,提高处理器的任务管理能力,并为后续的开发和应用奠定坚实的基础。
参考
https://blog.csdn.net/qq_46467126/article/details/121441622
https://blog.csdn.net/m0_37788080/article/details/116606051