基于FreeRTOS同步与通信机制的CO浓度监测报警装置设计
2021-07-20李燕马强邓凯旋
李燕,马强,邓凯旋
(华北科技学院电子信息工程学院,北京,065201)
0 引言
上世纪70年代开始出现嵌入式系统,距今已有近50年的历史。传统的嵌入式裸机开发运行的程序代码一般由一个main函数中的while死循环和各种中断服务程序组成,异常情况或者需要执行其他任务时,通过调用中断服务程序进行处理,没有多任务、线程的概念。但是引入操作系统后,程序执行时可以把一个应用程序分割为多个任务,且系统内核支持抢占式、合作式和时间片轮转调度,极大地提高了系统实时性,降低了软件开发难度。操作系统根据任务的优先级,通过任务调度器使CPU分时执行各个任务,保证每个任务都能够高效执行[1]。因此基于操作系统的嵌入式开发受到越来越多的开发者的青睐。
基于实时操作系统的软件开发,由系统进行多任务的管理与调度。如果任务设计不合理,将会出现任务运行不稳定、通信的实时性差等严重后果,所以软件结构与多任务的同步与通信机制是基于操作系统的嵌入式开发的难点和关键点[2]。FreeRTOS是实时操作系统的一种,该系统免费而且开源,高可移植性,主要用C语言编写;可以在资源有限的微控制器中运行,并且提供了用于低功耗的Tickless模式。本文以FreeRTOS为对象,对其同步与通信机制做了介绍,并在煤矿井下一氧化碳浓度监测报警装置的设计中应用。
1 FreeRTOS多任务管理机制
多任务管理是FreeRTOS系统的核心,采用了“分而治之”的思想,把大问题分解为许多个小问题,对其逐个击破,大问题也就迎刃而解;各个任务均以并发的方式处理,由任务调度器决定任务执行。FreeRTOS是基于抢占式内核的系统,高优先级的任务可以打断低优先级的任务运行,低优先级任务必须等高优先级任务运行完成之后,才能获得CPU的使用权。
FreeRTOS系统内核拥有队列、信号量和事件标志组来完成不同任务之间,任务与中断之间的消息传递。消息队列通常采用先进先出(FIFO)的存储缓冲机制,完成任务与任务、任务与中断间的消息传递;信号量分为二制信号量、计数型信号量、互斥信号量和递归互斥信号量;主要用来完成共享资源访问和任务同步的功能;事件标志组通过事件编号访问事件,用于实现多个任务或事件的同步。
2 同步通信机制分析
■2.1 队列
队列拥有独立权限的内核对象,本身并不属于或赋予任何任务。任何任务均可向同一队列写入或者读出。队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目,也可以发送不定长消息的场合。任务与任务、任务与中断之间要交流的数据保存在队列中,叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。通过字节拷贝将数据复制存储到队列中完成往队列中写入数据的任务;通过将队列中的数据拷贝删除完成从队列中读出数据的任务。读写队列均会指定一个阻塞超时时间,在这段时间里,任务将保持阻塞态等待队列数据有效;当等待的时间超过了阻塞超时时间,任务也会由阻塞态转为就绪态。
FreeRTOS总共含有14个对消息队列进行处理的函数,但是一般在使用时只需配置主要几个函数即可,主要有动态或静态创建队列、向队列发送消息、队列上锁和解锁,从队列读取消息。在使用队列之前,必须创建队列,队列创建有两种方法,一种静态创建,使用函数xQueueCreate Static();另一种是动态创建,使用函数xQueueCreate();两者的区别在于:使用静态创建队列时,需要用户自行分配内存,动态创建则不需要。队列是用来存储消息的,因此必须要给消息分配存储区。FreeRTOS使用参数uxQueuelength(队列长度)和uxItemsize(消息长度)来指定存储区域的大小。创建成功返回队列句柄,创建失败返回NULL。
■2.2 信号量
信号量可以用于两种场合,一是控制控制共享资源的访问,二是任务同步。信号量在控制共享资源访问的过程中相当于上锁机制,任务只有获得开锁的钥匙才能获得对共享资源的访问权。在任务同步场合中,信号量用来执行任务与任务,任务与中断之间的同步。信号量可以分为二值信号量和计数型信号量。
2.2.1 二值信号量
二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的,所以在处理中断与任务同步中,经常使用队列来代替二值信号量。下面三个步骤演示了二值信号量的工作过程:
(1)二值信号量无效
图1中任务Task通过函数xSemaphoreTake()获得该信号量,因为此时二值信号量处于无效状态,所以任务Task进入阻塞态。
图1 请求二值信号量
(2)中断释放信号量
当中断发生时,在中断服务函数中通过图2函数xSem aphoreGiveFromISR()释放信号量,所以此时信号量变为有效状态。
图2 释放信号量
(3)任务成功获取信号量
此时信号量已经有效,任务Task获取信号量成功,阻塞态解除,可以执行任务。
图3 任务请求信号量成功
2.2.2 计数型信号量
计数型信号量从本质上讲就是长度大于1的队列,用户并不需要知道队列中存储了什么数据,只需要知道队列是否为空即可。计数型信号量常用于两种场合,一是事件计数,二是资源管理。在事件计数场合中,每当有事件发生就在事件处理函数中增加信号量的计数值,其他任务信号量计数值减1。不同场合中,信号量值所代表的意思也不进行同。在计数场合中,信号量值就是队列结构体成员变量uxMessagesWaiting,所创建的计数型信号量初始计数值为0。在资源管理场合中,信号量值代表当前资源的可用数量。任何任务想要获得资源的使用权,必须首先获取信号量,获取成功之后信号量值就会减1。信号量值为0时说明此时已经没有资源了。每个任务使用完资源之后一定要将信号量释放,这样信号量值才会加1。在该场合中创建的信号量值的初始值应该是资源的数量。
2.2.3 互斥信号量
优先级翻转问题经常在可剥夺内核系统中出现,在这种情况下,高优先级任务要一直等待低优先级任务释放占用的共享资源,而实际情况是中优先级的任务剥夺了低优先级任务对CPU的使用权,使得高优先级任务无法先于中优先级任务使用共享资源,导致优先级翻转。FreeRTOS中的互斥信号量实质上是一种拥有优先级继承的二值信号量,非常适合应用在需要互斥访问的任务与任务或中断与任务之间的同步。互斥信号量具有优先级继承的特性。当一个互斥信号量正在被一个低优先级的任务使用时,此时有个高优先级的任务需要获得该信号量时就会被阻塞。但是在互斥信号量中高优先级的任务会将低优先级的任务提升到与自己相同的优先级,即优先级继承特性。该特性是通过降低高优先级任务处于阻塞态的时间,将“优先级翻转”的影响降到最低。但是优先级继承不能完全解决优先级翻转的问题,它只是尽可能降低优先级翻转带来的影响。在使用互斥信号量时必须注意的是它只能在任务中使用,不能用于中断服务函数中。
■2.3 事件标志组
前述使用信号量进行同步中,任务只能与一个任务或者事件进行同步。在需要多个任务或者事件同步的应用场景中,信号量就束手无策了。FreeRTOS采用事件标志组解决该问题。一个事件组就是一组的事件位,通过编号访问事件位。事件位用来标明某个事件是否发生,可以当作事件标志。收到一条消息并且已经将这条消息进行了处理就可以将该消息的标志位置1,当队列中没有需要处理的消息时将该位置0;事件标志组的第零位表示队列中的消息是否进行处理;事件标志组的第一位表示是否有消息需要从网络中发送出去;事件标志组的第二位表示是否需要向网络发送心跳信息。
事件标志组为EventGroupHandle_t结构体类型,其可以存储8、24或者32个事件位,但对于STM32内核而言,一个事件标志组最多可以存储24个事件位。
3 实际应用
设计了一套基于FreeRTOS实时操作系统、以STM32 F407ZGT6为核心的一氧化碳浓度检测和报警装置,如图4所示。该装置可以实时检测煤矿井下环境中一氧化碳浓度,采用红外遥控装置可以实现远程修改一氧化碳浓度报警值,方便工作人员操作。该检测报警装置基于实时多任务系统,显示任务、报警任务、RS485接收与发送任务的协调与配合的同步通信机制就是上述机制。
根据煤矿井下的特殊环境要求,本设计采用了NE-COBL这款工业级一氧化碳传感器,其具有良好的应答性和较高的输出电流,可达到80Na/ppm至110Na/ppm;能够轻松应对复杂气体;线性度较高,在清洁大气中的输出值小于10ppm;使用寿命长,达2年以上,稳定性强;性价比较高。
该系统基于实时多任务系统,其显示任务、运行状态更新任务、红外遥控任务、RS485接收与发送任务等的同步通信由前文所述的通信机制协调配合来实现。程序中使用了模拟量采集消息对列、RS485接收与发送消息二值信号量,设计创建了二值信号量RS485接收消息队列和RS485发送消息队列。软件设计总体结构框图设计如图4所示。
图4 软件设计总体框图
(1)任务开始函数START_TASK():任务开始函数主要用来创建其他任务,执行完任务开始函数,该任务将会被vTaskDelete(StartTask_Handler)删除并退出临界区。开始任务函数的优先级设置为1,任务堆栈大小为128个字节。通过调用vTaskStartScheduler()函数开始任务调度。
(2)二值信号量RS485_BinarySemaphore=xSemaph oreCreateBinary():敏感元件采集到的信号经调理电路处理后连接到STM32处理器的PC0引脚,即AD转换的通道10,将PC0配置为模拟量输入模式,对模拟信号连续转换十次并取其平均值,以减小转换误差,经数据换算后将结果通过消息队列传输至模式处理任务以实现浓度显示,然后判断浓度是否超过设定的报警值以决定是否触发声光报警。任务最后判断是否获取到RS485处理任务发送的请求数据信号量,若信号量获取成功,则将当前浓度发送至RS485处理任务。
(3)消息队列 Message_RS485RXD_Queue():该 消息队列用于读取RS485总线上的消息。QueueHandle_t Key_value_Queue():按键扫描消息队列QueueHandle_tAnalog_model_Queue():模拟模式消息队列;队列不是属于某个特别指定的任务的,任何任务都可以向队列中发送消息,或者从队列中读取消息。
4 结论
基于FreeRTOS同步与通信机制的CO浓度检测设计中,系统功能由各种实时任务协调配合完成,根据实际需求设置任务执行顺序的先后,由FreeRTOS操作系统内核解决任务间同步与通信问题。该系统实现了界面显示、监控报警以及RS485通信等功能,实际使用中证明了该系统具有较强的稳定性和良好的实时性。基于FreeRTOS系统不仅完成了任务间的协调配合,也使得程序开发相对容易,对嵌入式装置的研究与开发具有重要意义。