qidao123.com技术社区-IT企服评测·应用市场

标题: STM32 HAL库 Freertos创建多任务 [打印本页]

作者: 篮之新喜    时间: 2025-4-20 01:06
标题: STM32 HAL库 Freertos创建多任务
1. 引言

STM32F407 是 ST 公司推出的一款高性能微控制器,具有丰富的外设资源和强盛的处理能力。HAL(Hardware Abstraction Layer)库是 ST 为其微控制器提供的硬件抽象层,它简化了硬件操作,提高了开发服从。FreeRTOS 是一个开源的及时操作系统,具有轻量级、可移植性强等特点,广泛应用于嵌入式系统开发中。本文将详细介绍如何基于 STM32F407 HAL 库和 FreeRTOS 创建多任务。
2. 开发环境搭建

在开始开发之前,必要搭建好相应的开发环境。以下是详细步骤:
2.1 安装开发工具


2.2 安装 STM32F407 HAL 库

在 STM32CubeMX 中,通过 “Help” -> “Manage embedded software packages” 安装 STM32F4 系列的 HAL 库。
2.3 安装 FreeRTOS

在 STM32CubeMX 中,通过 “Middleware” -> “RTOS” 选择 FreeRTOS 进行安装。
3. 使用 STM32CubeMX 设置项目

打开 STM32CubeMX,创建一个新的项目,选择 STM32F407 芯片。以下是详细的设置步骤:
3.1 设置时钟

在 “RCC” 选项中,选择外部晶振作为时钟源,并设置系统时钟频率为 168MHz。
3.2 设置调试接口

在 “System Core” -> “SYS” 中,选择调试接口为 “Serial Wire”。
3.3 设置 FreeRTOS

在 “Middleware” -> “RTOS” 中,选择 FreeRTOS 的版本和内核选项。可以根据必要设置任务栈大小、优先级等参数。
3.4 天生代码

设置完成后,点击 “Project Manager”,选择天生代码的工具链为 “MDK-ARM”,然后点击 “Generate Code” 天生初始化代码。
4. 创建多任务

打开天生的 Keil 项目,在main.c文件中可以看到 FreeRTOS 的初始化代码。以下是创建多任务的详细步骤:
4.1 界说任务函数

在main.c文件中界说任务函数,每个任务函数都有一个特定的功能。例如,以下是两个简单的任务函数:
  1. #include "main.h"
  2. #include "stm32f4xx_hal.h"
  3. #include "cmsis_os.h"
  4. // 任务句柄
  5. osThreadId Task1Handle;
  6. osThreadId Task2Handle;
  7. // 任务1函数
  8. void Task1(void const * argument)
  9. {
  10.   for(;;)
  11.   {
  12.     // 任务1的具体操作
  13.     HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // 翻转LED引脚
  14.     osDelay(1000);  // 延时1秒
  15.   }
  16. }
  17. // 任务2函数
  18. void Task2(void const * argument)
  19. {
  20.   for(;;)
  21.   {
  22.     // 任务2的具体操作
  23.     HAL_UART_Transmit(&huart1, (uint8_t *)"Task 2 is running!\r\n", 20, 100);  // 发送串口信息
  24.     osDelay(2000);  // 延时2秒
  25.   }
  26. }
复制代码
4.2 创建任务

在main.c文件的MX_FREERTOS_Init函数中创建任务。代码如下:
  1. void MX_FREERTOS_Init(void) {
  2.   /* 创建任务 */
  3.   osThreadDef(Task1, Task1, osPriorityNormal, 0, 128);
  4.   Task1Handle = osThreadCreate(osThread(Task1), NULL);
  5.   osThreadDef(Task2, Task2, osPriorityNormal, 0, 128);
  6.   Task2Handle = osThreadCreate(osThread(Task2), NULL);
  7. }
复制代码
4.3 启动调度器

在main函数中启动 FreeRTOS 调度器。代码如下:
  1. int main(void)
  2. {
  3.   HAL_Init();
  4.   SystemClock_Config();
  5.   MX_GPIO_Init();
  6.   MX_USART1_UART_Init();
  7.   MX_FREERTOS_Init();
  8.   /* 启动调度器 */
  9.   osKernelStart();
  10.   while (1)
  11.   {
  12.     // 主循环一般为空
  13.   }
  14. }
