qt串口通信上位机遇到的问题

自己尝试用qt写了一个串口,可以接受数据 但是发送数据的时候遇到了一点问题,发送时数据不能到单片机,但是在用xcom试的时候,之前在自己写的串口上位机中发送的数据也会在xcom中显示出来,大家知道原因吗?

img

img

img

你试试设置串口的工作模式,强制关闭流控功能
你自己的程序只是把数据写到了串口的发送缓冲区,并没有发送出去。

回答引用ChatGPT:
从你提供的代码中,有几个潜在的问题需要注意。

首先,你在发送数据之前使用了 remove 函数来移除 tx_buf 中的空格字符,但是在移除之后没有对 tx_buf 进行检查,确保其长度不为零。如果 tx_buf 的长度为零,那么 serial->write(tx_buf_tmp) 将不会发送任何数据。

其次,在发送十六进制数据时,你使用了 toUInt 函数将字符串转换为整数。需要注意的是,toUInt 函数将会返回一个无符号整数,但是你将其强制转换为了一个有符号字符,这可能会导致数据溢出和意料之外的结果。

最后,在发送数据时,你使用了 send enter 复选框来确定是否在数据末尾添加回车符。需要注意的是,有些串口设备可能要求在数据末尾添加换行符(\n),而不是回车符(\r)。因此,你需要确认单片机或其他接收设备需要哪种换行符,并相应地在代码中进行设置。

综上所述,你需要检查 tx_buf 是否为空,使用正确的方式将字符串转换为整数,并确定正确的换行符。此外,你可能还需要添加错误日志或调试信息,以便更好地跟踪和解决问题。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
从描述中可以看出,问题比较复杂,需要对代码进行调试和分析。以下是一些可能导致该问题的原因:

  1. 串口设置不正确,导致发送的数据无法到达单片机。

  2. 数据格式问题,发送的数据格式不正确,单片机无法解析。

  3. 程序逻辑问题,程序中存在逻辑错误或者漏洞。

针对这些问题,请确认以下几个方面的内容:

  1. 串口设置是否正确:包括波特率、数据位、校验位、停止位等。

  2. 数据格式是否正确:发送的数据格式是否与单片机接收的格式一致。

  3. 程序逻辑是否正确:针对程序整体进行调试和分析,确认程序逻辑是否有错误。

同时,以下是一个简单的Qt串口通信上位机示例代码,需要根据自己实际情况进行修改和调试。

//包含头文件   
#include <QtSerialPort/QSerialPort>   
#include <QtSerialPort/QSerialPortInfo>   
#include <QDebug>   
#include <QThread>   
#include <QMessageBox>   
  
//用于存储串口数据的缓冲区数组   
QByteArray buffer;   
  
//构造函数   
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)   
{   
    ui->setupUi(this);   
  
    QStringList list;   
  
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())    
    {    
        list.append(info.portName());    
    }    
   
    ui->portBox->addItems(list); //将可用串口添加到comboBox中以供选择   
  
    ui->baudRateBox->setCurrentIndex(3); //设置波特率下拉菜单默认显示第4项   
  
    ui->sendBtn->setEnabled(false);//开始时“发送”按钮不可用   
    ui->openBtn->setText(tr("打开串口"));   
  
    //连接信号槽   
    connect(ui->openBtn,SIGNAL(clicked()),this,SLOT(openSerialPort()));   
    connect(ui->sendBtn,SIGNAL(clicked(bool)),this,SLOT(send()));   
    connect(ui->portBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(on_portBox_currentIndexChanged(QString)));   
    connect(ui->baudRateBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(on_baudRateBox_currentIndexChanged(QString)));   
    connect(ui->quitBtn,SIGNAL(clicked(bool)),this,SLOT(close()));   
    connect(&serialPort,SIGNAL(readyRead()),this,SLOT(readData()));   
}   
  
//析构函数   
MainWindow::~MainWindow()   
{   
    delete ui;   
}   
  
//函数:检查串口是否打开   
bool MainWindow::isSerialPortOpen()   
{   
    if(serialPort.isOpen())   
        return true;   
    else   
        return false;   
}   
  
