http://blog.csdn.net/zz709196484/article/details/66474917 这是博客网址
大致思路就是子线程去读取串口数据并传送到主线程,主线程在用widget对象画图实时显示波形图
QComboBox复选框选择串口端口号,并定义出自己封装好的画图的类的对象,并设置布局。如下图:
二、直接贴上代码
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()
{
}
三、串口代码就省略了,大家有需要看的可以去看我前面借鉴的大佬的博客
四、总结
之所以用线程读取数据,是因为一开始主线程读取数据的时候因为程序执行,也或许是画图影响反应事件
驱动信号的原因,导致接收数据与下位机发送数据不匹配,会丢失一部分数据,也做过算法改进,仍然不行,
后面采取开辟子线程读取串口,主线程显示,就没有这个问题了。总之在绘图上需要计算频率以及幅值,使图
形清楚明了。