Qt は複数の 485 デバイスと同期的に通信します

プロジェクトの要件により、4 つのレーザー変位センサーと通信するには 485 通信モードを使用する必要があるため、次のような例を書きました。

  • 使用センサーはBoyi Jingke社のBLシリーズレーザー変位センサーです。
  • 説明書に従って、4 つのレーザー変位センサーのアドレスを 0x01、0x02、0x03、0x04 に設定します。

.pro ファイル

QT       += core gui
QT       += serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    crc.cpp \
    main.cpp \
    mainwindow.cpp \
    rs485com.cpp

HEADERS += \
    crc.h \
    mainwindow.h \
    rs485com.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

 この記事の利点は、Qt 開発学習教材パッケージ、技術ビデオ (C++ 言語基礎、Qt プログラミング入門、QT シグナルおよびスロット メカニズム、QT インターフェイス開発イメージ描画、QT ネットワーク、QT データベース プログラミング、QTプロジェクトコンバット、QSS、OpenCV、クイックモジュール、インタビューの質問など) ↓↓↓↓下記を参照↓↓記事下部をクリックして料金を受け取ります↓↓ 

CRC チェック crc.h および crc.cpp

/// CRC校验码计算
unsigned short CRC16(unsigned char* pBuf, unsigned short len);

/// CRC校验码计算
unsigned short CRC16(unsigned char* pBuf, unsigned short len)
{
    unsigned short uCRC = 0xFFFF;
    int i, j;
    for (i = 0; i < len; i++)
    {
        uCRC ^= (*(pBuf + i));
        for (j = 0; j < 8; j++)
        {
            if ((uCRC & 0x0001) == 0x0001)
            {
                uCRC = (uCRC >> 1);
                uCRC ^= 0xA001;
            }
            else
                uCRC = (uCRC >> 1);
        }
    }
    return uCRC;
}

485 通信クラス rs485com.h および rs485com.cpp

/// rs485com.h
#include <QtSerialPort/QSerialPort>
#include <QObject>
#include <QThread>
#include <QDebug>

class Rs485Com : public QObject
{
    Q_OBJECT
public:
    explicit Rs485Com(QObject* parent = nullptr);
public slots:
    /// 串口通讯初始化
    /// 与对应串口建立连接,设置通讯波特率、读写方向、数据位等
    /// @param  portName    串口名,如 COM1、COM2 等
    void initPort(const QString& portName);
    /// 运行通信(同步)
    /// 与 485 设备不断进行同步通讯
    void runComSync(void);
private:
    /// 用于通讯的串口类成员
    QSerialPort* port;
    /// 串口通讯子线程成员
    QThread* subThread;
    /// 串口通讯报文
    QByteArray readCommand[4];
signals:
    /// 建立连接失败信号函数
    void failed(void);
    /// 建立连接成功信号函数
    void succeed(void);
    /// 接收数据发送给主线程的信号函数
    /// @param  addr    设备地址
    /// @param  dis 读取和处理后得到的数据
    void result(int addr,double dis);
};

/// rs485com.cpp
#include "rs485com.h"
#include "crc.h"

Rs485Com::Rs485Com(QObject *parent)
    : QObject{parent}
{
    // 创建用于485 通信的线程
    subThread = new QThread;

    // 初始化报文
    unsigned char hex[8]{ 0x01, 0x04, 0x00, 0x00, 0x00, 0x02 };
    unsigned short crc;
    for(int i = 0; i < 4;i++)
    {
        hex[0] = i + 1;
        crc = CRC16(hex,6);
        hex[6] = static_cast<unsigned char>(crc);
        hex[7] = static_cast<unsigned char>(crc >> 8);
        readCommand[i] = QByteArray((char*)hex,8);
        qDebug() << readCommand[i].toHex();
    }

    // 串口类必须在 moveToThread 之前初始化,否则程序会 crash(崩溃)
    port = new QSerialPort();

    this->moveToThread(subThread);
    port->moveToThread(subThread);

    // 启动线程
    subThread->start();
}

