队列:
队列又称为消息队列,是一种用于任务间通信的数据结构,是一种异步通信方式,实现接收来自其他任务或者中断的不固定长度的消息,任务能够从队列中读取消息,当队列中消息是空的时,读取消息的任务被阻塞,用户可以指定阻塞任务的时间xTickToWait,当队列中有新消息,被阻塞的任务会被唤醒并处理消息。当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。遵守FIFO原则。
消息队列的运作机制:
创建消息队列时,FreeRTOS先给消息队列分配一块内存空间,这块内存的大小等于消息队列控制块大小加上单个消息空间大小乘以消息队列长度,然后初始化消息队列,此时消息队列为空。当队列不再被使用,应该删除以释放系统资源,一旦操作完成,消息队列将被永久删除。
消息队列的阻塞机制:
每个对消息读写的函数都有这种机制,称为阻塞机制,如果有任务A对某个队列进行读操作,发现没有消息,任务A有三种选择:第一个选择任务A不等,直接紧着运行,第二个选择,任务A等待一定的时间,等着消息的到来,第三种选择,任务A一直等,一直等到队列中有消息。在发送消息时为了保护数据,当且仅当队列允许入队时,发送者才能成功发送消息,队列中无效消息空间时,说明队列已经满了,系统根据用户指定的阻塞时间将任务阻塞,在指定的时间内,如果不能完成如对操作,发送消息的任务会收到一个错误码,然后接触阻塞状态。
消息队列的应用场景:
用于发送不定长消息的场合,包括任务与任务之间的信息交换,发送到队列的消息是通过拷贝的方式实现的,意味着队列存储的是原始数据,不是原数据的引用。
消息队列常用函数:
消息队列创建函数 xQueueCreate():用于创建一个新的队列并返回这个队列的句柄。每创建一个队列就要为其分配RAM 一部分用于存储队列的状态 一部分用于作为消息队列的存储区域。使用该函数时 使用的是动态内存分配 使用该函数需要配置宏定义configSUPPORT_DYNAMIC_ALLOCATION为1
消息队列的内存空间示意图:
消息队列创建完成示意图:
//创建队列实例
QueueHandle_t Test_Queue=NULL;
#define QUEUE_LEN 4 //队列长度
#define QUEUE_SIZE 4 //队列中每个消息的大小
BaseType_t xReturn=pdPASS; //定义一个创建信息返回值 默认为pdPASS
taskENTER_CRITICAL() //进入临界区
//创建test_queue
Test_Queue=xQueueCreate((UBaseType_t)QUEUE_LEN,(UBaseType_t)QUEUE_SIZE);
if(NULL!=Test_Queue)
printf("创建成功!\n");
taskEXIT_CRITICAL //退出临界区
消息队列删除函数:
队列删除函数是根据消息队列句柄直接删除 删除之后这个消息队列的所有信息都会被系统回收清空 不能再次使用 消息队列删除函数的形参是消息队列的句柄
//队列删除实例
#define QUEUE_LENGTH 5
#define QUEUE_ITEM_SIZE 4
int main()
{
QueueHandle_t xQueue;
xQueue=xQueueCreate(QUEUE_LENGTH,QUEUE_ITEM_SIZE);
if(xQueue==NULL){}
else
{
vQueueDelete(xQueue); //删除已创建的消息队列
}
}
向消息队列发送消息函数:
在中断服务程序或者任务中都可以给消息队列发送消息,如果队列未满,会将消息拷贝到消息队列的队尾,当发送紧急消息时,发送的位置时消息队列的对头而不是队尾,接受者就可以优先接收到紧急信息,从而即使进行消息处理。
//实用实例
static void Send_Task(void * parameter)
{
BaseType_t xReturn=pdPASS;
uint32_t send_data1=1;
uint32_t send_data2=2;
while(1)
{
if(Key_Scan(KEY1_GPIO_PORT,KET1_GPIO_PIN)==KEY_ON)
{
xReturn=xQueueSend(Test_Queue,&send_data1,0);
if(pdPASS==xReturn)
{
printf("发送成功!\n");
}
}
if(Key_Scan(KEY2_GPIO_PORT,KET2_GPIO_PIN)==KEY_ON)
{
xReturn=xQueueSend(Test_Queue,&send_data2,0);
if(pdPASS==xReturn)
{
printf("发送成功!\n");
}
}
vTask_Delay(20);
}
}
从消息队列中读取消息函数:
xQueueReceive是一个宏定义,展开是调用函数xQueueGenericReceive,作用是从一个队列中接收消息并把消息从队列中删除,接受的消息以拷贝的形式进行,必须准备一个足够大的缓存空间。
//使用实例
static void Receive_Task(void *parameter)
{
BaseType_t xReturn=pdTURE;
uint32_t r_queue; //接收消息的变量
while(1)
{
xReturn=xQueueReceive(Test_Queue,&r_queue,portMAX_DELAY);
if(pdTURE==xReturn)
printf("本次接收到的消息是:\n");
else
printf("接收出错\n");
}
}
消息队列使用注意事项:
1.使用xQueueSend,xQueueSendFromISR,xQueueReceive这些函数之前应该先创建消息队列 并根据句柄进行操作、
2.队列采用先进先出形式,会先读取存储在队列中的数据
3.在获取队列中的消息的时候 要定义一个存储数据的地方,并且该数据区域大小不小于消息大小
4.无论是发送或者是接收消息都是以拷贝的方式进行,如果消息过于庞大 可以将消息的地址作为消息进行发送和接收
5.队列是具有自己独立权限的内核对象 不属于任何任务 所有任务可以向同一队列中写入和独处
消息队列实验
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)