• Qt 串口通信


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

    名称

    语言

    平台

     

    QextSerialPort

    QT C++

    Win/Linux

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

    QSerialPort

    QT C++

    QT5已经集成

    libserial

    C++

    Linux

     http://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] = '';
     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 }
  • 相关阅读:
    三种方法使HTML单页面输入密码才能访问
    JAVA知识汇总
    session 一致性的解决方案
    Debian 9 Stretch国内常用镜像源
    Java开发工具推荐
    Centos配置vsftpd
    [转]php实时输出内容
    php javascript comet
    使用安装 php-memcache-client
    [转]网页实时聊天之js和jQuery实现ajax长轮询 PHP
  • 原文地址:https://www.cnblogs.com/kyyblabla/p/3841199.html
Copyright © 2020-2023  润新知