基于HAL库移植μCOS

前言
  在之前的博客中,讲解的都是模块化、功能独立的基础内容。实质上之前的学习还算不上嵌入式,只能说是单片机。前期从学习层面考虑,模块化学习更易入门理解,同时为后续集成开发,做项目实践做积累。在实际项目和应用实践中需要移植操作系统,在本次博客中主要介绍移植操作系统,并将之前的模块化的功能通过系统实现。

一、嵌入式操作系统

1.嵌入式与单片机

  嵌入式系统,以应用为中心,以计算机技术为基础,软硬件可切割,适用于对功能、可靠性、成本、体积、功耗等有严格要求的特殊计算机系统。

  以应用为中心表明嵌入式系统具有明确的实际用途。以计算机技术为基础,表明它实际上是一种特殊的计算机。硬件和软件都可以切割,说明它具有很强的灵活性和可定制性。

  特殊计算机系统,“特殊”对应“一般”。我们经常使用个人PC、笔记本电脑、数据中心服务器,可以用于多种用途,是“通用计算机系统”。

  而单片机又称微控制器Microcontroller,英文全称为Single-Chip Microcomputer,我们了解或者听得比较多的也就是51和STM32。

<font name="宋体“ size=3>实际上是一个集成电路芯片,它是一种超大规模集成电路技术,把CPU、RAM、ROM、输入/输出和中断系统、定时器/计数器等功能都塞进一个硅片,变成一台微型计算机。这么看来,单片机不就是嵌入式系统吗?

  答主认为二者还是存在差别:(答主个人想法)

  嵌入式通俗来讲说,就是在已有的硬件上移植操作系统。而单片机的工作模式是利用软件编程控制硬件,实现一些功能,中间不会经过操作系统。二者的区别如下所示:

  单片机: 软件 —— 硬件
  嵌入式: 软件 ——操作系统——硬件

2.操作系统的定义

  **操作系统(Operating System,简称OS)**是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。

  简单地说,操作系统是用户和计算机的接口,同时也是计算机硬件和其他软件的接口。

  单片机通过软件直接控制硬件。在这种情况下:当用户想在另一个新的硬件平台实现相同的功能就面临着如下两个问题:

  🎈软件程序一定会发生改动。

  🎈软件开发者必须要先了解这个新的硬件平台,才能进行软件编程。

  如果在硬件开发时,没有采用操作系统,存在如下缺点:

  🎈软件开发者必须懂硬件,降低了开发效率。

  嵌入式是通过操作系统,间接控制硬件。因此当硬件平台发生改变,但是依旧与操作系统兼容,那么软件程序就不会改变。并且软件开发人员不需要了解硬件,只要学会操作系统中功能的调用,极大地提高了效率。因此嵌入式引入操作系统,他的优点如下:

  🎈软件移植性好。

  🎈软件开发人员不需要懂硬件,极大地提高了开发效率。

  🎈操作系统提供了很多开源的软件,工具,库。

  🎈操作系统提供了很多开源的软件,工具,库。

  🎈可以实现多任务。(所谓的多任务就是快速切换)。

二、μCOS系统移植

1.系统移植概念

  “移植”,大家可以对比 器官移植 整个概念。系统的移植,就是将系统代码从原生地,挪到其他的硬件芯片上,验证能不能跑的通。

  对于下文介绍的μCOS系统移植,移植原理就是将μCOS系统代码从原生地,挪到其他的硬件芯片上。μCOS的设计和实现上,充分考虑了未来系统代码移植的需求。比如使用C语言编写μCOS系统。代码组件化设计开发,将代码根据需求分为硬件不相关硬件相关应用相关三大类。方便了后续的代码移植工作。

2.μCOS介绍

  μC/OS-II是一个完整的、可移植、可固化、可裁剪的抢占式实时多任务内核。μC/OS-II绝大部分的代码是用ANSII的C语言编写的,包含一小部分汇编代码,使之可供不同架构的微处理器使用。

  任何的软件系统必须依赖于硬件才能够实现其软件的价值。μCOS作为一种软件的实时系统,必须依附于硬件系统才能够完成具体的任务。下面主要介绍在目前最流行单片机硬件控制器(STM32)上移植μCOS实时系统并进行简单的开发验证工作。

