QT子线程读取串口数据并传到主线程

《转载》

读取串口部分借鉴于Quartz010的文章《如何在QT中读取串口数据》

http://blog.csdn.net/zz709196484/article/details/66474917  这是博客网址

 

大致思路就是子线程去读取串口数据并传送到主线程,主线程在用widget对象画图实时显示波形图

 

一、在main.cpp定义一个自己封装的类myapp的对象w,在myapp界面中new出两个button按钮用于开关控制和

QComboBox复选框选择串口端口号,并定义出自己封装好的画图的类的对象,并设置布局。如下图:

QT子线程读取串口数据并传到主线程_第1张图片

二、直接贴上代码

myapp.h

 

#ifndef MYAPP_H

#define MYAPP_H

#include 
#include "widget.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "mythread.h"

class myapp : public QWidget

{
    Q_OBJECT

public:

    explicit myapp(QWidget *parent = 0);

signals:
    void close_serial(char*);//向子线程传递信号关闭串口

public slots:
      void setplay(float data1);//传数据

      void on_btn_clicked();//打开串口按钮槽函数

      void closeit();//关闭按钮槽函数

    void get_value2()
    {
        w2->setvote(data, setval,statu);//设置画图状态及数据
    }


private:

    int  setval;

    float data;

    Widget *w2;

    QPushButton *btn,*closebtn;

    QComboBox *box;

    //QTextEdit *TB;

    QString port1;//串口端口号

    int statu,j;

    MyThread *mthread;//开辟子线程,以第三方库封装的模式
};


#endif // MYAPP_H

 

 
myapp.cpp
#include "myapp.h"

#include 

#include 

#include "widget.h"

myapp::myapp(QWidget *parent) : QWidget(parent)

{
    setWindowTitle("心电图");

    //setMinimumSize(800,600);

    setFixedSize(1200,800);

    data = 0;

    setval = 1;

    //w1 = new Widget;

    w2 = new Widget;

    //w3 = new Widget;

    QPalette palette;

    palette.setBrush(QPalette::Background,QBrush(QPixmap("./Tim").scaled(this->size())));

    setPalette(palette);

    btn = new QPushButton("显示心电图");

    btn->setFixedSize(100,30);

    closebtn = new QPushButton("关闭");

    closebtn->setFixedSize(100,30);

    //TB= new QTextEdit();

    box = new QComboBox();

    box->setFixedSize(100,30);

    box->addItem("COM1");

    box->addItem("COM2");

    box->addItem("COM3");

    box->addItem("COM4");

    box->addItem("COM5");

    box->addItem("COM6");

    box->addItem("COM7");

    box->addItem("COM8");

    box->addItem("COM9");

    box->addItem("COM10");

    box->addItem("COM11");

    box->addItem("COM12");

    box->addItem("COM13");

    box->addItem("COM14");

    QHBoxLayout *hbox1 = new QHBoxLayout;

    hbox1->addWidget(btn);

    hbox1->addWidget(closebtn);

    hbox1->addWidget(box);

    QVBoxLayout *vbox1 = new QVBoxLayout;

    vbox1->addLayout(hbox1);

    //vbox1->addWidget(w1);

    vbox1->addWidget(w2);

    //vbox1->addWidget(TB);

    setLayout(vbox1);

    closebtn->setEnabled(false);

    connect(btn, SIGNAL(clicked()), this, SLOT(on_btn_clicked()));

    connect(closebtn,SIGNAL(clicked()),this,SLOT(closeit()));//监听两个按钮信号

}

void myapp::setplay(float data1)

{

    data = data1;

    setval = 10;

    get_value2();//调画图函数

}

void myapp::on_btn_clicked()

{

        statu = 1;

        btn->setEnabled(false);//设置按钮使能

        closebtn->setEnabled(true);

        qDebug()<<"open ok"<< endl;

        port1 = box->currentText();//获取端口号

        qDebug()<start();//开启线程

}

void myapp::closeit()

{

    statu = 0; 

    closebtn->setEnabled(false);

    btn->setEnabled(true);

  connect(this,SIGNAL(close_serial(char*)),mthread,SLOT(close_mthread_serial(char*)));

    char *a="2";

    emit this->close_serial(a);//发送关闭的信号

    delete mthread;//销毁子线程

}
 

mythread.h

#ifndef MYTHREAD_H

#define MYTHREAD_H

#include 

#include 

#include 

#include "qextserialbase.h"

#include "win_qextserialport.h"

#include 

class MyThread : public QThread

{

        Q_OBJECT

public:

    MyThread(QString port1);

    void run();

signals:

    void setsenddata(float data);//向主线程发送接收到的串口数据

public slots:

    void read_serial_data();//读取串口数据

