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

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

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

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

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

下面放上Qt工程与单片机的源代码链接:
https://download.csdn.net/download/Uncle_Tan123/12238290

头文件:

#ifndef DIALOG_H
#define DIALOG_H

#include 
#include 

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 
#include 
#include 
#include 
#include 

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上位机)