STM32CUBEIDE FreeRTOS操作教程(十二):std dynamic memory 标准动态内存

STM32CUBEIDE FreeRTOS操作教程(十二):std dynamic memory 标准动态内存

STM32CUBE开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件,不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F401RCT6开发板为例,只用到USB,USART1极少的接口,体现FreeRTOS的各种操作过程。

操作教程(十一)配置FreeRTOS及相关环境,采用C语言标准的的方法申请/释放动态内存空间,作为USB虚拟串口接收数据的数组空间,当USB虚拟串口接收到数据时,通过信号量方式指示给任务,由任务将数据从USB虚拟串口发出,实现USB虚拟串口数据发送环回功能。

FreeRTOS的教程较多,推荐参考正点原子所出的《STM32F407 FreeRTOS开发手册》了解相关知识。

STM32CUBEIDE工程配置

选择TIM1(也可以是其它TIM)作为FreeRTOS操作系统占用的时钟源:

配置时钟树包括USB的48MHz时钟:

配置PC13为低电平点灯的管脚:

配置USB串口:



配置UART1串口(但本例中不用到UART1):

FreeRTOS配置









保存并生成基础工程代码:

在生成代码的这个部分可以看到FreeRTOS代码部分:

任务实现

基于前述的配置,main.c代码里会加载Free-RTOS的配置,并启动几个任务的调度,当然,此时的任务都是什么也不干。实现LED闪灯,就在LED闪灯任务里加入代码即可:

csharp 复制代码
void StartTask_TASK_LED_FLASH(void *argument)
{
  /* USER CODE BEGIN StartTask_TASK_LED_FLASH */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1000);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  }
  /* USER CODE END StartTask_TASK_LED_FLASH */
}

也就实现了LED闪灯功能,其中osDelay(1000);实现1秒时间的操作系统调度延时,也就是1秒执行一次LED灯的亮灭。osDelay(1);是最小的调度延时,为1毫秒。要实现更小的延时,则可以用微秒延时函数实现,参考《STM32 HAL us delay(微秒延时)的指令延时实现方式及优化》

在USB数据接收回调函数里,开出了动态内存区域,进行数据转存和信号量设置:

csharp 复制代码
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
	extern uint8_t * USB_VCOM_BUFF;
	extern uint32_t USB_VCOM_INDEX;

	extern osSemaphoreId_t USB_VCOM_BinarySem01Handle;
	extern BaseType_t USB_VCOM_pxHigherPriorityTaskWaken;

	USB_VCOM_BUFF = malloc(*Len);

	memcpy(USB_VCOM_BUFF, Buf, *Len);
	USB_VCOM_INDEX = *Len;
	xSemaphoreGiveFromISR(USB_VCOM_BinarySem01Handle, &USB_VCOM_pxHigherPriorityTaskWaken);


  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
  /* USER CODE END 6 */
}

的main.c在USB数据处理任务里,发送完数据后释放内存空间:

csharp 复制代码
void StartTask_TASK_USB_VCOM(void *argument)
{
  /* USER CODE BEGIN StartTask_TASK_USB_VCOM */
  BaseType_t err_stu = pdFALSE;

  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
    USB_VCOM_xBlockTime = 0; //Block(waiting) time to get semaphore
    err_stu = xSemaphoreTake(USB_VCOM_BinarySem01Handle, USB_VCOM_xBlockTime);
    if(err_stu==pdTRUE)
    {
    	usbprintarray(USB_VCOM_BUFF, USB_VCOM_INDEX);
    	USB_VCOM_INDEX = 0;
    	free(USB_VCOM_BUFF);
    }
  }
  /* USER CODE END StartTask_TASK_USB_VCOM */
}

main.c文件的完整代码为:

csharp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
//Example 12: LED flash + USB VCOM loop back with dynamic memory apply/release in standard mode
//Written by Pegasus Yu
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "usb_device.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "semphr.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float usDelayBase = 7.63238716; //For STM32F401RCT6 working in 84MHz main clock

void PY_Delay_us_t(uint32_t Delay)
{
  __IO uint32_t delayReg;
  __IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);

  delayReg = 0;
  while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;

/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for TASK_LED_FLASH */
osThreadId_t TASK_LED_FLASHHandle;
const osThreadAttr_t TASK_LED_FLASH_attributes = {
  .name = "TASK_LED_FLASH",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityLow,
};
/* Definitions for TASK_UART1 */
osThreadId_t TASK_UART1Handle;
const osThreadAttr_t TASK_UART1_attributes = {
  .name = "TASK_UART1",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityLow,
};
/* Definitions for TASK_USB_VCOM */
osThreadId_t TASK_USB_VCOMHandle;
const osThreadAttr_t TASK_USB_VCOM_attributes = {
  .name = "TASK_USB_VCOM",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityLow,
};
/* Definitions for USB_VCOM_BinarySem01 */
osSemaphoreId_t USB_VCOM_BinarySem01Handle;
const osSemaphoreAttr_t USB_VCOM_BinarySem01_attributes = {
  .name = "USB_VCOM_BinarySem01"
};
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
void StartDefaultTask(void *argument);
void StartTask_TASK_LED_FLASH(void *argument);
void StartTask_TASK_UART1(void *argument);
void StartTask_TASK_USB_VCOM(void *argument);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
void usbprintstring(char * data)
{
	if(CDC_Transmit_FS((uint8_t *)data, strlen(data))==USBD_BUSY)
	{
		PY_Delay_us_t(1000000);
	    CDC_Transmit_FS((uint8_t *)data, strlen(data));
	}
}

