将uc/OS-III移植到stm32F103上的嵌入式实时操作系统(RTOS)-HAL库

前言

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

111

(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系统的理解,提高处理器的任务管理能力,并为后续的开发和应用奠定坚实的基础。

  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值