版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章消息队列Chapter4MessageQueue《物联网操作系统技术与应用》制作人张亚军
当多个任务要进行数据共享时,就要进行任务间的通信。例如,一个任务负责采集传感器的数据,并把数据写入通信媒介上,另一个任务可以从媒介中读出数据,并对这些数据进行处理。物联网操作系统最常用的的任务间通信媒介就是消息队列。本章将学习消息队列的使用。前言010302学习目标能够描述LiteOS消息队列的基本概念能够说出LiteOS消息队列的运行机制能够使用LiteOS消息队列的函数进行任务间的通信目录CONTENTS消息队列基本概念消息队列控制块消息队列运行机制消息队列常用函数4.14.24.34.4消息队列基本概念4.1
BasicConceptofMessageQueue
消息队列又称队列,是一种常用于任务间通信的数据结构,用于接收来自任务或中断的不固定长度的消息,并根据LiteOS提供的不同函数接口选择传递消息是否存放在自己的空间中。任务能够向队列中写入消息,也可以从队列里面读取消息,当队列中的消息是空时,读取消息的任务会被挂起;当队列中有新消息时,挂起的读取任务被唤醒,并处理新消息。
任务可以将一条或多条消息放入消息队列,当有多个消息写入到消息队列中时,其他任务从消息队列中读取消息时,遵循先进先出(FirstInFirstOut,FIFO)的原则,也就是说,读消息的任务先得到的是最先进入队列的消息。
用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,起到缓冲消息的作用。4.1消息队列基本概念HuaweiLiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:(1)消息以先进先出方式排队,支持异步读写工作方式;(2)读队列和写队列都支持超时机制;(3)发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)的任意类型消息;(4)一个任务能够从任意一个消息队列接收和发送消息;(5)多个任务能够从同一个消息队列接收和发送消息。消息队列控制块
MessageQueueControlBlock4.24.2消息队列控制块
消息队列通过一个队列控制块对队列状态和消息读写进行控制,队列控制块信息定义在LiteOS源码目录下的\kernel\base\include\los_queue.ph文件中,内容如下:
typedefstructtagQueueCB{UINT8*pucQueue;/**<队列指针*/UINT16usQueueState;/**<队列状态*/UINT16usQueueLen;/**<队列中消息的个数*/UINT16usQueueSize;/**<消息节点大小*/UINT16usQueueID;/**<队列ID*/UINT16usQueueHead;/**<消息头节点位置(数组下标)*/UINT16usQueueTail;/**<消息尾节点位置(数组下标)*/UINT16usReadWriteableCnt[2];/**<队列中可读或可写消息数,0:可读,1:可写*/LOS_DL_LISTstReadWriteList[2];/**<读取或写入消息任务等待链表,
0:读取链表,1:写入链表*/LOS_DL_LISTstMemList;/**<指向内存链表的指针*/}QUEUE_CB_S;4.2消息队列控制块
队列控制块中包含信息的说明如下:
(1)*pucQueue:队列指针,消息队列的地址,即存放消息的起始地址,指向消息节点区域,该区域是在创建队列时按照消息节点个数和节点大小从动态内存池中申请出来的一块空间。
(2)usQueueState:队列状态,表示该队列的使用情况,OS_QUEUE_UNUSED表示队列没有使用,OS_QUEUE_INUSED表示队列被使用。
(3)usQueueLen:队列中消息的个数,队列总长,表示该消息队列最大可存储多少个消息。
(4)usQueueSize:消息节点大小,每个消息节点占用的内存大小。
(5)usQueueID:队列ID,即队列标识号,用于区别其他消息队列。
(6)usQueueHead、usQueueTail:消息头、尾节点位置,用于标识读消息和写消息指针的位置。
(7)usReadWriteableCnt[2]:队列中已有的可读或可写消息的数量,下标为OS_QUEUE_READ(即0)表示可读消息数量,下标为OS_QUEUE_WRITE(即1)表示可写消息数量。
(8)stReadWriteList[2]:读取或写入消息任务等待链表,等待读、写消息的任务链表,下标为OS_QUEUE_READ(即0)表示读阻塞队列,下标为OS_QUEUE_WRITE(即1)表示写阻塞队列。
消息队列运行机制MessageQueueRunningMechanism4.34.3消息队列运行机制
创建队列时,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,并初始化消息队列的相关信息,创建成功后返回队列ID。
在队列控制块中维护一个消息头节点位置usQueueHead和一个消息尾节点位置usQueueTail,用以记录当前队列中消息存储情况。usQueueHead表示队列中被占用消息的起始位置。usQueueTail表示队列中被占用消息节点的结束位置(或者理解为空闲消息节点的起始位置)。刚创建时usQueueHead和usQueueTail均设置成队列起始位置。
写队列前,根据usReadWriteableCnt[1]判断队列是否可以写入,不能对已满(usReadWriteableCnt[1]为0)队列进行写队列操作。写队列时,根据usQueueTail找到被占用消息节点末尾的空闲节点作为消息写入区域。如果usQueueTail所示的位置已经是队列尾,则采用回卷方式(回到起点位置,可以将消息队列看作一个环形队列)进行操作。
读队列前,根据usReadWriteableCnt[0]判断队列是否有消息读取,对全部空闲(usReadWriteableCnt[0]为0)队列进行读队列操作会引起任务挂起。读队列时,根据usQueueHead找到最先写入队列中的消息节点进行读取。如果usQueueHead所示的位置是队列尾,则采用回卷方式进行操作。
删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,释放原队列所占的空间,对应的队列控制头置为初始状态。4.3消息队列运行机制LiteOS的消息队列采用两个双向链表来维护,stReadWriteList[0]读消息链表指向消息队列的头部,stReadWriteList[1]写消息链表指向消息队列的尾部,通过访问这两个链表就能直接访问对应的消息空间(消息空间中的每个节点称为消息节点)。
消息队列读写数据操作如图4-1所示。图4-1消息队列读写数据操作示意图消息队列常用函数CommonFunctionsofMessageQueue4.44.4
消息队列常用函数
HuaweiLiteOS中消息队列处理的常用函数及功能如表4-1所示。
表4-1消息队列处理的常用函数及功能功能分类函数名功能创建/删除消息队列LOS_QueueCreate创建一个消息队列,由系统动态申请队列空间LOS_QueueDelete根据队列ID删除一个指定队列读/写队列(不带拷贝)LOS_QueueRead读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)LOS_QueueWrite向指定队列尾节点中写入bufferAddr的值(即buffer的地址)读/写队列(带拷贝)LOS_QueueReadCopy读取指定队列头节点中的数据LOS_QueueWriteCopy向指定队列尾节点中写入bufferAddr中保存的数据获取队列信息LOS_QueueInfoGet获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务4.4
消息队列常用函数
4.4.1消息队列创建函数LOS_QueueCreate() 表4-2LOS_QueueCreate()函数语法要点
消息队列创建函数LOS_QueueCreate()用于创建一个队列,用户可以根据自己的需要指定队列的长度、消息节点的大小等信息,LOS_QueueCreate()语法要点如表4-2所示。函数原型LITE_OS_SEC_TEXT_INITUINT32LOS_QueueCreate(CHAR*pcQueueName,UINT16usLen,UINT32*puwQueueID,UINT32uwFlags,UINT16usMaxMsgSize)函数传入值*pcQueueName:消息队列的名称usLen:消息队列的长度,值为1~0xFFFF*puwQueueID:消息队列ID变量的指针,该变量用于保存创建队列成功时返回的消息队列ID,由用户定义,对消息队列的读写操作都是通过消息队列ID来操作的uwFlags:队列模式,FIFO或者PRIOusMaxMsgSize:消息节点大小(单位为字节),其取值为1~(0xFFFF-4)函数返回值LOS_OK:消息队列创建成功错误代码:出错LOS_QueueCreate()函数会根据传入的队列长度、消息节点长度来动态申请内存空间(这块内存的大小等于单个消息节点大小加4字节再乘以消息队列的长度,因为LiteOS实际在申请空间时,会将usMaxMsgSize的值再加上4),用于缓存用户写入队列的数据。4.4
消息队列常用函数4.4.2消息队列删除函数LOS_QueueDelete() 表4-3LOS_QueueDelete()函数语法要点
消息队列删除函数LOS_QueueDelete()可根据队列ID删除消息队列,删除之后,这个队列的所有信息都会被系统回收清空,而且不能再次使用这个队列。需要注意的是,队列在使用或者阻塞中是不能被删除的。函数原型LITE_OS_SEC_TEXT_INITUINT32LOS_QueueDelete(UINT32uwQueueID)函数传入值uwQueueID:消息队列的ID函数返回值LOS_OK:成功删除消息队列错误代码:出错4.4
消息队列常用函数4.4.3消息队列写数据函数
表4-4LOS_QueueWrite()函数语法要点
LiteOS消息队列的传递方式有两种,一种是不带复制传递消息,另一种是带复制传递消息,带复制的读写方式,就是将指定地址的消息数据全部存入消息队列中;不带复制的读写方式,本质上是将消息的地址存入消息队列中。1.不带复制方式写入函数LOS_QueueWrite()
任务或者中断服务程序都可以给消息队列写入消息,当写入消息时,如果队列未满,LiteOS会将消息写入到消息队列队尾;如果队列已满,则会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列还是满的,该任务将保持阻塞状态以等待队列有空闲的消息节点,假如此时系统中有任务从其等待的队列中读取了消息(队列状态变为未满),该任务将自动由阻塞态转为就绪态,执行写入操作。但是,当任务等待的时间超过了指定的阻塞时间,即使队列中还是满的,任务也会自动从阻塞态变成就绪态,此时写入消息的任务或者中断程序会收到一个错误代码LOS_ERRNO_QUEUE_ISFULL。
函数原型LITE_OS_SEC_TEXTUINT32LOS_QueueWrite(UINT32uwQueueID,VOID*pBufferAddr,UINT32uwBufferSize,UINT32uwTimeOut)函数传入值uwQueueID:消息队列的ID*pBufferAddr:要写入的消息的起始地址uwBufferSize:写入消息的大小uwTimeOut:等待时间,其值范围为0~LOS_WAIT_FOREVER,单位为Tick,当uwTimeOut为0的时候是不等待,为LOS_WAIT_FOREVER时候是一直等待,在中断中使用该函,uwTimeOut的值必须为0函数返回值LOS_OK:写消息成功错误代码:出错4.4
消息队列常用函数表4-5LOS_QueueWriteCopy()函数语法要点2.带复制方式写入函数LOS_QueueWriteCopy()LOS_QueueWriteCopy()函数语法要点如表4-5所示。函数原型LITE_OS_SEC_TEXTUINT32LOS_QueueWriteCopy(UINT32uwQueueID,VOID*pBufferAddr,UINT32uwBufferSize,UINT32uwTimeOut)函数传入值uwQueueID:消息队列的ID*pBufferAddr:要写入的消息的起始地址uwBufferSize:写入消息的大小uwTimeOut:等待时间,其值范围为0~LOS_WAIT_FOREVER,单位为Tick,当uwTimeOut为0的时候是不等待,为LOS_WAIT_FOREVER时候是一直等待函数返回值LOS_OK:写消息成功错误代码:出错写入消息队列时需要注意:(1)在使用写入队列的操作前应先创建要写入的队列;(2)写入由uwBufferSize指定大小的消息,该值不能大于消息节点的大小;(3)在中断上下文环境中,必须使用非阻塞模式写入,也就是等待时间为0个Tick;(4)LOS_QueueWrite()函数写入队列节点中的是消息的地址;(5)LOS_QueueWriteCopy()函数写入队列节点中的是存储在BufferAddr中的消息。4.4
消息队列常用函数4.4.4消息队列读数据函数
表4-6LOS_QueueRead()函数语法要点1.不带复制方式读取函数LOS_QueueRead()不带复制方式读取函数LOS_QueueRead()用于读取指定队列中的消息,并将获取的消息存储到pBufferAddr指定的地址,使用时用户需要指定读取消息的存储地址与大小。LOS_QueueRead()函数语法要点如表4-6所示。函数原型LITE_OS_SEC_TEXTUINT32LOS_QueueRead(UINT32uwQueueID,VOID*pBufferAddr,UINT32uwBufferSize,UINT32uwTimeOut)函数传入值uwQueueID:消息队列的ID*pBufferAddr:要读取的消息的起始地址uwBufferSize:读取消息缓冲区的大小,该值不能小于消息节点大小uwTimeOut:等待时间,其值范围为0~LOS_WAIT_FOREVER,单位为Tick,当uwTimeOut为0的时候是不等待,为LOS_WAIT_FOREVER时候是一直等待函数返回值LOS_OK:读消息成功错误代码:出错4.4
消息队列常用函数表4-7LOS_QueueReadCopy()函数语法要点2.带复制方式读取函数LOS_QueueReadCopy()LOS_QueueReadCopy()是带复制读取读取消息函数,其语法要点如表4-7所示。函数原型LITE_OS_SEC_TEXTUINT32LOS_QueueReadCopy(UINT32uwQueueID,VOID*pBufferAddr,UINT32*puwBufferSize,UINT32uwTimeOut)函数传入值uwQueueID:消息队列的ID*pBufferAddr:要读取的消息的起始地址。*puwBufferSize:读取消息缓冲区的大小,该值不能小于消息节点大小uwTimeOut:等待时间,其值范围为0~LOS_WAIT_FOREVER,单位为Tick,当uwTimeOut为0的时候是不等待,为LOS_WAIT_FOREVER时候是一直等待函数返回值LOS_OK:读消息成功错误代码:出错4.4
消息队列常用函数读取消息时需要注意:(1)使用消息队列读取函数之前应先创建需要读取消息的队列,并根据队列ID进行读取消息;(2)队列读取采用的是先进先出(FIFO)模式,即先读取存储在队列头部的消息;(3)用户必须在读取消息时指定读取消息的大小,其值不能小于消息节点大小。如buffsize,该变量既作为输入又作为输出,作为输入是指定读取缓冲区的大小;作为输出,buffsize是用于保存读取到消息的大小,把读取到的消息大小写在buffsize变量中;(4)不要在非阻塞模式下读取或写入队列,例如中断,如果非要在中断中读取消息(一般中断是不读取消息的,但也有例外,比如在某个定时器中断中读取信息进行判断时),则应将队列设为非阻塞模式,也就是等待时间为0个Tick;(5)使用LOS_QueueRead()函数时,用户必须定义一个存储地址的变量,假设为r_queue,并且把存储消息的地址传递给LOS_QueueRead()函数,否则,将发生地址非法的错误。r_queue变量中存放的是队列节点的地址;(6)使用LOS_QueueReadCopy()函数时,用户自己定义一个存储空间,如r_queue,并且把存储消息的起始地址传递给LOS_QueueReadCopy()函数,否则,将发生地址非法的错误。r_queue中存放的是队列节点中的消息而非地址,因此该空间必须是足够大。
任务描述
在LiteOS中创建两个任务,一个是写消息任务,另一个是读消息任务。两个任务独立运行。写消息任务检测按键的按下情况,按下KEY1键时向消息队列中写入一条消息,按下KEY2键时向消息队列中写入另一条消息;读消息任务一直等待消息的到来,当读取成功时,将读出的数据通过串口输出。
任务4-1消息队列使用(不带复制读写方式)任务描述
在LiteOS中创建两个任务,一个是写消息任务,另一个是读消息任务。两个任务独立运行,按下KEY1键时向消息队列中写入消息,按下KEY2键时从消息队列中读出消息。任务4-2消息队列使用(带复制读写方式)
谢谢观看THANKYOUFORWATCHING任务4-1消息队列使用(不带复制读写方式)Task4-1UsingMessageQueue(withoutcopymode)《物联网操作系统技术与应用》制作人张亚军
任务描述
在LiteOS中创建两个任务,一个是写消息任务,另一个是读消息任务。两个任务独立运行。写消息任务检测按键的按下情况,按下KEY1键时向消息队列中写入一条消息,按下KEY2键时向消息队列中写入另一条消息;读消息任务一直等待消息的到来,当读取成功时,将读出的数据通过串口输出。
任务实现1.打开第2章中移植好LiteOS的裸机工程TEST,修改main.c文件,添加头文件。
任务4-1消息队列使用(不带复制读写方式)26
/*USERCODEBEGINIncludes*/27
/*LiteOS头文件*/28#include"los_sys.h"29#include"los_task.ph"30#include"los_queue.h"31
/*USERCODEENDIncludes*/2.定义任务ID变量、消息队列ID变量、消息队列长度、消息节点长度以及全局变量。3.创建和管理读消息任务Receive_Task和写消息任务Send_Task。1)定义任务实现函数Receive_Task()和Send_Task()。
任务4-1消息队列使用(不带复制读写方式)60/*USERCODEBEGIN0*/61/*定义任务ID变量*/62UINT32Receive_Task_Handle;63UINT32Send_Task_Handle;64
/*定义消息队列的ID*/65UINT32Test_Queue_Handle;66
/*定义消息队列长度*/67#defineTEST_QUEUE_LEN1068#defineTEST_QUEUE_SIZE1069
/*写消息队列需要用到的全局变量*/70UINT32send_data1=1;71UINT32send_data2=2;72
/************************************************************73*@函数名:Receive_Task74*@功能说明:Receive_Task任务实现75*@参数:无76*@返回值:无77***********************************************************/
任务4-1消息队列使用(不带复制读写方式)78
static
voidReceive_Task(void)79
{80
/*定义一个返回类型变量,初始化为LOS_OK*/81UINT32uwRet=LOS_OK;82UINT32r_queue;83UINT32buffsize=10;84
/*任务都是一个无限循环,不能返回*/85
while(1)86
{87
/*队列读取(接收),等待时间为一直等待*/88uwRet=LOS_QueueRead(Test_Queue_Handle,
/*读取(接收)队列的ID(句柄)*/89
&r_queue,
/*读取(接收)的数据保存位置*/90buffsize,
/*读取(接收)的数据的长度*/91LOS_WAIT_FOREVER);
/*等待时间:一直等*/92LOS_TaskDelay(500);
93
if(LOS_OK==uwRet)94
{95printf("本次从消息队列中读出的数据是:%d,读出数据的长度是:%d\n",*(UINT32*)r_queue,buffsize);96
}97
else98
{99printf("数据接收出错,错误代码0x%X\n",uwRet);
任务4-1消息队列使用(不带复制读写方式)100
}101
/*20ms扫描一次*/102LOS_TaskDelay(20);
103
}104}105/************************************************************106*@函数名:Send_Task107*@功能说明:Send_Task任务实现108*@参数:无109*@返回值:无110***********************************************************/111static
voidSend_Task(void)112{113
/*定义一个返回类型变量,初始化为LOS_OK*/114UINT32uwRet=LOS_OK;
115
/*任务都是一个无限循环,不能返回*/116
while(1)117
{118
/*KEY1键被按下*/119
if(
!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4))
//读取KEY按键引脚,低电平表示按下120
{
任务4-1消息队列使用(不带复制读写方式)121
/*将数据写入(发送)到队列中,等待时间为0*/122uwRet=LOS_QueueWrite(Test_Queue_Handle,
/*写入(发送)队列的ID(句柄)*/123
&(send_data1),
/*写入(发送)的数据*/124
sizeof(send_data1),
/*数据的长度*/125
0);
/*等待时间为0*/126
if(LOS_OK==uwRet)127
{128printf("本次写入消息队列的数据是:%d\n",send_data1);129
}130
else131
{132printf("数据不能发送到消息队列!错误代码0x%X\n",uwRet);133
}134LOS_TaskDelay(500);
//等待松手,延时防松手抖动135
}
136
/*KEY2键被按下*/137
if(
!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5))
//读取KEY按键引脚,低电平表示按下138
{139
/*将数据写入(发送)到队列中,等待时间为0*/
任务4-1消息队列使用(不带复制读写方式)140uwRet=LOS_QueueWrite(Test_Queue_Handle,
/*写入(发送)队列的ID(句柄)*/141
&(send_data2),
/*写入(发送)的数据*/142
sizeof(send_data2),
/*数据的长度*/143
0);
/*等待时间为0*/144
if(LOS_OK==uwRet)145
{146printf("本次写入消息队列的数据是:%d\n",send_data2);147
}148
else149
{150printf("数据不能发送到消息队列!错误代码0x%X\n",uwRet);151
}152LOS_TaskDelay(500);
//等待松手,延时防松手抖动153
}
154
/*20ms扫描一次*/155LOS_TaskDelay(20);
156
}157}2)定义任务创建函数Creat_Receive_Task()和Creat_Send_Task()。
任务4-1消息队列使用(不带复制读写方式)158/***********************************************************159*@函数名:Creat_Receive_Task160*@功能说明:创建Receive_Task任务161*@参数:
无
162*@返回值:无163**********************************************************/164staticUINT32Creat_Receive_Task()165{166
//定义一个返回类型变量,初始化为LOS_OK167UINT32uwRet=LOS_OK;
168
//定义一个用于创建任务的参数结构体169TSK_INIT_PARAM_Stask_init_param;
170task_init_param.usTaskPrio=
5;
/*任务优先级,数值越小,优先级越高*/171task_init_param.pcName=
"Receive_Task";/*任务名*/172task_init_param.pfnTaskEntry=
(TSK_ENTRY_FUNC)Receive_Task;/*任务函数入口*/173task_init_param.uwStackSize=
1024;
/*堆栈大小*/174uwRet=LOS_TaskCreate(&Receive_Task_Handle,
&task_init_param);/*创建任务*/175
returnuwRet;176}
任务4-1消息队列使用(不带复制读写方式)177/************************************************************178*@函数名:Creat_Send_Task179*@功能说明:创建Send_Task任务180*@参数:
无
181*@返回值:无182**********************************************************/183staticUINT32Creat_Send_Task()184{185
//定义一个返回类型变量,初始化为LOS_OK186UINT32uwRet=LOS_OK;
187TSK_INIT_PARAM_Stask_init_param;188task_init_param.usTaskPrio=
4;
/*任务优先级,数值越小,优先级越高*/189task_init_param.pcName=
"Send_Task";
/*任务名*/190task_init_param.pfnTaskEntry=
(TSK_ENTRY_FUNC)Send_Task;/*任务函数入口*/191task_init_param.uwStackSize=
1024;
/*堆栈大小*/
192uwRet=LOS_TaskCreate(&Send_Task_Handle,
&task_init_param);/*创建任务*/193
returnuwRet;194}
3)定义任务管理函数AppTaskCreate()。
任务4-1消息队列使用(不带复制读写方式)195/***********************************************************196*@函数名:AppTaskCreate197*@功能说明:任务创建,为了方便管理,所有的任务创建函数都可以放在这个函数里面198*@参数:无199*@返回值:无200***********************************************************/201staticUINT32AppTaskCreate(void)202{203
/*定义一个返回类型变量,初始化为LOS_OK*/204UINT32uwRet=LOS_OK;
205
/*创建一个测试队列*/206uwRet=LOS_QueueCreate("Test_Queue",
/*队列的名称*/207TEST_QUEUE_LEN,
/*队列的长度*/208
&Test_Queue_Handle,
/*队列的ID(句柄)*/209
0,
/*队列模式,官方暂时未使用*/210TEST_QUEUE_SIZE);
/*节点大小,单位为字节*/211
if
(uwRet!=LOS_OK)212
{213printf("Test_Queue队列创建失败!失败代码0x%X\n",uwRet);214
returnuwRet;215
}
任务4-1消息队列使用(不带复制读写方式)216uwRet=Creat_Receive_Task();217
if
(uwRet!=LOS_OK)218
{219printf("Receive_Task任务创建失败!失败代码0x%X\n",uwRet);220
returnuwRet;221
}222uwRet=Creat_Send_Task();223
if
(uwRet!=LOS_OK)224
{225printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);226
returnuwRet;227
}228
returnLOS_OK;229}230/*USERCODEEND0*/
4.在主函数中修改代码。
任务4-1消息队列使用(不带复制读写方式)236intmain(void)237{238
/*USERCODEBEGIN1*/239
//定义一个返回类型变量,初始化为LOS_OK240UINT32uwRet=LOS_OK;
241
/*USERCODEEND1*/242
/*MCUConfiguration---------------------------------------*/243
/*Resetofallperipherals,InitializestheFlashinterfaceandtheSystick.*/244HAL_Init();245
/*Configurethesystemclock*/246SystemClock_Config();247
/*Initializeallconfiguredperipherals*/248MX_GPIO_Init();249MX_USART1_UART_Init();250MX_USART2_UART_Init();251MX_USART3_UART_Init();
任务4-1消息队列使用(不带复制读写方式)252
/*LiteOS内核初始化*/253uwRet=LOS_KernelInit();
254
if
(uwRet!=LOS_OK)255
{256printf("LiteOS内核初始化失败!失败代码0x%X\n",uwRet);257
returnLOS_NOK;258
}259printf("任务4-1消息队列使用(不带复制读写方式)!\n\n");260uwRet=AppTaskCreate();261
if
(uwRet!=LOS_OK)262
{263printf("AppTaskCreate创建任务失败!失败代码0x%X\n",uwRet);264
returnLOS_NOK;265
}266
/*开启LiteOS任务调度*/267LOS_Start();268
//正常情况下不会执行到这里269
while(1);270}5.添加串口发送函数。
任务4-1消息队列使用(不带复制读写方式)328/*USERCODEBEGIN4*/329intfputc(intch,
FILE
*f)330{
331HAL_UART_Transmit(&huart3,
(uint8_t
*)&ch,
1,
0xFFFF);
332
returnch;
333}
334/*USERCODEEND4*/6.查看运行结果。
编译并下载程序到开发板中。打开串口调试助手,按下开发板RST复位键,复位开发板,按下开发板上的KEY1键,向队列中写入send_data1的地址,按下KEY2键,向队列中写入send_data2的地址,读消息任务读出数据,并通过串口输出相应的信息,串口打印信息如图4-2所示。图4-2任务4-1运行结果
任务4-1消息队列使用(不带复制读写方式)谢谢观看THANKYOUFORWATCHING任务4-2消息队列使用(带复制读写方式)Task4-2UsingMessageQueue(withcopymode)《物联网操作系统技术与应用》制作人张亚军
任务描述
在LiteOS中创建两个任务,一个是写消息任务,另一个是读消息任务。两个任务独立运行,按下KEY1键时向消息队列中写入消息,按下KEY2键时从消息队列中读出消息。
任务实现1.打开第2章中移植好LiteOS的裸机工程TEST,修改main.c文件,添加头文件。
任务4-2消息队列使用(带复制读写方式)26
/*USERCODEBEGINIncludes*/27
/*LiteOS头文件*/28#include"los_sys.h"29#include"los_task.ph"30#include"los_queue.h"31
/*USERCODEENDIncludes*/2.定义任务ID变量、消息队列ID变量、消息队列长度、消息节点长度以及全局变量。3.创建和管理读消息任务Receive_Task和写消息任务Send_Task。1)定义任务实现函数Receive_Task()和Send_Task()。
任务4-2消息队列使用(带复制读写方式)60/*USERCODEBEGIN0*/61/*定义任务ID变量*/62UINT32Receive_Task_Handle;63UINT32Send_Task_Handle;64
/*定义消息队列的ID*/65UINT32Test_Queue_Handle;66
/*定义消息队列长度*/67#defineTEST_QUEUE_LEN1068#defineTEST_QUEUE_SIZE1069
/*写消息队列需要用到的全局变量*/70UINT32send_data,i=1;71
/************************************************************72*@函数名:Receive_Task73*@功能说明:Receive_Task任务实现74*@参数:无75*@返回值:无76***********************************************************/
任务4-2消息队列使用(带复制读写方式)77
static
voidReceive_Task(void)78
{79
/*定义一个返回类型变量,初始化为LOS_OK*/80UINT32uwRet=LOS_OK;81UINT32r_queue;82UINT32buffsize;83
/*任务都是一个无限循环,不能返回*/84
while(1)85
{86buffsize=10;87
/*KEY2键被按下*/88
if(
!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5))
89
{90
/*队列读取(接收),等待时间为一直等待*/91uwRet=LOS_QueueReadCopy(Test_Queue_Handle,
/*读取(接收)队列的ID(句柄)*/92
&r_queue,
/*读取(接收)的数据保存位置*/93
&buffsize,
/*读取(接收)的数据的长度*/94LOS_WAIT_FOREVER);
/*等待时间:一直等*/
任务4-2消息队列使用(带复制读写方式)95LOS_TaskDelay(500);
//等待松手,延时防松手抖动96
if(LOS_OK==uwRet)97
{98printf("本次从消息队列中读出的数据是:%d,读出数据的长度是:%d\n",r_queue,buffsize);99
}100
else101
{102printf("数据接收出错,错误代码0x%X\n",uwRet);103
}104
}105
/*20ms扫描一次*/106LOS_TaskDelay(20);
107
}108}109/***********************************************************110*@函数名:Send_Task111*@功能说明:Send_Task任务实现112*@参数:无113*@返回值:无114***********************************************************/
任务4-2消息队列使用(带复制读写方式)115static
voidSend_Task(void)116{117
/*定义一个返回类型变量,初始化为LOS_OK*/118UINT32uwRet=LOS_OK;
119
/*任务都是一个无限循环,不能返回*/120
while(1)121
{122
/*KEY1键被按下*/123
if(
!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4))
//读取KEY按键引脚,低电平表示按下124
{125send_data=i;126
/*将数据写入(发送)到队列中,等待时间为0*/127uwRet=LOS_QueueWriteCopy(Test_Queue_Handle,
/*写入(发送)队列的ID(句柄)*/128
&(send_data),
/*写入(发送)的数据*/129
sizeof(send_data),
/*数据的长度*/130
0);
/*等待时间为0*/131
if(LOS_OK==uwRet)132
{133printf("本次写入消息队列的数据是:%d\n",send_data);134
}135
else
任务4-2消息队列使用(带复制读写方式)136
{137printf("数据不能发送到消息队列!错误代码0x%X\n",uwRet);138
}139LOS_TaskDelay(500);
//等待松手,延时防松手抖动140i++;141
}
142
/*20ms扫描一次*/143LOS_TaskDelay(20);
144
}145}2)定义任务创建函数Creat_Receive_Task()和Creat_Send_Task()。146/**********************************************************147*@函数名:Creat_Receive_Task148*@功能说明:创建Receive_Task任务149*@参数:
无
150*@返回值:无151**********************************************************/152staticUINT32Creat_Receive_Task()
任务4-2消息队列使用(带复制读写方式)153{154
//定义一个返回类型变量,初始化为LOS_OK155UINT32uwRet=LOS_OK;
156
//定义一个用于创建任务的参数结构体157TSK_INIT_PARAM_Stask_init_param;
158task_init_param.usTaskPrio=
5;
/*任务优先级,数值越小,优先级越高*/159task_init_param.pcName=
"Receive_Task";/*任务名*/160task_init_param.pfnTaskEntry=
(TSK_ENTRY_FUNC)Receive_Task;/*任务函数入口*/161task_init_param.uwStackSize=
1024;
/*堆栈大小*/162uwRet=LOS_TaskCreate(&Receive_Task_Handle,
&task_init_param);/*创建任务*/163
returnuwRet;164}165/************************************************************166*@函数名:Creat_Send_Task167*@功能说明:创建Send_Task任务168*@参数:无169*@返回值:无170***********************************************************/
任务4-2消息队列使用(带复制读写方式)171staticUINT32Creat_Send_Task()172{173
//定义一个返回类型变量,初始化为LOS_OK174UINT32uwRet=LOS_OK;
175TSK_INIT_PARAM_Stask_init_param;176task_init_param.usTaskPrio=
4;
/*任务优先级,数值越小,优先级越高*/177task_init_param.pcName=
"Send_Task";
/*任务名*/178task_init_param.pfnTaskEntry=
(TSK_ENTRY_FUNC)Send_Task;/*任务函数入口*/179task_init_param.uwStackSize=
1024;
/*堆栈大小*/
180uwRet=LOS_TaskCreate(&Send_Task_Handle,
&task_init_param);/*创建任务*/181
returnuwRet;182}
3)定义任务管理函数AppTaskCreate()。
任务4-2消息队列使用(带复制读写方式)183/*************************************************************184*@函数名:AppTaskCreate185*@功能说明:任务创建,为了方便管理,所有的任务创建函数都可以放在这个函数里面186*@参数:无187*@返回值:无188************************************************************/189staticUINT32AppTaskCreate(void)190{191
/*定义一个返回类型变量,初始化为LOS_OK*/
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 学生会学风部考勤制度
- 如何写公司考勤制度
- 学校炊事员考勤制度
- 四川各地教师考勤制度
- 基层水管所考勤制度
- 员工无视考勤制度
- 企止考勤制度
- 国企企业考勤制度
- 医院医疗数据分析报告模板
- 货物搬运服务方案范本
- AIGC发展研究4.0版本
- 2025年磷酸燃料电池行业分析报告及未来发展趋势预测
- 设备润滑保养培训
- 湖南公费定向师范生协议书
- TCHES65-2022生态护坡预制混凝土装配式护岸技术规程
- 二氧化碳排放计算方法与案例分析
- 美的微波炉EG823LC3-NS1说明书
- 老年骨折术后谵妄护理
- 大健康趋势下的干细胞技术发展与应用
- DB6107∕T 70-2025 汉中市学校食堂食品安全管理规范
- 河南专升本高等数学2012-2021年真题和答案解析
评论
0/150
提交评论