//函数:打开串口   
void MainWindow::openSerialPort()   
{   
    if(ui->openBtn->text()==tr("打开串口"))    
    {    
        //设置串口名    
        serialPort.setPortName(ui->portBox->currentText());    
        
        //设置波特率    
        serialPort.setBaudRate(QSerialPort::Baud9600,QSerialPort::AllDirections);    
        
        //设置数据位数    
        switch(ui->dataBitsBox->currentIndex())    
        {    
        case 8:serialPort.setDataBits(QSerialPort::Data8);break;    
        default:break;    
        }    
        
        //设置奇偶校验    
        switch(ui->parityBox->currentIndex())    
        {    
        case 0:serialPort.setParity(QSerialPort::NoParity);break;    
        default:break;    
        }    
          
        //设置停止位    
        switch(ui->stopBitsBox->currentIndex())    
        {    
        case 1:serialPort.setStopBits(QSerialPort::OneStop);break;    
        case 2:serialPort.setStopBits(QSerialPort::TwoStop);break;    
        default:break;    
        }    
          
        //设置流控制      
        serialPort.setFlowControl(QSerialPort::NoFlowControl);    
          
        //打开串口    
        if(!serialPort.open(QIODevice::ReadWrite))    
        {    
            QMessageBox::warning(this,tr("警告"),tr("串口打开失败!"),QMessageBox::Ok);    
            return;    
        }    
          
        //初始化状态栏    
        ui->statusBar->showMessage(tr("串口打开成功!"));    
        ui->openBtn->setText(tr("关闭串口"));    
  
        //“发送”按钮可用    
        ui->sendBtn->setEnabled(true);    
            
    }   
    else    
    {    
        //关闭串口    
        serialPort.close();    
        ui->statusBar->showMessage(tr("串口已关闭!"));    
        ui->openBtn->setText(tr("打开串口"));    
                 
        //“发送”按键不可用    
        ui->sendBtn->setEnabled(false);    
    }    
}   
  
//函数:发送数据   
void MainWindow::send()   
{   
    //以ASCII码形式发送数据,以“\n”作为结束符    
    if(!isSerialPortOpen()) //检查串口是否打开    
    {   
        QMessageBox::warning(this,tr("警告"),tr("请先打开串口!"),QMessageBox::Ok);    
        return;   
    }   
  
    QString str = ui->sendTextEdit->toPlainText();   
    QByteArray data;   
    data = str.toLatin1();   
    data += '\n';   
  
    serialPort.write(data,QByteArray(data).length()); //发送串口数据   
}   
  
//函数:读取数据   
void MainWindow::readData()   
{   
    QByteArray data;   

    data = serialPort.readAll(); //读取串口数据   
    
    buffer += data;   
  
    //刷新界面   
    QString str = QString(buffer);   
    ui->receiveTextEdit->setText(str);   
}   
  
//函数:连接的串口改变   
void MainWindow::on_portBox_currentIndexChanged(QString portName)   
{   
    if(isSerialPortOpen())   
    {   
        serialPort.close();   
        serialPort.setPortName(portName);   
        serialPort.open(QIODevice::ReadWrite);   
    }   
}   
  
//函数:波特率改变   
void MainWindow::on_baudRateBox_currentIndexChanged(QString baudRate)   
{   
    if(isSerialPortOpen())   
    {   
        if(ui->baudRateBox->currentIndex() == 3)   
            serialPort.setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);   
        else   
            serialPort.setBaudRate(baudRate.toInt(),QSerialPort::AllDirections);   
    }   
}   

