Qt5下通信串口(SerialPort )单发及导入表格连续下发(Modbus)

Qt5下通信串口单发及导入表格连续下发(Modbus Rtu)

  • 界面预览
    • 言归正传
      • .Pro文件下
    • 源码
      • 表格excel的编写源码
      • 功能实现源码
      • 功能展示

界面预览

这是我第一次使用CSDN来写博客,写这篇博客也是对自己入门以来的一个总结和该项目的记录。如图所示:
Qt5下通信串口(SerialPort )单发及导入表格连续下发(Modbus)_第1张图片
大家可以看到,基本的功能跟串口助手是类似的,在此基础上我加入了表格导入数据的方式,把表格数据转换为16进制数据的过程,软件数据发送显示及下位机接收显示,来确保我们的程序是否正常工作。

言归正传

本文讲述的 QSerialPort 是在qt5 + 版本以上才有
与下位机,单片机通信少不了使用串口进行通信,Qt 也提供了串口通信的类

.Pro文件下

使用的时候在 pro 添加这句导入模块 QT += serialport

QT		+= serialport

QT下读取excel文件使用的预处理的文件

QT      +=axcontainer

那么Pro文件内就不多做介绍了,直接进入核心部落。
首先是对UI界面的设计,我把我的贴出来供大家参考。
Qt5下通信串口(SerialPort )单发及导入表格连续下发(Modbus)_第2张图片

源码

表格excel的编写源码

excelengine.h

#ifndef EXCELENGINE_H
#define EXCELENGINE_H




#include
#include 
#include 
#include 
#include 
#include "qt_windows.h"
#include 
class ExcelEngine
{
public:
    ExcelEngine();
    ExcelEngine(QString xlsFile);
    ~ExcelEngine();
    bool Open(UINT nSheet, bool visible);
    bool Open(QString xlsFile, UINT nSheet, bool visible);
    void Save();
    void Close();
    void Clear();
    bool SaveDataFrTable(QTableWidget *tableWidget);
    bool ReadDataToTable(QTableWidget *tableWidget);
    QVariant GetCellData(UINT row, UINT column);
    bool SetCellData(UINT row, UINT column, QVariant data);
    bool IsOpen();
    bool IsValid();
    UINT GetRowCount()const;
    UINT GetColumnCount()const;
private:
    QAxObject* pExcel;
    QAxObject* pWorkbooks;
    QAxObject* pWorkbook;
    QAxObject* pWorksheet;
    QString sXlsFile;
    int nRowCount;
    int nColumnCount;
    int nStartRow;
    int nStartColumn;
    int nCurrSheet;
    bool bIsOpen;
    bool bIsValid;
    bool bIsANewFile;
    bool bIsSaveAlready;
    bool bIsVisible;
};
#endif // EXCELENGINE_H

excelengine.cpp

#include "excelengine.h"


ExcelEngine::ExcelEngine()
{
    pExcel     = NULL;
    pWorkbooks = NULL;
    pWorkbook  = NULL;
    pWorksheet = NULL;

    sXlsFile     = "";
    nRowCount    = 0;
    nColumnCount = 0;
    nStartRow    = 0;
    nStartColumn = 0;

    bIsOpen     = false;
    bIsValid    = false;
    bIsANewFile = false;
    bIsSaveAlready = false;

    HRESULT r = OleInitialize(0);
    if (r != S_OK && r != S_FALSE)
    {
        qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
    }
}

ExcelEngine::ExcelEngine(QString xlsFile)
{
    pExcel     = NULL;
    pWorkbooks = NULL;
    pWorkbook  = NULL;
    pWorksheet = NULL;

    sXlsFile     = xlsFile;
    nRowCount    = 0;
    nColumnCount = 0;
    nStartRow    = 0;
    nStartColumn = 0;

    bIsOpen     = false;
    bIsValid    = false;
    bIsANewFile = false;
    bIsSaveAlready = false;

    HRESULT r = OleInitialize(0);
    if (r != S_OK && r != S_FALSE)
    {
        qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
    }
}

