基于Qt5的MODBUS协议编程与实现
2016-05-23李晓锋胡良君等
李晓锋++胡良君+等
摘 要:上位机软件编写在嵌入式系统开发中是很重要的一环,一直得到嵌入式工程师的广泛关注。文中介绍了采用最新Qt5库的串口模块解码MODBUS数据包的实现方案,详细阐述了Qt5的串口编程接口,和用有限状态机进行数据解码的实现方法,实践证明该方法编程简单、工作稳定可靠。
关键词:QT;串口通信;有限状态机;MODBUS
中图分类号: TP311.11 文献标识码: A 文章编号: 1673-1069(2016)11-138-2
0 引言
在“智能电子线路故障诊断实训装置”研制过程中,需要开发一款上位机控制软件,在一般的嵌入式应用开发中,也总是会遇到各种上位机软件编写的任务,上位机软件编写的核心任务之一是串口通信。传统的上位机软件开发工具是VB6、VC++一类工具,但VB6过于陈旧不能较好支持微软新的操作系统,VC++又因为MFC的复杂而很难被嵌入式开发工程师掌握。因此本文将介绍采用Qt5的串口编程方法,既能轻松掌握,又功能强大。
1 Qt5的串口通信
Qt是一个跨平台的C++和GUI开发框架,是一个模块化的C++类库,与Visual C++使用的MFC类库相比,Qt简单方便、功能完善、跨平台、扩展能力强,可以用于嵌入式开发。使用Qt编程的核心优势在于优美的信号槽机制和强大易用的开发工具Qt Creator。Qt目前最新版本为Qt 5。Qt 5中用于串口通信编程的模块是类QSerialPort和类QSerialPortInfo。
1.1 串口的枚举
调用静态方法QSerialPortInfo::availablePorts()可以枚举系统中所有的串口,得到系统中可用串口的QSerialPortInfo对象列表,通过QSerialPortInfo类可以获取串口的有关信息,常用的有方法isBusy()可用于判断串口是否处于忙碌状态,方法portName()可用于获取串口的名称,也可将QSerialPortInfo对象作为输入参数调用QSerialPort对象的setPort()或setPortName()方法,设置想要操作的串口设备。
1.2 串口的初始设置
与在嵌入式设备上的串口开发一致,上位机中串口通信的第一步也是选择串口并对通信参数进行设置。Qt 5中,用QSerialPort对象来抽象串口端口,封装串口有关的操作。构造一个QSerialPort对象后,通过setPort()或setPortName()方法选择想要操作的串口设备,然后使用open()方法打开该端口,当打开成功后,QSerialPort会尝试检测串口的当前配置,并用作为自己的初始设置,也可使用setBaudRate(), setDataBits(), setParity(), setStopBits(), and setFlowControl()方法来重新设置波特率、数据帧格式、流控模式等通信参数。将串口设置为19200波特率、8N1数据帧。
1.3 串口数据的读写
串口通信的核心在于数据的收发,借助于强大的QSerialPort类,只需要使用简单的read()或write()方法,就可以读和写串口了。也可使用readLine()、readAll()读取串口接收到的数据,如果没有一次性读取完所有收到的数据,剩余的数据会存放在QSerialPort的内部数据缓存区中,新接收到的数据会附加到数据缓冲区的尾部。可以使用setReadBufferSize()方法限制内部读缓冲区的大小。串口数据读取的另一个关键是读取的时机的选择,这通常有两种选择,一是用一个循环不断的读取串口直到接收到所有需要的数据,但这会阻塞掉其他任务,一般只用于非GUI的应用;另一种选择是使用Qt强大的信号槽机制,连接QSerialPort的readyRead()信号到自己的串口数据读取槽函数,这样串口一旦接收到数据,槽函数就会被调用,在这里可以编写串口接收数据的处理代码,可以在该函数中,将收到的数据存入一个数据队列,方便后续对数据的解包操作,可参考如下代码。
void serialRead()
{
QByteArray bytes;
while(!serial->atEnd()){
bytes += serial->read(300);
}
for(int i = 0; i < bytes.count(); ++i)
dataBuffer.push_back(bytes[i]);
parseSerialData();
}
1.4 关闭串口
串口操作完成后,需要使用close()方法,关闭串口停止I/O操作。
2 MODBUS协议的实现
要实现可靠的串口通信,还需要一个可靠的串口通信协议,MODBUS协议在工业界已经得到广泛的运用,下文就简要介绍一下MODBUS协议在Qt串口通信中的实现。
2.1 MODBUS简介
Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
2.2 MODBUS的消息帧
MODBUS的通用消息帧分为ASCII消息帧和RTU消息帧,其中ASCII消息帧采用LRC纵向冗余校验,RTU消息帧采用CRC循环冗余校验。消息帧的结构如图1所示。
2.3 采用状态机方式解码MODBUS RTU消息帧
实现MODUBS协议的关键在于解码MODBUS 消息帧,考虑到串口通信中可能出现的各种传输错误,可靠的解码消息帧的方法是使用状态机编程模型。根据消息帧的结构可以设计如下的状态转换图进行数据的解码操作。(如图2)
解包程序首先进入起始状态等待消息头,每收到一部分数据就进入相应的下一个功能状态,接收过程中遇到任何错误,都简单的丢弃掉所有已经接收到的数据,重新等待下一个消息帧。
3 结语
本文介绍了使用Qt5 中串口通信模块用于MODBUS协议解包的实现方法,该设计方案已成功用于某课题的电子线路自动故障测试仪的上位机软件开发中,数据收发可靠、稳定,较好地满足了功能需求。
参 考 文 献
[1] 霍亚飞.Qt Creator快速入门(第2版)[M].北京:北京航空航天大学出版社,2014.
[2] 李晓锋.AVR单片机原理与应用[M].北京:北京理工大学出版社,2010.
[3] 李晓锋,宋锐.有限状态机在嵌入式系统中的实现及应用[J].广西轻工业,2008-04.