今天我们来说一下uCOS的消息队列与信号量。
一、消息队列
队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列里面读取消息,当队列中的消息是空时,读取消息的任务将被阻塞,用户还可以指定阻塞的任务时间 timeout,在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当队列中有新消息时,被阻塞的任务会被唤醒并处理新消息;当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。消息队列是一种异步的通信方式。
通过消息队列服务,任务或中断服务程序可以将消息放入消息队列中。同样,一个或多个任务可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入消息队列的消息,即先进先出原则(FIFO),但是 uCOS 也支持后进先出原则(LIFO)。
编程要点:
(1)声明和创建消息队列
OS_Q queue; //声明消息队列
void OSQCreate (OS_Q *p_q, //指向消息队列的指针
CPU_CHAR *p_name, //队列的名字
OS_MSG_QTY max_qty, //最多可存放消息的数目
OS_ERR *p_err) //返回错误类型
(2)调用API函数
发送消息:
void OSQPost (OS_Q *p_q,
void *p_void,
OS_MSG_SIZE msg_size,
OS_OPT opt,
OS_ERR *p_err)
获取消息:
void *OSQPend (OS_Q *p_q,
OS_TICK timeout,
OS_OPT opt,
OS_MSG_SIZE *p_msg_size,
CPU_TS *p_ts,
OS_ERR *p_err)
删除消息队列:
OS_OBJ_QTY OSQDel (OS_Q *p_q,
OS_OPT opt,
OS_ERR *p_err)
二、信号量
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务之间同步或临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。在多任务系统中,各任 务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。抽象的来讲,信号量是一个非负整数,所有获取它的任务都会将该整数减一(获取它当然是为了使用资源),当该整数值为零时,所有试图获取它的任务都将处于阻塞状态。通常一个信号量的计数值用于对应有效的资源数,表示剩下可被占用的临界资源数,其值的含义分两种情况:
0:表示没有积累下来的释放信号量操作,且有可能有在此信号量上阻塞的任务。
正值:表示有一个或多个释放信号量操作。
在uCOS里面,没有严格区分二值信号量和多值信号量,其实就是初值不同,
二值信号量一般初值为0或者1,为0表示资源不可用,为1表示资源可用。多值信号量初值可以更大,理论上没有限制。
二值信号量多用于同步。比如说一个任务结束之后,释放一个信号量,另一个任务在等待这个信号量,当获取到这个信号量的时候便开始执行,这样就实现了两个任务的基本同步。
而多值信号量多用于标记可用资源有多少,任务每获取一个信号量,就代表占用了一个资源,当没有资源可用的时候,就得等其他任务释放了。
编程要点:
(1)
声明和创建信号量:
OS_SEM key_sem;
void OSSemCreate (OS_SEM *p_sem,
CPU_CHAR *p_name,
OS_SEM_CTR cnt,
OS_ERR *p_err)
(2)调用API函数
释放信号量
OS_SEM_CTR OSSemPost (OS_SEM *p_sem,
OS_OPT opt,
OS_ERR *p_err)
获取信号量
OS_SEM_CTR OSSemPend (OS_SEM *p_sem,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)
删除信号量
OS_OBJ_QTY OSSemDel (OS_SEM *p_sem, //信号量指针
OS_OPT opt, //选项
OS_ERR *p_err) //返回错误类型
编程时注意,创建任务时的函数名必须与实际的函数名一致,否则将会产生HardFault_Handler类型错误。
总结:总的来说,这两个内容比较简单,只要合理调用API函数即可。