ExcelEngine::~ExcelEngine()
{
    if ( bIsOpen )
    {
        //析构前,先保存数据,然后关闭workbook
        Close();
    }
    OleUninitialize();
}

/**
  *@brief 打开sXlsFile指定的excel报表
  *@return true : 打开成功
  *        false: 打开失败
  */
bool ExcelEngine::Open(UINT nSheet, bool visible)
{

    if ( bIsOpen )
    {
        //return bIsOpen;
        Close();
    }

    nCurrSheet = nSheet;
    bIsVisible = visible;

    if ( NULL == pExcel )
    {
        pExcel = new QAxObject("Excel.Application");
        if ( pExcel )
        {
            bIsValid = true;
        }
        else
        {
            bIsValid = false;
            bIsOpen  = false;
            return bIsOpen;
        }

        pExcel->dynamicCall("SetVisible(bool)", bIsVisible);
    }

    if ( !bIsValid )
    {
        bIsOpen  = false;
        return bIsOpen;
    }

    if ( sXlsFile.isEmpty() )
    {
        bIsOpen  = false;
        return bIsOpen;
    }

    /*如果指向的文件不存在,则需要新建一个*/
    QFile f(sXlsFile);
    if (!f.exists())
    {
        bIsANewFile = true;
    }
    else
    {
        bIsANewFile = false;
    }

    if (!bIsANewFile)
    {
        pWorkbooks = pExcel->querySubObject("WorkBooks"); //获取工作簿
        pWorkbook = pWorkbooks->querySubObject("Open(QString, QVariant)",sXlsFile,QVariant(0)); //打开xls对应的工作簿
    }
    else
    {
        pWorkbooks = pExcel->querySubObject("WorkBooks");     //获取工作簿
        pWorkbooks->dynamicCall("Add");                       //添加一个新的工作薄
        pWorkbook  = pExcel->querySubObject("ActiveWorkBook"); //新建一个xls
    }

    pWorksheet = pWorkbook->querySubObject("WorkSheets(int)", nCurrSheet);//打开sheet

    //至此已打开,开始获取相应属性
    QAxObject *usedrange = pWorksheet->querySubObject("UsedRange");//获取该sheet的使用范围对象
    QAxObject *rows = usedrange->querySubObject("Rows");
    QAxObject *columns = usedrange->querySubObject("Columns");

    //因为excel可以从任意行列填数据而不一定是从0,0开始,因此要获取首行列下标
    nStartRow    = usedrange->property("Row").toInt();    //第一行的起始位置
    nStartColumn = usedrange->property("Column").toInt(); //第一列的起始位置

    nRowCount    = rows->property("Count").toInt();       //获取行数
    nColumnCount = columns->property("Count").toInt();    //获取列数

//    qDebug()<
//    qDebug()<
//    qDebug()<
//    qDebug()<
    bIsOpen  = true;
    return bIsOpen;
}

/**
  *@brief Open()的重载函数
  */
bool ExcelEngine::Open(QString xlsFile, UINT nSheet, bool visible)
{
    sXlsFile = xlsFile;
    nCurrSheet = nSheet;
    bIsVisible = visible;

    return Open(nCurrSheet,bIsVisible);
}

/**
  *@brief 保存表格数据,把数据写入文件
  */
void ExcelEngine::Save()
{
    if ( pWorkbook )
    {
        if (bIsSaveAlready)
        {
            return ;
        }

        if (!bIsANewFile)
        {
            pWorkbook->dynamicCall("Save()");
        }
        else /*如果该文档是新建出来的,则使用另存为COM接口*/
        {
            pWorkbook->dynamicCall("SaveAs (const QString&,int,const QString&,const QString&,bool,bool)",
                      sXlsFile,56,QString(""),QString(""),false,false);

        }

        bIsSaveAlready = true;
    }
}

/**
  *@brief 关闭前先保存数据,然后关闭当前Excel COM对象,并释放内存
  */