    void close_mthread_serial(char *st);//关闭

private:

    Win_QextSerialPort *mycom;

    QString port;

    float data;

};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"


MyThread::MyThread(QString port1)

{

    port = port1;

}

void MyThread::run()

{

    //重写run()函数初始化串口

    mycom = new Win_QextSerialPort(port,QextSerialBase::EventDriven);//读取串口采用事件驱动模式

    mycom->open(QIODevice::ReadWrite);//读写方式打开

    mycom->setBaudRate(BAUD115200);//波特率

    mycom->setDataBits(DATA_8);//数据位

    mycom->setParity(PAR_NONE);//奇偶校验

    mycom->setStopBits(STOP_1);//停止位

    mycom->setFlowControl(FLOW_OFF);//控制位

    mycom->write("1");//向下位机发送1告诉它开始发送数据

    connect(mycom,SIGNAL(readyRead()),this,SLOT(read_serial_data()));//有数据就读

}

void MyThread::read_serial_data()

{

    if(mycom->bytesAvailable()>= 9)

    {

        qDebug()<bytesAvailable() << endl;

        QByteArray temp;

        temp = mycom->read(9);//每串数据为9个字节

          union dat{

            char a[4];

            int x;

        };

        dat data_serial;

        data_serial.a[0] = 0;

        data_serial.a[1] = temp[8];

        data_serial.a[2] = temp[7];

        data_serial.a[3] = temp[6];

        data = data_serial.x*2.4/256/8288607*10000;//提取有效数据位,根据需要的数据设计的算法

        emit setsenddata(data);//发送数据给主线程

        qDebug() <insertPlainText(temp.toHex()+"  ");

      }

}

void MyThread::close_mthread_serial(char *st)

{

    mycom->write(st);//告知下位机读端已关闭

    qDebug() <<"close ok"<close();//关闭子线程

}

 

widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include 
#include 
#include 
#include 

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0,float pwidth = 0.5);

    ~Widget();

    void paintEvent(QPaintEvent *event)
    {
        QPainter p(this);
        QPen pen;

        pen.setColor(QColor("green"));笔的颜色
        pen.setWidth(3);//笔的粗细
        p.setPen(pen);


        QFont font;//画text的大小
        font.setPixelSize(30);//请画家并给画家一支调好的笔
        p.drawLine(0, height()/2, width(), height()/2);//X轴
        p.drawLine(0, height()-5, 0, 5);//Y轴
        pen.setColor(QColor("red"));
        p.setPen(pen);
        p.setFont(font);
        p.drawText(QPoint(width()-15, height()/2-5), "S");//横坐标
        p.drawText(QPoint(10, 15), "mv");//纵坐标

#if 1
        pen.setColor(QColor("gray"));//网格
        pen.setWidth(1);
        p.setPen(pen);

        for(int i=10; i width())//画满
            fresh+=penwidth;

//        set_path.lineTo(QPoint(set_x+=set_penwidth, height()-vote-10));
//        if(set_x > width())//画满
//            set_fresh+=set_penwidth;

            update();自动刷新

        }
    }

    void setvote(float value, int set,int status)//最关键的一个方法!!!要向显示电压信号直接调这个方法就可以了
    {
        vote = value;//传入的数据值
        setval = set;
        statu = status;
        draw();
    }


private:

    QPainterPath path, set_path;
    float fresh, set_fresh;//滚屏
    float penwidth, set_penwidth;//滚屏速度

    float x, set_x;
    int  setval,statu;
    float vote;
};

#endif // WIDGET_H
widget.cpp
#include "widget.h"

#include 

Widget::Widget(QWidget *parent, float pwidth)

    : QWidget(parent),penwidth(pwidth)
{
    QPalette pal(palette());
    pal.setColor(QPalette::Background, Qt::black);
    setAutoFillBackground(true);
    setPalette(pal);
    path.moveTo(QPoint(10, height()-5));
    set_path.moveTo(QPoint(10, height()-5));
    vote = 0;
    setval = height()-10;

    x = 0;
    set_x = 10;
    fresh = 0;
    set_fresh = 0;
    setFixedHeight(300);
}

Widget::~Widget()
{

}
 

三、串口代码就省略了,大家有需要看的可以去看我前面借鉴的大佬的博客

 

四、总结
    之所以用线程读取数据,是因为一开始主线程读取数据的时候因为程序执行,也或许是画图影响反应事件
驱动信号的原因,导致接收数据与下位机发送数据不匹配,会丢失一部分数据,也做过算法改进,仍然不行,
后面采取开辟子线程读取串口,主线程显示,就没有这个问题了。总之在绘图上需要计算频率以及幅值,使图
形清楚明了。

你可能感兴趣的:(QT程序开发)