void Rs485Com::initPort(const QString& portName)
{
    // 如果串口已打开
    if (this->port->isOpen())
    {
        this->port->clear();// 清除缓冲区数据,终止读写操作
        this->port->close();// 关闭串口
    }
    // 设置要打开的串口名
    this->port->setPortName(portName);

    if(!this->port->open(QIODevice::ReadWrite))
    {
        emit failed();// 打开串口失败信号
    }
    else
    {
        this->port->setBaudRate(115200,QSerialPort::AllDirections);//设置波特率和读写方向
        this->port->setDataBits(QSerialPort::Data8);              //数据位为8位
        this->port->setFlowControl(QSerialPort::NoFlowControl);   //无流控制
        this->port->setParity(QSerialPort::NoParity);             //无校验位
        this->port->setStopBits(QSerialPort::OneStop);            //一位停止位
        this->runComSync();
        emit succeed();// 打开串口成功信号
    }
}

void Rs485Com::runComSync(void)
{
    int i = 0;
    QByteArray bytes;
    unsigned char cdata[4];
    int temp;
    double displacement;
    while(true)
    {
		if(i > 3){ i = 0; }
        // 发出指令
        port->write(readCommand[i]);
        qDebug() << "发送: " << readCommand[i].toHex();
        port->flush();
        port->waitForReadyRead(200);
        bytes.resize(9);
        bytes = port->readAll();
        qDebug() << "接收: " << bytes.toHex();

        for(int i = 3; i <= 6; i++)
        {
            cdata[i - 3] = bytes[i];
        }
        temp = (cdata[3]&0xff)|(cdata[2]<<8)|(cdata[1]<<16)|(cdata[0]<<24);
        displacement = temp / 1000.0;

        emit result(i,displacement);
        i++;
    }
}

インターフェース:

 

メインウィンドウクラス:

/// mainwindow.h
#include <QMainWindow>
#include <QtSerialPort/QSerialPortInfo>
#include "rs485com.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void refreshPortList(void);
    void connect2SensorSlots(void);
    void connectSlots(void);

private:
    Rs485Com* lds;
    Ui::MainWindow *ui;
signals:
    // 连接到传感器信号
    void connect2Sensor(QString portName);
};

/// mainwindow.h
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    lds = new Rs485Com;
    this->refreshPortList();
    this->connectSlots();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::refreshPortList(void)
{
    ui->comboBox->clear();
    QStringList portList;
    foreach(const QSerialPortInfo& info,QSerialPortInfo::availablePorts())
    {
        portList.append(info.portName());
    }
    ui->comboBox->addItems(portList);
}

void MainWindow::connect2SensorSlots(void)
{
    emit connect2Sensor(ui->comboBox->currentText());
}


void MainWindow::connectSlots(void)
{
    connect(ui->refreshButton,&QPushButton::clicked,this,&MainWindow::refreshPortList);


    connect(this,&MainWindow::connect2Sensor,lds,&Rs485Com::initPort);


    connect(lds,&Rs485Com::failed,this,[=]{
        qDebug() << "连接错误";
    });

    connect(lds,&Rs485Com::result,this,[=](int addr, double d){
        switch(addr)
        {
        case 0:
            ui->d1Edit->setText(QString::number(d));
            break;
        case 1:
            ui->d2Edit->setText(QString::number(d));
            break;
        case 2:
            ui->d3Edit->setText(QString::number(d));
            break;
        case 3:
            ui->d4Edit->setText(QString::number(d));
            break;
        }
    });

    connect(ui->connectButton,&QPushButton::clicked,this,&MainWindow::connect2SensorSlots);

}

ブログガーデン(チーズ頭_茶色のパンツ)から記事を転載しました:Qtは複数の485デバイスと同期的に通信します - チーズ頭_茶色のパンツ - ブログガーデン

 この記事の利点は、Qt 開発学習教材パッケージ、技術ビデオ (C++ 言語基礎、Qt プログラミング入門、QT シグナルおよびスロット メカニズム、QT インターフェイス開発イメージ描画、QT ネットワーク、QT データベース プログラミング、QTプロジェクトコンバット、QSS、OpenCV、クイックモジュール、インタビューの質問など) ↓↓↓↓下記を参照↓↓記事下部をクリックして料金を受け取ります↓↓

おすすめ

転載: blog.csdn.net/QtCompany/article/details/132249801