Qt 串口通信

  在Qt5之前,串口通信基本依赖于第三方库,下面是我曾接触过的串口通信类库:

名称

语言

平台

 

QextSerialPort

QT C++

Win/Linux

http://sourceforge.net/projects/qextserialport/files/

QSerialPort

QT C++

 

QT5已经集成

libserial

C++

Linux

 https://files.cnblogs.com/kyyblabla/libserial-0.5.2.gz.7z

 

  以上串口通信类库通信过程基本是一下步骤,即:打开串口 > 配置串口参数 > 收发数据。

  注意,串口参数(波特率、数据位、停止位、奇偶校验、流控等)必须在串口打开之后进行配置才有效。

  在使用串口接收数据时,会出现数据接收不完整的情况,这种情况很常见,尤其是在 QextSerialPort 和 QSerialPort 中,有一段时间我不得不怀疑是不是参数或者是硬件问题。后来发现这并不是异常,在通信中我依赖 readAll() 函数获取串口数据,但 readAll() 由 readyRead()信号触发,readyRead在串口读到起始标志时立即发送,并不一保证一定是当前所发数据的起始部分。因此串口通信双方通信前应制定好通信协议,规定好数据的起始于结尾标志,串口当读到完整的起始于结束标志之后,才认定读完一条完整的数据。

  下面分别就这三种串口通信类库进行实例代码的编写。

QextSerialPort使用小例

  QextSerialPort在Window平台下可用Win_QextSerialPort进行串口通信,下面对Win_QextSerialPort再一次封装的串口通信类SerialPort:

  头文件:serialport.h

  1 #ifndef SERIALPORT_H
  2 #define SERIALPORT_H
  3 
  4 #include <QObject>
  5 
  6 
  7 
  8 /**
  9  * @brief 串口参数
 10  */
 11 struct SerialConfig{
 12     int baudRate;        //波特率
 13     int characterSize;   //传输位
 14     int stopBits;        //停止位
 15     int parity;          //校验位 0无校验 1奇校验 2偶校验
 16     //char*serialPort[20];     //设备文件名
 17     int flowControl;     //流控
 18     long timeOut;        //超时时间
 19 };
 20 
 21 class Win_QextSerialPort;
 22 
 23 /**
 24  * @brief 串口通信类
 25  */
 26 class SerialPort : public QObject
 27 {
 28     Q_OBJECT
 29 public:
 30 
 31     explicit SerialPort(QString portName, QObject *parent = 0);
 32     //~SerialPort();
 33 
 34     /**
 35      * @brief 串口数据大发送格式
 36      */
 37     enum SerialDataType{
 38         ASCLL=0, //ascll方式
 39         HEX      //二进制方式
 40     };
 41     /**
 42      * @brief 配置串口参数
 43      * @param config
 44      */
 45     void setSerila(SerialConfig *config);
 46 
 47     /**
 48      * @brief 获取串口开启状态
 49      * @return
 50      */
 51     bool isOpend();
 52 
 53     /**
 54      * @brief 设置数据发送方式
 55      * @param type
 56      */
 57     void setSerialDataType(SerialDataType type);
 58 signals:
 59     /**
 60      * @brief 串口获取到数据
 61      */
 62     void strSerial(QString);
 63 public slots:
 64 
 65 
 66     /**
 67      * @brief  开启串口
 68      * @param  串口参数
 69      * @return 是否成功打开串口
 70      */
 71     bool openSerial(SerialConfig *config);
 72 
 73     /**
 74      * @brief 关闭串口
 75      */
 76     void closeSerial();
 77 
 78     /**
 79      * @brief 写入数据到串口,系统默认是ascll方式
 80      * @param str 待写入数据
 81      */
 82     void writeSerial(QString str);
 83 private slots:
 84     /**
 85      * @brief 读取数据
 86      */
 87     void readSerial();
 88 private:
 89     /**
 90      * @brief 基本串口通信类
 91      */
 92     Win_QextSerialPort*serial;
 93 
 94     /**
 95      * @brief 数据发送形式
 96      */
 97     SerialDataType serialDataType;
 98 
 99 
100 };
101 
102 #endif // SERIALPORT_H

  源文件:serialport.cpp

  1 #include "serialport.h"
  2 #include "serial_inc/win_qextserialport.h"
  3 
  4 #include <QDebug>
  5 
  6 SerialPort::SerialPort(QString portName,QObject *parent):QObject(parent),serialDataType(HEX)
  7 {
  8 
  9     this->serial=new Win_QextSerialPort(portName, QextSerialBase::EventDriven);
 10     connect(serial,SIGNAL(readyRead()),this,SLOT(readSerial()));
 11 
 12 }
 13 
 14 void SerialPort::setSerila(SerialConfig *config)
 15 {
 16 
 17     //波特率
 18     BaudRateType baudRate;
 19 
 20     switch (config->baudRate) {
 21     case 9600:
 22         baudRate=BAUD9600;
 23         break;
 24     case 115200:
 25         baudRate=BAUD115200;
 26         break;
 27     default:
 28         baudRate=BAUD4800;
 29         break;
 30     }
 31 
 32     //数据位
 33     DataBitsType dataBits;
 34     switch (config->characterSize) {
 35     case 7:
 36         dataBits=DATA_7;
 37         break;
 38     default:
 39         dataBits=DATA_8;
 40         break;
 41     }
 42 
 43     //停止位
 44     StopBitsType stopBits;
 45     switch (config->stopBits) {
 46     case 1:
 47         stopBits=STOP_1;
 48         break;
 49     case 2:
 50         stopBits=STOP_2;
 51         break;
 52     default:
 53         stopBits=STOP_1_5;
 54         break;
 55     }
 56 
 57     //奇偶校验
 58     ParityType parity;
 59     switch (config->parity) {
 60     case 0:
 61         parity=PAR_NONE;
 62         break;
 63     case 1:
 64         parity=PAR_ODD;
 65         break;
 66     default:
 67         parity=PAR_EVEN;
 68         break;
 69     }
 70 
 71     //数据流控
 72     FlowType flow=FLOW_OFF;
 73 
 74     serial->setBaudRate(baudRate);
 75     serial->setDataBits(dataBits);
 76     serial->setStopBits(stopBits);
 77     serial->setParity(parity);
 78     serial->setFlowControl(flow);
 79 
 80     serial->setDtr(false);
 81     serial->setRts(false);
 82 
 83 
 84 }
 85 
 86 bool SerialPort::isOpend()
 87 {
 88     return this->serial!=NULL?serial->isOpen():false;
 89 }
 90 
 91 void SerialPort::setSerialDataType(SerialPort::SerialDataType type)
 92 {
 93     this->serialDataType=type;
 94 }
 95 
 96 
 97 void SerialPort::writeSerial(QString str)
 98 {
 99 
100     if(this->serialDataType==this->ASCLL){
101         serial->write(str.toLocal8Bit());
102     }else{
103 
104         QByteArray b;
105         b=QByteArray::fromHex(str.toUtf8());
106         serial->write(b);
107     }
108 
109 }
110 
111 void SerialPort::readSerial()
112 {    
113 
114     qDebug()<<serial->bytesAvailable();
115 
116     QString str="";
117 
118     QByteArray array=serial->readAll();
119 
120     if(this->serialDataType==SerialPort::ASCLL){
121         str=QString::fromLocal8Bit(array.data());
122     }else{
123         array=array.toHex();
124         str=QString::fromUtf8(array.data());
125     }
126 
127     str=str.trimmed();
128 
129     qDebug()<<"serial get:"<<str;
130 
131     emit this->strSerial(str);
132 
133 
134 }
135 
136 
137 /**打开
138  * @brief SerialPort::openSerial
139  * @return
140  */
141 bool SerialPort::openSerial(SerialConfig*config)
142 {
143 
144     bool isOpen=serial->open(QIODevice::ReadWrite);
145 
146     qDebug()<<"isOpen:"<<isOpen;
147     //如果已经成功打开串口,则经行串口参数配置
148     //这里有一个概念:串口配置必须在串口设备成功打开后才有效!
149     if(isOpen){
150         this->setSerila(config);
151     }
152 
153     return isOpen;
154 }
155 
156 void SerialPort::closeSerial()
157 {
158     serial->close();
159 
160 }

 

