1、问题说明
通过HAL创建STM32裸机程序后,移植FreeRTOS程序且编译不报错。创建了两个串口打印的任务,却只有后创建的任务运行,不会进行任务间的调度。
主要代码:
/*
*功能:将C库printf函数重定向到USART1
*参数:无
*返回值:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/*任务1的函数*/
void vTask1( void * param)
{
while(1)
{
printf("1");
}
}
/*任务2的函数*/
void vTask2( void * param)
{
while(1)
{
printf("2");
}
}
main()
{
......
xTaskCreate(vTask1, "task1", 100, NULL, 1, NULL); /*创建任务1*/
xTaskCreate(vTask2, "task2", 100, NULL, 1, NULL); /*创建任务2*/
/* 启动调度器 */
vTaskStartScheduler();
}
2、问题原因
2.1、可能原因
- 任务调度算法配置错误,检查口,任务调度算法已配置为可抢占+时间片轮转+空闲任务让步;排除这种情况
- 中断函数冲突,最终发现就是该情况
2.2、原因解释
(1)串口打印使用函数 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
该函数中使用了HAL库的时基定时器,与FreeRTOS的时基定时器产生冲突。
(2)串口的阻塞发送使用定时器计算超时时间;FreeRTOS的任务调度也需要定时器计算时间。
3、解决办法
3.1、禁止中断
在调用printf前先禁用中断,调用后再使能代码。代码修改如下:
/*
*功能:将C库printf函数重定向到USART1
*参数:无
*返回值:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/*任务1的函数*/
void vTask1( void * param)
{
while(1)
{
taskENTER_CRITICAL(); // 屏蔽中断
printf("1");
taskEXIT_CRITICAL(); // 重新使能中断
}
}
/*任务2的函数*/
void vTask2( void * param)
{
while(1)
{
taskENTER_CRITICAL(); // 屏蔽中断
printf("2");
taskEXIT_CRITICAL(); // 重新使能中断
}
}
main()
{
......
xTaskCreate(vTask1, "task1", 100, NULL, 1, NULL); /*创建任务1*/
xTaskCreate(vTask2, "task2", 100, NULL, 1, NULL); /*创建任务2*/
/* 启动调度器 */
vTaskStartScheduler();
}
3.2、修改串口打印函数
修改串口重定向的函数,不使用HAL库提供的函数,使用最原始方法编写,代码修改如下:
/*
*功能:将C库printf函数重定向到USART1
*参数:无
*返回值:无
*/
int fputc( int ch, FILE *f )
{
USART_TypeDef *USARTx = USART1;
while( (USARTx->SR & (1<<7)) == 0); // 等待上次的数据发送完成
USARTx->DR = ch;
return ch;
}
/*任务1的函数*/
void vTask1( void * param)
{
while(1)
{
printf("1");
}
}
/*任务2的函数*/
void vTask2( void * param)
{
while(1)
{
printf("2");
}
}
main()
{
......
xTaskCreate(vTask1, "task1", 100, NULL, 1, NULL); /*创建任务1*/
xTaskCreate(vTask2, "task2", 100, NULL, 1, NULL); /*创建任务2*/
/* 启动调度器 */
vTaskStartScheduler();
}