void usbprintarray(uint8_t * data, uint16_t len)
{
	if(CDC_Transmit_FS(data, len)==USBD_BUSY)
	{
		PY_Delay_us_t(1000000);
		CDC_Transmit_FS(data, len);
	}
}

uint8_t * USB_VCOM_BUFF;
uint32_t USB_VCOM_INDEX;

BaseType_t USB_VCOM_pxHigherPriorityTaskWaken;
TickType_t USB_VCOM_xBlockTime = 0;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* Create the semaphores(s) */
  /* creation of USB_VCOM_BinarySem01 */
  USB_VCOM_BinarySem01Handle = osSemaphoreNew(1, 0, &USB_VCOM_BinarySem01_attributes);

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* creation of TASK_LED_FLASH */
  TASK_LED_FLASHHandle = osThreadNew(StartTask_TASK_LED_FLASH, NULL, &TASK_LED_FLASH_attributes);

  /* creation of TASK_UART1 */
  TASK_UART1Handle = osThreadNew(StartTask_TASK_UART1, NULL, &TASK_UART1_attributes);

  /* creation of TASK_USB_VCOM */
  TASK_USB_VCOMHandle = osThreadNew(StartTask_TASK_USB_VCOM, NULL, &TASK_USB_VCOM_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

  /* Start scheduler */
  osKernelStart();

  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
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_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses 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();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : LED_Pin */
  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);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* init code for USB_DEVICE */
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END 5 */
}

/* USER CODE BEGIN Header_StartTask_TASK_LED_FLASH */
/**
* @brief Function implementing the TASK_LED_FLASH thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask_TASK_LED_FLASH */
void StartTask_TASK_LED_FLASH(void *argument)
{
  /* USER CODE BEGIN StartTask_TASK_LED_FLASH */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1000);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  }
  /* USER CODE END StartTask_TASK_LED_FLASH */
}

/* USER CODE BEGIN Header_StartTask_TASK_UART1 */
/**
* @brief Function implementing the TASK_UART1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask_TASK_UART1 */
void StartTask_TASK_UART1(void *argument)
{
  /* USER CODE BEGIN StartTask_TASK_UART1 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartTask_TASK_UART1 */
}

/* USER CODE BEGIN Header_StartTask_TASK_USB_VCOM */
/**
* @brief Function implementing the TASK_USB_VCOM thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask_TASK_USB_VCOM */
void StartTask_TASK_USB_VCOM(void *argument)
{
  /* USER CODE BEGIN StartTask_TASK_USB_VCOM */
  BaseType_t err_stu = pdFALSE;

  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
    USB_VCOM_xBlockTime = 0; //Block(waiting) time to get semaphore
    err_stu = xSemaphoreTake(USB_VCOM_BinarySem01Handle, USB_VCOM_xBlockTime);
    if(err_stu==pdTRUE)
    {
    	usbprintarray(USB_VCOM_BUFF, USB_VCOM_INDEX);
    	USB_VCOM_INDEX = 0;
    	free(USB_VCOM_BUFF);
    }
  }
  /* USER CODE END StartTask_TASK_USB_VCOM */
}

/**
  * @brief  Period elapsed callback in non blocking mode
  * @note   This function is called  when TIM1 interrupt took place, inside
  * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
  * a global variable "uwTick" used as application time base.
  * @param  htim : TIM handle
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

/**
  * @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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

例程下载

STM32 STM32CUBEIDE FreeRTOS操作教程(十二):std dynamic memory标准动态内存 例程

例程测试

例程测试效果如下:

--End--

相关推荐
richxu2025100114 分钟前
嵌入式学习之路->stm32篇->(14)通用定时器(上)
stm32·单片机·嵌入式硬件·学习
Deitymoon2 小时前
STM32——外部中断按键控制led
stm32·单片机·嵌入式硬件
czwxkn2 小时前
7STM32(stdl)flash内部闪存
stm32·单片机·嵌入式硬件
咕噜咕噜啦啦3 小时前
STlink下载程序
stm32·单片机
Deitymoon4 小时前
STM32——串口中断接收
stm32·单片机·嵌入式硬件
Deitymoon6 小时前
STM32——串口通信发送数据
stm32·单片机·嵌入式硬件
czwxkn7 小时前
8STM32(stdl)低功耗模式
stm32·单片机·嵌入式硬件
czwxkn7 小时前
9STM32(stdl)看门狗
stm32·单片机·嵌入式硬件
LCG元8 小时前
STM32实战:基于STM32F103的SPI通信驱动W25Qxx Flash存储
stm32·单片机·嵌入式硬件
iCxhust9 小时前
led_pattern = (led_pattern << 1) | (led_pattern >> 7)执行顺序
stm32·单片机·嵌入式硬件·51单片机·微机原理