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

《转载》

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

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

 

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

 

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

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

二、直接贴上代码

myapp.h

 

#ifndef MYAPP_H

#define MYAPP_H

#include <QWidget>
#include "widget.h"
#include <QTimer>
#include <QComboBox>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QDebug>
#include <QPalette>
#include <QTextEdit>
#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 <QVBoxLayout>

#include <QHBoxLayout>

#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()<<port1<< endl;

        mthread =new MyThread(port1);

        connect(mthread,SIGNAL(setsenddata(float)),this,SLOT(setplay(float)),Qt::QueuedConnection);

	//接收子线程传输数据的信号

        mthread->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 <QObject>

#include <QDebug>

#include <QThread>

#include "qextserialbase.h"

#include "win_qextserialport.h"

#include <QPushButton>

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()<<mycom->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() <<data ;

    //TB->insertPlainText(temp.toHex()+"  ");

      }

}

void MyThread::close_mthread_serial(char *st)

{

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

    qDebug() <<"close ok"<<st<<endl;

    mycom->close();//关闭子线程

}

 

widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPainter>
#include <QPen>
#include <QDebug>

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(); i+=10)
            p.drawLine(i, 0, i, height()-5);

        for(int j=10;j<height(); j+=10)
           p.drawLine(0, j, width(), j);

        pen.setColor(QColor("red"));
        pen.setWidth(10);

        p.setPen(pen);
        font.setPixelSize(16);
        p.setFont(font);
        p.drawText(QPoint(5, height()/2+15), "0");

        float a= 0.2;
        for(int k= 50;k<width();k+=50)
         {
            pen.setColor(QColor("white"));
            pen.setWidth(3);
            p.setPen(pen);
            p.drawLine(k, 0, k, height()-5);

            QString data = QString("%1").arg(a);
            pen.setColor(QColor("red"));
            pen.setWidth(10);
            p.setPen(pen);
            p.drawText(QPoint(k+5, height()/2+15), data);

            a=a+0.2;//横轴代表时间,每小格0.04s,每大格0.2s
        }

#endif
        p.translate(-fresh, 0);
        pen.setColor(QColor("red"));
        pen.setWidth(penwidth);

        p.setPen(pen);
        p.drawPath(path);//曲线图(波形)

        QPainter set_p(this);
        //QPen set_pen;

        set_p.translate(-set_fresh, 0);
//        set_pen.setColor(QColor("green"));
//        set_pen.setWidth(3);
//        set_p.setPen(set_pen);
//        set_p.drawPath(set_path);//参考线
//set_p.drawLine(QPoint(0, height()-setval), QPoint(width(), height()-setval));

    }

public slots:
    void draw()
    {
        if(statu == 1)
        {
           path.lineTo(QPoint(x+=penwidth, height()/2-vote));//每个数据的纵坐标路径

            if(x > 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 <QPalette>

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()
{

}
 

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值