void ExcelEngine::Close()
{
    //关闭前先保存数据
    Save();

    if ( pExcel && pWorkbook )
    {
        pWorkbook->dynamicCall("Close(bool)", true);
        pExcel->dynamicCall("Quit()");

        delete pExcel;
        pExcel = NULL;

        bIsOpen     = false;
        bIsValid    = false;
        bIsANewFile = false;
        bIsSaveAlready = true;
    }
}

/**
  *@brief 把tableWidget中的数据保存到excel中
  *@param tableWidget : 指向GUI中的tablewidget指针
  *@return 保存成功与否 true : 成功
  *                  false: 失败
  */
bool ExcelEngine::SaveDataFrTable(QTableWidget *tableWidget)
{
    if ( NULL == tableWidget )
    {
        return false;
    }
    if ( !bIsOpen )
    {
        return false;
    }

    int tableR = tableWidget->rowCount();
    int tableC = tableWidget->columnCount();

    //获取表头写做第一行
    for (int i=0; i<tableC; i++)
    {
        if ( tableWidget->horizontalHeaderItem(i) != NULL )
        {
            this->SetCellData(1,i+1,tableWidget->horizontalHeaderItem(i)->text());
        }
    }

    //写数据
    for (int i=0; i<tableR; i++)
    {
        for (int j=0; j<tableC; j++)
        {
            if ( tableWidget->item(i,j) != NULL )
            {
                this->SetCellData(i+2,j+1,tableWidget->item(i,j)->text());
            }
        }
    }

    //保存
    Save();

    return true;
}

/**
  *@brief 从指定的xls文件中把数据导入到tableWidget中
  *@param tableWidget : 执行要导入到的tablewidget指针
  *@return 导入成功与否 true : 成功
  *                   false: 失败
  */
bool ExcelEngine::ReadDataToTable(QTableWidget *tableWidget)
{
    if ( NULL == tableWidget )
    {
        return false;
    }

    //先把table的内容清空
    int tableColumn = tableWidget->columnCount();
    tableWidget->clear();
    for (int n=0; n<tableColumn; n++)
    {
        tableWidget->removeColumn(0);
    }

    int rowcnt    = nStartRow + nRowCount;
    int columncnt = nStartColumn + nColumnCount;

    //获取excel中的第一行数据作为表头
    QStringList headerList;
    for (int n = nStartColumn; n<columncnt; n++ )
    {
        QAxObject * cell = pWorksheet->querySubObject("Cells(int,int)",nStartRow, n);
        if ( cell )
        {
            headerList<<cell->dynamicCall("Value2()").toString();
        }
    }

    //重新创建表头
    tableWidget->setColumnCount(nColumnCount);
    tableWidget->setHorizontalHeaderLabels(headerList);


    //插入新数据
    for (int i = nStartRow+1, r = 0; i < rowcnt; i++, r++ )  //行
    {
        tableWidget->insertRow(r); //插入新行
        for (int j = nStartColumn, c = 0; j < columncnt; j++, c++ )  //列
        {
            QAxObject * cell = pWorksheet->querySubObject("Cells(int,int)", i, j );//获取单元格

            //在r新行中添加子项数据
            if ( cell )
            {
                tableWidget->setItem(r,c,new QTableWidgetItem(cell->dynamicCall("Value2()").toString()));
            }
        }
    }

    return true;
}

/**
  *@brief 获取指定单元格的数据
  *@param row : 单元格的行号
  *@param column : 单元格的列号
  *@return [row,column]单元格对应的数据
  */
QVariant ExcelEngine::GetCellData(UINT row, UINT column)
{
    QVariant data;

    QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//获取单元格对象
    if ( cell )
    {
        data = cell->dynamicCall("Value2()");
    }

    return data;
}

/**
  *@brief 修改指定单元格的数据
  *@param row : 单元格的行号
  *@param column : 单元格指定的列号
  *@param data : 单元格要修改为的新数据
  *@return 修改是否成功 true : 成功
  *                   false: 失败
  */
