Qt 串口通信(QSerialPort)

与下位机,单片机通信少不了使用串口进行通信,Qt 也提供了串口通信的类

QSerialPort

https://doc.qt.io/qt-5.9/qserialport.html //小伙伴们具体去看文档

使用的时候在 pro 添加这句导入模块 QT += serialport
1.连接串口 第一步就是 要先获取到 可连接的所有的串口的名字

QSerialPortInfo::availablePorts()
[static] QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
Returns a list of available serial ports on the system.
返回系统上可用串行端口的列表

QSerialPortInfo

Provides information about existing serial ports.
Use the static functions to generate a list of QSerialPortInfo objects. Each QSerialPortInfo object in the list represents a single serial port and can be queried for the port name, system location, description, and manufacturer. The QSerialPortInfo class can also be used as an input parameter for the setPort() method of the QSerialPort class.
See also QSerialPort.

提供关于现有串行端口的信息。
使用静态函数生成QSerialPortInfo对象列表。列表中的每个QSerialPortInfo对象表示一个串行端口,可以查询端口名称、系统位置、描述和制造商。QSerialPortInfo类还可以用作QSerialPort类的setPort()方法的输入参数。


//这样我们就获取到 可用的串口名字了

QStringList m_serialPortName;
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
    m_serialPortName << info.portName();
    qDebug()<<"serialPortName:"<<info.portName();
}

获取到串口名字列表以后,我们需要选择一个需要连接的 (自行根据选择)

2.根据串口名字 打开串口

#include<QSerialPort>

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

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

//设置串口名字 假设我们上面已经成功获取到了 并且使用第一个
m_serialPort->setPortName(m_serialPortName[0]);

if(!m_serialPort->open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口
{
    qDebug()<<m_serialPortName[0]<<"打开失败!";
    return;
}
//打开成功

    m_serialPort->setBaudRate(QSerialPort::Baud115200,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()));

3.下位机(单片机) ,上位机(Qt程序) 发送交互数据

    //接收单片机的数据
    void receiveInfo()
    {
        QByteArray info = m_serialPort->readAll();
        QByteArray hexData = info.toHex();
        //这里面的协议 你们自己定义就行  单片机发什么 代表什么 我们这里简单模拟一下
        if(hexData == "0x10000")
        {
            //do something
        }
        else if(hexData  == "0x100001") 
        {
            //do something
        }

    }
    //向单片机发送数据

    //基本和单片机交互 数据 都是16进制的 我们这里自己写一个 Qstring 转为 16进制的函数  
    void 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 SerialPort::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 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 sendInfo(const QString &info){

        QByteArray sendBuf;
        if (info.contains(" "))
        {
            info.replace(QString(" "),QString(""));//我这里是把空格去掉,根据你们定的协议来
        }
        qDebug()<<"Write to serial: "<<info;
        convertStringToHex(info, sendBuf); //把QString 转换 为 hex 

        m_serialPort->write(sendBuf);////这句是真正的给单片机发数据 用到的是QIODevice::write 具体可以看文档

    }

4.析构的时候 关闭串口

    if (m_serialPort->isOpen())
    {
        m_serialPort->close();
    }
    delete m_serialPort;

源码:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QComboBox>
#include <QPushButton>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void initUI();

    QStringList getPortNameList();//获取所有可用的串口列表

    void openPort();//打开串口
public slots:
    void receiveInfo();
private:
    Ui::Widget *ui;
    QSerialPort* m_serialPort; //串口类
    QStringList m_portNameList;

    QComboBox* m_PortNameComboBox;
    QPushButton* m_OpenPortButton;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QLayout>

#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    m_serialPort = new QSerialPort();

    initUI();

    m_portNameList = getPortNameList();

    m_PortNameComboBox->addItems(m_portNameList);

    connect(m_OpenPortButton,&QPushButton::clicked,this,&Widget::openPort);

}

Widget::~Widget()
{
    if (m_serialPort->isOpen())
    {
        m_serialPort->close();
    }
    delete m_serialPort;

    delete ui;
}

void Widget::initUI()
{
    this->setWindowTitle("码农小明 test QSerialPort");


    m_OpenPortButton = new QPushButton();
    m_OpenPortButton->setText("打开串口");

    m_PortNameComboBox  = new QComboBox();

    QHBoxLayout *m_layout = new QHBoxLayout();

    m_layout->addWidget(m_PortNameComboBox);
    m_layout->addWidget(m_OpenPortButton);

    this->setLayout(m_layout);
}

QStringList Widget::getPortNameList()
{
    QStringList m_serialPortName;
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        m_serialPortName << info.portName();
        qDebug()<<"serialPortName:"<<info.portName();
    }
    return m_serialPortName;
}

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


    m_serialPort->setPortName(m_PortNameComboBox->currentText());//当前选择的串口名字

    if(!m_serialPort->open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口
    {
        qDebug()<<"打开失败!";
        return;
    }
    qDebug()<<"串口打开成功!";

    m_serialPort->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);//设置波特率和读写方向
    m_serialPort->setDataBits(QSerialPort::Data8);      //数据位为8位
    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//无流控制
    m_serialPort->setParity(QSerialPort::NoParity); //无校验位
    m_serialPort->setStopBits(QSerialPort::OneStop); //一位停止位

    connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(receiveInfo()));
}

//接收到单片机发送的数据进行解析
void Widget::receiveInfo()
{
    QByteArray info = m_serialPort->readAll();

    qDebug()<<"receive info:"<<info;

}

这里写图片描述
这里写图片描述
这里写图片描述

下面处理数据的就不写了 简单的串口小demo 就完成了

        ———— 98年菜鸡一枚,请大佬们多多关照!

猜你喜欢

转载自blog.csdn.net/weixin_42837024/article/details/81669540
今日推荐