其他分享
首页 > 其他分享> > 【FreeRTOS实战01】CubeIDE快速整合FreeRTOS创建第一个任务

【FreeRTOS实战01】CubeIDE快速整合FreeRTOS创建第一个任务

作者:互联网

整个专栏主要是博主结合自身对FreeRTOS的实战学习以及源码分析,基于STM32F767 Nucleo-144平台,在CubeIDE下进行开发,结合官方的HAL库,将硬件环节的问题减少到最小,将精力主要放在RTOS的学习上.

文章目录

1 FreeRTOS

FreeRTOS是免费的嵌入式实时系统,可以访问官网,至少目前是免费,并且社区相当活跃,但是以后会不会被割韭菜就不清楚了,所以感觉还是支持国产比较好,大家可以参考一下RT-Thread

1.1 获取源码

我们可以登陆到官网下载源码的压缩包,如下图所示;
在这里插入图片描述
FreeRTOS还将源码托管到github上,登陆官网可以看到下图的两个仓库;

在这里插入图片描述

但是本文暂不会介绍如何移植RTOS,在远古时期,因为第三方的支持力度不够,因此有一些平台只能自己移植,现在第三方的支持相当于给力,直接拿来用即可.

1.2 源码结构

自动生成的代码中找到FreeRTOS的源码如下;


在这里插入图片描述


对于相应的文件夹和源码文件做一下介绍;

2 CubeMX 整合 RTOS

  1. 在配置工程的时候或者打开后缀名为.ioccubemx配置文件;
  2. 点击菜单栏Pinout&Configuration
  3. 点击Middleware选择FREERTOS

具体如下图所示;

在这里插入图片描述

最终生成的文件结构如下图所示;
在这里插入图片描述
这时候已经将FreeRTOS集成到工程中了,*****,简直不能再方便了;

3 新建RTOS任务

直接生成的工程中,系统已经创建好了一个任务StartDefaultTask;
整体的main.c代码如下;

#include "main.h"
#include "cmsis_os.h"

/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .priority = (osPriority_t) osPriorityNormal,
  .stack_size = 128 * 4
};

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
void StartDefaultTask(void *argument);

int main(void)
{
  HAL_Init();
  
  SystemClock_Config();

  MX_GPIO_Init();

  osKernelInitialize();

  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
  /* Start scheduler */
  osKernelStart();
  /* We should never get here as control is now taken by the scheduler */
  while (1)
  {

  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

}
void StartDefaultTask(void *argument)
{
  for(;;)
  {
    osDelay(1);
  }
}

void Error_Handler(void)
{

}

#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)
{ 

}
#endif /* USE_FULL_ASSERT */

这里可以看到整体的流程为两部分HAL层和OS层;

HAL

OS

整体流程图如下所示;

Created with Raphaël 2.2.0开始HAL_InitSystemClock_ConfigBSP_InitosKernelInitializeosThreadNewosKernelStart结束
从OS的设计上来讲,`Thread`拥有自己的`id`,并且可以分配`timer` 并且拥有一个类似线程的任务函数或者称为任务回调函数(可能不太严谨,下面统一称之为任务回调函数),因此这里定义一个FreeRTOS任务需要三点;
  1. osThreadId_t defaultTaskHandle;定义一个变量,后面创建任务会分配一个id作为该任务的唯一标识符/身份证;
  2. osThreadAttr_t defaultTask_attributes;作为定义一个任务时的参数,包括任务的优先级,所需要分配的栈空间大小.以及任务的名字等等;具体结构体osThreadAttr_t如下所示;
typedef struct {
  const char                   *name;   ///< name of the thread
  uint32_t                 attr_bits;   ///< attribute bits
  void                      *cb_mem;    ///< memory for control block
  uint32_t                   cb_size;   ///< size of provided memory for control block
  void                   *stack_mem;    ///< memory for stack
  uint32_t                stack_size;   ///< size of stack
  osPriority_t              priority;   ///< initial thread priority (default: osPriorityNormal)
  TZ_ModuleId_t            tz_module;   ///< TrustZone module identifier
  uint32_t                  reserved;   ///< reserved (must be 0)
} osThreadAttr_t;
  1. 创建任务回调函数,这里有一个生命周期的问题,通常在任务中放一个死循环,以便于任务保持存活,可以被一直调度;
void StartDefaultTask(void *argument)
{
  	for(;;)
  	{
    	osDelay(1);
  	}
}

最后,调用osThreadNew创建任务;该函数声明如下所示;

osThreadId_t osThreadNew (	osThreadFunc_t func, 
							void *argument, 
							const osThreadAttr_t *attr);

4 总结

通过cube自动生成了一个FREERTOS工程,简单分析了一下如何创建一个任务,后续需要在实践中深入到源码中学习FreeRTOS

标签:01,HAL,FreeRTOS,void,任务,CubeIDE,源码,RCC
来源: https://blog.csdn.net/u010632165/article/details/105208751