STM32移植ucos-III并实现多任务——HAL

文章目录

  • 前言
  • 一、uC/OS-III简介
    • 1、什么是uC/OS-III
    • 2、uC/OS-III的特点
  • 二、基于HAL库stm32移植uC/OS-III
    • 1、STM32CubeMX新建一个工程
    • 2、用keil打开工程完成uC/OS-III的移植
  • 三、对一些文件的修改
  • 四、代码编写及实际效果展示
    • 1. main.c
    • 2.实物效果
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


一、uC/OS-III简介

1、什么是uC/OS-III

  • uC/OS-III(Micro C OS Three 微型的C 语言编写的操作系统第3版)是一个可升级的可固化的,基于优先级的实时内核。它对任务的个数无限制。uC/OS-III 是一个第3 代的系统内核,支持现代的实时内核所期待的大部分功能。例如资源管理,同步,任务间的通信等等。然而,uC/OS-III 提供的特色功能在其它的实时内核中是找不到的,比如说完备的运行时间测量性能,直接地发送信号或者消息到任务,任务可以同时等待多个内核对象等。
  • uC/OS-III 是一个可扩展的,可固化的,抢占式的实时内核,它管理的任务个数不受限制。它是第三代内核,提供了现代实时内核所期望的所有功能包括资源管理、同步、内部任务交流等。uC/OS-III 也提供了很多特性是在其他实时内核中所没有的。比如能在运行时测量运行性能,直接得发送信号或消息给任务,任务能同时等待多个信号量和消息队列。

2、uC/OS-III的特点

  • 抢占式多任务处理
    uC/OS-III是一个抢占式多任务处理的内核,因此,uC/OS-III正在运行的经常是最重要的就绪任务。
  • 源代码
    uC/OS-III 完全根据ANSI-C 标准写的。代码的规范是Micrium 团队的一种文化。虽然很多商业内核供应商提供他们产品的源代码,但是这些产品很有可能是笨重且难以利用的。除非代码严格地遵循标准并且产品有完整的带例子的说明书以展示代码是怎样工作的。
  • 应用程序接口(API)
    uC/OS-III 是很直观的。如果你熟悉类似的编码规范,你能轻松地知道函数名所对应的服务,以及需要怎样的参数。例如:指向对象的指针通常是第一个参数,指向错误代码的指针通常是最后一个参数。
  • 快速响应中断
    uC/OS-III 有一些内部的数据结构和变量。uC/OS-III 保护临界段可以通过锁定调度器代替关中断。因此关中断的时间会非常少。这样就使uC/OS-III 可以响应一些非常快的中断源了。
  • 可扩展性
    根据应用的需求,代码大小可以被调整。编译时通过调整uC/OS-III 源代码中的大约40 个#define(见OS_CFG.H)可以在添加或移除一些功能。uC/OS-III 的服务还提供一些实时检查功能。特别的,uC/OS-III 能检传递的参数是否为NULL 指针,ISR 是否就绪了任务级服务。参数有允许范围,指定选项都是有用的。检测功能可以被关闭(在编译时)以提供更好的性能和缩减代码大小。实际上,可扩展的uC/OS-III 支持更广泛的应用和项目。
  • 易移植性
    uC/OS-III 可以被移植到大部分的CPU 架构中。大部分的支持uC/OS-II 的器件通过改动就能支持uC/OS-III。而uC/OS-II已经移植到45 种CPU 架构中了。
  • 任务数量无限制
    uC/OS-III 对任务数量无限制。实际上,任务的数量限制于处理器能提供的内存大小。每一个任务需要有自己的堆栈空间,uC/OS-III 在运行时监控任务堆栈的生长。uC/OS-III 对任务的大小无限制,
  • 优先级无限制
    uC/OS-III 对优先级的数量无限制。然而,配置uC/OS-III 的优先级在32 到256 之间已经满足大多数的应用了。
  • 可实时配置性
    uC/OS-III 允许用户在运行时配置内核。特别的,所有的内核对象如任务、堆栈、信号量、事件标志组、消息队列、消息、互斥信号量、内存分区、软件定时器等都是在运行时分配的,以免在编译时的过度分配。
  • 挂起多个对象
    uC/OS-III 允许任务等待多个事件的发生。特别的,任务可以同时等待多个信号量和消息队列被提交。等待中的任务在事件发生的时候被唤醒。
  • 可优化性
    uC/OS-III 被设计于能够根据CPU 的架构被优化。uC/OS-III 所用的大部分数据类型能够被改变,以更好地适应CPU 固有的字大小。优先级调度法则可以通过编写一些汇编语言而获益于一些特殊的指令如位设置、位清除、计数清零指令(CLZ),find-first-one(FF1)指令。

