STM32CUBEIDE FreeRTOS操作教程(六):recursive mutexes递归互斥信号量 ...

打印 上一主题 下一主题

主题 1845|帖子 1845|积分 5535

STM32CUBEIDE FreeRTOS操作教程(六):recursive mutexes互斥信号量

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

操作教程(六)配置FreeRTOS及相干情况,实现LED闪灯功能及基于recursive mutex递归互斥信号量的USB假造串口双任务打印输出。两个任务轮流获取和开释互斥信号量,在得到信号量时向外打印输出,其中任务会在获取两次信号量后向外打印输出,然后开释两次信号量。
递归互斥信号量是可以对单个信号量进行多次获取和开释的信号量,对于一个任务而言当然获取了多少次后就应该开释多少次,然后别的任务才能去获取改信号量。因为中断服务步伐中不能应用阻塞时间,所以递归信号量不能用在中断服务步伐中,也就是重要用在任务过程中。
FreeRTOS的教程较多,保举参考正点原子所出的《STM32F407 FreeRTOS开辟手册》相知趣干知识。


STM32CUBEIDE工程配置

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


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

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

配置USB串口:




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




FreeRTOS配置












任务实现

基于前述的配置,main.c代码里会加载Free-RTOS的配置,并启动几个任务的调理,当然,此时的任务都是什么也不干。实现LED闪灯,就在LED闪灯任务里参加代码即可:
  1. void StartTask_TASK_LED_FLASH(void *argument)
  2. {
  3.   /* USER CODE BEGIN StartTask_TASK_LED_FLASH */
  4.   /* Infinite loop */
  5.   for(;;)
  6.   {
  7.     osDelay(1000);
  8.     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  9.   }
  10.   /* USER CODE END StartTask_TASK_LED_FLASH */
  11. }
复制代码
也就实现了LED闪灯功能,其中osDelay(1000);实现1秒时间的操作系统调理延时,也就是1秒执行一次LED灯的亮灭。osDelay(1);是最小的调理延时,为1毫秒。要实现更小的延时,则可以用微秒延时函数实现,参考《STM32 HAL us delay(微秒延时)的指令延时实现方式及优化》
main.c文件里两个任务分别通过获取递归互斥信号量权柄,再发送信息:
  1. void StartTask_TASK_USB_VCOM_H(void *argument)
  2. {
  3.   /* USER CODE BEGIN StartTask_TASK_USB_VCOM_H */
  4.         BaseType_t err_stu = pdFALSE;
  5.   /* Infinite loop */
  6.   for(;;)
  7.   {
  8.     osDelay(8);
  9.     err_stu = xSemaphoreTake(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime);
  10.     if(err_stu==pdTRUE)
  11.     {
  12.         if(USB_CONN_STATUS())
  13.         {
  14.                 usbprintstring("High Priority Task Outputting\r\n");
  15.         }
  16.         xSemaphoreGive(USB_VCOM_RcsMutex01Handle);
  17.     }
  18.   }
  19.   /* USER CODE END StartTask_TASK_USB_VCOM_H */
  20. }
  21. void StartTask_TASK_USB_VCOM_L(void *argument)
  22. {
  23.   /* USER CODE BEGIN StartTask_TASK_USB_VCOM_L */
  24.         BaseType_t err_stu = pdFALSE;
  25.   /* Infinite loop */
  26.   for(;;)
  27.   {
  28.     osDelay(5);
  29.     err_stu = xSemaphoreTake(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime); //First get
  30.     if(err_stu==pdTRUE)
  31.     {
  32.             xSemaphoreTakeRecursive(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime);//Second get
  33.         if(USB_CONN_STATUS())
  34.         {
  35.                 usbprintstring("Low Priority Task Outputting\r\n");
  36.         }
  37.         xSemaphoreGive(USB_VCOM_RcsMutex01Handle); //First release
  38.         xSemaphoreGiveRecursive(USB_VCOM_RcsMutex01Handle); //Second release
  39.         osDelay(10);
  40.     }
  41.   }
  42.   /* USER CODE END StartTask_TASK_USB_VCOM_L */
  43. }
