1. 引言
文献 [1] 规范了MQTT协议,MQTT (Message Queuing Telemetry Transport,消息队列遥测传输)是基于发布/订阅模式的轻量级即时通信协议,已成为OASIS (Organization for the Advancement of Structured Information Standards结构化信息标准促进组织)标准规范。MQTT协议使用TCP/IP提供网络连接,传输的消息分为主题(Topic)和负载(Payload)两部分,通过主题对消息进行分类,并允许使用通配符订阅主题;支持三种消息发布QoS (Quality of Service,服务质量);使用遗言机制Will通知客户端异常中断;协议采用交换控制帧来工作,一个控制帧由固定头(Fixed header)、可变头(Variable header)和消息体(payload)三部分构成,固定长度的头部是2字节,开销很小,非常适合需要低功耗和网络带宽有限的物联网场景。本研究实现了标准帧格式发布订阅功能。
文献 [2] 规范了串行链路和TCP/IP两个通信规程中使用Modbus应用层协议和服务规范,Modbus是一个请求/应答的应用层报文传输协议,提供PDU (Protocol Data Unit 协议数据单元)的功能码规定的服务,用于在通过不同类型的总线或网络连接的设备之间的客户机/服务器通信。Modbus协议的通讯格式主要分ASCII、RTU、TCP等,其中RTU格式由于传输效率高被大多数厂商采用 [3] 。此协议支持传统的RS-232、RS-422、RS-485和光纤、无线设备,本研究采用RS-232实现Modbus-RTU异步串行通信,系统采用主/从技术,通过唯一设备地址完成通讯任务,主设备发出请求从设备根据主设备发出的请求消息作出响应。
在工程应用中,经常需要将符合通用电力规约的设备传来的MODBUS协议数据提取出来,经由物联网MQTT协议转换传输到服务器做后续处理,实现设备数据到云平台的传递。该智能系统平台基于此工程应用通过嵌入式方式实现了标准电力通信规约MODBUS到工业物联网标准规约MQTT的灵活转换,解决工业电力电子设备无法直接与物联网云平台通信问题。
2. 设计方案选择
协议算法常见的实现方案有两种:
(1) 依赖于MQTT及MODBUS协议具体实现,针对实现编程。研究各协议机制,从底层代码编写,实现各协议功能。这种方式灵活度高,可实现自定义的数据帧收发功能,但开发周期长,对开发人员编程能力要求较高,实现协议完全标准化可靠性不高,开发调试过程复杂。
(2) 依赖于开源库API库函数,针对接口编程。在开源库基础上进行协议开发,加快开发进程。根据需求通过设置不同参数调用API库函数接口,设计协议传输数据内容,对不同的通讯格式保持一致的代码形式,将开发人员大量精力从编写底层代码的工作转移到上层功能应用开发。基于ARM嵌入式平台实现的MQTT协议开源库和MODBUS协议开源库可参考的资料较多,借助于ARM嵌入式测试平台即可完成所有软件的开发,对软件平台要求和开发难度相对较低,通信软件的扩展灵活性高。
3. 设计实现
综合评估开发的难度和现有的开发软件平台,该智能终端系统采用上文中提到的第二种方案,针对接口编程,以C函数加动态库的形式进行ARM嵌入式工控主板协议转换应用程序开发。本方案选择libmodbus库和libmosquitto库作为协议开发基础,见图1:嵌入式智能系统协议转换设计实现流程图。在PC机上进行协议功能配置并交叉编译,将编译成功的libmosquitto.so、libmodbus.so及所依赖动态库移植ARM嵌入式智能系统进行LD_LIBRARY_PATH库路径配置;将交叉编译可执行程序Mosquitto安装在ARM嵌入式智能系统平台,进行PATH环境变量路径配置;调用API函数库接口,实现协议转换功能应用程序开发并进行交叉编译,移植嵌入式智能系统进行功能调试。

