STM32F103C8T6基于HAL库移植μC/OS

本文介绍了嵌入式实时操作系统(RTOS),以μC/OS为例,将其移植到stm32F103上,构建至少3个任务(task):其中两个task分别以1s和3s周期对LED灯进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。记录了详细的移植过程。

一.题目描述

  1. 学习嵌入式实时操作系统(RTOS),以uc/OS为例,将其移植到stm32F103上,构建至少3个任务(task):其中两个task分别以1s和3s周期对LED灯进行点亮-熄灭的控制;另外一个task以2s周期通过串口发送“hello uc/OS! 欢迎来到RTOS多任务环境!”。记录详细的移植过程。

二.嵌入式实时操作系统(RTOS)

(一)RTOS简介

实时多任务操作系统(Real Time Operating System,简称RTOS)是根据操作系统的工作特性而言的,实时是指物理进程的真实时间。实时操作系统是指具有实时性,能支持实时控制系统工作的操作系统。其首要任务是调度一切可利用的资源完成实时控制任务,其次才着眼于提高计算机系统的使用效率,重要特点是要满足对时间的限制和要求。

实时多任务操作系统(RTOS)是嵌入式应用软件的基础和开发平台。大多数嵌入式开发还是在单片机上直接进行,没有RTOS,但仍要有一个主程序负责调度各个任务。RTOS是一段嵌入在目标代码中的程序,系统复位后首先执行,相当于用户的主程序,用户的其他应用程序都建立在RTOS之上。不仅如此,RTOS还是一个标准的内核,将CPU时间、中断、I/O、定时器等资源都包装起来,留给用户一个标准的API(系统调用),并根据各个任务的优先级,合理地在不同任务之间分配CPU时间。

我们常常说的嵌入式操作系统都是嵌入式实时操作系统。比如μClinux、μC/OS-II、eCos、FreeRTOS、mbed OS、RTX、Vxworks、QNX、NuttX等,而国产的嵌入式操作系统包括都江堰操作系统(djyos)、Alios Things、Huawei LiteOS、RT-Thread、SylixOS等。

(二)μC/OS简介

μC/OS:Micrium公司下的一款实时操作系统(RTOS)。
以µC/OS-II或µC/OS-III为内核,附带有多种插件以实现不同的功能。这款操作系统主要面向于微处理器,如单片机、DSP等。它具有优秀的可移植性、功能可伸展性等特点,是抢占式的硬实时多任务操作系统。

它是以源代码的形式分发,附有相当完善的资料。开发时可以按需调整内核的体积,占用代码空间为6-24KB,以及数据空间1KB,以适用多种硬件环境。可以支持无限任务、无限优先级。系统中断时进入临界区时间极短,能用于安全要求高的产品中。2另外,Micrium还提供了多种扩展配合使用,包括有TCP/IP网络协议支持、USB通信协议支持、文件系统、图形界面等等。

1.μC/OS特性

  • 可移植性。 提供前所未有的易用性,μC/OS内核提供完整的源代码和深入的文档。 μC/ OS内核运行在大量处理器架构上,端口可供下载。

  • 可扩展性。 μC/ OS内核允许无限制的任务和内核对象。内核的内存占用可以缩小,仅包含应用程序所需的功能,通常为6-24 KB的代码空间和1KB的数据空间。

  • 可靠。 μC/ OS内核包括减少开发时间的调试功能。内核提供广泛的范围检查,包括检查API调用中传递的指针,来自ISR的任务级服务,允许范围内的参数以及有效的指定选项。

  • 高效。 Micrium的内核还包括有价值的运行时统计信息,使您的应用程序的内部可视化。 识别性能瓶颈,并在开发周期的早期优化电源使用。

μC/ OS内核的特性包括以下亮点(Highlights):

  • 抢占式多任务实时内核,可选择循环调度
  • 提供完整,干净,一致的源代码,具有深入的文档。
  • 高可扩展性:无限数量的任务,优先级和内核对象
  • 同时等待多个内核对象
  • 直接向任务发送信号/消息
  • 资源高效:6K至24K字节代码空间,1K +字节数据空间)
  • 非常低的中断禁用时间
  • 广泛的性能测量指标(可配置)
  • 可用于关注安全型应用

