目录
一个任务或者中断有时候需要和另一个任务交流信息,这个就是消息传递的过程就叫做任务间通信,任务之间的信息传递有两种途径,一是使用全局变量,二是通过发布消息。
使用全局变量的时候,每一个任务或者中断服务程序都必须保证气全局变量的独占访问,(通常解决方式:关中断、临界区、信号量)。消息也可以通过消息队列作为中介发布给任务。
消息队列:
下边是正点原子的解释:
中断服务程序中只能使用OSPost()函数!!!在UCOSIII中对于消息队列的读取可以使先进先出(FIFO)也可以是后进先出(LIFO)的方式。接收消息的任务旁边的小沙漏表示任务可以指定一个超时时间,如果任务在这段时间内没有接收到消息的话就会唤醒任务,并且返回一个错误码告诉UCOSIII超时,任务是因为接收消息超时而被唤醒的,不是因为接收到了消息。如果将这个超时时
间指定为0的话,那么任务就会一直等待下去,直到接收到消息。消息列队中有一个列表,记录了所有正在等待获取得消息的任务,
消息列队相关的API函数
有关消息列队的API函数:
我们经常用的关于消息队列的函数主要有三个,创建消息队列函数OSQCreate(),向消息队列发送消息函数OSQPost()和等待消息队列函数OSQPend()。
创建消息队列:
OSQCreate函数用来创建一个消息队列,创建信号列队之前要先定义一个信号列队对象OS_Q + 列队对象名字;,消息队列使得任务或者中断服务程序可以向一个或者多个任务发送消息,函数原型如下:
p_q:指向一个消息队列,消息队列的存储空间必须由应用程序分配。
p_name:消息队列的名字。
max_qty: 指定消息队列的长度,必须大于 0。当然,如果 OS_MSGs 缓冲池中没有足够多的 OS_MSGs 可用,那么发送消息将会失败,并且返回相应的错误码,指明当前没有可用的 OS_MSGs。
p_err:保存调用此函数后返回的错误码
等待消息列队:
当一个任务想要从消息队列中接收一个消息的话就需要使用函数 OSQPend()。当任务调用这个函数的时候,如果消息队列中有至少一个消息时,这些消息就会返回给函数调用者。函数原型如下:
p_q:指向一个消息队列。
timeout:等待消息的超时时间,如果在指定的时间没有接收到消息的话,任务就会被唤醒,接着运行。这个参数也可以设置为0,表示任务将一直等待下去,直到接收到消息。
opt:用来选择是否使用阻塞模式,有两个选项可以选择 OS_OPT_PEND_BLOCKING 如果没有任何消息存在的话就阻塞任务,一直等待,直到接收到消息。 OS_OPT_PEND_NON_BLOCKING 如果消息队列没有任何消息的话任务就直接返回。
p_msg_size: 指向一个变量用来表示接收到的消息长度(字节数)。
p_ts:指向一个时间戳,表明什么时候接收到消息。如果这个指针被赋值为 NULL的话,说明用户没有要求时间戳。
p_err:用来保存调用此函数后返回的错误码。如果消息队列中没有任何消息,并且参数 opt 为OS_OPT_PEND_NON_BLOCKING 时,那么调用 OSQPend()函数的任务就会被挂起,直到接收到消息或者超时。如果有消息发送给消息队列,但是同时有多个任务在等待这个消息,那么 UCOSIII 将恢复等待中的最高优先级的任务。
向消息列队发送消息:
可以通过函数 OSQPost()向消息队列发送消息,如果消息队列是满的,则函数 OSQPost()就
会立刻返回,并且返回一个特定的错误代码,函数原型如下:
如果有多个任务在等待消息队列的话,那么优先级最高的任务将获得这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,则系统会执行任务调度,等待消息的任务立即恢复运行,而发送消息的任务被挂起。可以通过 opt 设置消息队列是FIFO 还是 LIFO。如果有多个任务在等待消息队列的消息,则 OSQPost()函数可以设置仅将消息发送给等待任务中优先级最高的任务(opt 设置为 OS_OPT_POST_FIF 或者 OS_OPT_POST_LIFO),也可以将消息发送给所有等待的任务(opt 设置为OS_OPT_POST_ALL) 。 如 果 opt 设 置OS_OPT_POST_NO_SCHED,则在发送完消息后,会进行任务调度。
p_q:指向一个消息队列。
p_void:指向实际发送的内容,p_void 是一个执行 void 类型的指针,其具体含义由用户程序的决定。
msg_size: 设定消息的大小,单位为字节数。
opt:用来选择消息发送操作的类型,基本的类型可以有下面四种。
OS_OPT_POST_ALL将消息发送给所有等待该消息队列的任务,需要和选项 OS_OPT_POST_FIFO 或者
OS_OPT_POST_LIFO 配合使用。
OS_OPT_POST_FIFO待发送消息保存在消息队列的末尾
OS_OPT_POST_LIFO待发送的消息保存在消息队列的开头
OS_OPT_POST_NO_SCHED禁止在本函数内执行任务调度。
我们可以使用上面四种基本类型来组合出其他几种类型,如下:
OS_OPT_POST_FIFO + OS_OPT_POST_ALL
OS_OPT_POST_LIFO + OS_OPT_POST_ALL
OS_OPT_POST_FIFO + OS_OPT_POST_NO_SCHED
OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED OS_OPT_POST_FIFO + OS_OPT_POST_ALL +
OS_OPT_POST_NO_SCHED
OS_OPT_POST_LIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHEDp_err:用来保存调用此函数后返回的错误码。
消息队列实验
设计一个应用程序,该程序有 4 任务、两个消息队列和一个定时器。任务A 用于创建其他 3 个任务。任务B 为主任务,用于检测按键,并且将按键的值通过消息队列KEY_Msg 发送给任任务C,任务B 任务还用于检测消息队列 DATA_Msg的总大小和剩余空间大小,并且控制 LED0 的闪烁。任务C获取KEY_Msg内的消息,根据不同的消息做出相应的处理,定时器1的回调函数tmr1_callback通过消息队列DATA_Msg,将定时器1的运行次数作为信息发给任务D,任务D将DATA_Msg中的消息通过串口打印出来。
实验代码:
#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "includes.h" #include "os_app_hooks.h" #include "key.h" //UCOSIII中以下优先级用户程序不能使用,ALIENTEK //将这些优先级分配给了UCOSIII的5个系统内部任务 //优先级0:中断服务服务管理任务 OS_IntQTask() //优先级1:时钟节拍任务 OS_TickTask() //优先级2:定时任务 OS_TmrTask() //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask() //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask() //创建任务A、、开始任务 //定义任务优先级 #define TASK_A_PRIO 3 //定义任务控制块 OS_TCB TASK_A_TCB; //定义任务堆栈大小 #define TASK_A_STK_SIZE 128 //定义任务堆栈 CPU_STK TASK_A_STK[TASK_A_STK_

本文围绕UCOSIII展开,介绍了任务间通信的两种途径,重点讲解消息队列和任务内嵌消息队列。详细阐述了消息队列相关API函数,如创建、等待、发送消息函数,并给出实验设计与代码。同时介绍任务内嵌消息队列的API函数及其实验,包括任务设计与现象。






最低0.47元/天 解锁文章
2408

被折叠的 条评论
为什么被折叠?