QSerialPort 使用小例

  QSerialPort通信方式与 Win_QextSerialPort方式类似。

  串口初始化代码片段:

 1   QSerialPort serial=new QSerialPort(this);
 2 
 3     connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
 4 
 5     serial->setPortName("COM4");
 6     serial->setBaudRate(9600);
 7     serial->setDataBits(QSerialPort::Data8);
 8     serial->setParity(QSerialPort::NoParity);
 9     serial->setStopBits(QSerialPort::OneStop);
10     serial->setFlowControl(QSerialPort::NoFlowControl);
11     if (serial->open(QIODevice::ReadWrite)) {
12 
13         qDebug()<<"yes";
14 
15     } else {
16 
17         qDebug()<<"no";
18     }

  数据接收函数:

1 void QPort::readData()
2 {
3     QByteArray data = serial->readAll();
4     qDebug()<<data;
5    
6 }

libserial使用小例

  libserial只使用于Linux平台,下载源码后,进行编译和安装。下面是封装的串口通信类 Serial

  头文件:serial.h

 1 #ifndef SERIAL_H
 2 #define SERIAL_H
 3 
 4 #include "common.h"
 5 #include "SerialStream.h"
 6 #include "SerialStreamBuf.h"
 7 #include <QObject>
 8 
 9 using namespace std;
