非白不是黑 发表于 2018-11-18 22:27:18

尝试用多线程处理数据时,串口数据传输出现问题

之前在主界面处理串口传输的数据发生界面卡死状态,经过大神指点,可以使用多线程解决问题,最近两天学习了多线程,并尝试编写,但效果不佳。编译倒是没有问题,但运行时出现QIODevice::read (QSerialPort): device not open的情况,添加了OPEN也不行。程序太多,放在附件上了。希望大佬们不吝赐教QAQ


猿来在这 发表于 2018-11-19 11:09:49

既然开辟线程就想多次执行,有可能线程执行一次就退出了,可以添加QEventLoop loop; loop.exec(); 防止线程退出

非白不是黑 发表于 2018-11-19 16:11:41

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>

class MyThread : public QObject
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);
    void read(QByteArray temp);
signals:
    void update(QByteArray temp);
};


#endif // MYTHREAD_H

非白不是黑 发表于 2018-11-19 16:13:48

#include "mymainwindow.h"
#include "ui_mymainwindow.h"
MyMainWindow::MyMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MyMainWindow)
{
    ui->setupUi(this);
    //查找可用的串口
       foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
       {
         QSerialPort serial;
         serial.setPort(info);
         if(serial.open(QIODevice::ReadWrite))
         {
               ui->PortBox->addItem(serial.portName());
               serial.close();
         }
       }
       //设置波特率下拉菜单默认显示第0项
       ui->BaudBox->setCurrentIndex(0);
       //关闭发送按钮的使能
       ui->sendButton->setEnabled(false);
       qDebug() << tr("界面设定成功!");
       thread = new QThread(this);
       myThread = new MyThread;
       myThread->moveToThread(thread);
       thread->start();
       connect(ui->pushButton, &QPushButton::pressed, myThread, &MyThread::drawImage);
       connect(this, &MyMainWindow::update, thread, &MyThread::read);
       connect(this, &MyMainWindow::destroyed, this, &MyMainWindow::dealClose);
}
void MyMainWindow::Read_Data()
{
    QByteArray buf;
    buf = serial->readAll();
    QDataStream out(&buf,QIODevice::ReadWrite);    //将字节数组读入
   while(!out.atEnd())
    {
      qint8 outChar = 0;
      out>>outChar;   //每字节填充一次,直到结束
      QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0'));//十六进制的转换
      ui->textEdit->insertPlainText(str.toUpper());//大写
      ui->textEdit->insertPlainText(" ");//每发送两个字符后添加一个空格
      ui->textEdit->moveCursor(QTextCursor::End);
   }
   emit update(buf);
}
void MyMainWindow::on_openButton_clicked()
{
    if(ui->openButton->text()==tr("打开串口"))
    {
      serial = new QSerialPort;
      //设置串口名
      serial->setPortName(ui->PortBox->currentText());
      //打开串口
      serial->open(QIODevice::ReadWrite);
      //设置波特率
      serial->setBaudRate(ui->BaudBox->currentText().toInt());
      //设置数据位数
      switch(ui->BitNumBox->currentIndex())
      {
      case 8: serial->setDataBits(QSerialPort::Data8); break;
      default: break;
      }
      //设置奇偶校验
      switch(ui->ParityBox->currentIndex())
      {
      case 0: serial->setParity(QSerialPort::NoParity); break;
      default: break;
      }
      //设置停止位
      switch(ui->StopBox->currentIndex())
      {
      case 1: serial->setStopBits(QSerialPort::OneStop); break;
      case 2: serial->setStopBits(QSerialPort::TwoStop); break;
      default: break;
      }
      //设置流控制
      serial->setFlowControl(QSerialPort::NoFlowControl);
      //关闭设置菜单使能
      ui->PortBox->setEnabled(false);
      ui->BaudBox->setEnabled(false);
      ui->BitNumBox->setEnabled(false);
      ui->ParityBox->setEnabled(false);
      ui->StopBox->setEnabled(false);
      ui->openButton->setText(tr("关闭串口"));
      ui->sendButton->setEnabled(true);
      //连接信号槽
      QObject::connect(serial, &QSerialPort::readyRead, this, &MyMainWindow::Read_Data);
    }
    else
    {
      //关闭串口
      serial->clear();
      serial->close();
      serial->deleteLater();
      //恢复设置使能
      ui->PortBox->setEnabled(true);
      ui->BaudBox->setEnabled(true);
      ui->BitNumBox->setEnabled(true);
      ui->ParityBox->setEnabled(true);
      ui->StopBox->setEnabled(true);
      ui->openButton->setText(tr("打开串口"));
      ui->sendButton->setEnabled(false);
    }
}
void MyMainWindow::dealClose()
{
    //退出子线程
   thread->quit();
   //当子线程结束后,完成相关的资源回收工作
   thread->wait();

   //因为(作为子线程加载)的类没有指定父对象, 所以在这里手动回收
   delete myThread;
}

非白不是黑 发表于 2018-11-19 16:14:42

#include "mythread.h"
#include <QElapsedTimer>

