版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第10章FreeRTOS进程间通信技术第10章
FreeRTOS进程间通信技术【实践案例10-1】消息队列的访问【实践案例10-2】二值信号量的应用【实践案例10-3】计数信号量的应用【实践案例10-4】互斥量的应用【实践案例10-5】事件组的创建及其应用【实践案例10-6】任务通知的应用
10.1.1队列的创建和存储10.1.2队列管理函数10.1.3CMSIS接口函数【实践案例10-1】消息队列的访问【照猫画虎10-1】消息队列的访问10.1队
列队列(Queue)又称消息队列(MessageQueue),是一种常用于任务和进程间通信的组件对象,可以在任务与任务之间或者任务与中断服务程序之间传递消息(Message)。任务或中断服务程序可以将一条或多条消息放入队列中,也可以从队列中获取消息。当有多个消息发送到消息队列时,多个消息通常遵循先进先出(First-In
&
First-Out,FIFO)的原则,在FreeRTOS中也支持后进先出(First-In
&Last-Out,LIFO)原则。10.1队
列队列实际上是一种数据结构。创建队列时,将为队列分配指定个数的存储单元,每个存储单元存储固定大小的数据,进程间传递的消息数据就保存在这些存储单元中。10.1.1队列的创建和存储队列的创建在queue.h中提供了两个基本的队列创建函数,即xQueueCreate()和xQueueCreateStatic()。在调用上述两个函数实现队列的创建时,只需要给定队列的长度和队列中每个消息的字节数。例如,如下语句Queue_KeysHandle=xQueueCreate(5,2);创建了一个长度为5的队列,队列中每个存储单元的字节数为2,返回指向所创建队列的队列句柄Queue_KeysHandle。10.1队
列队列中的各存储单元可以设置为任意大小,可以存储任意数据类型。在FreeRTOS中,队列存储数据采用数据复制的方式,而有些操作系统中是将数据的指针存放到队列中。此外,一个队列不仅需要存放消息数据的存储单元,还需要占用另外的存储单元存放队列本身的状态信息等,这些单元称为队列控制块(Queue-ControlBlock,QCB)。10.1队
列CubeMX中队列的创建10.1队
列10.1队
列队列名队列单元数队列单元位数存储器分配方案缓冲器名缓冲器大小队列控制块名10.1队
列在CubeMX生成的工程代码中,根据上述配置,将自动调用CMSIS-FreeRTOS接口函数osMessageQueueNew()实现队列的创建。在cmsis_os2.h中,该函数的原型声明如下:osMessageQueueId_tosMessageQueueNew(uint32_tmsg_count, uint32_tmsg_size, constosMessageQueueAttr_t*attr);其中参数msg_count指定队列的最多消息个数(即队列的长度),msg_size指定队列中每个消息的字节数,参数attr指定队列的属性,默认值为NULL。例如,osMessageQueueNew(5,
2,NULL);10.1.2队列管理函数10.1队
列队列是一个共享的存储区域,有队列头和队列尾,队列中的消息可以被多个进程访问。任务或进程向队列写入数据称为发送(Send)消息,从队列读取数据称为接收(Receive)消息。10.1队
列接收消息时,总是从队头读取数据,从队列中读出消息后,该消息将从队列中删除,后面的数据顺序前移。向队列发送的消息可以存入队头或队尾,队列中原来的消息顺序向后或向前移动。因此,队列的访问可以有两种模式,即FIFO和FILO模式。10.1队
列xQueueSendToBack():写一个消息到队列尾(FIFO模式)
xQueueSendToFront():写一个消息到队列头(FILO模式)
xQueueReceive():从队列中读取一个消息,读出后从队列中删除该消息
xQueuePeek():从队列中读取一个消息,读出后不从队列中删除该消息
消息的发送(写)和接收(读)函数10.1队
列写消息返回值:如果在指定的阻塞等待时间内能够将消息写入队列,则返回pdPASS。如果队列已满,并且在指定的阻塞时间到时,队列中仍然没有可用的存储空间,则新的消息无法写入,此时返回errQUEUE_FULL。读消息返回值:当从队列成功读取到消息后,返回pdTRUE;否则返回0。如果队列为空,则可以在指定的阻塞时间内等待其他任务将消息放入队列。10.1队
列structAMessage{charucMessageID;charucData[20];}xMessage; //定义消息数据结构QueueHandle_txQueue; //定义队列句柄voidvATask(void*pvParameters){ //定义消息发送的任务函数structAMessage*pxMessage; //定义消息结构体指针xQueue=xQueueCreate(10,sizeof(structAMessage*)); //创建队列if(xQueue==pdTRUE){ //如果队列创建成功
pxMessage=&xMessage;
xQueueSend(xQueue,(void*)&pxMessage,(TickType_t)0);//发送消息}……}10.1队
列voidvADifferentTask(void*pvParameters){ //定义消息接收的任务structAMessage*pxRMessage; //定义接收消息结构体if(xQueue!=0){ if(xQueueReceive(xQueue,&pxRMessage,(TickType_t)1)){//接收消息 …… //对消息进行处理 }}……}10.1队
列对接收消息的任务来说,当队列中没有消息时,任务将被阻塞,以等待队列数据有效。
当队列中有新消息时,被阻塞的任务会被唤醒进入就绪态,以便等待调度运行处理新消息。
当等待的时间超过了接收消息时指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。队列访问的阻塞状态10.1队
列对发送消息的任务来说,如果队列未满或者允许队列中的消息被覆盖,待发送的消息将被拷贝到消息队列队尾;否则任务将进入阻塞状态,以等待队列允许将消息写入队列。
当其他任务从队列中读取了数据(队列未满),该任务将自动由阻塞态转移为就绪态。
当等待的时间超过了指定的发送消息超时时间,即使队列中还不允许入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码errQUEUE_FULL。10.1.3CMSIS接口函数10.1队
列在cmsis_os2.c/.h文件中,将上述消息队列的访问操作函数进一步封装,得到的CMSIS接口函数名都以osMessageQueue为前缀。以实现消息的发送和接收为例,相应的两个函数原型声明如下:osStatus_tosMessageQueuePut(osMessageQueueId_tmq_id,
constvoid*msg_ptr,
uint8_tmsg_prio,uint32_ttimeout);osStatus_tosMessageQueueGet(osMessageQueueId_tmq_id,void*msg_ptr,
uint8_t*msg_prio,uint32_ttimeout);其中,mq_id为消息队列句柄,一般为osMessageQueueNew()函数的返回值;msg_ptr为收发消息数据指针;msg_prio为消息的优先级;timeout为超时时间,0表示不等待,osWaitForever表示一直等待。10.1队
列函数的返回值:osStatus_t枚举类型,具体有如下几种情况:如果消息收发成功,则返回osOK;如果在给定的超时等待时间内无法将消息放入队列,则返回osErrorTimeout;如果消息队列中没有足够空间用于存放待写入的消息,或者无法从队列获取到消息,则返回osErrorResource;如果函数的参数错误,则返回osErrorParameter。【实践案例10-1】消息队列的访问创建两个任务,分别实现消息的发送和接收。两个任务独立运行,发送消息任务不断检测按键K1和K2是否按下,当有按键按下后,发送消息。另一个任务一直等待消息,一旦获取到消息就把消息打印在串口调试助手里。10.1队
列CubeMX配置10.1队
列在CubeMX中新建工程,并做如下组件配置:系统时钟为168MHz;USART1为异步模式Asynchronous,参数都取默认值;PA0(连接K1)和PC13(连接K2)为输入模式;FreeRTOS为CMSIS_V2模式,HAL时基源为TIM6。此外在CodeGenerator中注意勾选Generateperipheralinitializationasapairof...选项。
创建任务和队列10.1队
列编写应用程序10.1队
列CubeMX导入头文件自行导入头文件10.1队
列发送消息任务函数10.1队
列接收消息任务函数
10.2.1信号量和互斥量的分类10.2.2互斥量的优先级继承10.2.3信号量和互斥量管理函数10.2.4CMSIS接口函数【实践案例10-2】二值信号量的应用【实践案例10-3】计数信号量的应用【实践案例10-4】互斥量的应用10.2信号量和互斥量10.2.1分类10.2信号量和互斥量信号量(Semaphore)和互斥量(Mutex)都是基于消息队列的基本数据结构,具体又分别包括二值信号量、计数信号量、互斥量和递归互斥量,如图10-6所示。10.2信号量和互斥量信号量是一种实现进程间通信的机制,可以实现任务之间的同步或临界资源的互斥访问,常用于在一组相互竞争的任务之间对临界资源进行协调访问。信号量(Semaphore)信号量分为二值信号和计数信号量。二值信号量(BinarySemaphore)实质上是只有一个消息的队列,这个队列只有两种状态,即空或满。二值信号量一般用作标志,用于进程之间的同步,这种情况下只需要知道队列中是否有消息即可,而无需关注消息是什么。10.2信号量和互斥量如果信号量为空(其中无消息),也就是任务1还没有给出(Give)该信号量,则需要获取(Take)该信号量的任务2将因为没有获取到消息而进入阻塞等待状态。只有等到任务1满足一定的条件从而给出或释放该信号量时,任务2才能获得信号量从而进入就绪态。如果该任务的优先级是当前就绪任务列表中最高的,则立即进入运行态,从而实现任务1和任务2之间的同步。利用二值信号量实现两个任务之间同步的基本原理10.2信号量和互斥量计数信号量是有固定长度的队列,其中的每个消息都是一个标志,而不是一个具体的消息数据。计数信号量的计数值表示当前队列的长度。在任务或ISR不断给出和获取信号量的过程中,计数信号量的计数值在0(表示信号量队列空)和给定的最大值(表示信号量队列满)之间不断变化。如果在队列满了后再释放信号量,或者在队列空了以后再获取信号量,都将导致失败,从而使访问该信号量的任务进入阻塞状态。计数信号量(CountingSemaphore)10.2信号量和互斥量在实际使用中,计数信号量通常用于多个共享资源的访问控制,一般用于事件的计数和系统资源的管理。每当某个事件发生时,任务或者中断将给出或者释放信号量,使信号量的计数值加1;当该事件得到某任务的处理时,该任务会获取信号量,使其计数值减1。由此可见,信号量的计数值表示还有多少个事件没被处理。
10.2信号量和互斥量互斥量(Mutex,MutualExclusion)互斥量其实是一种特殊的二值信号量,利用互斥量可以给临界资源(任何时刻只能被一个任务访问的资源)建立一个标志,互斥量表示了该临界资源被占用的情况。刚创建时,互斥量队列是满的。当某个任务需要使用临界资源时,先获取互斥量并使其变空,这样其他任务(即便是高优先级任务)就会因为无法获取信号量而进入阻塞等待状态,无法访问同一个临界资源。当任务访问临界资源结束时,释放互斥量,其他任务才能获得互斥量,实现该临界资源的访问。10.2信号量和互斥量递归互斥量(RecursiveMutex)当一个任务持有互斥量时,其他任务将不能再对该互斥量进行开锁或持有,而持有该互斥量的任务能够再次获得这个锁而不被挂起,这种互斥量称为递归互斥量。一个任务在获得了互斥量之后就不能再获得互斥量,而一个任务获得递归互斥量之后,可以再次获得此递归互斥量,当然每次获取必须与一次释放配对使用。互斥量和递归互斥量都不能在ISR函数中使用,因为互斥量具有任务的优先级继承机制,而ISR不是任务。另外,获取互斥量时经常需要阻塞超时等待时间,而在ISR函数中不能设置阻塞等待时间。10.2.2优先级继承10.2信号量和互斥量二值信号量也可以用于互斥型资源访问控制,但是容易出现优先级翻转问题。在互斥量中,通过引入优先级继承(PriorityInheritance)机制,可以在一定程度上减少优先级翻转问题。在系统运行过程中,高优先级的任务可以打断低优先级的任务,抢占CPU的使用权。但是在很多场合中,某些资源只有一个,当低优先级任务正在占用该资源的时候,高优先级任务必须等待低优先级任务使用完该资源后再释放资源。这里高优先级任务无法运行而低优先级任务可以运行的现象称为优先级翻转(PriorityInversion)。优先级翻转问题10.2信号量和互斥量t2时刻,任务3由于需要一个临界资源而无法继续运行,进入阻塞状态,任务1继续运行。此时出现了优先级翻转。t3时刻,任务2被唤醒。由于任务2不需要任务1中的临界资源,并且优先级高于任务1,因此将立即抢占任务1得到运行。此时,虽然任务3的优先级高于任务2,但由于所需的临界资源还未得到任务1的释放,因此无法得到运行。此时也出现了优先级翻转问题。10.2信号量和互斥量优先级继承机制在t1时刻,任务3被唤醒,但所需的临界资源还未被任务1释放。此时,系统临时将任务1的优先级提高到与任务3相同,使得任务1能够继续运行。10.2信号量和互斥量t3时刻,虽然任务2被唤醒,但由于其优先级低于任务1,因此将被推后运行,系统继续运行任务1。10.2信号量和互斥量直到t4时刻,任务3所需的临界资源被任务1释放,任务1的优先级又回到最低。由于临界资源已经释放,最高优先级的任务3获得相应的互斥量得以继续运行,直到运行结束,在t5时刻进入阻塞状态。t5时刻,由于此时任务1的优先级已经回到最低,因此任务2得以运行,直到在t6时刻运行结束回到阻塞状态,继续运行任务1。10.2.3信号量和互斥量管理函数10.2信号量和互斥量xSemaphoreCreateBinary() //创建二值信号量
xSemaphoreCreateCounting(uxMaxCount,uxInitialCount)//创建计数信号量信号量的创建(semphr.h)创建二值信号量时没有入口参数。创建的二值信号量初始值为空,必须等到释放给出后才能获取成功。创建计数信号量时,参数uxMaxCount为信号量的最大计数值,当信号量的计数值达到该计数值时,将不能再释放信号量;参数uxInitialCount为创建信号量时的初始计数值。10.2信号量和互斥量例如,如下语句SemaphoreHandle_txSemphr1=NULL;SemaphoreHandle_txSemphr2=NULL;xSemphr1=xSemaphoreCreateBinary();xSemphr2=xSemaphoreCreateCounting(10,0);分别创建了一个二值信号量xSemphr1和一个计数信号量xSemphr2,计数信号量的最大计数值为10,初始计数值为0。如果创建成功,则返回所创建的二值信号量或计数信号量句柄;否则返回NULL。10.2信号量和互斥量xSemaphoreGive(xSemaphore) //给出(释放)信号量xSemaphoreTake(xSemaphore,xBlockTime) //获取信号量uxSemaphoreGetCount(xSemaphore) //获取信号量的计数值信号量的给出和获取(semphr.h)调用这两个函数释放信号量时,只需要给出信号量句柄参数。在获取信号量时,还需要另外给定一个xBlockTime,该参数表示阻塞等待信号量的时间节拍数。如果将该参数设为0,则表示不等待。如果释放或在给定的阻塞等待时间内成功获得信号量,则以上两个函数返回BaseType_t类型的pdTRUE,否则返回pdFALSE。获取计数值时,对计数信号量,返回当前计数值;对二值信号量,当信号量可用(满)时返回1,当信号量不可用(空)时返回0。10.2信号量和互斥量SemaphoreHandle_txSemaphore=NULL; //定义信号量句柄voidvATask(void*pvParameters){ //定义任务函数1xSemaphore=xSemaphoreCreateBinary(); //创建信号量}voidvAnotherTask(void*pvParameters){ //定义任务函数2 …… if(xSemaphore!=NULL){ //如果信号量创建成功 if(xSemaphoreTake(xSemaphore,(TickType_t)10)==pdTRUE){ //如果获取信号量成功 …… //访问共享资源 xSemaphoreGive(xSemaphore); //释放信号量 }}}二值信号量创建和使用的一个基本程序结构10.2信号量和互斥量xSemaphoreCreateMutex() //创建互斥量xSemaphoreCreateRecursiveMutex() //创建递归互斥量互斥量的创建和使用(semphr.h)对互斥量和递归互斥量,必须用不同的创建函数,不能混用。互斥量和递归互斥量都采用了优先级继承机制,因此当任务不再需要时,需要及时释放。互斥量的释放和获取函数与信号量相同,而由入口参数是信号量句柄还是互斥量句柄进行区分。递归互斥量可以被持有者重复获取。互斥量持有者必须释放所有获取的互斥量后,该互斥量才能再次使用。互斥量和递归互斥量都不能在ISR使用。10.2.4CMSIS接口函数10.2信号量和互斥量osSemaphoreId_tosSemaphoreNew(uint32_tmax_count,uint32_tinitial_count, constosSemaphoreAttr_t*attr)osMutexId_tosMutexNew(constosMutexAttr_t*attr)osStatus_tosSemaphoreAcquire(osSemaphoreId_tsemaphore_id,uint32_ttimeout)osStatus_tosSemaphoreRelease(osSemaphoreId_tsemaphore_id)uint32_tosSemaphoreGetCount(osSemaphoreId_tsemaphore_id)osStatus_tosMutexAcquire(osMutexId_tmutex_id,uint32_ttimeout)osStatus_tosMutexRelease(osMutexId_tmutex_id)10.2信号量和互斥量例如,如下语句
KeyBinarySemHandle=osSemaphoreNew(1,1,NULL);创建了一个二值信号量,第二个参数指定信号量的初值为1,意味着创建的二值信号量非空,即创建的二值信号量在系统复位运行时已经给出(释放)。再如,如下语句
CountSemHandle=osSemaphoreNew(5,5,&CountSem_attributes);其中前面两个参数分别指定计数信号量的最大计数值(队列的最大长度)和初始计数值。10.2信号量和互斥量注
意:在利用osSemaphoreNew()函数创建二值信号量时,将首先调用xSemaphoreCreateBinary()函数创建一个空的二值信号量。如果给定osSemaphoreNew()函数的第二个参数为1,则在创建了信号量,将继续调用xSemaphoreGive()给出(或释放)所创建的二值信号量,从而使其非空。因此创建信号量后,相关的任务将可以立即获取。如果设置函数的第二个参数为0,则表示创建一个空的二值信号量。此时必须等待某个任务给出该信号量后才能在其他任务中获取成功。10.2信号量和互斥量【实践案例10-2】二值信号量的应用创建两个任务Task1和Task2,分别用于获取和释放一个二值信号量。两个任务独立运行,Task1等待获取信号量。在Task2中,不断检测开发板上的按键K1是否按下。当按下按键时,释放信号量,此时唤醒任务Task1获取该信号量开始运行。如果没有按下按键,Task2不释放信号量,则Task1一直等待。这样就实现了两个任务的同步,在运行过程中利用串口调试助手显示相关信息,当Task1运行时,LED闪烁;在等待信号量的过程中,LED停止闪烁。10.2信号量和互斥量CubeMX中的配置在CubeMX中配置PA0为下拉输入模式;PF6为输出模式,初始输出高电平,以保证红色LED初始处于熄灭状态;配置FreeRTOS为CMSIS_V2模式。此外,配置USART1为Asynchronous模式,参数都取默认值,以便向PC机上的串口调试助手串行发送信息。10.2信号量和互斥量任务和信号量的创建10.2信号量和互斥量应用程序的编写导入头文件10.2信号量和互斥量信号量的获取,并控制LED闪烁10.2信号量和互斥量按键K1的检测,并给出信号量10.2信号量和互斥量程序的工作过程系统复位后,创建的信号量为空。在任务1中无法获取信号量,因此红色LED保持熄灭。通过osDelay()函数进行阻塞延时,从而使得任务2得到运行。在任务2运行过程中,检测按键K1是否按下。如果是,则给出信号量。一旦给出信号量,优先级高的任务1将立即获得该信号量,使LED闪烁50次(即1s的时间)。在任务2运行过程中,如果按键K1没有按下,则任务2不给出信号量,任务1将不执行if语句,而通过执行osDelay()函数重新进入阻塞状态。由此可见,本案例中利用二值信号量实现了任务1中LED闪烁与任务2中按键按动的同步。尽管任务1的优先级高于任务2,如果没有获取到信号量,也不能得到执行。10.2信号量和互斥量【实践案例10-3】计数信号量的应用在本案例中,用一个计数信号量表示一个小吃店的空余座位数,用开发板上的两个按键K1和K2模拟客人的进出。每按动一次K1,模拟进入一位客人,空余座位数减1;每按动一次K2,表示一位客人离开。假设该小吃店能够同时只能容量5人就餐。当没有空余座位时,再按动K1,将通过串口调试助手提示“座位已满!”;当没有客人时,再按动K2,则提示“没有客人啦!”。由此可见,当K1按下时,应获取信号量,使其计数值减1,当给出信号量失败,表示座位已满,没有空余座位;当K2按下时,应给出信号量,使其计数值加1,当获取信号量失败,表示没有客人。10.2信号量和互斥量CubeMX中的配置本案例除了K1外,还需要用到按键K2,因此在CubeMX中将K2连接的PC13也配置为下拉输入模式,其他配置与案例10-2相同。此外,本案例需要两个任务和一个计数信号量。在CubeMX中创建两个任务Task1和Task2,另外创建计数信号量CountSem,其属性设置如图10-11所示。特别注意两个任务的优先级。另外,计数信号量CountSem的最大计数值和初始计数值都设为5。10.2信号量和互斥量10.2信号量和互斥量应用程序的编写10.2信号量和互斥量10.2信号量和互斥量【实践案例10-4】互斥量的应用创建3个具有不同优先级的任务、一个二值信号量和一个互斥量,观察优先级翻转现象。10.2信号量和互斥量10.2信号量和互斥量10.2信号量和互斥量10.3事件组10.3.1基本工作原理10.3.2事件组管理函数10.3.3CMSIS接口函数【实践案例10-5】事件组的创建及其应用10.3.1工作原理10.3事件组事件组指的是一组事件标志,事件组变量的数据类型为EventBits_t,也就是TickType_t,在STM32处理器中等同于类型uint32_t。当FreeRTOSConfig.h头文件中的configUSE_16_BIT_TICKS宏常量参数配置为1和0时,分别对应设置事件组的具体位数为16位或32位。事件组中的每一位代表一个事件,称为事件位,取值为1和0,分别表示对应的事件发生或者没有发生。所有获得事件组的任务或ISR都可以对事件组的各位进行读或写。在16位或32位的事件位变量中,最高8位都是未用的保留位,因此一个事件组最多只能管理8个或24个事件。10.3事件组当某个事件发生时,将事件组中的相应事件位置位。假设同时有任务1和任务2处于阻塞状态,并且设置任务1必须等待两个事件都发生(逻辑与),任务2只需要等待其中的某一个事件发生(逻辑或),则当两个事件都发生时,任务1将解除阻塞而得到运行。对任务2来说,两个事件只要有一个发生,都将使任务解除阻塞状态而得到运行。10.3.2事件组管理函数(event_groups.h)10.3事件组EventBits_txEventGroupSetBits(EventGroupHandle_txEventGroup, constEventBits_tuxBitsToSet)EventBits_txEventGroupClearBits(EventGroupHandle_txEventGroup, constEventBits_tuxBitsToClear)EventBits_txEventGroupWaitBits(EventGroupHandle_txEventGroup, constEventBits_tuxBitsToWaitFor, constBaseType_txClearOnExit, constBaseType_txWaitForAllBits, TickType_txTicksToWait);10.3事件组xEventGroup:事件组句柄;uxBitsToSet、uxBitsToClear:待置位/复位的事件位掩码,其中待置位/复位的事件位用1表示,其他用0表示的事件位不受影响;uxBitsToWaitFor:所等待的事件位,其中需要等待的事件位为1;xClearOnExit:取值为pdTRUE或pdFALSE,表示函数返回时是否将所等待的事件位复位;xWaitForAllBits:指定是否等待多个事件成立,取值pdTRUE表示需等待指定的所有事件位都置位;取值为pdFALSE,则表示只需等待指定的某个事件位置位(逻辑或运算);xTicksToWait:在阻塞状态等待事件成立的阻塞等待时间。参
数多任务的同步10.3事件组利用事件组可以实现两个任务与事件之间的同步,实现的原理与二值信号量类似。但是,如果直接使用上述事件组操作函数,由于各任务对事件位的置位操作是相互独立的,将无法实现各任务之间的同步。要成功地使用事件组来实现同步,必须将事件位的设置和测试作为单一的不间断操作(称为原子操作)来执行。为此,FreeRTOS中提供了专用的xEventGroupSync()函数,该函数的原型声明如下:10.3事件组EventBits_txEventGroupSync(EventGroupHandle_txEventGroup, constEventBits_tuxBitsToSet, constEventBits_tuxBitsToWaitFor, TickType_txTicksToWait)参数:uxBitsToSet:指定要置位的事件位;uxBitsToWaitFor:需要等待的同步条件;xTicksToWait:阻塞等待时间。例如,假设要求在事件位D0、D1和D2位都置位时,任务解除阻塞状态,开始同步运行,则参数uxBitsToWaitFor必须设为0x07。10.3.3CMSIS接口函数10.3事件组osEventFlagsId_tosEventFlagsNew(constosEventFlagsAttr_t*attr); //创建uint32_tosEventFlagsSet(osEventFlagsId_tef_id,uint32_tflags); //置位uint32_tosEventFlagsClear(osEventFlagsId_tef_id,uint32_tflags); //复位uint32_tosEventFlagsGet(osEventFlagsId_tef_id); //状态读取uint32_tosEventFlagsWait(osEventFlagsId_tef_id,uint32_tflags, uint32_toptions,uint32_ttimeout); //事件等待返回值分别为事件组句柄或一个uint32_t类型的整数。10.3事件组参
数ed_id:指定待操作的事件组;flags:指定事件位;options:标志选项,取值可以是osFlagsWaitAny(等待任意一个事件位置位)、osFlagsWaitAll(等待所有事件位置位)或osFlagsNoClear(不清除事件位)。对函数osEventFlagsWait(),如果将options参数设置为osFlagsWaitAny或osFlagsWaitAll时,则在等待获取到任何一个或所有事件位时,将自动清除事件位。10.3事件组【实践案例10-5】事件组的创建及其应用创建事件KeyDownEvent和两个任务Task1和Task2。Task1实现开发板上两个按键的检测,当按键K1和K2按下时,分别将事件组中的对应位置位。任务Task2等待获取这两个事件标志位,当两个事件位都置位,意味着先后按动了两个按键,则控制红色LED闪烁一次,并在串口调试助手显示相应的提示信息。10.3事件组10.3事件组每隔20ms检测一次两个按键。当按键K1或K2按动并释放后,分别将两个事件位置位。10.3事件组待指定的两个事件位置位。一旦这两个事件位置位,表示交替按动了两个按键,则立即使红色LED闪烁一次,并向串口调试助手发送相应的提示信息。10.4任务通知10.4.1工作原理10.4.2任务通知管理函数10.4.3CMSIS接口函数【实践案例10-6】任务通知的应用10.4任务通知在大多数情况下,任务通知(TaskNotifications)可以替代二值信号量、计数信号量、事件组等通信组件,也可以替代长度为1的队列(可以保存一个32位整数或指针值)。相对于以前使用FreeRTOS内核通信的资源,必须创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。任务通知的使用无需借助于队列和信号量等,可以在任务之间直接进行通信。10.4任务通知在FreeRTOS中,任务通知是默认使能的。此时,任务的运行状态将增加一个通知(Notification)状态,该状态可以是挂起(Pending)或非挂起状态。当任务接收到任务通知时,该任务的通知状态被设置为挂起状态;当任务读取其通知值时,其通知状态被设置为非挂起状态。在给定的超时等待时间内,任务将处于阻塞等待状态,直到其通知状态变为挂起状态。10.4.1工作原理10.4任务通知FreeRTOS提供以下几种方式发送通知给任务:
(1)直接覆盖通知值;(2)如果有通知未读,不覆盖通知值;
(3)递增通知值,可以当做计数信号量使用;(4)设置通知值的一个或者多个位,可以当做事件组来使用。任务通知虽然处理更快,RAM开销更小,通过对以上任务通知方式的合理使用,可以在一定场合下替代前面介绍的各种组件。但是在使用任务通知时,只能有一个任务接收通知消息,因为必须指定接收通知的任务。此外,只有等待通知的任务可以被阻塞,在任何情况下发送通知的任务都不会因为发送失败而进入阻塞态。10.4任务通知xTaskNotify(xTaskToNotify,ulValue,eAction)xTaskNotifyAndQuery(xTaskToNotify,ulValue,eAction,pulPreviousNotifyValue)10.4.2任务通知管理函数(task.c/.h)通知发送函数参数参数xTaskToNotify为TaskHandle_t类型的任务句柄,代表通知需要发送到的任务;ulValue:发送的通知值;pulPreviousNotificationValue返回该任务原来的通知值;10.4任务通知eAction:用于指定更新通知值的方式,其取值是如下枚举类型:typedefenum{ eNoAction=0, /*接收通知,但
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 新版鲁科版(五四学制)物理八年级上学期全套综合测试卷(1)合集
- 2025奇台中等职业技术学校工作人员招聘考试试题
- 2025合浦县中等职业技术学校工作人员招聘考试试题
- 2026年中国厨房家用小电器市场调查研究报告
- 《6 热对流》分层作业及答案-2026-2027学年苏教版(新教材)小学科学五年级上册
- 八年级历史鲁教版课后巩固第一单元同步测试卷基础版A卷
- 银行对公业务办理操作流程SOP
- 医院检验科仪器校准流程优化设计方案
- 八年级历史沪科版开学季第二单元同步测试卷基础版A卷
- 医疗质量提升三年行动方案
- 2026年乡镇自来水抄表客服招聘考试笔试试题(含答案)
- 容县辅警招聘考试题库 (答案+解析)
- 2025年福州市鼓楼区城投集团招聘笔试历年参考题库(含答案详解)
- 2026内蒙古呼伦贝尔市海拉尔区红旅文化旅游开发有限责任公司下属四家子公司招聘23人考试参考题库及答案详解
- 2026年山东事业编统考考试《综合应用能力》真题及答案解析
- 现代渔业园区规划布局方案
- 期末模拟测试卷(试卷)2025-2026学年五年级数学下册人教版(含答案)
- 中华人民共和国生态环境法典测试题及答案
- 2026年急诊科质量控制考核细则
- 《化妆品用植物来源原料技术要求通则》
- 驾驭式课堂培训心得体会
评论
0/150
提交评论