欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt上位机:与STM32串口通信,数据收发,按钮控制LED

程序员文章站 2024-02-22 10:22:34
...

Qt学习了几周,做一个串口助手巩固一下最近学习的内容。

遇到的问题1: write函数只能发送一次数据,想要继续发送必须重新关闭打开串口,每次只能发送一次数据
解决办法:在网上找不到类似的问题,机缘巧合下发现别人Qt工程封装好的.exe文件可以正常多条发送,在自己电脑的Qt环境下编译就只能发送一条数据,怀疑是环境的问题,卸载后下载最新版本Qt,解决了该问题。

遇到的问题2:STM32只能发送数据给上位机,接收不到Qt上位机的数据
解决办法:原因是Qt发送的是字符串,不是16进制数据,而且单片机串口中断服务函数的机制是每条数据的帧尾必须是0x0d 0x0a,这条数据才为有效数据,才能够被STM32单片机接收。因此发送的每条数据除了需要把字符串转换为16进制以外,还需要在数据增加单片机标志帧尾。
需要注意的是不同的单片机串口协议可能是不同的,我使用的是正点原子STM32F1单片机。可以通过打开两个串口助手,向设置好的虚拟串口发送数据,点选hex接收,查看该单片机串口通讯协议的校验帧。

上位机图片:
Qt上位机:与STM32串口通信,数据收发,按钮控制LED

下面放上Qt的源代码:

头文件:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QSerialPort>

QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

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

public:
    bool getSerialPortConfig(void);

private slots:  //槽函数,遇到相应信号就触发
    void on_btn_open_clicked();
    void on_btn_send_clicked();
    void on_SerialPort_readyRead();

    void StringToHex(QString str, QByteArray &senddata);
    char ConvertHexChar(char ch);
private:
    Ui::Dialog *ui;
    bool mIsOpen;  //串口按钮是否打开
     //串口对象指针及配置参数
    QSerialPort *mSerialPort;
    QString mPortName;
    QString mBaudRate;
    QString mParity;
    QString mDataBits;
    QString mStopBits;
};
#endif // DIALOG_H

CPP文件:

#include "dialog.h"
#include "ui_dialog.h"
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QList>
#include <QDebug>
#include <QTextEdit>

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

    mSerialPort = new QSerialPort; //创建一个串口对象

    mIsOpen = false; //初始化按钮状态标志位
    ui->btn_send->setEnabled(mIsOpen);

    //识别系统的所有可用串口号,并添加到下拉列表中
    QList<QSerialPortInfo> serialPortInfo = QSerialPortInfo::availablePorts();
    int count = serialPortInfo.count();
    for(int i = 0;i < count;i++)
    {
        ui->Cboxport->addItem(serialPortInfo.at(i).portName());
    }

    //等待一个触发信号,接收串口数据
    connect(mSerialPort, SIGNAL(readyRead()), this, SLOT(on_SerialPort_readyRead()));
}

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

