引言
随着嵌入式系统的发展,具有数据采集、处理与传输功能的智能传感器节点近年来得到飞速发展。该节点可以内置多种传感器,采集声、光、力学、化学、生物、位置等多种信息,并通过通信网络将数据传输到远程处理中心。嵌入式智能传感器节点是物联网(IOT)的重要组成部分,目前已经在环境监测、航空航天、通信设备、消费类电子产品、智能仪器等领域得到广泛应用。
本文设计了一种基于ARM微处理器的嵌入式智能传感器节点,并设计了一种并发数据的处理方案。该节点集成了温度传感器、声传感器、图像传感器,可以满足对目标对象的监测需求,并可根据具体应用配置相应的传感器。该技术可以广泛用于环境监测、智能家居、战场侦察等领域。节点采集数据之后进行简单处理,然后通过无线网络传输到远程数据中心,无线通信采用IEEE 802.11b协议。
1 系统组成与原理
系统结构如图1所示。系统以ARM微处理器为数据采集、处理与转发的核心,主要包括传感器模块、数据处理模块和通信模块。传感器模块包括温度传感器、声传感器、图像传感器,完成对监测对象的数据采集;数据处理模块主要包括嵌入式微处理器和相应的外围电路,完成数据的缓存、封装等操作;通信模块采用比较成熟的WiFi模块,完成封装后的网络数据包由该模块转发出去。
图1 系统结构框图
系统采用三星公司的ARM微处理器S3C2410X[1],其核心部件采用了ARM公司设计的16/32位ARM920T内核。ARM处理器采用RSIC架构,具有体积小、功耗低、成本低、性能高等特点,在消费电子、工业控制、网络、通信终端等领域用途广泛。为了有效减少微控制器外部扩展接口的数量,最大限度地降低整个系统的设计成本,S3C2410X内部集成了一套较为完善的I/O接口功能模块。许多I/O接口部件不仅支持中断控制操作,也支持DMA控制操作[12]。
系统选用嵌入式Linux作为操作系统,作为一种源码开放的系统,Linux操作系统具有开发成本低、内核可定制、适用于多种硬件平台、性能优异、网络功能强大、稳定性强、开发工具丰富等优点,非常适合本系统。
2 关键技术分析
由于系统主要由于监测,对实时性要求较高,而节点集成了多个传感器,所以节点必须具有对并发数据较强的实时处理能力。
并发数据的采集方面,一般有3种方式:查询、中断和DMA。查询方式比较简单,但是CPU的负担较重,实时性不好,效率不高;中断方式下CPU利用率要高,实时性较好,但CPU负担较重,并且当多个中断同时发生时也会发生中断不能及时响应的情况;DMA采用纯硬件技术控制源设备和目的设备之间的数据传输,CPU除了在数据传输开始和结束时进行简单处理外,在传输过程中可以进行其他工作,因此数据传输速率高,多个DMA通道即可实现并行采集。
由于Linux是一个多用户、多任务的操作系统,并且基于单一的体系结构,具有良好的速度和性能,同时又不失扩展性,在并发数据处理方面具有一定的优势,所以本系统采用Linux下的多进程/多线程方法来实现并发数据的处理、转发。同时,由于各个传感器的数据类型、速率不同,所以采用消息队列机制进行进程间通信,而在本地节点和远程数据中心则采用套接字(Socket)进行通信。
综上所述,系统采用DMA+多进程/多线程方法来提高并发数据处理的实时性,该方法软硬结合,充分利用了系统软硬件各方面的资源,最大限度地提高系统数据采集、处理和转发的实时性。
3 并发数据处理技术的实现
3.1 并发数据采集技术——DMA
大多数ARM微控制器都集成了DMA控制器(以下简称DMAC),作为一种独立于CPU的后台批量数据传输技术。DMA以其快速、高效的特点,在数据采集领域得到广泛应用。
S3C2410X微处理器内置4通道DMAC,位于系统总线和外围总线之间,每个通道分别对应于5个硬件请求源。DMA传送包括3种方式:I/O接口到存储器、存储器到I/O接口以及存储器到存储器。本系统中数据从I/O接口传送到存储器中。
典型DMAC工作原理如图2所示,其数据传送工作过程如下:
① 外设向DMAC发出DMA传送请求。
② DMAC通过连接到CPU的HOLD信号向CPU提出DMA请求。
③ CPU在完成当前总线操作后会立即对DMA请求作出响应——CPU将控制总线、数据总线和地址总线浮空,放弃对这些总线的控制权;CPU将有效的HLDA信号加到DMAC上,通知DMAC CPU己经放弃了总线的控制权。
④ CPU放弃对总线控制权后,DMAC接管系统总线的控制权,并向外设送出DMA应答信号。
⑤ DMAC送出地址信号和控制信号,实现外设与内存或内存之间大量数据的快速传送。
⑥ DMAC将规定的数据字节传送完之后,通过向CPU发HOLD信号,撤消对CPU的DMA请求。CPU收到此信号,使HLDA无效,同时重新开始控制总线,实现正常指令操作。
图2 典型DMAC工作原理
DMA操作可以通过软件、内部外设的请求或者外部请求引脚(nXDREQ0,1)来启动。DMAC的初始化也比较简单,主要是相关寄存器的设置,包括源地址寄存器、目的地址寄存器和各自的控制器,以及配置DMA模式的控制寄存器等。下面以系统用到的UART0通道为例说明DMAC的初始化[2]:
① 初始化源地址寄存器(DISRC)端口。写入源数据存储区首地址。
② 初始化源控制寄存器(DISRCC)端口。指明源数据存储区处于地址总线,地址自增。
③ 初始化目的寄存器(DIDST)端口。写入UART0的FIFO队列地址,由FIFO队列接收来自源数据存储区的数据。
④ 初始化目的控制寄存器(DIDSTC)端口。指明UART0处于外设总线,地址不变。
⑤ 初始化控制寄存器(DCON)端口。因为是内部DMA传送,可以任意选择请求与响应协议——选择与系统总线同步、开放DMA通道中断请求、单元(Unit)传送模式、全服务(Whole Service)模式、UART0通道、硬件请求模式、非自动装入、8位数据字长、数据块长度为16。
⑥ 初始化触发掩码寄存器(DMASKTRIG)端口。开放DMA通道0,屏蔽软件DMA请求。
⑦ UART0的初始化。设置串行数据帧格式,使能FIFO发送模式,设置DMA请求模式,设置FIFO触发电平,发送第一组FIFO数据。
接收数据时,初始化UART0的接收缓冲区为16字节。当接收缓冲区满时,会产生DMA请求,然后在DMAC的控制下,将UART0的FIFO中16字节的数据转移到指定的缓冲区SRAM中。当数据转移完毕(DMA计数到0)后,DMAC一方面自动重载和自动启动,设置好目标(缓冲区)首地址、源地址(UART接收寄存器)以及DMA计数器,准备好下次DMA请求,同时产生DMA中断。DMA中断服务程序对全局标志Rev_flag置位,通知主程序有新的命令需要处理。然后主程序可以直接读取SRAM中的数据,并对Rev_flag清零,这样就不需要花费时间去读取UART的接收缓冲区。
图3 消息队列机制
本系统中,由于DMA请求源包括温度传感器、声传感器等外设,可以通过以下方法解决多请求源的问题:充分利用已有的4个通道,选择带有合适接口的传感器;利用总线或者多路转换逻辑对通道进行扩展;多个DMA控制器级联。在这里不作过多阐述。
3.2 并发数据处理技术——多进程/多线程模型
当各传感器对应的存储空间到达设定的阈值时,会置位Rev_flag,通知主程序有新的命令需要处理。这里存在多个中断源的并发处理问题,采用软件中断来解决。这里的“并发”并非真正同时处理多个请求,而是利用多进程、多线程等技术实现用户看上去的“并发”。
Linux提供进程和线程两种形式的“并发”。多线程作为一种多任务、并发的模式,消耗的资源较少,而且同一个进程所包含的多个线程间不需要通信,具有效率高、共享存储空间等优点,所以系统在读取存储器的数据时使用多线程来实现“并发”。
在进行无线网络通信时,为了提高发送的效率和实时性,借鉴了操作系统设计中“生产者—消费者”模型的思想,流动的商品是数据。该模型包括两个进程:生产者进程和消费者进程。生产者进程从存储器中读取数据,并存放在公共缓冲区中;消费者进程负责与远程数据中心节点的通信,将数据从缓冲区中读出,然后封装成网络数据包发送出去。
生产者进程和消费者进程使用消息队列机制进行进程间的通信,将消息队列作为公共缓冲区。消息队列能传送更多的数据信息,组织方式也更加灵活,并可避免线程共享进程资源和地址空间所导致的复杂的互斥和同步问题。消息队列主要用于进程间传递大量不同长度和格式的数据。
消息队列机制如图3所示[3]。消息队列中存放不同类型的消息包,同类型消息包由消息类型头部结构来组织,构成虚拟的链表式消息子队列。线程通过向消息队列注册模块消息类型,创建专用子队列。向消息队列发送消息包数据时,必须指明消息包的类型,消息包将插入对应的子队列末尾。接收方模块则从相应的子队列中获取期望消息包。
进行数据处理的多进程/多线程模型如图4所示。
图4 基于多进程/多线程的数据处理模型
图4中主线程一直在运行,负责侦听和接收来自中断源的连接请求。当Rev_flag置位时,就会向主线程发出连接请求,主线程将创建对应的从线程负责处理连接,接收存储器中的数据,并将数据发送到消息队列中,直到数据接收完毕,从线程终止。在系统中,使用消息类型来区分不同的线程,也就是不同的数据源。
要使用消息队列,首先要创建一个消息队列,创建的消息队列位于内核中。消息队列的编程接口(API)共有4个[4],如表1所列。
表1 消息队列API
下面列出了对消息队列进行操作的部分程序代码[5]:
/*定义消息队列结构体*/
struct message{
long msg_type;//消息类型
int msg_text[BUFSZ];//消息内容,BUFSZ为消息长度
}msg;
……
/*创建消息队列的关键字值*/
if((key=ftok(".",a)==-1){
perror("ftok");
exit(1);
}
……
/*创建一个消息队列*/
if((qid=msgget(key, IPC_CREAT|00666))==-1){
perror("msgget");
exit(1);
}
/*非阻塞发送一个类型为1的消息*/
msg.msg_type=1;
len=strlen(msg.msg_text);//从存储器里读取的数据的长度
if((msgsnd(qid,&msg,len, IPC_NOWAIT))==-1) {
perror("message posted");
exit(1);
}
……
/*从消息队列中顺序接收消息*/
if(msgrcv(qid,&msg,BUFSZ,0,IPC_NOWAIT)==-1){//接收当前队列的第1条消息
perror("msgrcv");
exit(1);
}
……
/*从内核中删除消息队列*/
if((msgctl(qid,IPC_RMID,NULL))==-1) {
perror("msgctl");
exit(1);
}
4 无线通信模块
WiFi(Wireless Fidelity)是IEEE定义的无线通信标准IEEE 802.11,它是1种无线局域网的标准。相比其他无线通信方式,WiFi具有传输速率高、部署容易、应用规模大、经济性好等优势,同时还具有易扩展、易管理、易维护、抗干扰等特点。
在Linux系统中,可以调用Socket套接字实现网络通信功能,用户只需要完成模块的移植和配置,而无需了解底层网络细节。在工作时,嵌入式节点充当客户端,运行发送进程,在需要传输数据时发送连接请求。远程数据中心节点为服务器端,运行接收进程来响应客户端的连接,接收数据。
目前,Internet给分布式应用提供两类服务:面向连接的服务和无连接的服务,分别由TCP和UDP提供。由于系统对数据传输的实时性要求较高,所以在这里使用UDP,因为UDP协议不需要建立一个明确的连接,并且不需要每次对发送数据进行确认,所以比TCP更高效,能更好地解决实时性问题。
在使用WiFi模块前,首先编译好模块的驱动程序,并将其移植到目标板上。在发送数据时,首先将消息队列里的数据交给TCP/IP协议栈,TCP/IP协议栈根据目的地址和端口将该数据封装成完整的UDP数据包,接着在IP层被封装为IP包,然后提交给WiFi驱动模块,并封装成IEEE 802.11b格式的数据包,由WiFi模块发送到远程数据中心。
结语
嵌入式系统应用越来越广泛,本文设计了一种基于ARM微处理器S3C2410X和嵌入式Linux操作系统的智能传感器节点,能够同时采集、处理多种环境参数,可以广泛地应用于环境监测等领域。针对多种数据并发处理的难题,本文提出了一种DMA+多进程/多线程的方法,该方法软硬结合,相比于其他技术,可以有效提高监测的速度和实时性。目前,该技术已在某监控系统中得到应用。