如果我的回答解决了您的问题,请采纳!

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/193916
  • 这篇博客你也可以参考下:QT通讯过程中多个窗口只需要一个套接字的解决方法,简单实用好理解(后面有最终版,完全实用于一个套接字)
  • 除此之外, 这篇博客: Qt 开发经验总结中的 很多初学者甚至几年工作经验的人,对多线程有很深的误解和滥用,尤其是在串口和网络通信这块,什么都往多线程里面丢,一旦遇到界面卡,就把数据收发啥的都搞到多线程里面去,殊不知绝大部分时候那根本没啥用,因为没找到出问题的根源。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:
    1. 如果你没有使用wait***函数的话,大部分的界面卡都出在数据处理和展示中,比如传过来的是一张图片的数据,你需要将这些数据转成图片,这个肯定是耗时的;
    2. 还有就是就收到的数据曲线绘制出来,如果过于频繁或者间隔过短,肯定会给UI造成很大的压力的,最好的办法是解决如何不要频繁绘制UI比如合并数据一起绘制等;
    3. 如果是因为绘制UI造成的卡,那多线程也是没啥用的,因为UI只能在主线程;
    4. 串口和网络的数据收发默认都是异步的,由操作系统调度的,如果数据处理复杂而且数据量大,你要做的是将数据处理放到多线程中;
    5. 如果没有严格的数据同步需求,根本不需要调用wait***之类的函数来立即发送和接收数据,实际需求中大部分的应用场景其实异步收发数据就足够了;
    6. 有严格数据同步需求的场景还是放到多线程会好一些,不然你wait***就卡在那边了;
    7. 多线程是需要占用系统资源的,理论上来说,如果线程数量超过了CPU的核心数量,其实多线程调度可能花费的时间更多,各位在使用过程中要权衡利弊;

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^该回答引用ChatGPT
根据问题描述和截图,可以看出该问题出现在qt串口通信上位机的发送数据过程中。

首先,我们需要确认单片机和上位机之间的串口通信参数是否一致。具体来说,波特率、数据位、停止位、校验位等参数需要保持一致。

其次,我们需要检查qt程序中的发送数据是否正确。可以尝试使用xcom等工具发送同样的数据,确保发送的数据本身没有问题。在qt程序中,可以使用串口通信库提供的write函数向串口发送数据,示例代码如下:


QByteArray data = "hello world"; //要发送的数据
if(m_serialport->isOpen()){ //判断串口是否打开
m_serialport->write(data); //向串口发送数据
}


需要注意的是,write函数并不保证数据一定即刻发送成功,需要使用waitForBytesWritten函数等待数据写入操作完成。

如果以上两点均无问题,还需要检查qt程序中串口接收数据的代码是否干扰了串口的发送操作。具体来说,需要确认是否在接收数据的函数中使用了while等循环阻塞了线程,或使用了信号槽机制导致线程阻塞。示例代码如下:


void MainWindow::readSerialData()
{
QByteArray data = m_serialport->readAll(); //读取串口的数据
ui->textEdit->append(data); //将数据显示在界面上

//可能阻塞串口发送的代码
while(m_serialport->bytesAvailable()){ //阻塞等待串口有数据可读
QByteArray temp = m_serialport->readAll(); //读取串口数据
data += temp;
}
}


针对以上问题,我们可以通过在串口读取数据前加上m_serialport->waitForReadyRead(100)等待一段时间来避免循环阻塞。同时,也可以使用单独的线程来处理串口数据读取和发送操作,避免信号槽机制导致的线程阻塞。具体代码如下:


void MainWindow::sendSerialData()
{
QByteArray data = "hello world"; //要发送的数据
if(m_serialport->isOpen()){ //判断串口是否打开
m_serialport->write(data); //向串口发送数据
m_serialport->waitForBytesWritten(100); //等待数据写入完成
}
}

void SerialThread::run()
{
while(!isStopped){
if(m_serialport->bytesAvailable()){ //判断串口是否有数据可读
QByteArray data = m_serialport->readAll(); //读取串口数据
emit receivedData(data); //发送数据到主线程
}
msleep(50); //线程休眠,避免过多占用CPU资源
}
}

void MainWindow::onReceivedData(QByteArray data)
{
ui->textEdit->append(data); //将数据显示在界面上
}

void MainWindow::startSerialThread()
{
serialThread = new SerialThread(this);
connect(serialThread, &SerialThread::receivedData, this, &MainWindow::onReceivedData);
serialThread->start();
}


通过以上方法可以避免qt串口通信上位机发送数据的问题,提高数据传输的可靠性和稳定性。