bool Dialog::getSerialPortConfig()  //配置串口
{
    //获取串口配置
    mPortName = ui->Cboxport->currentText();
    mBaudRate = ui->Cboxboudrate->currentText();
    mParity = ui->Cboxparity->currentText();
    mDataBits = ui->Cboxdatabits->currentText();
    mStopBits = ui->Cboxstopbits->currentText();

    //设置串口
    //串口号
    mSerialPort->setPortName(mPortName);
    //波特率
    if("115200" == mBaudRate)
    {
        mSerialPort->setBaudRate(QSerialPort::Baud115200);
    }
    else
    {
        mSerialPort->setBaudRate(QSerialPort::Baud9600);
    }
    //校验位
    if("EVEN" == mParity)
    {
        mSerialPort->setParity(QSerialPort::EvenParity);
    }
    else if("ODD" == mParity)
    {
        mSerialPort->setParity(QSerialPort::OddParity);
    }
    else
    {
        mSerialPort->setParity(QSerialPort::NoParity);
    }
    //数据位
    if("5" == mDataBits)
    {
        mSerialPort->setDataBits(QSerialPort::Data5);
    }
    else if("6" == mDataBits)
    {
        mSerialPort->setDataBits(QSerialPort::Data6);
    }
    else if("7" == mDataBits)
    {
        mSerialPort->setDataBits(QSerialPort::Data7);
    }
    else
    {
        mSerialPort->setDataBits(QSerialPort::Data8);
    }
    //停止位
    if("1.5" == mStopBits)
    {
        mSerialPort->setStopBits(QSerialPort::OneAndHalfStop);
    }
    if("2" == mStopBits)
    {
        mSerialPort->setStopBits(QSerialPort::TwoStop);
    }
    else
    {
        mSerialPort->setStopBits(QSerialPort::OneStop);
    }
    qDebug() << "配置";
    return mSerialPort->open(QSerialPort::ReadWrite);
}
void Dialog::on_btn_open_clicked()  //打开关闭按钮状态
{
    if(true == mIsOpen)
    {
        //当前已经打开了串口,点击后将按钮更新为关闭状态
        mSerialPort->close();
        ui->btn_open->setText("打开");
        mIsOpen = false;
        //此时可以配置串口
        ui->Cboxport->setEnabled(true);
        ui->Cboxboudrate->setEnabled(true);
        ui->Cboxparity->setEnabled(true);
        ui->Cboxdatabits->setEnabled(true);
        ui->Cboxstopbits->setEnabled(true);
        ui->btn_send->setEnabled(mIsOpen);
        qDebug() << "关闭";
    }
    else
    {
        //当前处于关闭串口状态,打开前需要配置串口
        //getSerialPortConfig();
        if(true == getSerialPortConfig())
        {
            mIsOpen = true;
            ui->btn_open->setText("关闭");
            qDebug() << "成功打开串口" << mPortName;
            ui->Cboxport->setEnabled(false);
            ui->Cboxboudrate->setEnabled(false);
            ui->Cboxparity->setEnabled(false);
            ui->Cboxdatabits->setEnabled(false);
            ui->Cboxstopbits->setEnabled(false);
            ui->btn_send->setEnabled(mIsOpen);
        }
//        else
//        {
//            mIsOpen = false;
//        }
    }
}

void Dialog::on_btn_send_clicked() //发送按钮
{
    if(true == mIsOpen)
    {
        //mSerialPort->write(ui->textEdit_send->toPlainText().toLatin1());// toPlainText(将文本编辑的文本转换为纯文本)
        //mSerialPort->write(ui->textEdit_send->toPlainText().toStdString().c_str());
        //注意:write函数的传递参数是QString,先转换为C++标准的string,再转为char型
        QString str = ui->textEdit_send->toPlainText();
        int len = str.length();
        if(len%2 == 1)
        {
            str = str.insert(len - 1, '0');
        }
        QByteArray senddata;  //写入编辑框的数据
        StringToHex(str,senddata);

        int length = senddata.length();  //在帧尾追加STM32的关键帧
        senddata[length + 1] = 0x0d;
        senddata[length + 2] = 0x0a;
        mSerialPort->write(senddata);
    }
}

void Dialog::on_SerialPort_readyRead()  //读取串口数据
{
    if(true == mIsOpen)
    {
        QByteArray recvData = mSerialPort->readAll();
        //ui->textEdit_Recv->setPlainText(QString(recvData)); //显示内容每次会被覆盖
        ui->textEdit_Recv->append(QString(recvData));
        qDebug() << "正在接收数据";
    }
}

void Dialog::StringToHex(QString str, QByteArray &senddata) //字符串转换为十六进制数据0-F
{
    int hexdata,lowhexdata;
    int hexdatalen = 0;
    int len = str.length();
    senddata.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 = ConvertHexChar(hstr);
        lowhexdata = ConvertHexChar(lstr);
        if((hexdata == 16) || (lowhexdata == 16))
            break;
        else
            hexdata = hexdata*16+lowhexdata;
        i++;
        senddata[hexdatalen] = (char)hexdata;
        hexdatalen++;
    }
    senddata.resize(hexdatalen);
}


char Dialog::ConvertHexChar(char ch)
{
    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 ch-ch;//不在0-f范围内的会发送成0
}
相关标签: Qt上位机