在上一期内容中我们简单的介绍了任务通知的几个函数以及简单的使用了任务通知来实现两个信号之间的通信。
本期我们将利用任务通知来模拟三种方式的任务间通信。
信号量
在我们介绍信号量的文章中介绍过,信号分为二进制信号量和计数信号量。
接着我们使用任务通知来模拟这两项功能。
二进制信号量可以看作长度为1的队列,我们不关心其值为多少,只关心它的状态。
在直达任务通知中我们可以用xTaskNotifyGive来模拟二进制信号量的释放以及ulTaskNotifyTake()来模拟二进制信号量的读取。
在ulTaskNotifyTake()中需要注意的是,我们需要设置一个参数用来确定我们模拟的是二进制信号量还是计数信号量。
代码测试
void Mid_Task(void * pvParameters)//参数为 void * pvParameters
{
while(1)
{
if(KEY_Scan(0)==1)
{
printf("Key_Pressrn");
xTaskNotifyGive(High_Handler);//传入任务函数句柄,模拟信号量释放
}
}
vTaskDelay(10);
}
void High_Task(void * pvParameters)
{
BaseType_t err;
while(1)
{
err = ulTaskNotifyTake(pdFALSE,10);//读取后清零,模拟二进制信号量
if(err == pdTRUE)
{
printf("Recieve Message!rn");
}
vTaskDelay(10);
}
}
模拟二进制信号量成功。
之后,我们将接收的函数中的pdFALSE修改为pdTRUE,这样子我们就可以模拟我们的计数信号量了。
这里就不作演示了,但是要注意的是,只用这样子的模拟二进制信号量也要注意优先级反转问题,关于优先级反转的问题可以参考公众号中的关于二进制信号量的文章。
事件组
合理的运用RTOS中的事件组可以很好的处理许多事件,在事件组的介绍中我们说过,我们常用的事件组可以做到24位事件位。而在直达任务通知中,我们也同样可以指定某些位的改变来实现事件组的效果。
我们可以修改xTaskNotify中的eAction来将通知值作为事件组,修改特定位来实现事件位的效果。
代码测试
复制
void Mid_Task(void * pvParameters)//参数为 void * pvParameters
{
int i = 0;
while(1)
{
if(KEY_Scan(0)==1)
{
printf("Key_Press keynumber : 1rn");
xTaskNotify( (TaskHandle_t) High_Handler,//目标任务句柄
(uint32_t) 0x04,//第二位 00000100
(eNotifyAction) eSetBits);//位设置模式,模拟事件组
}
if(KEY_Scan(0)==2)
{
printf("Key_Press keynumber : 2rn");
xTaskNotify( (TaskHandle_t) High_Handler,//目标任务句柄
(uint32_t) 0x08,//第三位 00001000
(eNotifyAction) eSetBits);//位设置模式,模拟事件组
}
}
vTaskDelay(10);
}
void High_Task(void * pvParameters)
{
BaseType_t err;
uint32_t number;//存放通知值
uint32_t Value; //模拟事件组
while(1)
{
err = xTaskNotifyWait( (uint32_t) 0x0000,//不清理
(uint32_t) 0xffff,//清理当前
(uint32_t*) &number,//接收任务值
(TickType_t) 10 );//等待事件
Value = Value | number ; //获得事件位
if((Value&(0x08+0x04)) == (0x08+0x04))
{
printf("KEY1 and KEY2 have Pressedrn");
Value = 0;//事件组清零
}
vTaskDelay(10);
}
}