前言
最近给硬件组的同事做串口通信的界面,本来依凭着自己之前是电子信息专业的,自以为很快会完成的,但是现实总是和梦想相悖,架子搭出来了,一个字节的十六进制数据怎么也生成不了,难煞我,最终被人科普内存基础知识才恍然大悟,真是羞愧。
简言
Qt实现串口通信,挺简单的。Qt有封装好的类QSerialPort、QSerialPortInfo,只要熟悉这两个类,发送或接收数据是没问题的。对于界面通过串口控制硬件的操作来说,十六进制数据很重要,因为一般硬件接收的命令都是十六进制的,但是这个东西对于基础好的不算什么。
步骤
QSerialPort提供了访问串口的接口函数。使用辅助类QSerialPortInfo可以可用的串口信息。将QSerialPortInfo辅助类对象作为参数,使用setPort() 或setPortName()函数可以设置访问的串口设备。(要想对串口通信类更详细的了解,可参考博客http://blog.51cto.com/9291927/1879164)
在所有代码操作之前,要在pro文件里添加如下代码,添加串口通信模块。
QT += serialport
当然在.h文件中,添加包含文件是少不了的。
#include<QSerialPort>
#include<QSerialPortInfo>
(1)串口设置和配置
设置访问的串口设备,上面已经说了要用到setPort() 或setPortName()函数。在本设计中,我通过下拉框来选择需要访问的串口,这里用到了串口辅助类QSerialPortInfo来获取系统可用的串口。具体代码如下:
为QComboBox添加项
foreach (const QSerialPortInfo &qspinfo, QSerialPortInfo::availablePorts())
{
ui->comboBox->addItem(qspinfo.portName());
}
定义了一个槽函数,更改当前设置的串口设备
void SerialTest::changePort()
{
QString portName=ui->comboBox->currentText();
m_serialPort.close();
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
if(info.portName()==portName)
{
m_serialPort.setPortName(info.systemLocation());
}
}
m_isOpen=m_serialPort.open(QIODevice::ReadWrite);
if(!m_isOpen)
{
qDebug()<<"open port is fail";
}else{
qDebug()<<"open port is successful";
}
}
设置完需要访问的串口后,下面对串口进行配置,包括串口的波特率、数据位,奇偶校验、停止位等。在设置串口属性之前,先普及下基础知识:
①波特率:表示通信速度的参数,表示每秒传送bit的个数。
②数据位:表示通信中实际数据位的参数,表示有效数据位个数。
③奇偶校验:表示通信中检错方式。
④停止位:用于表示单个包的最后一位。典型的值为1,1.5和2。
配置代码如下:
QSerialPort m_serialPort;
m_serialPort.setDataBits(QSerialPort::Data8);
m_serialPort.setStopBits(QSerialPort::OneStop);
m_serialPort.setParity(QSerialPort::NoParity);
m_serialPort.setBaudRate(QSerialPort::Baud19200,QSerialPort::AllDirections);
(2)对串口的读写
串口的读写很简单,跟很多通信很像,都是用write()、read()或readAll(),都支持char* 和QByteArray。
本设计中只是给硬件发命令,有的有反馈有的没反馈,所以代码是这样书写的。data用来存储接收来的数据。
void SerialTest::sendOrder(QByteArray order, uchar* data)
{
qDebug()<<m_serialPort.write(order);
if(m_serialPort.waitForReadyRead(100))
{
m_serialPort.read((char*)data,16);
}
}
十六进制
先说下(大白话),十六进制、十进制、ASCII码还是其他,最终都是转化成01二进制数据流,这个什么进制的只是方便人观看,他们只是一种显示方式。所以我们接收到是数据都是二进制数据流,这样转换成什么格式都是我们自己操作的。因为对硬件的都是十六进制显示的命令,所以这里也都是将接收的数据转化成十六进制进行显示,或者是将十六进制的数据发送出去。
接收的十六进制转字符串
因为uchar是一个字节,一个十六进制的数据大小也是一个字节(比如0xff),所以我是直接用一个数组接收(我接收的数据大小是16个字节,所以大小是16)。
uchar data[16];
memset(data,0,16);
m_serialPort.read((char*)data,16);
下面转化成十六进制,用的是QString::number()。
QString str=QString::number(data[5],16)
当然,也可以用QByteArray接收数据。
QByteArray data=m_serialPort.readAll();
QString str=data.toHex();
字符串转十六进制
这个更简单,我只用了一行解决。
QByteArray type=QByteArray::fromHex(tr("B1").toLatin1());
结束语
这个串口通信界面的设计,让我深深的意识到自己的基础不扎实,所以没事的时候还是多看看C++基础知识吧,相信可以有很多收获。