3.μCOS移植硬件需求

  μCOS的系统移植,必须对环境进行匹配检查。对于硬件处理器的需求如下图所示
在这里插入图片描述

  🎐中断需求:UCOS的启动和正常运行,尤其是前面提到的heartbeat都是依赖于定时中断

  🎐编译器需求:开关中断,处理器的汇编语言操作都需要由编译器支撑

  🎐处理器堆栈:在保存中断上下文和中断现场中,需要使用处理器提供的堆栈

  🎐处理器指令:对于特殊寄存器的访问,需要处理器开放操作指令

4.μCOS代码架构

  μCOS系统在设计和开发过程中,充分考虑了未来代码的移植可能性,实现了代码的组件化设计。这样,与硬件系统无关的代码,只要满足了编译器的需求,即可以无修改的进行代码直接复制。与硬件相关的代码部分,需要使用待移植硬件的特定指令和硬件特点进行移植。而与应用相关的部分,则需要根据具体的应用场景进行配置
在这里插入图片描述

  OS_CFG.H头文件:主要用于配置ucos的配置类宏定义,即是否开启ucos的某些功能或者配置。

  其中:功能开关类,EN置位表示启用ucos对应软件功能。

  INCLUDE.H头文件,是一个主头文件,被每个C源文件所引用,所以一些通用的引用关系和声明都在该文件中进行声明和引用。

  OS_CPU_A.ASM汇编文件,为整个移植工作的核心部分。具体而言,需要使用汇编语言实现以下4个主要接口,实现系统的任务级别调度功能。

  OS_CPU_C.C该文件需要实现以下10个标准函数。其中OSTaskStkInit为必须实现。

  OS_CPU.H头文件,定义了与处理器(CPU)有关的常数,宏定义以及数据类型。

  

三、实验内容

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

四、Cubemx新建HAL工程

1.配置时钟源

  点击"RCC"-选择“HSE”-选择“外部时钟源”
在这里插入图片描述

2.配置调试接口

  点击“SYS”-“Debug”-选择“Serial Wire
在这里插入图片描述

3.配置GPIO接口

  在实验的要求中,实现两个LED灯的亮灭。因此配置两路GPIO输出端口

  在这里答主选择PA3PA10复用为GPIO_OUTPUT,配置如下:
在这里插入图片描述

4.配置UART串口输出

  点击“Connectivity”-选择“USART1”–配置为"异步通信 Asynchronous““-最后"中断使能
在这里插入图片描述

5.输出配置代码

  按照之前的博客教程输出代码即可,如下图所示:
在这里插入图片描述
在这里插入图片描述

五、系统移植

1.μCOS源码下载

  官网下载入口

  github下载地址:

  打开gihub后看到如下文件。其中,μCOS-BSPμCOS-config是自己新建的文件夹,可以不用下载,如果觉得后续配置是重复造轮子,就可以全部下载下来(答主移植到STM32F103C8系列)

在这里插入图片描述

2.移植前准备

  如果将答主上述的μCOS-BSP与μCOS-config全部下载下来的话,就可以直接跳过(1),(2)步

  (1)新建uC-BSP文件夹,在其内新建bsp.c和bsp.h文件在这里插入图片描述

  (2)新建文件夹μCOS-config添加以下文件(从以下路径复制过来)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  (3)将μCOS相关文件复制到HAL工程的MDK-ARM文件夹下,也就是在前面配置好的MDK代码文件。

在这里插入图片描述
在这里插入图片描述

3.开始移植

  (1)打开MDK文件,将μCOS文件添加到项目中

  首先,点击"文件管理"按钮,

在这里插入图片描述

  为项目新建文件夹如下所示:

在这里插入图片描述

  之后,为新建的文件夹添加文件

  🎈CPU🎈

  点击CPU–>Add Files…,选中以下文件,Add

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  🎈LIB🎈

  点击LIB–>Add Files…,选中以下文件,Add

在这里插入图片描述
在这里插入图片描述
  🎈PORT🎈

  点击PORT–>Add Files…,选中以下文件,Add