2.μC/OS移植

所谓移植,就是使一个实时内核能在某个微处理器或微控制器上运行。为了方便移植,大部分的µC/OS-Ⅱ代码是用C语言写的;但仍需要用C和汇编语言写一些与处理器相关的代码。
要使µC/OS正常运行,处理器必须满足以下要求:

  1. 处理器的C编译器能产生可重入代码。

l 用C语言就可以打开和关闭中断。

l 处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。

l 处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。

l 处理器有将堆栈指针和其它CPU寄存器读出和存储到堆栈或内存中的指令。

像Motorola 6805系列的处理器不能满足上面的第4条和第5条要求,所以µC/OS不能在这类处理器上运行。
2. 移植工作包括以下几个内容:

l 用#define设置一个常量的值(OS_CPU.H)

l 声明10个数据类型(OS_CPU.H)

l 用#define声明三个宏(OS_CPU.H)

l 用C语言编写六个简单的函数(OS_CPU_C.C)

l 编写四个汇编语言函数(OS_CPU_A.ASM)

根据处理器的不同,一个移植实例可能需要编写或改写50至300行的代码,需要的时间从几个小时到一星期不等。
一旦代码移植结束,下一步工作就是测试。测试一个象µC/OS一样的多任务实时内核并不复杂。甚至可以在没有应用程序的情况下测试。换句话说,就是让内核自己测试自己。这样做有两个好处:第一,避免使本来就复杂的事情更加复杂;第二,如果出现问题,可以知道问题出在内核代码上而不是应用程序。刚开始的时候可以运行一些简单的任务和时钟节拍中断服务例程。一旦多任务调度成功地运行了,再添加应用程序的任务就是非常简单的工作了。

如前所述,移植µC/OS需要一个C编译器,并且是针对用户用的CPU的。因为µC/OS是一个可剥夺型内核,用户只有通过C编译器来产生可重入代码;C编译器还要支持汇编语言程序。绝大部分的C编译器都是为嵌入式系统设计的,它包括汇编器、连接器和定位器。连接器用来将不同的模块(编译过和汇编过的文件)连接成目标文件。定位器则允许用户将代码和数据放置在目标处理器的指定内存映射空间中。所用的C编译器还必须提供一个机制来从C中打开和关闭中断。一些编译器允许用户在C源代码中插入汇编语言。这就使得插入合适的处理器指令来允许和禁止中断变得非常容易了。还有一些编译器实际上包括了语言扩展功能,可以直接从C中允许和禁止中断。

三.实验过程

(一)建立CubeMX工程

  1. 打开STM32 CubeMX,选择芯片stm32f103c8t6,配置系统时钟为72M.在这里插入图片描述
    在这里插入图片描述

  2. 配置RCC在这里插入图片描述

  3. 配置SYS在这里插入图片描述

  4. 配置USART1在这里插入图片描述

  5. 设置PA3 PC13
    在这里插入图片描述
    在这里插入图片描述
    作为两个LED的输出控制

  6. 其他设置
    注意路径中不能出现中文在这里插入图片描述
    在这里插入图片描述
    打开工程文件,在keil中修改
    在这里插入图片描述

(二)获取uCOS-III源码

进入 Micrium 公司官网下载中心: http://micrium.com/downloadcenter/
选择ST系列,点击View all STMicroelectronics,点击 STMicroelectronics STM32F107
之后按照提示注册下载即可。

可直接下载此网盘链接内容
链接: https://pan.baidu.com/s/10RqsDRecbmVteWmDv2oUNQ
提取码:1234

(三)移植前的文件准备

打开下载好的源码,将一下5个文件复制到cubeMX工程的MDK-ARM文件夹下
在这里插入图片描述
在这里插入图片描述

(四)移植过程

打开cubeMX生成的keil文件

1.将uCOS文件添加到项目中

点击Manage Project Items,按下图所示操作,为项目新建文件夹,在对应文件夹下添加文件。
在这里插入图片描述

  1. 为CPU添加文件
    点击CPU–>Add Files…
    MDK-ARM\uC-CPU路径下选中以下文件,点击Add或双击文件添加在这里插入图片描述
    MDK-ARM\uC-CPU\ARM-Cortex-M3\RealView路径下选中以下文件,点击Add或双击文件添加在这里插入图片描述

  2. 为LIB添加文件
    LIB–>Add Files…
    MDK-ARM\uC-LIB路径下选中下图红框文件,点击Add或双击文件添加在这里插入图片描述