复制代码
下面是一个基于 STM32F407 HAL 库和 FreeRTOS 创建多任务的示例代码:
  1. #include "main.h"
  2. #include "stm32f4xx_hal.h"
  3. #include "cmsis_os.h"
  4. // 任务句柄
  5. osThreadId Task1Handle;
  6. osThreadId Task2Handle;
  7. // 任务1函数
  8. void Task1(void const * argument)
  9. {
  10.     for(;;)
  11.     {
  12.         // 任务1的具体操作
  13.         HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // 翻转LED引脚
  14.         osDelay(1000);  // 延时1秒
  15.     }
  16. }
  17. // 任务2函数
  18. void Task2(void const * argument)
  19. {
  20.     for(;;)
  21.     {
  22.         // 任务2的具体操作
  23.         HAL_UART_Transmit(&huart1, (uint8_t *)"Task 2 is running!\r\n", 20, 100);  // 发送串口信息
  24.         osDelay(2000);  // 延时2秒
  25.     }
  26. }
  27. void SystemClock_Config(void);
  28. static void MX_GPIO_Init(void);
  29. static void MX_USART1_UART_Init(void);
  30. static void MX_FREERTOS_Init(void);
  31. int main(void)
  32. {
  33.     HAL_Init();
  34.     SystemClock_Config();
  35.     MX_GPIO_Init();
  36.     MX_USART1_UART_Init();
  37.     MX_FREERTOS_Init();
  38.     /* 启动调度器 */
  39.     osKernelStart();
  40.     while (1)
  41.     {
  42.         // 主循环一般为空
  43.     }
  44. }
  45. void SystemClock_Config(void)
  46. {
  47.     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  48.     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  49.     /** 初始化RCC振荡器
  50.     */
  51.     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  52.     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  53.     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  54.     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  55.     RCC_OscInitStruct.PLL.PLLM = 8;
  56.     RCC_OscInitStruct.PLL.PLLN = 336;
  57.     RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  58.     RCC_OscInitStruct.PLL.PLLQ = 7;
  59.     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  60.     {
  61.         Error_Handler();
  62.     }
  63.     /** 初始化RCC时钟
  64.     */
  65.     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  66.                                   |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  67.     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  68.     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  69.     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  70.     RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  71.     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  72.     {
  73.         Error_Handler();
  74.     }
  75. }
  76. static void MX_GPIO_Init(void)
  77. {
  78.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  79.     /* GPIO Ports Clock Enable */
  80.     __HAL_RCC_GPIOA_CLK_ENABLE();
  81.     /*Configure GPIO pin Output Level */
  82.     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
  83.     /*Configure GPIO pin : PA5 */
  84.     GPIO_InitStruct.Pin = GPIO_PIN_5;
  85.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  86.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  87.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  88.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  89. }
  90. static void MX_USART1_UART_Init(void)
  91. {
  92.     huart1.Instance = USART1;
  93.     huart1.Init.BaudRate = 115200;
  94.     huart1.Init.WordLength = UART_WORDLENGTH_8B;
  95.     huart1.Init.StopBits = UART_STOPBITS_1;
  96.     huart1.Init.Parity = UART_PARITY_NONE;
  97.     huart1.Init.Mode = UART_MODE_TX_RX;
  98.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  99.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  100.     if (HAL_UART_Init(&huart1) != HAL_OK)
  101.     {
  102.         Error_Handler();
  103.     }
  104. }
  105. static void MX_FREERTOS_Init(void)
  106. {
  107.     /* 创建任务 */
  108.     osThreadDef(Task1, Task1, osPriorityNormal, 0, 128);
  109.     Task1Handle = osThreadCreate(osThread(Task1), NULL);
  110.     osThreadDef(Task2, Task2, osPriorityNormal, 0, 128);
  111.     Task2Handle = osThreadCreate(osThread(Task2), NULL);
  112. }
  113. void Error_Handler(void)
  114. {
  115.     while(1)
  116.     {
  117.     }
  118. }   
复制代码
代码解释


任务调度机制剖析

FreeRTOS 支持两种重要的任务调度算法:抢占式调度和时间片轮转调度。
1. 抢占式调度


2. 时间片轮转调度


3. 调度器工作流程


通过以上的设置和机制,FreeRTOS 可以或许有用地管理多个任务的实验,包管系统的及时性和稳定性。


 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4