Figure 1. Schematic diagram of embedded intelligent system implementation
图1. 嵌入式智能系统实现示意图
该系统选用嵌入式软硬件平台为基于ARMCortex-A9架构的Freescale i.MX6 Quad主控芯片,在windows系统安装虚拟机搭建嵌入式Linux开发环境。
文献 [4] 介绍了四核Freescale i.MX6 Quad系列平台特点。每个内核运行频率高达1.2 GHz,带有1 MB L2缓存,和64位DDR3或2通道、32位LPDDR2控制器,以更低的功耗提供更高的性能,适用于对功率有严格要求的应用。这个系列的器件集成了FlexCAN、UART、Ethernet、USB和SATA-2等,具有卓越的连接性,其广泛的集成I/O提供了高集成度和可扩展性,易于4G模块功能扩展及串口驱动安装,可降低设计复杂度。
3.1. MQTT协议实现
Mosquitto [5] 是一个开源的轻量级的C实现消息代理服务器,完全兼容了MQTT 3.1和MQTT 3.1.1协议。libmosquitto作为Mosquitto开源代码的一部分,主要用来实现MQTT协议栈和数据包通讯功能。文献 [6] 介绍了Mosquitto的消息推送机制,并针对大文件类型消息对消息机制进行改进。根据本研究实际应用,传输的消息长度不会高于25 MB,因此直接保留原有即时性高的传输方式。
3.1.1. Mosquitto编译及配置
本研究使用Mosquitto源码,分别通过config.mk和mosquitto.conf进行安装选项和启动参数配置。Mosquitto编译动态库libmosquitto.so依赖libuuid.so、libcrypto.so及libssl.so动态库,同时生成mosquitto、mosquitto_passwd、mosquitto_pub和mosquitto_sub四个工具,分别用于启动代理、管理密码、发布消息和订阅消息。
3.1.2. 订阅/发布设计
一个完整的Mosquitto通信包括一个代理服务器,一个发布者Publisher和一个订阅者Subscriber。其工作过程分为以下四个步骤,基本模型如图2。
(1) 启动服务mosquitto。
(2) 订阅者Subscriber通过mosquitto_sub订阅指定Topic的消息。
(3) 发布者Publisher通过mosquitto_pub发布指定Topic的消息。
(4) 代理服务器把Topic消息推送到订阅者。

Figure 2. Mosquitto basic model diagram
图2. Mosquitto基本模型图
本研究设计MQTT_t结构体用来存放sub_topic订阅主题、发布主题pub_topic、发送缓冲区mqtt_buffer、接收缓冲区mqtt_read_buffer及will_topic遗嘱主题等参数,主要分为初始化结构体、订阅数据及发布数据三部分实现。
typedefstruct {
charsub_topic[MQTT_TOPIC_SIZE];
charpub_topic[MQTT_TOPIC_SIZE];
charmqtt_buffer[MQTT_BUF_SIZE];
charmqtt_read_buffer[MQTT_BUF_SIZE];
charwill_topic[MQTT_TOPIC_SIZE];
}MQTT_t;
(1) 结构体的初始化
init部分实现代码,初始化订阅及发布主题信息:
voidervry_mqtt_init(MQTT_t *mqtt)
{
sprintf(mqtt->sub_topic/%s/to_condev,company);
sprintf(mqtt->pub_topic/%s/to_webapp,company);
}
(2) 订阅数据
mosquitto_sub部分实现代码,订阅指令编码:
voidervry_mosquitto_sub(MQTT_t * mqtt)
{
strcat(strCmd, mosquitto_sub -h );
strcat(strCmd, MQTT_HOST);
strcat(strCmd, -t );
strcat(strCmd, mqtt->sub_topic);
fp = popen(strCmd, r) ;
memset(mqtt->mqtt_read_buffer,0,MQTT_BUF_SIZE);
fgets(mqtt->mqtt_read_buffer,MQTT_BUF_SIZE,fp);
}
(3) 发布数据
mosquitto_pub部分实现代码,发布指令编码:
voidervry_mosquitto_pub(MQTT_t *mqtt,void *pbuf)
{
strcat(strCmd, mosquitto_pub -h );
strcat(strCmd, MQTT_HOST);
strcat(strCmd, -t );
strcat(strCmd, mqtt->pub_topic);
strcat(strCmd, -m );
strcat(strCmd, pbuf);
system(strCmd);
}
3.2. Modbus通信功能实现
Modbus的核心是一个串行通信协议,采用主从模式,主机向从机发送请求,从机予以回复 [3] 。文献 [7] 采用VC编写Modbus RTU通讯,重点说明了数据的传输过程和CRC冗余循环码校验功能。文献 [8] 采用C++开发Modbus RTU及TCP/IP通信协议,实现嵌入式系统数据采集及上送服务器功能。本研究使用libmodbus库进行Modbus-RTU开发。libmodbus是一个快速且可移植的Modbus库,支持传统的RS-232、RS-422、RS-485和以太网设备。Modbus-RTU主程序设计流程如图3。
(1) libmobus实例创建,并设置参数,调用库函数modbus_new_rtu()实现功能;
(2) 设置从站ID,调用库函数modbus_set_slave()实现功能;
(3) 建立连接,调用库函数modbus_connect()实现功能;
(4) Modbus读取数据功能码与库函数对应关系如表1所示;

