由于目前制作的下位机是使用串口通信,因此需要使用QT中的串口解决方法来获取通信中的数据。在本文中您将看到QT对串口的使用非常简单易用,如果采用的是网络通信,QT也提供了同样简便的解决方法。
串口操作使用的是QT5支持的QtSerialPort类和QSerialPortInfo类,需要在程序中挂载相应的头文件:
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
另外还需要在工程文件.pro中添加一个QT值:
QT += serialport
这样您就已经可以在程序中使用串口了,根据需求来决定QSerialPort对象是在类中定义还是在函数中定义。对QSerialPort对象的属性设置也很常规,您需要决定的只是应该在窗体的构造函数中连接串口,还是应该在某个控件的槽函数中连接串口。
串口属性配置如下:
mySerialport = new QSerialPort();
mySerialport->setPortName("COM3"); //端口名称
if(mySerialport->open(QIODevice::ReadWrite))
{
mySerialport->setBaudRate(9600); //波特率
mySerialport->setDataBits(QSerialPort::Data8); //数据位
mySerialport->setParity(QSerialPort::NoParity); //校验
mySerialport->setStopBits(QSerialPort::OneStop); //停止位
mySerialport->setFlowControl(QSerialPort::NoFlowControl); //流控制
connect(mySerialport, SIGNAL(readyRead()), this, SLOT(update()));
}
else
QMessageBox::warning(NULL, "warning", "Serial Port is occupied", QMessageBox::Retry);
其它的参数各位都很熟悉,比较关键的一点是QT中的串口有一个机制,每当接收到一个数据时都会抛出一个signal(readyRead())表示已经可以读取串口数据。通常的做法都是将这个信号和某个槽函数连接起来,每当接收到串口数据就可以在槽函数中进行相应的实时处理。此处我绑定了update函数,这个函数是我自定义的。
void AutomaticStation::update()
{
recData = mySerialport->readAll(); //读取数据
QString buf;
int showdata;
buf = ShowHex(recData);
showdata = buf.toInt();
...... //数据处理
}
槽函数中通常的做法是用QSerialPort类的readAll函数将串口缓冲区中的所有数据都读出来,该类还提供了一些其它的read函数,如读取指定长度等等。这里读出的recData是一个QByteArray类型的变量,可以存储一个字节。如果希望像普通的数据一样处理,可以用一个自定义函数ShowHex将QByteArray类型转换为字符串类型,还可以再用QString类的toInt和toFloat等方法将它转化为常规数字类型。自定义的ShowHex函数如下所示:
QString AutomaticStation::ShowHex(QByteArray str)
{
QDataStream out(&str,QIODevice::ReadWrite);
QString buf;
while(!out.atEnd())
{
qint8 outChar = 0;
out >> outChar;
QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')).toUpper() + QString(" ");
buf += str;
}
return buf;
}
数据处理过程中需要解决的最重要的问题就是对通信格式的拆解。假设我定义了一种简单的通信格式,通信内容为“123456\n”,实际的意义是“12.3”和“45.6”两个数据,我设计的提取过程如下(注意这个步骤是在槽函数update中):
if (showdata <= 39 && showdata >= 30) //数字0~9
{
showdata -= 30;
a[i++] = showdata;
}
else
{
i = 0;
... //数组数据整理
}
简单来说处理步骤大概有三个:
1. if中提取有效通信数据,(此处是123456,没有换行\n,依次存储到数组a中);
2. else中判断一帧通信是否结束,(此处因为\n为无效数据,只要检测到非字符类型就表示一帧通信结束,i置0重新开始接收数据)
3. 每完成一帧通信后就可以在else中对数组中的数据进行整理得到有效数据,(比如此处要得到12.3,便是a[0]*10+a[1]+a[2]*0.1)
上述示例虽然简单,但这个方法可以应用到所有通信格式中,只要多增加一些值的判断即可。至此,上位机程序已经可以接收到串口中传来的各气象要素数据,如果想显示数据值,可以放置一些Label控件来显示。