MyThread::MyThread(QObject *parent) : QObject(parent)
{

}
void MyThread::read()
{
      QByteArray buf=temp;
      QByteArray kjs;
      QPalette pal(ui->widget_1->palette());
      QPalette pal2(ui->widget_2->palette());
      QPalette pal3(ui->widget_3->palette());
      QElapsedTimer t;
      int i=0;
            while(buf.contains("\001"))
            {
               for(i=0;i<buf.length()/4;i++)
                {
               //kjs = buf.left(buf.indexOf('#')-1);*/
               kjs = buf.left(4);
               if(kjs.at(0)==0)//0X00表示停机
               {
                  pal.setColor(QPalette::Background, Qt::yellow); //设置背景黄色
                  ui->widget_1->setAutoFillBackground(true);
                  ui->widget_1->setPalette(pal);
                  ui->widget_1->show();
                  t.start();
                  while(t.elapsed()<10000);//停机30秒
                  {
                        if(kjs.at(0)==0)
                        {
                            pal.setColor(QPalette::Background, Qt::red); //设置背景红色
                            ui->widget_1->setAutoFillBackground(true);
                            ui->widget_1->setPalette(pal);
                            ui->widget_1->show();
                        }
                  }
                }
                else if(kjs.at(0)==1)
                {

                  pal.setColor(QPalette::Background, Qt::green); //设置背景绿色
                  ui->widget_1->setAutoFillBackground(true);
                  ui->widget_1->setPalette(pal);
                  ui->widget_1->show();
                }
                else
                {

                  pal.setColor(QPalette::Background, Qt::gray); //设置背景灰色
                  ui->widget_1->setAutoFillBackground(true);
                  ui->widget_1->setPalette(pal);
                  ui->widget_1->show();
                }
               if(kjs.at(1)==0)//0X00表示停机
               {

                  pal2.setColor(QPalette::Background, Qt::yellow); //设置背景黄色
                  ui->widget_2->setAutoFillBackground(true);
                  ui->widget_2->setPalette(pal2);
                  ui->widget_2->show();
                  t.start();
                  while(t.elapsed()<10000);//停机30秒
                  {
                        if(kjs.at(1)==0)
                        {
                            pal2.setColor(QPalette::Background, Qt::red); //设置背景红色
                            ui->widget_2->setAutoFillBackground(true);
                            ui->widget_2->setPalette(pal2);
                            ui->widget_2->show();
                        }
                  }
                }
                else if(kjs.at(1)==1)
                {
                  pal2.setColor(QPalette::Background, Qt::green); //设置背景绿色
                  ui->widget_2->setAutoFillBackground(true);
                  ui->widget_2->setPalette(pal2);
                  ui->widget_2->show();
                }
                else
                {
                  pal2.setColor(QPalette::Background, Qt::gray); //设置背景灰色
                  ui->widget_2->setAutoFillBackground(true);
                  ui->widget_2->setPalette(pal2);
                  ui->widget_2->show();
                }
               if(kjs.at(2)==0)//0X00表示停机
               {
                  pal3.setColor(QPalette::Background, Qt::yellow); //设置背景黄色
                  ui->widget_3->setAutoFillBackground(true);
                  ui->widget_3->setPalette(pal3);
                  ui->widget_3->show();
                  t.start();
                  while(t.elapsed()<10000);//停机30秒
                  {
                        if(kjs.at(2)==0)
                        {
                            pal3.setColor(QPalette::Background, Qt::red); //设置背景红色
                            ui->widget_3->setAutoFillBackground(true);
                            ui->widget_3->setPalette(pal);
                            ui->widget_3->show();
                        }
                  }
                }
                else if(kjs.at(2)==1)
                {
                   qDebug() << tr("界面颜色设定成功!");
                  pal3.setColor(QPalette::Background, Qt::green); //设置背景绿色
                  ui->widget_3->setAutoFillBackground(true);
                  ui->widget_3->setPalette(pal3);
                  ui->widget_3->show();
                }
                else
                {
                  pal3.setColor(QPalette::Background, Qt::gray); //设置背景灰色
                  ui->widget_3->setAutoFillBackground(true);
                  ui->widget_3->setPalette(pal3);
                  ui->widget_3->show();
                }
               buf=buf.right(buf.size()-4*i);

               }

         }
       buf.clear();
}

非白不是黑 发表于 2018-11-19 16:15:26

#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <mythread.h>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
namespace Ui {
class MyMainWindow;
}

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MyMainWindow(QWidget *parent = 0);
    ~MyMainWindow();

private slots:
    void on_clearButton_clicked();
    void on_sendButton_clicked();
    void on_openButton_clicked();
    void Read_Data();
    void dealClose();
    void on_checkBox_toggled(bool checked);

private:
    Ui::MyMainWindow *ui;
    QSerialPort *serial;
    MyThread *myThread;
    QThread *thread;
    QByteArray temp;
};

#endif // MYMAINWINDOW_H

非白不是黑 发表于 2018-11-19 16:27:17

以上的程序是我的新改动,把图形界面刷新放在了次线程里,IO数据没出错,但是显示这个错误 error: 'class Ui::MyMainWindow' has no member named 'pushButton'
      connect(ui->pushButton, &QPushButton::pressed, myThread, &MyThread::drawImage);
                  ^

非白不是黑 发表于 2018-11-19 16:40:46

非白不是黑 发表于 2018-11-19 16:13
void MyMainWindow::Read_Data()
{
    QByteArray buf;


connect(ui->pushButton, &QPushButton::pressed, myThread, &MyThread::drawImage);这个是我复制错了没有这个~

非白不是黑 发表于 2018-11-19 17:05:45

思路有点乱,我再去学习一下线程,打扰各位了,不好意思QAQ

quserv 发表于 2018-11-21 01:47:19

QT是不能在子线程里面更新界面的,也就是子线程不可以操作UI界面,我记得是这样的

驲屋安阮 发表于 2019-1-12 09:00:37

楼主解决了吗?我这两天也在做这个,对线程有点懵:L

one-rabbit 发表于 2019-11-14 13:38:39

没有回答了吗,这个一收一发多线程了解一下

流落地球 发表于 2020-10-12 16:21:54

楼主解决了吗?我这两天也在做这个,对线程有点懵
页: [1]
查看完整版本: 尝试用多线程处理数据时,串口数据传输出现问题