在FreeRTOS开发中,低优先级任务(数据打印任务)被抢占。导致打印任务出现+1延时。
一、问题描述
理想情况:按下一次按键打印一个当前数据
实际情况:第一次按下按键,程序没有打印数据,当我按下第二次按键,才会打印第一次按下的数据。第三次按键,打印第二次数据···
二、具体任务描述
我在程序中定义了两个任务:
(1)按键按下一次,进入按键计数任务(StartButtonTask),按键数目+1,‘按键按下标志位’置1。
void StartButtonTask(void *argument)
{
/* USER CODE BEGIN StartButtonTask */
/* Infinite loop */
for(;;)
{
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin))
{
osDelay(10);
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin)){
buttonCount++;
buttonPressed = 1;
}
while(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin)){
osDelay(10);
/*这里在while中加延时,是不想让时间片在阻塞式等待中浪费,我们只需要每10ms确定按钮是否按下就够了,
其余时间让操作系统忙别的任务*/
};
}
}
(2)在数据打印任务(StartDataTask)中,查询到‘按键按下标志位’为1,进入按键打印程序,同时清除‘按键按下标志位’。
void StartDataTask(void *argument)
{
/* USER CODE BEGIN StartDataTask */
/* Infinite loop */
for(;;)
{
osDelay(10);
if(1 == buttonPressed){
/*这里一定要注意FreeRTOS抢占式调度机制,
如果数据处理任务(StartDataTask)的优先级比按键任务(StartButtonTask)低,就会导致数据处理任务一直抢不到cpu,
直到按键任务进入阻塞态,数据处理任务才能抢到cpu,打印数据,也就是需要按下第n+1次,才能打印第n次结果。*/
osDelay(1000);//模拟数据处理过程,花费1s。
dataCount ++;//数据计数器加一
/************************************************************************/
/*打印中文,要先用sprintf将中文打印进字符串
在嵌入式/RTOS 开发中,用 sprintf通常是为了组合多条信息 + 方便调试/日志系统。
统一在一个变量里面方便管理*/
sprintf(msg,"按键:%d 次,数据:%d 次",(int)buttonCount,(int)dataCount);
printf("%s",msg);
/*直接打印中文,不推荐,不方便后续的调试/日志系统*/
// printf("按键:%d 次,数据:%d 次",(int)buttonCount,(int)dataCount);
/*最直接,打印英文,这个不容易产生因编码问题而导致的报错
由于不利于日志生成,同样不推荐*/
//printf("button:%d , data:%d",(int)buttonCount,(int)dataCount);
/***************************************************************************/
buttonPressed = 0;//打印后标志位清0
}
}
/* USER CODE END StartDataTask */
}
任务配置结构体:
osThreadId_t ButtonTaskHandle;
const osThreadAttr_t ButtonTask_attributes = {
.name = "ButtonTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for DataTask */
osThreadId_t DataTaskHandle;
const osThreadAttr_t DataTask_attributes = {
.name = "DataTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
三、问题分析
由于配置时,按键任务(ButtonTask)优先级比数据打印任务(DataTask)优先级高,导致进入任务进入阻塞态osDelay(1000)后,按键任务结束了延时,于是一直抢占cpu资源。直到第二次按键按下,按键任务进入阻塞态osDelay(10),此时数据打印任务才有机会执行osDelay(1000)后的打印程序
sprintf(msg,"按键:%d 次,数据:%d 次",(int)buttonCount,(int)dataCount);
printf("%s",msg);
四、问题解决
(1)修改任务优先级:
osThreadId_t ButtonTaskHandle;
const osThreadAttr_t ButtonTask_attributes = {
.name = "ButtonTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityLow,
};
/* Definitions for DataTask */
osThreadId_t DataTaskHandle;
const osThreadAttr_t DataTask_attributes = {
.name = "DataTask",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
(2)在按键任务加入延时调用
void StartButtonTask(void *argument)
{
/* USER CODE BEGIN StartButtonTask */
/* Infinite loop */
for(;;)
{
osDelay(10);
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin))
{
osDelay(10);
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin)){
buttonCount++;
buttonPressed = 1;
}
while(GPIO_PIN_RESET == HAL_GPIO_ReadPin(Key_GPIO_Port,Key_Pin)){
osDelay(10);
/*这里在while中加延时,是不想让时间片在阻塞式等待中浪费,我们只需要每10ms确定按钮是否按下就够了,
其余时间让操作系统忙别的任务*/
};
}
}

浙公网安备 33010602011771号