bool ExcelEngine::SetCellData(UINT row, UINT column, QVariant data)
{
    bool op = false;

    QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//获取单元格对象
    if ( cell )
    {
        QString strData = data.toString(); //excel 居然只能插入字符串和整型,浮点型无法插入
        cell->dynamicCall("SetValue(const QVariant&)",strData); //修改单元格的数据
        op = true;
    }
    else
    {
        op = false;
    }

    return op;
}

/**
  *@brief 清空除报表之外的数据
  */
void ExcelEngine::Clear()
{
    sXlsFile     = "";
    nRowCount    = 0;
    nColumnCount = 0;
    nStartRow    = 0;
    nStartColumn = 0;
}

/**
  *@brief 判断excel是否已被打开
  *@return true : 已打开
  *        false: 未打开
  */
bool ExcelEngine::IsOpen()
{
    return bIsOpen;
}

/**
  *@brief 判断excel COM对象是否调用成功,excel是否可用
  *@return true : 可用
  *        false: 不可用
  */
bool ExcelEngine::IsValid()
{
    return bIsValid;
}

/**
  *@brief 获取excel的行数
  */
UINT ExcelEngine::GetRowCount()const
{
    return nRowCount;
}

/**
  *@brief 获取excel的列数
  */
UINT ExcelEngine::GetColumnCount()const
{
    return nColumnCount;
}

以上是对excel表格的导入程序描述,控件实现如下源码中查找。

功能实现源码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 

#include 
#include 
#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include
#include
#include 
#include 
#include 
//#include 
#include 
#include 


#include 

// CRC16码表
#define UCHAR unsigned char
static const UCHAR aucCRCHi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40};

static const UCHAR aucCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
    0x41, 0x81, 0x80, 0x40};

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::MainWindow *ui;

    ExcelEngine eetest;

    void McMBCRC16(unsigned char *pDataIn, int iLenIn, unsigned int *pCRCOut);


public slots:
   // void  readallexcel();//读取串口
   void sleep(unsigned int msec);

private slots:

    void on_cin_Button_clicked();

    void on_save_Button_clicked();

    void Serial_read();//读取串口

    void on_send_Button_clicked();

    void on_open_Button_clicked();

    void on_search_Button_clicked();

    void on_clear_r_Button_clicked();

    void on_up_Button_clicked();

    void on_receiveEdit_textChanged();

public:
    QSerialPort Serial;

};

#endif // MAINWINDOW_H

main.cpp

#include "mainwindow.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("多功能串口开发软件 作者:Cola.Liu");
    w.show();

    return a.exec();
}

mainwindow.cpp

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

//#define cunction - like macro

#include 

#include 

#include 
#include 


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle("TEST窗口  作者:cola.liu");                //设置子窗口标题
    Serial.setPortName("/dev/ttyUSB4");

       connect(&Serial, &QSerialPort::readyRead , this , &MainWindow::Serial_read);

       ui->bandRateBox->setCurrentIndex(0);    //波特率默认9600

       Serial.setPortName("/dev/ttyUSB4");                      //设置端口号
       Serial.setBaudRate(9600);                        //设置波特率
       Serial.setDataBits(QSerialPort::Data8);          //设置数据位
       Serial.setStopBits(QSerialPort::OneStop);        //设置停止位
       Serial.setParity(QSerialPort::NoParity);          //设置奇偶校验
       Serial.setFlowControl(QSerialPort::NoFlowControl);//设置流控制模式

}

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

void MainWindow::on_cin_Button_clicked()
{
    QString FilePath = QFileDialog :: getOpenFileName(this, NULL, NULL, "All File(*.*)");
    if(FilePath!=""){
        eetest.Open(FilePath,1,false);
        eetest.ReadDataToTable(ui->tableWidget);
    }
}

void MainWindow::on_save_Button_clicked()
{
    //    eetest.Open("a.xlsx"11,1,false);
        eetest.SaveDataFrTable(ui->tableWidget);
}