复制代码
完整的main.c代码:
  1. /* 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 6: LED flash + Recursive Mutex.//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 clockvoid 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_H */osThreadId_t TASK_USB_VCOM_HHandle;const osThreadAttr_t TASK_USB_VCOM_H_attributes = {  .name = "TASK_USB_VCOM_H",  .stack_size = 128 * 4,  .priority = (osPriority_t) osPriorityHigh,};/* Definitions for TASK_USB_VCOM_L */osThreadId_t TASK_USB_VCOM_LHandle;const osThreadAttr_t TASK_USB_VCOM_L_attributes = {  .name = "TASK_USB_VCOM_L",  .stack_size = 128 * 4,  .priority = (osPriority_t) osPriorityLow,};/* Definitions for USB_VCOM_RcsMutex01 */osMutexId_t USB_VCOM_RcsMutex01Handle;const osMutexAttr_t USB_VCOM_RcsMutex01_attributes = {  .name = "USB_VCOM_RcsMutex01",  .attr_bits = osMutexRecursive,};/* 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_H(void *argument);void StartTask_TASK_USB_VCOM_L(void *argument);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 */uint8_t USB_CONN_STATUS(void);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);        }}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 */  PY_Delay_us_t(1000000);  /* USER CODE END 2 */  /* Init scheduler */  osKernelInitialize();  /* Create the recursive mutex(es) */  /* creation of USB_VCOM_RcsMutex01 */  USB_VCOM_RcsMutex01Handle = osMutexNew(&USB_VCOM_RcsMutex01_attributes);  /* USER CODE BEGIN RTOS_MUTEX */  /* add mutexes, ... */  USB_VCOM_RcsMutex01Handle = xSemaphoreCreateRecursiveMutex(); //"USB_VCOM_RcsMutex01Handle = osMutexNew(&USB_VCOM_RcsMutex01_attributes);" is bad code. Redefine here.  /* USER CODE END RTOS_MUTEX */  /* 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_H */  TASK_USB_VCOM_HHandle = osThreadNew(StartTask_TASK_USB_VCOM_H, NULL, &TASK_USB_VCOM_H_attributes);  /* creation of TASK_USB_VCOM_L */  TASK_USB_VCOM_LHandle = osThreadNew(StartTask_TASK_USB_VCOM_L, NULL, &TASK_USB_VCOM_L_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)
  2. {
  3.   /* USER CODE BEGIN StartTask_TASK_LED_FLASH */
  4.   /* Infinite loop */
  5.   for(;;)
  6.   {
  7.     osDelay(1000);
  8.     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  9.   }
  10.   /* USER CODE END StartTask_TASK_LED_FLASH */
  11. }
  12. /* 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_H *//*** @brief Function implementing the TASK_USB_VCOM_H thread.* @param argument: Not used* @retval None*//* USER CODE END Header_StartTask_TASK_USB_VCOM_H */void StartTask_TASK_USB_VCOM_H(void *argument){  /* USER CODE BEGIN StartTask_TASK_USB_VCOM_H */        BaseType_t err_stu = pdFALSE;  /* Infinite loop */  for(;;)  {    osDelay(8);    err_stu = xSemaphoreTake(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime);    if(err_stu==pdTRUE)    {        if(USB_CONN_STATUS())        {                usbprintstring("Task 1 Outputting\r\n");        }        xSemaphoreGive(USB_VCOM_RcsMutex01Handle);    }  }  /* USER CODE END StartTask_TASK_USB_VCOM_H */}/* USER CODE BEGIN Header_StartTask_TASK_USB_VCOM_L *//*** @brief Function implementing the TASK_USB_VCOM_L thread.* @param argument: Not used* @retval None*//* USER CODE END Header_StartTask_TASK_USB_VCOM_L */void StartTask_TASK_USB_VCOM_L(void *argument){  /* USER CODE BEGIN StartTask_TASK_USB_VCOM_L */        BaseType_t err_stu = pdFALSE;  /* Infinite loop */  for(;;)  {    osDelay(5);    err_stu = xSemaphoreTake(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime); //First get    if(err_stu==pdTRUE)    {            xSemaphoreTakeRecursive(USB_VCOM_RcsMutex01Handle, USB_VCOM_xBlockTime);//Second get        if(USB_CONN_STATUS())        {                usbprintstring("Task 2 Outputting\r\n");        }        xSemaphoreGive(USB_VCOM_RcsMutex01Handle); //First release        xSemaphoreGiveRecursive(USB_VCOM_RcsMutex01Handle); //Second release        osDelay(10);    }  }  /* USER CODE END StartTask_TASK_USB_VCOM_L */}/**  * @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操作教程(六):recursive mutexes递归互斥信号量 例程
例程测试

例程测试结果如下:

–End–

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表