MDK-ARM\uC-LIB\Ports\ARM-Cortex-M3\RealView路径下选中下图红框文件,点击Add或双击文件添加
在这里插入图片描述

  1. 为PORT添加文件
    PORT–>Add Files…
    MDK-ARM\uCOS-III\Ports\ARM-Cortex-M3\Generic\RealView路径下选中以下文件,点击Add或双击文件添加在这里插入图片描述

  2. 为CONFIG添加文件
    CONFIG–>Add Files…
    MDK-ARM\uC-CONFIG路径下选中以下全部文件,点击Add或双击文件添加在这里插入图片描述

  3. 为BSP添加文件
    BSP–>Add Files…
    MDK-ARM\uC-BSP路径下选中以下全部文件,点击Add或双击文件添加在这里插入图片描述

  4. 为SOURCE添加文件
    SOURCE–>Add Files…
    MDK-ARM\uCOS-III\Source路径下选中以下全部 .c .h 文件,点击Add或双击文件添加
    在这里插入图片描述

最后一定要点击OK 点击OK 点击OK,不然以上六部的操作就白做了!!!!!!!!!!!!!

2.导入文件路径

按下图所示步骤操作即可在这里插入图片描述

3.构建三个任务

(1)代码编写
  • 为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添加(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 */

在这里插入图片描述

(2)初始化管脚

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);//将PC13LED周期设置为1秒
    /* 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);//将PA3LED周期设置为3秒
		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!欢迎来到RTOS多任务环境!\r\n");
		OSTimeDlyHMSM(0, 0, 2,0,OS_OPT_TIME_HMSM_STRICT,&err);//将周期设置为2秒
    /* 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
在这里插入图片描述
编译无误后,即可烧录

(五)实现效果

1.线路连接

USB to TTL——STM32F103
3V3 —— 3V3
GND ——GND
RXD ——A9
TXD ——A10
STM32F103——LED
PA3——LED短脚
3V3——LED长脚
在这里插入图片描述

2.烧录

打开烧录软件,选择烧录文件
boot0置1,boot1置0
在这里插入图片描述

3.视频展示

1s和3s周期对LED等进行点亮

2s周期通过串口发送“hello uc/OS! “

四.总结

通过本次实验学习了嵌入式实时操作系统(RTOS)的基本原理,通过提供的链接按部就班地完成了以μC/OS为例,将其移植到stm32F103上,构建至少3个任务的实验;在进行uCOS移植时,务必要仔细,否则在编译时很容易报一大堆错误,原因只是因为在移植过程中汇编代码的缩进和添加文件的遗漏,注意参数、文件路径的设置等问题;可以发现这次实验由于代码地增多,烧录文件大小明显增大;移植步骤一定注意完成后点击OK保存,不然所做的工作就将付之东流。

五.参考链接

1: https://blog.csdn.net/gaoji0526/article/details/81184105?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166730569716800182768855%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166730569716800182768855&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-81184105-null-null.142v62pc_search_tree,201v3control_1,213v1control&utm_term=OSTimeDlyHMSM%28%29&spm=1018.2226.3001.4187
2: https://blog.csdn.net/qq_46467126/article/details/121441622
3: https://blog.csdn.net/wangyijieonline/article/details/77584726?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166769855316800192262721%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166769855316800192262721&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~hot_rank-1-77584726-null-null.nonecase&utm_term=RTOS&spm=1018.2226.3001.4450
4: https://blog.csdn.net/menuconfig/article/details/1719167?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166769902316782417034945%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166769902316782417034945&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~hot_rank-1-1719167-null-null.nonecase&utm_term=%C2%B5C%2FOS&spm=1018.2226.3001.4450link
5: https://blog.csdn.net/P837091317/article/details/101160647?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166769902316782417034945%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166769902316782417034945&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~hot_rank-13-101160647-null-null.nonecase&utm_term=%C2%B5C%2FOS&spm=1018.2226.3001.4450

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值