void MainWindow::Serial_read()
{
    //读取串口收到的数据
    QByteArray buffer = Serial.readAll();
    //判断是否需要16进制显示
    if(ui->show16Box->isChecked()==true)
    {
       int count = buffer.size();
       QString receive;
       for ( int i= 0; i< count; i++)
       {
           receive += QString(" %1").arg( (quint8)buffer.data()[i], 2, 16, QLatin1Char( '0' ) );
       }
        //buffer = buffer.toHex() ;//转换为16进制 例:"1234" -->“31323334”

        //ui->receiveEdit->insertPlainText(receive+"\n");
       //设置时间

       QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间

       QString str = time.toString("yyyy-MM-dd hh:mm:ss ddd"); //设置显示格式

         receive = ui->receiveEdit->toPlainText() +"\n"+receive;
         ui->receiveEdit->setText( receive );

    }
    //QString receive = QString(buffer);

    //在接受窗口显示收到的数据
   // ui->receiveEdit->insertPlainText(receive);
  //ui->receiveEdit->setText( ui->receiveEdit->toPlainText() + "\nghjxsdhjsd:\n" + ui->SendEdit->toPlainText() );

}


void MainWindow::on_open_Button_clicked()
{


    if(ui->open_Button->text() == QString("打开串口"))  //串口未打开
        {
            //设置端口号
            Serial.setPortName(ui->comBox->currentText());
            //设置波特率
            Serial.setBaudRate(ui->bandRateBox->currentText().toInt());
            //设置数据位
            switch (ui->dataBitBox->currentText().toInt())
            {
                case 8: Serial.setDataBits(QSerialPort::Data8); break;
                case 7: Serial.setDataBits(QSerialPort::Data7); break;
                case 6: Serial.setDataBits(QSerialPort::Data6); break;
                case 5: Serial.setDataBits(QSerialPort::Data5); break;
                default: break;
            }
            //设置停止位
            switch (ui->stopBitBox->currentText().toInt())
            {
                case 1: Serial.setStopBits(QSerialPort::OneStop);break;
                case 2: Serial.setStopBits(QSerialPort::TwoStop);break;
                default:break;
            }
            //设置校验方式
            switch (ui->checkoutBox->currentIndex())
            {
                case 0: Serial.setParity(QSerialPort::NoParity);break;
                default:break;
            }
            //设置流控制模式
            Serial.setFlowControl(QSerialPort::NoFlowControl);
            //打开串口
            if(Serial.open(QIODevice::ReadWrite)==false)
            {
                QMessageBox::warning(NULL , "提示", "串口打开失败!");
                return;
            }
            // 失能串口设置控件
            ui->comBox->setEnabled(false);
            ui->checkoutBox->setEnabled(false);
            ui->bandRateBox->setEnabled(false);
            ui->dataBitBox->setEnabled(false);
            ui->stopBitBox->setEnabled(false);
            ui->search_Button->setEnabled(false);
            //调整串口控制按钮的文字提示
            ui->open_Button->setText(QString("关闭串口"));
        }
        else       //串口已经打开
        {
            Serial.close();
            // 使能串口设置控件
            ui->comBox->setEnabled(true);
            ui->checkoutBox->setEnabled(true);
            ui->bandRateBox->setEnabled(true);
            ui->dataBitBox->setEnabled(true);
            ui->stopBitBox->setEnabled(true);
            ui->search_Button->setEnabled(true);
            //调整串口控制按钮的文字提示
            ui->open_Button->setText(QString("打开串口"));
        }
}

void MainWindow::on_search_Button_clicked()
{
    // 清除当前显示的端口号
       ui->comBox->clear();
       //检索端口号
       foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
       {
           ui->comBox->addItem(info.portName());
       }

}

void MainWindow::on_clear_r_Button_clicked()
{
     ui->receiveEdit->clear();
}