二、基于HAL库stm32移植uC/OS-III

1、STM32CubeMX新建一个工程

  • New Project
    STM32移植ucos-III并实现多任务——HAL_第1张图片
  • 芯片选型
    STM32移植ucos-III并实现多任务——HAL_第2张图片
  • 配置是时钟和gpio
    STM32移植ucos-III并实现多任务——HAL_第3张图片
  • 配置串口
    STM32移植ucos-III并实现多任务——HAL_第4张图片
  • 配置时钟树
    STM32移植ucos-III并实现多任务——HAL_第5张图片
  • 导出工程
    STM32移植ucos-III并实现多任务——HAL_第6张图片
    STM32移植ucos-III并实现多任务——HAL_第7张图片

2、用keil打开工程完成uC/OS-III的移植

  • uCOS源码下载
    百度网盘链接
    链接: https://pan.baidu.com/s/1cdVei7GmbKfZGAFT7IfGQw
    提取码:ucos

下载下来如下
STM32移植ucos-III并实现多任务——HAL_第8张图片

  • 打开keil工程,添加文件
    STM32移植ucos-III并实现多任务——HAL_第9张图片
  • 添加如下文件
    STM32移植ucos-III并实现多任务——HAL_第10张图片
  • 并在这些文件添加我们刚刚下载的库
    CPU->/uC-CPU中
    STM32移植ucos-III并实现多任务——HAL_第11张图片
    LIB->/uC-LIB中
    STM32移植ucos-III并实现多任务——HAL_第12张图片
    PORT->/Generic/RealView中
    STM32移植ucos-III并实现多任务——HAL_第13张图片
    SOURCE->/uCOS-III/SOURCE
    STM32移植ucos-III并实现多任务——HAL_第14张图片
    CONFIG->/uC-CONFIG
    STM32移植ucos-III并实现多任务——HAL_第15张图片
    BSP->/uC_BSP
    STM32移植ucos-III并实现多任务——HAL_第16张图片
    至此,文件的添加工作已经完毕,后面需要导入头文件
  • 为工程添加头文件路径
    STM32移植ucos-III并实现多任务——HAL_第17张图片
    对整个工程文件的添加以及路径修改已经完成,接下来就是对工程内一些文件夹的修改

三、对一些文件的修改

  • 找到启动文件,将以下修改成我这样
    STM32移植ucos-III并实现多任务——HAL_第18张图片
    STM32移植ucos-III并实现多任务——HAL_第19张图片
  • 找到app_cfg.h文件修改成我这样
    STM32移植ucos-III并实现多任务——HAL_第20张图片
    STM32移植ucos-III并实现多任务——HAL_第21张图片
  • 找到icludes.h文件修改成我这样
    STM32移植ucos-III并实现多任务——HAL_第22张图片
  • 找到lib_cfg.h文件修改成我这样
    STM32移植ucos-III并实现多任务——HAL_第23张图片
  • keil的一些修改
    STM32移植ucos-III并实现多任务——HAL_第24张图片

至此,所有都已经完成,可以编写程序运行看效果了

四、代码编写及实际效果展示

1. main.c

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include 
#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 		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 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);	
								 
	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_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 */
  }
}

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 world \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)
{

}

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

编译无错误
STM32移植ucos-III并实现多任务——HAL_第25张图片

2.实物效果


总结

在实际实验过程中,并不是一帆风顺的,会遇到许许多多的问题。遇到了问题我们要善于上网查询资料,找到我们想要的答案,操作系统之前我并没有接触过,在实际移植过程中,我们要细心一点,就不会遇到许多奇奇怪怪的问题,加油!加油!

你可能感兴趣的:(stm32,单片机,arm)