QT通信-串口通信

4 篇文章 0 订阅
1 篇文章 0 订阅


前言

QT 串口通信基于QT的QSerialPort类,先在项目文件pro中添加QT += serialport。
我使用的是ubuntu16.04,window下未测试是否能用。
QT的QSerialPort类说明见官网

一、串口搜索

使用QT串口通信类中QSerialPortInfo类的availablePorts()来获取计算机存在的串口。
初始化串口对象

m_serialPort = new QSerialPort();//实例化串口类一个对象

foreach是for的简化式,主要用于循环次数未知,这里获取的串口数目未知,将串口名称存放在QStringList中。

//选择串口
void CommuncationCenter::serial_select()
{
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        m_serialPortName << info.portName();
        QString c= "串口:";
        emit(error_log(c+info.portName()));

    }
    if(m_serialPort->isOpen())//如果串口已经打开了 先给他关闭了
    {
        m_serialPort->clear();
        m_serialPort->close();
    }

}

二、打开串口

选择QStringList中的串口名称,通过setPortName(QString)来设置打开那个串口,使用open(QIODevice::ReadWrite)用ReadWrite 的模式尝试打开串口,打开成功后设置串口通信的波特率,校验方式等配置。(打开方式有多种,只读(r/o)、只写(w/o)或读写(r/w)模式)

m_serialPort->setPortName(m_serialPortName[0]);

                if(!m_serialPort->open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口
                {
                    c = "打开失败!:";
                    emit(error_log(c+m_serialPortName[i]));
                    return false;
                }
                else
                {
                    m_serialPort->setBaudRate(my_baud,QSerialPort::AllDirections);//设置波特率和读写方向
                    m_serialPort->setDataBits(QSerialPort::Data8);		//数据位为8位
                    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//无流控制
                    m_serialPort->setParity(QSerialPort::NoParity);	//无校验位
                    m_serialPort->setStopBits(QSerialPort::OneStop); //一位停止位

                    //连接信号槽 当下位机发送数据QSerialPortInfo 会发送个 readyRead 信号,我们定义个槽void receiveInfo()解析数据
                    connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(receiveInfo()));
                    connect(timer, SIGNAL(timeout()), this, SLOT(timeUpdate()));
                    c = "打开成功!:";
                    emit(error_log(c+m_serialPortName[i]));

注意:串口始终以独占访问方式打开(即没有其他进程或线程可以访问已打开的串口)。

二、发送或接收数据

使用read () 和write () ,也可以调用readLine () 和readAll () 。如果不是一次读取所有数据,剩余的数据将在以后可用,因为新的传入数据将附加到 QSerialPort 的内部读取缓冲区。也可以使用setReadBufferSize ()限制读取缓冲区的大小。
从串口读取数据:QByteArray info = m_serialPort->readAll();
发送数据给串口:m_serialPort->write(info,len);

二、程序如下:

.h:

#ifndef COMMUNCATIONCENTER_H
#define COMMUNCATIONCENTER_H
#include<QtCore>
#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <AgvTypeData.h>
class CommuncationCenter : public QThread
{
    Q_OBJECT //使用信号与槽函数
public:
    explicit CommuncationCenter(QObject *parent = nullptr);
    QStringList m_serialPortName;
    void run();
    void serial_select();//选择串口
    bool serial_port(QString my_com, qint32 my_baud);//打开串口
    void sendInfo(const QString &info);//发送数据
    void sendInfo(char* info,int len);//发送数据
    void serial_close();//关闭串口
    QString Crc16(const QString &data_str);//CRC校验

private:  
    QSerialPort *m_serialPort;
    QTimer *timer;
    QString read_data;
    char convertCharToHex(char ch);
    void convertStringToHex(const QString &str, QByteArray &byteData);
//声明信号
signals:
    void error_log(QString error_port);
    void get_data(QString read_data);
    void error_data(QString e_data);
private slots:
    void receiveInfo();//接受分段数据
    void timeUpdate(); //接受全部数据
};

#endif // COMMUNCATIONCENTER_H

.cpp

#include "communcationcenter.h"

CommuncationCenter::CommuncationCenter(QObject *parent):QThread(parent)
{
    m_serialPort = new QSerialPort();//实例化串口类一个对象
    timer = new QTimer();
    read_data = "";
}

//选择串口
void CommuncationCenter::serial_select()
{
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        m_serialPortName << info.portName();
        QString c= "串口:";
        emit(error_log(c+info.portName()));

    }
    if(m_serialPort->isOpen())//如果串口已经打开了 先给他关闭了
    {
        m_serialPort->clear();
        m_serialPort->close();
    }

}
//打开串口
bool CommuncationCenter::serial_port(QString my_com, qint32 my_baud)
{
    if(m_serialPort->isOpen())//如果串口已经打开了 先给他关闭了
    {
        m_serialPort->clear();
        m_serialPort->close();
    }
    if (m_serialPortName[0]!=0)
    {
        //设置串口名字 假设我们上面已经成功获取到了
        for(int i = 0; i < m_serialPortName.size(); i++)
        {
            if (m_serialPortName[i] == my_com)
            {
                QString c= "找到匹配的串口::";
                emit(error_log(c+m_serialPortName[i]));

                m_serialPort->setPortName(m_serialPortName[0]);

                if(!m_serialPort->open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口
                {
                    c = "打开失败!:";
                    emit(error_log(c+m_serialPortName[i]));
                    return false;
                }
                else
                {
                    m_serialPort->setBaudRate(my_baud,QSerialPort::AllDirections);//设置波特率和读写方向
                    m_serialPort->setDataBits(QSerialPort::Data8);		//数据位为8位
                    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//无流控制
                    m_serialPort->setParity(QSerialPort::NoParity);	//无校验位
                    m_serialPort->setStopBits(QSerialPort::OneStop); //一位停止位

                    //连接信号槽 当下位机发送数据QSerialPortInfo 会发送个 readyRead 信号,我们定义个槽void receiveInfo()解析数据
                    connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(receiveInfo()));
                    connect(timer, SIGNAL(timeout()), this, SLOT(timeUpdate()));
                    c = "打开成功!:";
                    emit(error_log(c+m_serialPortName[i]));

                    return true;
                }

            }
        }
    }
    QString c= "没有找到匹配的串口!";
    emit(error_log(c));
    return false;
}