在这里插入图片描述
  🎈SOURCE🎈

  点击SOURCE–>Add Files…,选中以下文件,Add

在这里插入图片描述

  🎈CONFIG🎈

  点击CONFIG–>Add Files…,选中以下文件,Add

在这里插入图片描述

  🎈BSP🎈

  点击BSP–>Add Files…,选中以下文件,Add

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  最后,一定要点击“OK”保存!!!!!,此时发现项目结构发生变化

在这里插入图片描述

  (2)将第(1)步中添加的文件的文件路径包含进来

在这里插入图片描述
在这里插入图片描述
  (3)为bsp.cbsp.h添加代码

  bsp.h添加代码如下:

// 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

  (3)修改startup_stm32f103xb_s文件内容

  将PendSV_Handler 修改为OS_CPU_PendSVHandler ;将 SysTick_Handler 修改为OS_CPU_SysTickHandler

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  (4)修改文件app_cfg.h

在这里插入图片描述
  (5)修改文件includes.h

  在#include <bsp.h>代码下添加如下代码:

#include "gpio.h"
#include "app_cfg.h"

在这里插入图片描述

  继续修改#include "stm32f10x_lib.h" #include "stm32f1xx_hal.h"

在这里插入图片描述

  (6)修改文件lib_cfg.h

  此处修改为5(该处宏定义设置堆空间的大小,STM32F103C8T6的RAM只有20K,所以要改小一点)

在这里插入图片描述

  (6)在uart.c中添加重定向代码

/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f){
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
	return ch;
}
/* USER CODE END 1 */

  (7)配置环境参数

在这里插入图片描述

六、实验关键代码

1.添加初始化代码

  打开gpio.c文件,初始GPIO.3

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);

}

2.修改main()函数

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include "stm32f1xx_hal.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* 任务优先级 */
#define START_TASK_PRIO		3
#define LED0_TASK_PRIO		4
#define MSG_TASK_PRIO		5
#define LED1_TASK_PRIO		6

/* 任务堆栈大小	*/
#define START_STK_SIZE 		64
#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 PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 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_pa1(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 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

//  HAL_Init();
//  SystemClock_Config();
//  MX_GPIO_Init();
//  MX_USART1_UART_Init();
	
	
	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). */

				 
				 

  /* USER CODE BEGIN WHILE */
//  while (1)
//  {
//    /* USER CODE END WHILE */
//	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);		//设置PC为高电平
//	HAL_Delay(500);				//延时500ms
//	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
//	HAL_Delay(500);
//    /* USER CODE BEGIN 3 */
//  }
  /* USER CODE END 3 */
}





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_pa1, 			
                 (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, 0, 500,OS_OPT_TIME_HMSM_STRICT,&err);
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
		OSTimeDlyHMSM(0, 0, 0, 500,OS_OPT_TIME_HMSM_STRICT,&err);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

static  void  led_pa1 (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 μCOS! \r\n");
			printf("Fighting!细心,一定要细心!!! \r\n");
			//printf("多任务环境!\r\n");
		OSTimeDlyHMSM(0, 0, 0, 500,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)
{

}













/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  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 buses 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 BEGIN 4 */

/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: 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****/

 

3.编译

在这里插入图片描述

  编译成功!

4.烧录程序

  利用FLYmcu将代码烧录到单片机中
在这里插入图片描述

5.实物运行

在这里插入图片描述

七、总结

  在移植过程中,一定要要注意细节和耐心,注意每一步。不要像答主(憨憨本憨)一样,一早就一直好了,结果一运行,报了很多错误,在网上找相关资料后,提示我这个错误是因为“堆空间不够”????!!离谱,真的当时感觉非常离谱,本来给的空间就很大,怎么可能空间不够!
在这里插入图片描述
  开始一直都以为是移植过程中出了问题,后续发现不对劲,改代码完全没有用,结果返回去查看Cubemx发现!!!!!芯片选错了……So,大家一定要细心!!!
在这里插入图片描述

参考文献

[1] https://blog.csdn.net/m0_67034740/article/details/124103073
[2] https://blog.csdn.net/m0_67034740/article/details/124103073

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值