事件标志组
事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦,搞个全局变量不是更简单,其实不然。在裸机编程时,使用全局变量的确比较方便,但是在加上 RTOS 后就是另一种情况了。使用全局变量相比事件标志组主要有如下三个问题:
使用事件标志组可以让 RTOS 内核有效的管理任务,全局变量是无法做到的,任务的超时等机制需要用户自己去实现。
使用了全局变量就要防止多任务的访问冲突,使用事件标志组已经处理好了这个问题。用户无需担心。
使用事件标志组可以有效的解决中断服务程序和任务之间的同步问题。任务间事件
标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。RTX 每个任务创建的时候,会自动创建 16 个事件标志,事件标志被存储到每个任务的任务控制块中。也就是说每个任务支持 16 个事件标志。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2018111518303610.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoZW5nXzUyMzA=,size_16,color_FFFFFF,t_70)
运行条件:
创建 2 个任务 Task1 和 Task2
运行过程描述如下:
任务 Task1 运行过程中调用函数 os_evt_wait_and,等待事件标志位被设置,任务 Task1 由运行态进
入到挂起态
任务 Task2 设置了任务 Task1 的事件标志,任务 Task1 由挂起态进入到就绪态,在调度器的作用下
由就绪态又进入到运行态。
实际应用中,中断方式的消息机制切记注意以下四个个问题:
中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效的保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
中断服务程序中一定要调用专用于中断的事件标志设置函数 isr_evt_set。
在 RTX 操作系统中实现中断函数跟裸机编程是一样的。
另外强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407 的NVIC 优先级分组设置为 4,即NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。
用户要在 RTX 多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。
事件标志组API函 数
使用如下 6 个函数可以实现 RTX 的事件标志组:
os_evt_clr
os_evt_get
os_evt_set
os_evt_wait_and
os_evt_wait_or
isr_evt_set
信号量
信号量的作用又该如何体现呢?比如有个 30 人的电脑机房,我们就可以创建信号量的初始化值是 30,表示 30 个可用资源,不理解的初学者表示信号量还有初始值?是的,信号量说白了就是共享资源的数量。另外我们要求一个同学使用一台电脑,这样每有一个同学使用一台电脑,那么信号量的数值就减一,直到 30 台电脑都被占用,此时信号量的数值就是 0。如果此时还有几个同学没有电脑可
以使用,那么这几个同学就得等待,直到有同学离开,有一个同学离开,那么信号量的数值就加 1,有两个就加 2,依次类推。刚才没有电脑用的同学此时就有电脑可以用了,有几个同学用,信号量就减几,直到再次没有电脑可以用,这么一个过程就是使用信号量来管理共享资源的过程。
平时使用信号量主要实现以下两个功能:
两个任务或者中断函数跟任务之间的同步功能,这个和上章节讲解的事件标志组是类似的。其实就是共享资源为 1 的时候。
多个共享资源的管理
![在这里插入图片描述](https://img-blog.csdnimg.cn/20181115183737788.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoZW5nXzUyMzA=,size_16,color_FFFFFF,t_70)
运行条件:
创建 2 个任务 Task1 和 Task2。
创建信号量可用资源为 1。
运行过程描述如下:
任务Task1运行过程中调用函数os_sem_wait获取信号量资源,如果信号量没有被任务Task2占用,Task1 将直接获取资源。如果信号被 Task2 占用,任务 Task1 将由运行态转到挂起状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数 os_sem_send 释放掉资源。
任务Task2运行过程中调用函数os_sem_wait获取信号量资源,如果信号量没有被任务Task2占用,Task1 将直接获取资源。如果信号被 Task2 占用,任务 Task1 将由运行态转到挂起状态,等待资源可以。一旦获取了资源并使用完毕后会通过函数 os_sem_send 释放掉资源。
信号量API函数
os_sem_init
os_sem_send
isr_sem_send
os_sem_wait
互斥信号量
互斥信号量就是信号量的一种特殊形式,也就是信号量初始值为 1 的情况。有些 RTOS 中也将信号量初始值设置为 1 的情况称之为二值信号量。为什么叫二值信号量呢?因为信号量资源被获取了,信号量值就是 0,信号量资源被释放,信号量值就是 1,把这种只有 0 和 1 两种情况的信号量称之为二值信号量。
互斥信号量的主要作用就是对资源实现互斥访问。下面举一个通过二值信号量实现资源独享,即互斥访问的例子,让大家有一个形象的认识运行条件:
让两个任务 Task1 和 Task2 都有运行串口打印 printf,这里我们就对函数 printf 通过二值信号量实
现互斥访问。如果不对函数 printf 进行互斥访问,串口打印容易出现乱码。
用信号量实现二值信号量只需将信号量的初始值设置为 1 即可。
RTX 互斥信号量的实现
![在这里插入图片描述](https://img-blog.csdnimg.cn/20181115184415623.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoZW5nXzUyMzA=,size_16,color_FFFFFF,t_70)
运行条件:
创建 2 个任务 Task1 和 Task2,优先级分别为 1 和 3,也就是任务 Task2 的优先级最高
任务 Task1 和 Task2 互斥访问串口打印 printf。
使用 RTX 的互斥信号量实现串口打印 printf 的互斥访问。
运行过程描述如下:
低优先级任务 Task1 执行过程中先获得互斥资源 printf 的执行。此时任务 Task2 抢占了任务 Task1
的执行,任务 Task1 被挂起。任务 Task2 得到执行。
任务 Task2 执行过程中也需要调用互斥资源,但是发现任务 Task1 正在访问,此时任务 Task1 的优
先级会被提升到跟 Task2 同一个优先级,也就是优先级 3,这个就是所谓的优先级继承(Priority
inheritance),这样就有效的防止了优先级翻转问题。任务 Task2 被挂起,任务 Task1 有新的优先
级继续执行。
任务 Task1 执行完毕并释放互斥资源后,优先级恢复到原来的水平。由于互斥资源可以使用,任务Task2 获得互斥资源后开始执行。
消息邮箱
RTX 的消息邮箱实际上就是消息队列,通过内核提供的服务,任务或中断服务子程序可以将一个消息(注意,RTX 消息邮箱传递的是消息的地址而不是实际的数据)放入到消息队列。同样,一个或者多个任务可以通过内核服务从消息队列中得到消息。通常,先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入到消息队列的消息,即先进先出的原则(FIFO)。也许有不理解的初学者会问采用消息邮箱多麻烦,搞个全局数组不是更简单,其实不然。在裸机编程
时,使用全局数组的确比较方便,但是在加上 RTOS 后就是另一种情况了。
使用全局数组相比消息邮箱主要有如下四个问题:
使用消息邮箱可以让 RTOS 内核有效的管理任务,全局数组是无法做到的,任务的超时等机制需要用户自己去实现。
使用了全局数组就要防止多任务的访问冲突,使用消息邮箱已经处理好了这个问题。用户无需担心。
使用消息邮箱可以有效的解决中断服务程序跟任务之间消息传递的问题。
FIFO 机制更有利于数据的处理。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20181115185053853.jpg)
运行条件:
创建消息邮箱,可以存放 10 个消息。
创建 2 个任务 Task1 和 Task2,任务 Task1 向消息邮箱放数据地址,任务 Task2 从消息邮箱取数据地址。
RTX 的消息读取和存放仅支持 FIFO 方式。
运行过程主要有以下两种情况:
任务 Task1 向消息邮箱放数据地址,任务 Task2 从消息邮箱取数据地址,如果放数据地址的速度快
于取数据的速度,那么会出现消息邮箱存放满的情况,RTX 的消息存放函数 os_mbx_send 支持超时等待,可以设置超时等待,直到有位置可以存放消息放或者设置时间超时。
任务 Task1 向消息邮箱放数据地址,任务 Task2 从消息邮箱取数据地址,如果放数据地址的速度慢于取数据的速度,那么会出现消息邮箱为空的情况,RTX 的消息获取函数 os_mbx_wait 支持超时等待,可以设置超时等待,直到消息邮箱中有消息放或者设置时间超时。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)