void MainWindow::on_send_Button_clicked()
{
    if(Serial.isOpen()==false)  //判断串口是否正常打开
        {
            QMessageBox::warning(NULL , "提示", "请打开串口!");
            return;
        }
        //toPlainText() 转换为纯文本格式
        //toUtf8() 转换为UTF-8 编码
        QByteArray senddata = ui->SendEdit->toPlainText().toUtf8();

        //判断是否有非16进制字符
        if(ui->send16Box->isChecked()==true) //勾选了16进制发送
         {

            int cnt = senddata.size();          //要发送数据的长度

            char *data = senddata.data();
            for(int i=0;i<cnt;i++)//判断是否有非16进制字符
            {
                if(data[i]>='0' && (data[i]<='9'))
                    continue;
                else if(data[i]>='a' && (data[i]<='f'))
                    continue;
                else if(data[i]>='A' && (data[i]<='F'))
                    continue;
                else if(data[i] == ' ')     //输入为空格
                    continue;
                else
                {
                    QMessageBox::warning(NULL , "提示", "输入非16进制字符!");
                    return;
                }
            }

            //字符串转化为16进制数   "1234" --> 0X1234
            //转换时会自动除去非16进制字符
            senddata = senddata.fromHex(senddata);
        }
        //勾选了发送新行
        if(ui->newlineBox->isChecked()==true)
        {
            int cnt = senddata.size();
            senddata = senddata.insert(cnt,"\r\n"); //插入回车换行符
        }

        //设置时间

        QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间

        QString str = time.toString("yyyy-MM-dd hh:mm:ss ddd"); //设置显示格式

        ui->receiveEdit->setText( ui->receiveEdit->toPlainText() +"\n"+ str +":\n"  + ui->SendEdit->toPlainText() );

        Serial.write(senddata); //通过串口发送数据
       // ui->receiveEdit->setText( ui->SendEdit-> );


    }

void MainWindow::on_up_Button_clicked()
{
    quint16  index  = ui->tableWidget->currentRow();
    quint16 count = ui->tableWidget->columnCount();
    for (int i=1;i<count;i++)
    {
        quint16 abc = ui->tableWidget->item(index,i)->text().toInt();
        unsigned char ab[8];
        unsigned int CrcTemp;
        ab[0]= 0x01;//从机地址
        ab[1]= 0x06;
        ab[2]= 0x90;
        ab[3]=i-1;    //指令地址:单元格从0-6,地址分别为0-6
        ab[4]= abc >> 8;//单元格的数据
        ab[5]=abc;  //发送

        McMBCRC16(ab,6,&CrcTemp);
            ab[6]=CrcTemp&0xFF;
            ab[7]=CrcTemp>>8;

        Serial.write((const char*)ab,8);


        QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间

        QString str = time.toString("yyyy-MM-dd hh:mm:ss ddd"); //设置显示格式

        QString receive;
        for ( int i= 0; i< 8; i++)
        {
            receive += QString(" %1").arg( (quint8)ab[i], 2, 16, QLatin1Char( '0' ) );
        }

        ui->receiveEdit->setText( ui->receiveEdit->toPlainText() +"\n"+ str +":\n" +receive );


        sleep(1000);
    }
}

void MainWindow::on_receiveEdit_textChanged()
{
    ui->receiveEdit->moveCursor(QTextCursor::End);
}

void MainWindow::McMBCRC16(unsigned char *pDataIn, int iLenIn, unsigned int *pCRCOut){
    UCHAR ucCRCHi = 0xFF;
    UCHAR ucCRCLo = 0xFF;
    int iIndex;
    while(iLenIn-- )
    {
        iIndex = ucCRCLo ^ *( pDataIn++ );
        ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
        ucCRCHi = aucCRCLo[iIndex];
    }
    *pCRCOut = ( ucCRCHi << 8 | ucCRCLo );
}

//延时
void MainWindow::sleep(unsigned int msec)
{
    //currentTime返回当前时间,用当前时间加上我们要延时的时间msec得到一个新时刻
    QTime reachTime = QTime::currentTime().addMSecs(msec);
    while (QTime::currentTime()<reachTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
}

功能展示

与下位机连接后的功能展示:
Qt5下通信串口(SerialPort )单发及导入表格连续下发(Modbus)_第3张图片
如果此文章对你有帮助请点个关注点个赞,这就是我最大的鼓励 谢谢。
让我们一起成长,大家可以把自己的见解在下方留言评论哦!

你可能感兴趣的:(Qt项目)