最近在学习freertos任务通知的时候,跟着正点原子教程做了个用任务通知模拟队列和事件标志组的小实验,结果发现用队列是可以传递为0的数据的,而用任务通知模拟队列就无法传递为0的数据,在用xTaskNotify(myTask01Handle, key ,eSetValueWithoutOverwrite);传递为值0的数据key时,此时任务通知模拟队列的接收函数xTaskNotifyWait(0,0xFFFFFFFF,&value,portMAX_DELAY);不会让任务退出阻塞状态。
硬件:正点原子miniV3.0开发板
软件:keil5、stm32cubemx
实验主要代码如下:
void StartTask01(void *argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
QueueSetMemberHandle_t member_handle;
uint32_t value;
for(;;)
{
//osMessageQueueGet(myQueue02Handle ,&key ,0 , portMAX_DELAY);
//myprintf("获取队列数据:%d\r\n", key);
xTaskNotifyWait(0,0xFFFFFFFF,&value,portMAX_DELAY);
if(value != NULL)
myprintf("任务通知值为:%d\r\n",value);
osDelay(1000);
}
}
uint8_t state;
/* USER CODE END Header_StartTask03 */
void StartTask03(void *argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
uint32_t key = 0;
for(;;)
{
key = KEY_Scan(0); //保存返回值,方便后面判断
if(key == KEY0_PRES)
{
if(myTask01Handle != NULL)
{
key = 0;
state = xTaskNotify(myTask01Handle, key ,eSetValueWithoutOverwrite);
if(state == pdPASS) myprintf("任务通知模拟队列传输:%d\r\n",key);
}
}
if(key == KEY1_PRES)
{
if(myTask01Handle != NULL)
{
key = 200;
myprintf("任务通知模拟队列传输:%d\r\n",key);
xTaskNotify(myTask01Handle, key ,eSetValueWithoutOverwrite);
}
}
if(key == WKUP_PRES)
{
key = 0;
state = osMessageQueuePut(myQueue02Handle ,&key ,0 , portMAX_DELAY);
if(state == osOK) myprintf("往队列写入数据为:%d\r\n",key);
}
osDelay(10);
}
}
分别测试队列写入读取数据和任务通知模拟队列写入读取数据,按下key_wkup就是向队列中写入数据,按下key0、key1就是通过任务通知模拟队列写入数据,结果分别如下:
我们可以看到,用队列写入为0的数据,另一个任务可以接收到;而用任务通知模拟队列写入为0的数据,另一个任务无法接收;
至于原因是为什么,首先我们直到队列接收函数判断队列中是否有数据是通过一个指针,只要该指针指向的地址不为NULL即有数据,不管这个地址中的值是0还是其他值,该队列接收函数都会让任务退出阻塞并读取该数据,因此队列可以传输为0的数据;
那为什么任务通知模拟队列无法传输为0的数据呢?我个人没有找到具体代码来进行验证,希望有大佬能说一下。不过由于xTaskNotifyWait(0,0xFFFFFFFF,&value,portMAX_DELAY)函数既可以做任务通知模拟队列接收函数,也可以做任务通知模拟事件标志组接收函数,再结合这位作者的博客中所说:FreeRTOS操作系统——任务通知模拟消息邮箱及事件标志组(十八)-优快云博客
因此我们可以推断,在该函数的具体代码实现中,只有任务通知值不为0才可以使该任务退出阻塞状态;这也就说明了为什么传输为0的数据时,目标任务无法接收到该数据并退出阻塞状态;