近期有朋友和我讨论STM32CubeMX生成的FreeRTOS的代码中有许多奇怪的地方。
void LED01Tog(void const * argument){ /* USER CODE BEGIN LED01Tog */ /* Infinite loop */ for(;;) { HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10); osDelay(500); } /* USER CODE END LED01Tog */}
/* USER CODE BEGIN Header_LED02Tog *//*** @brief Function implementing the LED02 thread.* @param argument: Not used* @retval None*//* USER CODE END Header_LED02Tog */void LED02Tog(void const * argument){ /* USER CODE BEGIN LED02Tog */ /* Infinite loop */ for(;;) { HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9); osDelay(500); } /* USER CODE END LED02Tog */}
我们添加两个LED翻转的函数,编译我们的代码,发现任务是正常的可以启动。
MX_FREERTOS_Init();
/* Start scheduler */ osKernelStart();
主函数中有着初始化任务的函数以及CubeMX中开启任务调度的函数,在任务调度函数进行任务的创建,在调度函数中,我发现其就是一句 vTaskS
tartScheduler()。
那么就非常奇怪为什么他的函数调度不了。
然后我就将HAL库的函数注释掉,自己调用任务调度函数,发现任务调度也是正常进行的。
osThreadDef(LED02, LED02Tog, osPriorityIdle, 0, 128); LED02Handle = osThreadCreate(osThread(LED02), NULL); vTaskSuspend(LED02Handle); vTaskStartScheduler();
并且也可以成功的调度vTaskSuspend来停止任务。
不过,有一个情况倒是会导致FreeRTOS启动失败。
当我们的定时器没有配置成硬件定时器而是使用系统定时器的时候,创建工程的时候会提醒我们强烈建议当我们使用FreeRTOS的时候,不要使用systick作为时钟源。
因为如果选用了systick的话,就会使得系统的时钟和操作系统的时钟都依靠Systick,但是我们在进行任务调度的时候需要有一个中断来切换各个任务之间切换。
void SysTick_Handler(void){ /* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */ HAL_IncTick();#if (INCLUDE_xTaskGetSchedulerState == 1 ) if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {#endif /* INCLUDE_xTaskGetSchedulerState */ xPortSysTickHandler();#if (INCLUDE_xTaskGetSchedulerState == 1 ) }#endif /* INCLUDE_xTaskGetSchedulerState */ /* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */}
但是使用Systick的话就可能出现任务调度失败的情况。
我们可以看到,系统定时器的优先级是最低的15,这时候我们在FreeRTOS任务调度的时候如果用到了HAL_Delay的话,就会导致无法任务无法正常调度。
就是说当中断函数里边调用HAL_Delay()的时候,必须保证systick的优先级比中断函数的优先级高。
所以CubeMX中建议使用一个通用定时器来充当系统时钟源。
其实在FreeRTOS中导致任务无法开始调度的原因有许多,但是大部分的情况下都是和定时器相关。
就像上次我的盗版STM32无法启动,本来也是开始因为无法使用定时器发现是一块盗版芯片,然后之后导致的FreeRTOS无法启动调度。
因此如果你的FreeRTOS出现了问题,不妨去看看定时器是否正常。