10 using namespace LibSerial;
11 
12 
13 typedef struct
14 {
15     int baudRate;        //!<波特率
16     int characterSize;   //!<传输位
17     int stopBits;        //!<停止位
18     int parity;          //!校验位 0无校验 1奇校验 2偶校验
19     char*serialPort; //!设备文件名
20 
21 }SerialConfig;
22 
23 
24 class Serial : public QObject
25 {
26     Q_OBJECT
27 public:
28     explicit Serial(QObject *parent = 0);
29 
30 signals:
31 
32     void message(QString msg);
33 public slots:
34     //打开串口
35     bool open(SerialConfig*config);
36     void work();
37     void close();
38     void sendMesg(QString msg);
39 private slots:
40 
41 private:
42     /**
43      * @brief 初始化串口数据
44      * @param config
45      */
46     void initSerialStream(SerialConfig*config);
47 
48     /**
49      * @brief 串口字节流
50      */
51     SerialStream serialStream;
52 
53     bool isRuning;
54 };
55 
56 #endif // SERIAL_H

  源文件:serial.cpp

  1 #include "serial.h"
  2 
  3 //数据开始标示
  4 #define SERIAL_DATA_START 2
  5 
  6 //数据结束标示
  7 #define SERIAL_DATA_END 3
  8 
  9 Serial::Serial(QObject *parent) :
 10     QObject(parent)
 11 {
 12 }
 13 
 14 bool Serial::open(SerialConfig *config){
 15 
 16 
 17     serialStream.Open(config->serialPort);
 18 
 19     if(!serialStream.IsOpen())
 20     {
 21         qDebug()<<"cannot open serial "<<config->serialPort;
 22         return false;
 23     }else{
 24 
 25         qDebug()<<"success open serial "<<config->serialPort;
 26     }
 27 
 28     initSerialStream(config);
 29 
 30     return true;
 31 
 32 }
 33 
 34 
 35 void Serial::work(){
 36 
 37     //缓存数据
 38     char *msg = new char[255];
 39     int index = 0;
 40     char next_byte ;    //串口接收到的下一个字节
 41     this->isRuning=true;
 42     forever{
 43         //
 44         if(this->isRuning==false){
 45             break;
 46         }
 47 
 48         serialStream.get( next_byte );
 49 
 50         int char_num=next_byte+0;
 51 
 52         if(char_num<30){
 53             qDebug()<<":"<<next_byte+0;
 54         }else{
 55             qDebug()<<next_byte;
 56         }
 57 
 58         if(char_num!=SERIAL_DATA_END)
 59         {
 60             if(char_num==SERIAL_DATA_START){
 61                 index=0;
 62                 continue;
 63             }
 64 
 65             msg[index] = next_byte;
 66             index++;
 67         }
 68         else
 69         {
 70             msg[index] = '\0';
 71             index = 0;
 72             qDebug("%s",msg);
 73             emit message(QString(msg).trimmed());
 74         }
 75     }
 76 }
 77 
 78 void Serial::close(){
 79 
 80     this->isRuning=false;
 81 }
 82 
 83 void Serial::sendMesg(QString msg)
 84 {
 85     msg.insert(0,2);
 86     msg.append(3);
 87 
 88     char*cmsg =msg.toUtf8().data();
 89     serialStream.write(cmsg,strlen(cmsg));
 90 
 91 }
 92 
 93 void Serial::initSerialStream(SerialConfig *config)
 94 {
 95 
 96     SerialStreamBuf::BaudRateEnum baudRate;
 97 
 98     switch (config->baudRate) {
 99     case 9600:
100         baudRate=SerialStreamBuf::BAUD_9600;
101         break;
102     case 115200:
103         baudRate=SerialStreamBuf::BAUD_115200;
104         break;
105     default:
106         baudRate=SerialStreamBuf::BAUD_4800;
107         break;
108     }
109 
110     SerialStreamBuf::CharSizeEnum characterSize;
111     switch (config->characterSize) {
112     case 7:
113         characterSize=SerialStreamBuf::CHAR_SIZE_7;
114         break;
115     default:
116         characterSize=SerialStreamBuf::CHAR_SIZE_8;
117         break;
118     }
119 
120 
121     SerialStreamBuf::ParityEnum parity;
122     switch (config->characterSize) {
123     case 0:
124         parity=SerialStreamBuf::PARITY_NONE;
125         break;
126     case 1:
127         parity=SerialStreamBuf::PARITY_ODD;
128         break;
129     default:
130         parity=SerialStreamBuf::PARITY_EVEN;
131         break;
132     }
133 
134 
135     serialStream.SetBaudRate(baudRate);
136     serialStream.SetCharSize(characterSize);
137     serialStream.SetNumOfStopBits(config->stopBits);
138     serialStream.SetParity(parity);
139 }

 

 

posted @ 2014-07-13 17:18  颜不改  阅读(4761)  评论(0编辑  收藏  举报