Table 1. Correspondence table of read data function code and library function
表1. 读取数据功能码与库函数对应关系表
(5) Modbus写数据功能码与库函数对应关系如表2所示;

Table 2. Correspondence table of write data function code and library function
表2. 写数据功能码与库函数对应关系表
(6) 关闭连接,调用库函数modbus_close()及modbus_free()释放modbus资源;

Figure 3. Flow chart of Modbus-RTU main program design
图3. Modbus-RTU主程序设计流程图
3.3. 协议间数据收发自动转换设计
本研究设计双线程实现协议间数据收发自动转换功能,更高效的利用CPU,加快应用程序的响应,系统软件设计流程如图4所示。线程thread_read_pub实现Modbus-RTU采集底层数据格式转换后经MQTT上送服务器功能;线程thread_sub_write实现MQTT订阅主题数据格式转换后经Modbus-RTU发送至底层控制装置。
各个线程间有方便的通信和数据交换机制,可共享数据空间,一个线程的数据可以直接为另一个线程使用,快捷而且方便。本研究定义MODBUS_t结构体来存放Modbus接收发送缓存数据。
typedefstruct {
uint16_t modbus_read_buffer[BUF_SIZE];
uint16_t modbus_write_buffer[BUF_SIZE];
}MODBUS_t;

Figure 4. System software design flow chart
图4. 系统软件设计流程图
本研究要解决协议自动转换功能,核心问题是解决协议数据格式转换。文献 [9] 采用JSON模块解析判断Modbus协议方式(RTU/TCP)来连通Modbus和MQTT模块。本研究应用需求采用RTU协议方式,根据3.1.2设计的MQTT_t结构体及Mosquitto数据格式要求,针对Modbus转MQTT使用格式化输出sprintf()函数将Modbus无符号整型数据转为Mosquitto指令可辨识的字符串类型,实现字符转字符串功能;针对MQTT转Modbus使用标准atoi()函数将Mosquitto订阅指令接收到的字符串类型转换为Modbus无符号整型数据类型,实现字符串转字符功能,最终实现一帧Modbus数据与多个MQTT主题发布订阅灵活转换功能,简便可靠且易于操作。
4. 功能验证
该嵌入式智能系统采用OKMX6X-C开发平台,基于Freescale i.MX6 Quad处理器,ARMCortex-A9架构,每个内核运行频率高达1 GHz,支持串口、USB、通用以太网口及WIFI模块。
4.1. 试验环境搭建
系统功能试验环境如图5,嵌入式智能系统平台通过内核配置安装CP210x UART驱动模块采用USB转RS232方式,与具有Modbus-RTU从站功能的工业电力电子设备装置通信,实现Modbus串口通信数据采集及发送;与物联网云平台采用WIFI模块通信,根据物联网云平台发布订阅数据,通过TCP/IP实现MQTT把数据上传到服务器或接收服务器数据,完成Modbus与MQTT不同协议数据灵活转换功能。

