[其他ST产品] 使用 FreeRTOS 和 HAL 库的 STM32 例程,多个任务例程

[复制链接]
2189|33
 楼主| 1988ChenSir 发表于 2023-5-29 16:03 | 显示全部楼层 |阅读模式
本帖最后由 1988ChenSir 于 2023-5-29 16:04 编辑



使用 FreeRTOS 和 HAL 库的 STM32 例程,多个任务例程使用 FreeRTOS 和 HAL 库的 STM32 例程,它包含多个任务来控制 LED 灯的闪烁、串口数据发送和按键检测:
  1. #include "main.h"
  2. #include "cmsis_os.h"
  3. #include <stdio.h>

  4. // 定义全局变量
  5. TIM_HandleTypeDef htim2;
  6. UART_HandleTypeDef huart2;
  7. osThreadId defaultTaskHandle, uartTaskHandle, buttonTaskHandle;
  8. uint8_t uart_buf[16];
  9. osSemaphoreId uart_sem;

  10. // 声明函数原型
  11. void SystemClock_Config(void);
  12. static void MX_GPIO_Init(void);
  13. static void MX_TIM2_Init(void);
  14. static void MX_USART2_UART_Init(void);
  15. void StartDefaultTask(void const * argument);
  16. void UartSendTask(void const * argument);
  17. void ButtonCheckTask(void const * argument);

  18. int main(void)
  19. {
  20.   // 初始化 HAL 库和 RTOS 内核
  21.   HAL_Init();
  22.   SystemClock_Config();
  23.   MX_GPIO_Init();
  24.   MX_TIM2_Init();
  25.   MX_USART2_UART_Init();

  26.   // 创建默认任务
  27.   osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  28.   defaultTaskHandle = osThreadCreate(osThread(defaultTask));

  29.   // 创建串口发送任务
  30.   osThreadDef(uartTask, UartSendTask, osPriorityNormal, 0, 128);
  31.   uartTaskHandle = osThreadCreate(osThread(uartTask));

  32.   // 创建按键检测任务
  33.   osThreadDef(buttonTask, ButtonCheckTask, osPriorityNormal, 0, 128);
  34.   buttonTaskHandle = osThreadCreate(osThread(buttonTask));

  35.   // 创建信号量
  36.   osSemaphoreDef(uartSem);
  37.   uart_sem = osSemaphoreCreate(osSemaphore(uartSem), 1);

  38.   // 启动 RTOS 内核
  39.   osKernelStart();

  40.   while (1) {}
  41. }

  42. // 默认任务的入口函数
  43. void StartDefaultTask(void const * argument)
  44. {
  45.   for (;;) {
  46.     HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);  // 切换 LED 状态
  47.     osDelay(500);                                // 延迟 500ms
  48.   }
  49. }

  50. // 串口发送任务的入口函数
  51. void UartSendTask(void const * argument)
  52. {
  53.   uint32_t tick_count;
  54.   sprintf((char *)uart_buf, "Hello, world!\r\n");
  55.   for (;;) {
  56.     osSemaphoreWait(uart_sem, osWaitForever);  // 等待信号量
  57.     tick_count = osKernelSysTick();
  58.     HAL_UART_Transmit(&huart2, uart_buf, strlen((char*)uart_buf), 1000);
  59.     tick_count = osKernelSysTick() - tick_count;
  60.     printf("UART send time: %ld\r\n", tick_count);  // 打印发送时间
  61.   }
  62. }

  63. // 按键检测任务的入口函数
  64. void ButtonCheckTask(void const * argument)
  65. {
  66.   GPIO_PinState button_state = GPIO_PIN_SET;
  67.   GPIO_PinState last_state = GPIO_PIN_SET;
  68.   for (;;) {
  69.     button_state = HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin);
  70.     if (button_state != last_state) {
  71.       sprintf((char *)uart_buf, "Button state: %d\r\n", button_state);
  72.       osSemaphoreRelease(uart_sem);  // 发送数据
  73.       last_state = button_state;
  74.     }
  75.     osDelay(10);  // 延迟一段时间
  76.   }
  77. }

  78. // 定时器中断回调函数
  79. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  80. {
  81.   if (htim->Instance == TIM2) {
  82.     HAL_IncTick();  // 增加 HAL 的滴答计数器
  83.     osSystickHandler();  // 调用 RTOS 的 SysTick 处理函数
  84.   }
  85. }

  86. // 配置系统时钟源和频率
  87. void SystemClock_Config(void)
  88. {
  89.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  90.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  91.   __HAL_RCC_PWR_CLK_ENABLE();
  92.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  93.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  94.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  95.   RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  96.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  97.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  98.   {
  99.     Error_Handler();
  100.   }

  101.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  102.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  103.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  104.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  105.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  106.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  107.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  108.   {
  109.     Error_Handler();
  110.   }
  111. }

  112. // 配置 GPIO 和 TIM2
  113. static void MX_GPIO_Init(void)
  114. {
  115.   GPIO_InitTypeDef GPIO_InitStruct = {0};

  116.   __HAL_RCC_GPIOA_CLK_ENABLE();
  117.   __HAL_RCC_GPIOC_CLK_ENABLE();

  118.   GPIO_InitStruct.Pin = LED_Pin;
  119.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  120.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  121.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  122.   HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

  123.   GPIO_InitStruct.Pin = BUTTON_Pin;
  124.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  125.   GPIO_InitStruct.Pull = GPIO_PULLUP;
  126.   HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct);
  127. }

  128. static void MX_TIM2_Init(void)
  129. {
  130.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  131.   TIM_MasterConfigTypeDef sMasterConfig = {0};

  132.   __HAL_RCC_TIM2_CLK_ENABLE();

  133.   htim2.Instance = TIM2;
  134.   htim2.Init.Prescaler = 7999;
  135.   htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  136.   htim2.Init.Period = 999;
  137.   htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  138.   if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  139.   {
  140.     Error_Handler();
  141.   }

  142.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  143.   if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  144.   {
  145.     Error_Handler();
  146.   }

  147.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  148.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  149.   if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  150.   {
  151.     Error_Handler();
  152.   }
  153. }

  154. static void MX_USART2_UART_Init(void)
  155. {
  156.   huart2.Instance = USART2;
  157.   huart2.Init.BaudRate = 115200;
  158.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  159.   huart2.Init.StopBits = UART_STOPBITS_1;
  160.   huart2.Init.Parity = UART_PARITY_NONE;
  161.   huart2.Init.Mode = UART_MODE_TX_RX;
  162.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  163.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  164.   if (HAL_UART_Init(&huart2) != HAL_OK)
  165.   {
  166.     Error_Handler();
  167.   }
  168. }

  169. // 错误处理函数
  170. void Error_Handler(void)
  171. {
  172.   while(1) {}
  173. }