void CommuncationCenter::run()
{

}

//串口接收单片机的数据
void CommuncationCenter::receiveInfo()
{
    timer->start(100);//启动定时器,接收100毫秒数据(根据情况设定)
    QByteArray info = m_serialPort->readAll();
    QByteArray heData = info.toHex();
    QString    hexData(heData);
    read_data = read_data+hexData;
    //这里面的协议 你们自己定义就行  单片机发什么 代表什么 我们这里简单模拟一下

}
void CommuncationCenter::timeUpdate()
{
    timer->stop();
    if(read_data.size()!=0)
    {
        if(read_data == "010000")
        {
            emit(error_log("do"+read_data));//do something
        }
        else if(read_data == "100001")
        {
            emit(error_log("you"+read_data));//do something
        }
        else{
            emit(error_log(read_data));
            emit(get_data(read_data));//发送数据给主线程
        }
    }
    read_data = "";
}

//串口向单片机发送数据======================================================

//基本和单片机交互 数据 都是16进制的 我们这里自己写一个 Qstring 转为 16进制的函数
void CommuncationCenter::convertStringToHex(const QString &str, QByteArray &byteData)
{
    int hexdata,lowhexdata;
    int hexdatalen = 0;
    int len = str.length();
    byteData.resize(len/2);
    char lstr,hstr;
    for(int i=0; i<len; )
    {
        //char lstr,
        hstr=str[i].toLatin1();
        if(hstr == ' ')
        {
            i++;
            continue;
        }
        i++;
        if(i >= len)
            break;
        lstr = str[i].toLatin1();
        hexdata = convertCharToHex(hstr);
        lowhexdata = convertCharToHex(lstr);
        if((hexdata == 16) || (lowhexdata == 16))
            break;
        else
            hexdata = hexdata*16+lowhexdata;
        i++;
        byteData[hexdatalen] = (char)hexdata;
        hexdatalen++;
    }
    byteData.resize(hexdatalen);
}

//另一个 函数 char 转为 16进制
char CommuncationCenter::convertCharToHex(char ch)
{
    /*
    0x30等于十进制的48,48也是0的ASCII值,,
    1-9的ASCII值是49-57,,所以某一个值-0x30,,
    就是将字符0-9转换为0-9

    */
    if((ch >= '0') && (ch <= '9'))
         return ch-0x30;
     else if((ch >= 'A') && (ch <= 'F'))
         return ch-'A'+10;
     else if((ch >= 'a') && (ch <= 'f'))
         return ch-'a'+10;
     else return (-1);
}

//写两个函数 串口向单片机发送数据
void CommuncationCenter::sendInfo(char* info,int len){

    for(int i=0; i<len; ++i)
    {
        printf("0x%x\n", info[i]);
    }
    m_serialPort->write(info,len);//这句是真正的给单片机发数据 用到的是QIODevice::write 具体可以看文档
}
void CommuncationCenter::sendInfo(const QString &info){

    QByteArray sendBuf;
    convertStringToHex(info, sendBuf); //把QString 转换 为 hex
    m_serialPort->write(sendBuf);//这句是真正的给单片机发数据 用到的是QIODevice::write 具体可以看文档
    emit(error_log("发送数据成功!"+info));
}

//========================================================================

//关闭串口
void CommuncationCenter::serial_close()
{
    if (m_serialPort->isOpen())
       {
           m_serialPort->close();
       }
       delete m_serialPort;
}


//====================CRC校验====================================
QString CommuncationCenter::Crc16(const QString &data_str)
{
    quint8 buf;
    quint16 crc16 = 0xFFFF;
    QByteArray data;
    convertStringToHex(data_str, data); //把QString 转换 为 hex
    for ( auto i = 0; i < data.size(); ++i )
    {
        buf = data.at( i ) ^ crc16;
        crc16 >>= 8;
        crc16 ^= crc16Table[ buf ];
    }
    QString str  = QString::number(crc16,16).toUpper();
    qDebug()<<"CRC校验"<<str;
    return str;

}


总结

QT的串口通信程序可能有沉余代码,可以更加简洁,谢谢大家点赞及指导!
希望和大家一起学习,交流!

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值