Figure 5. Establishment of system function test environment
图5. 系统功能试验环境搭建
该系统使用/MQTT/to_webapp0至/MQTT/to_webapp9共十个主题来订阅数据,使用/MQTT/to_condev0至/MQTT/to_condev9共十个发布主题发布数据,使用服务器地址为192.168.2.140。具有Modbus-RTU从站功能的工业电力电子控制设备接收该智能系统主站的命令包、回送数据包,实现Modbus通讯协议通信,支持功能01,02,03,04,05,06,15,16,22和23,监视串口数据。
4.2. MQTT转MODBUS协议功能
(1) 该系统订阅/MQTT/to_condev 10个主题,服务器向该系统发送消息,发布数据十进制表示分别为11、22、33、…99、100,如图6所示。

Figure 6. Server publishes MQTT data
图6. 服务器发布MQTT数据
(2) 该系统数据协议自动转换程序运行,接收服务器192.168.2.140发布的数据,进行数据格式转换,将数据进行打包整合通过/dev/ttyUSB0串口设备经一帧Modbus-RTU协议报文发送出去,完成MQTT转Modbus-RTU数据格式转换功能。
(3) 具有Modbus-RTU从站功能的工业电力电子设备装置收到该系统主站发送的RX报文,发送回复报文TX进行确认,RX报文与MQTT发布的10个协议点数据一一对应,如图7所示,000Bh对应十进制11,0016h对应十进制12,以此类推,可知Modbus从站控制设备收到服务器发送过来的MQTT协议数据,由此可验证MQTT转Modbus-RTU数据格式转换功能正确。

Figure 7. Modbus slave station control equipment receives Modbus-RTU messages
图7. Modbus从站控制设备接收Modbus-RTU报文
4.3. MODBUS转MQTT协议功能
(1) 该系统采集底层数据,向具有Modbus-RTU从站功能的工业电力电子设备装置发起Modbus读03功能码报文,从站控制设备发送回复报文TX进行响应,其发送分别为0064h、0063h、0058h、…、000Bh等10个协议点数据,如图8所示。

Figure 8. Modbus slave responds to the master station and sends Modbus-RTU message interface
图8. 从站响应主站并发送Modbus-RTU报文
(2) 该系统主站收到Modbus回复数据报文,通过数据格式转换,将一帧Modbus-RTU数据转换为/MQTT/to_webapp 10个发布主题发送至服务器,实现Modbus-RTU转MQTT数据格式转换功能。
(3) 该系统向服务器发送消息,发布/MQTT/to_webapp10个主题,服务器订阅数据如图9所示,与Modbus从站设备装置发送的报文数据内容一一对应,分别为0064h、0063h、0058h、…、000Bh,可知服务器已接收到Modbus从站控制设备发送的数据,由此可验证Modbus-RTU转MQTT功能块的正确性。

Figure 9. Server subscription receives MQTT data
图9. 服务器订阅接收MQTT数据
5. 结束语
该系统采用高性能工业Freescale i.MX6作为核心控制单元,基于ARM嵌入式Linux实时操作系统运行环境,采用C函数加动态库的接口编程形式实现了MODBUS-RTU通信协议及MQTT通信协议,并采用双线程及数据格式转换实现了异步协议的相互自动转换功能设计,解决传统工业电力电子设备无法与物联网云平台直接通信互联问题,经试验验证,系统运行稳定,能够满足数据传输的实时性、可靠性要求,同时系统便于升级和标准化,可以满足不同的工程应用需求。
参考文献