1493964745c37bd4d3.png
Pretext 发表于 2023-5-29 16:48 | 显示全部楼层
多任务的优势就在这。可以同时运行多个任务。
biechedan 发表于 2023-6-7 13:51 | 显示全部楼层
使用HAL库生成的FreeRTOS版本
MessageRing 发表于 2023-6-7 23:10 | 显示全部楼层
直接用cubemx生成的
ingramward 发表于 2023-6-8 13:53 | 显示全部楼层
使用FreeRTOS和HAL库可以方便地实现嵌入式系统的多任务处理。
macpherson 发表于 2023-6-10 17:12 | 显示全部楼层
在使用FreeRTOS和HAL库时,需要合理分配系统资源,避免出现资源冲突和浪费问题。
AloneKaven 发表于 2023-6-10 23:36 | 显示全部楼层
有没有移植freeRTOS的教程啊
minzisc 发表于 2023-6-14 12:56 | 显示全部楼层
可以参考相关文档和示例代码,学习如何使用FreeRTOS和HAL库进行STM32开发。
houjiakai 发表于 2023-6-14 14:41 | 显示全部楼层
安装好Keil或者IAR等开发工具,并下载好相应的HAL库和FreeRTOS源码。
sheflynn 发表于 2023-6-14 19:28 | 显示全部楼层
跑 FreeRTOS 要多大的Flash比较好?
houjiakai 发表于 2023-6-14 19:54 | 显示全部楼层
可以避免在等待延迟时出现意外阻塞任务的情况。
MessageRing 发表于 2023-6-14 22:22 | 显示全部楼层
这是直接使用cubeMX生成的吗?
51xlf 发表于 2023-6-15 21:22 | 显示全部楼层
由于在FreeRTOS环境下使用HAL库,因此建议使用OS编写的延时函数(例如osDelay()函数),而不是HAL库中的延时函数(例如HAL_Delay()函数)。
updownq 发表于 2023-6-15 21:31 | 显示全部楼层
在程序启动时,需要对HAL库和FreeRTOS进行初始化。可以在main函数中或者Startup文件中添加相关代码,以完成系统时钟、外设、任务等方面的初始化工作。
pixhw 发表于 2023-6-15 22:25 | 显示全部楼层
RTOS只是一个操作系统,多任务并行时建议使用RTOS
Bowclad 发表于 2023-6-15 22:34 | 显示全部楼层
使用RTOS会占用多少系统资源啊?
Undshing 发表于 2023-6-16 23:52 | 显示全部楼层
可以保证各个任务的实时性
AloneKaven 发表于 2023-6-17 22:48 | 显示全部楼层
在主函数里加task不就行了
sdlls 发表于 2023-6-19 08:52 | 显示全部楼层
stm32 为什么要用freertos
minzisc 发表于 2023-6-19 10:07 | 显示全部楼层
使用了FreeRTOS会强制使用systick作为自己的心跳?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

18

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部