打印
[其他ST产品]

使用 FreeRTOS 和 HAL 库的 STM32 例程,多个任务例程

[复制链接]
322|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 1988ChenSir 于 2023-5-29 16:04 编辑



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

// 定义全局变量
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart2;
osThreadId defaultTaskHandle, uartTaskHandle, buttonTaskHandle;
uint8_t uart_buf[16];
osSemaphoreId uart_sem;

// 声明函数原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART2_UART_Init(void);
void StartDefaultTask(void const * argument);
void UartSendTask(void const * argument);
void ButtonCheckTask(void const * argument);

int main(void)
{
  // 初始化 HAL 库和 RTOS 内核
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_USART2_UART_Init();

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

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

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

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

  // 启动 RTOS 内核
  osKernelStart();

  while (1) {}
}

// 默认任务的入口函数
void StartDefaultTask(void const * argument)
{
  for (;;) {
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);  // 切换 LED 状态
    osDelay(500);                                // 延迟 500ms
  }
}

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

// 按键检测任务的入口函数
void ButtonCheckTask(void const * argument)
{
  GPIO_PinState button_state = GPIO_PIN_SET;
  GPIO_PinState last_state = GPIO_PIN_SET;
  for (;;) {
    button_state = HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin);
    if (button_state != last_state) {
      sprintf((char *)uart_buf, "Button state: %d\r\n", button_state);
      osSemaphoreRelease(uart_sem);  // 发送数据
      last_state = button_state;
    }
    osDelay(10);  // 延迟一段时间
  }
}

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

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

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

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

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

// 配置 GPIO 和 TIM2
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  GPIO_InitStruct.Pin = LED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = BUTTON_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct);
}

static void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  __HAL_RCC_TIM2_CLK_ENABLE();

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 7999;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 999;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_USART2_UART_Init(void)
{
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
}

// 错误处理函数
void Error_Handler(void)
{
  while(1) {}
}



1493964745c37bd4d3.png (141.47 KB )

1493964745c37bd4d3.png

使用特权

评论回复
沙发
Pretext| | 2023-5-29 16:48 | 只看该作者
多任务的优势就在这。可以同时运行多个任务。

使用特权

评论回复
板凳
biechedan| | 2023-6-7 13:51 | 只看该作者
使用HAL库生成的FreeRTOS版本

使用特权

评论回复
地板
MessageRing| | 2023-6-7 23:10 | 只看该作者
直接用cubemx生成的

使用特权

评论回复
5
ingramward| | 2023-6-8 13:53 | 只看该作者
使用FreeRTOS和HAL库可以方便地实现嵌入式系统的多任务处理。

使用特权

评论回复
6
macpherson| | 2023-6-10 17:12 | 只看该作者
在使用FreeRTOS和HAL库时,需要合理分配系统资源,避免出现资源冲突和浪费问题。

使用特权

评论回复
7
AloneKaven| | 2023-6-10 23:36 | 只看该作者
有没有移植freeRTOS的教程啊

使用特权

评论回复
8
minzisc| | 2023-6-14 12:56 | 只看该作者
可以参考相关文档和示例代码,学习如何使用FreeRTOS和HAL库进行STM32开发。

使用特权

评论回复
9
houjiakai| | 2023-6-14 14:41 | 只看该作者
安装好Keil或者IAR等开发工具,并下载好相应的HAL库和FreeRTOS源码。

使用特权

评论回复
10
sheflynn| | 2023-6-14 19:28 | 只看该作者
跑 FreeRTOS 要多大的Flash比较好?

使用特权

评论回复
11
houjiakai| | 2023-6-14 19:54 | 只看该作者
可以避免在等待延迟时出现意外阻塞任务的情况。

使用特权

评论回复
12
MessageRing| | 2023-6-14 22:22 | 只看该作者
这是直接使用cubeMX生成的吗?

使用特权

评论回复
13
51xlf| | 2023-6-15 21:22 | 只看该作者
由于在FreeRTOS环境下使用HAL库,因此建议使用OS编写的延时函数(例如osDelay()函数),而不是HAL库中的延时函数(例如HAL_Delay()函数)。

使用特权

评论回复
14
updownq| | 2023-6-15 21:31 | 只看该作者
在程序启动时,需要对HAL库和FreeRTOS进行初始化。可以在main函数中或者Startup文件中添加相关代码,以完成系统时钟、外设、任务等方面的初始化工作。

使用特权

评论回复
15
pixhw| | 2023-6-15 22:25 | 只看该作者
RTOS只是一个操作系统,多任务并行时建议使用RTOS

使用特权

评论回复
16
Bowclad| | 2023-6-15 22:34 | 只看该作者
使用RTOS会占用多少系统资源啊?

使用特权

评论回复
17
Undshing| | 2023-6-16 23:52 | 只看该作者
可以保证各个任务的实时性

使用特权

评论回复
18
AloneKaven| | 2023-6-17 22:48 | 只看该作者
在主函数里加task不就行了

使用特权

评论回复
19
sdlls| | 2023-6-19 08:52 | 只看该作者
stm32 为什么要用freertos

使用特权

评论回复
20
minzisc| | 2023-6-19 10:07 | 只看该作者
使用了FreeRTOS会强制使用systick作为自己的心跳?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

18

帖子

0

粉丝