目录
内容
利用超声测距(hc-sr04)和温湿度检测(dht11)来判断人的靠近对环境温度造成的影响,结果状态以文字形式显示于文本框,温湿度曲线用qchart绘制。
项目全部代码在此:monitor_lx_code.zip 提取码:0ooc
或者愿意用c币支持的朋友在这里:monitor_lx_code.zip
(两个资源都是一样的,百度云那个免费下载)
界面
温湿度曲线、温湿度坐标轴、当前温湿度距离显示、当前状态:温湿度读取情况、有没有人靠近、正常记录的次数、温湿度状态(上升)下降、无变化)、数据开始获取按钮、暂停按钮等。
大致结构
主线程分析数据、绘制图像、写数据库;
一个线程测温;
一个线程测距。
使用多线程的原因
温湿度检测和距离检测要同时进行,而且根据dht11的特性要间隔两秒以上读取一次数据,所以如果放在主线程的话只能两秒读取一次数据。而当人移动较快时,超声传感器两秒检测一次是不能检测到人的经过的。所以在一个线程中2s一次获取温湿度数据,在另一个线程中每100ms检测一次距离一次判断是否有人。
一个简单多线程样例
样例来自:如何使用QT5实现多线程(一)
点击button后,在主线程开启定时器和启动线程,定时器每100ms更新一次LCD number。新线程启动后5s发出信号给主线程,主线程收到信号后停止定时器。
下面是实现步骤:
1、新建一个qt工程;
2、添加 一个类thread_one(名字任意);
添加代码:
thread_one.h
#ifndef THREAD_ONE_H
#define THREAD_ONE_H
#include <QThread>
class thread_one : public QThread
{
Q_OBJECT
public:
explicit thread_one(QObject *parent = nullptr);
protected:
void run();//多线程执行的内容将通过重新该虚函数实现
signals:
void over1();//发出的信号
public slots:
};
#endif // THREAD_ONE_H
thread_one.cpp
#include "thread_one.h"
thread_one::thread_one(QObject *parent) : QThread(parent)
{
}
void thread_one::run()
{
sleep(5);//模拟一个时长5s的复杂函数
emit over1();//复杂函数结束后发出信号
}
3、在ui里添加一个LCD Number和一个button
4、mainwindow
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include<QTimer>
#include<QThread>
#include <QWidget>
#include"thread_one.h"
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void dealclicked();
void dealtimeout();
private slots:
void dealover();//处理新线程返回的结束信号
private:
Ui::MainWindow *ui;
QTimer *timer;
thread_one *thread;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(this);
thread = new thread_one(this);
connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::dealclicked);//按下按钮后执行dealclicked()槽函数
connect(timer,&QTimer::timeout,this,&MainWindow::dealtimeout);//根据定时器发出的信号更新LCD显示器的数字
connect(thread,&thread_one::over1,this,&MainWindow::dealover);//当开辟的线程内的复杂函数执行完后,发出over信号,接收到该信号后便停下计时器
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::dealclicked()
{
timer->start(100);//启动计时器,每0.1秒发出一次信号
thread->start();//QThread 的对象通过start()函数调用线程文件中的run()函数
}
void MainWindow::dealtimeout()//更新LCD显示器的数字
{
static int time = 0;
ui->lcdNumber->display(time);
time++;
}
void MainWindow::dealover()//接收到信号后停下计时器
{
timer->stop();
}
结果:
1、配置Qt chart
2、多线程
先新建一个qt工程。
先列出最后项目下所有文件
pro文件
#-------------------------------------------------
#
# Project created by QtCreator 2020-05-30T16:32:58
#
#-------------------------------------------------
QT += core gui sql
QT += charts
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = monitor_lx
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp \
dht11_lx.cpp \
thread_1.cpp \
thread_2.cpp \
hcsr04_lx.cpp
HEADERS += \
mainwindow.h \
dht11_lx.h \
thread_1.h \
thread_2.h \
hcsr04_lx.h
FORMS += \
mainwindow.ui
LIBS += -lwiringPi
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
1、线程1,获取温湿度数据
新建一个类thread_1,从QThread继承,主要通过虚函数run()和信号函数over()实现线程的运行和信号的发出
thread_1.h
#ifndef THREAD_1_H
#define THREAD_1_H
#include "dht11_lx.h"
#include <QThread>
class thread_1 : public QThread
{
Q_OBJECT
public:
explicit thread_1(QObject *parent = nullptr);
volatile bool finishflag=0;
volatile bool thread1_start=0;
volatile bool checkerrorflag=0;
volatile double out_hum;
volatile double out_tem;
dht11_lx dht11;
protected:
void run();//多线程执行的内容将通过重新该虚函数实现
signals:
void over1();
public slots:
};
#endif // THREAD_ONE_H
在cpp里面写run()函数需要做的事情,这里是通过写好的dht11的类来读取dht11数据;读取完成后发出完成一次读取的信号over1,主线程与此信号建立函数关系连接,收到信号后执行相应的数据处理函数;每次读取前要通过完成主线程对应数据处理完成标志finishflag来等待上一次数据处理完成,再进行数据读取;为保证dht11正常运行,读取一次就delay(2000),目的是每2s读取一次;再通过while判断thread1_start标志位来让读取一直进行,标志位由主线程的开始和暂停按钮控制改变;
thread_1.cpp
#include "thread_1.h"
thread_1::thread_1(QObject *parent) : QThread(parent)
{
dht11.pininit();//引脚初始化
}
void thread_1::run()
{
//out_tem=20;
finishflag=1;
while(thread1_start==1)
{
while(finishflag==0);//wait for work in mian thread done.
uchar buffer[5];
buffer[0]=buffer[1]=buffer[2]=buffer[3]=buffer[4]=0;
if (dht11.dht11_read_data(buffer) == 0)
{
out_hum = buffer[0] + buffer[1] / 10.0;//整数位+小数位
out_tem = buffer[2] + buffer[3] / 10.0;
checkerrorflag=0;
}
else
{
checkerrorflag=1;
}
emit over1();
delay(2000);
}
}
dht11_lx.h
#ifndef DHT11_LX_H
#define DHT11_LX_H
#include <iostream>
#include <wiringPi.h>
//#define uchar unsigned char
#define dht11_pin 7 //wiringPi方式的引脚,dht11信号线接引脚7
class dht11_lx
{
public:
dht11_lx();
// ~dht11_lx();
void pininit();
void dht11_reset(void);
uint dht11_read_bit(void);
uint dht11_read_byte(void);
uint dht11_read_data(unsigned char buffer[5]);
};
#endif // DHT11_LX_H
dht11_lx.cpp
#include "dht11_lx.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
dht11_lx::dht11_lx()
{
wiringPiSetup();
}
void dht11_lx::pininit()
{
pinMode(dht11_pin,OUTPUT);//设置Pin 0为输出模式,若为’INPUT‘则为输入模式,编码格式为wiringpi
digitalWrite( dht11_pin, HIGH );
}
void dht11_lx::dht11_reset(void)
{
// pinMode( dht11_pin, OUTPUT );
// digitalWrite( dht11_pin, HIGH );
// delay(5);
digitalWrite( dht11_pin, LOW );
delay(20);
digitalWrite( dht11_pin, HIGH );
delayMicroseconds(30);
pinMode(dht11_pin,INPUT);
pullUpDnControl(dht11_pin,PUD_UP);
}
uint dht11_lx::dht11_read_bit(void)
{
uchar count1=0;
while (digitalRead( dht11_pin ) == 0);
delayMicroseconds(35);
if (digitalRead( dht11_pin ) == 1)
{
// while (digitalRead( dht11_pin ) == 1);
while (digitalRead( dht11_pin ) == 1)
{
delayMicroseconds(1);
count1++;
if(count1>50)
break;
}
return 1;
}
else
{
return 0;
}
}
uint dht11_lx::dht11_read_byte(void)
{
uint i;
uint data = 0;
for (i = 0; i < 8; i++)
{
data <<= 1;
data |= dht11_read_bit();
}
return data;
}
uint dht11_lx::dht11_read_data(uchar buffer[5])
{
uchar count2=0;
uint i = 0;
uchar checksum;
dht11_reset();
if (digitalRead( dht11_pin ) == 0)
{
while (digitalRead( dht11_pin ) == 0);
while (digitalRead( dht11_pin ) == 1);
for (i = 0; i < 5; i++)
{
buffer[i] = dht11_read_byte();
}
while (digitalRead( dht11_pin ) == 0);
pinMode( dht11_pin, OUTPUT );
digitalWrite( dht11_pin, HIGH );
checksum = buffer[0] + buffer[1] + buffer[2] + buffer[3];
if (checksum != buffer[4])
{
// checksum error
return 1;
}
}
return 0;
}
2、线程2,获取距离数据
同理,在线程2的run函数里面使用写好的类来获取距离信息:
thread_2.h
#ifndef THREAD_2_H
#define THREAD_2_H
#include "hcsr04_lx.h"
#include <QThread>
class thread_2 : public QThread
{
Q_OBJECT
public:
explicit thread_2(QObject *parent = nullptr);
volatile bool finishflag2=0;
volatile bool errorflag2=0;
volatile bool thread2_start=0;
float out_distance;
hcsr04_lx hcsr04;
protected:
void run();//多线程执行的内容将通过重新该虚函数实现
signals:
void over2();
public slots:
};
#endif // THREAD_2_H
thread_2.cpp
#include "thread_2.h"
thread_2::thread_2(QObject *parent) : QThread(parent)
{
hcsr04.pininit();//引脚初始化
}
void thread_2::run()
{
finishflag2=1;
while(thread2_start==1)
{
while(finishflag2==0);//wait for work in mian thread done.
errorflag2=hcsr04.hcsr04_read_data(&out_distance);
while(errorflag2==1)
{
errorflag2=hcsr04.hcsr04_read_data(&out_distance);
}
msleep(100);
emit over2();
}
}
hcsr04_lx.h
#ifndef HCSR04_LX_H
#define HCSR04_LX_H
#include <iostream>
#include <wiringPi.h>
#include <QTime>
#include <QThread>
#define trig_pin 28 //wiringPi方式的引脚,dht11信号线接引脚7
#define echo_pin 29 //wiringPi方式的引脚,dht11信号线接引脚7
class hcsr04_lx
{
public:
hcsr04_lx();
void pininit();
bool hcsr04_read_data(float *distance);
};
#endif // HCSR04_LX_H
hcsr04_lx.cpp
#include "hcsr04_lx.h"
#include <sys/time.h>
hcsr04_lx::hcsr04_lx()
{
}
void hcsr04_lx::pininit()
{
// wiringPiSetup();
pinMode(trig_pin,OUTPUT);//设置Pin 为输出模式,若为’INPUT‘则为输入模式,编码格式为wiringpi
digitalWrite( trig_pin, LOW );
pinMode(echo_pin,INPUT);
pullUpDnControl(echo_pin,PUD_UP);
}
bool hcsr04_lx::hcsr04_read_data(float *distance)
{
struct timeval tv1;
struct timeval tv2;
long start, stop;
int tempcount=0;
pinMode(trig_pin,OUTPUT);//设置Pin 为输出模式,若为’INPUT‘则为输入模式,编码格式为wiringpi
digitalWrite( trig_pin, HIGH );
delayMicroseconds(15);
digitalWrite( trig_pin, LOW );
// while (digitalRead( echo_pin ) == 0);
while (digitalRead( echo_pin ) == 0)
{
delayMicroseconds(10);
if(tempcount++ > 250)
return 1;
}
gettimeofday(&tv1, NULL);
while (digitalRead( echo_pin ) == 1);
gettimeofday(&tv2, NULL);
// double elapsed = startTime.msecsTo(stopTime);//ms
start = tv1.tv_sec * 1000000 + tv1.tv_usec; //微秒级的时间
stop = tv2.tv_sec * 1000000 + tv2.tv_usec;
float dis = (float)(stop - start) / 1000000 * 34000 / 2; //求出距离
*distance=dis;
return 0;
}
3、主线程获取数据并处理
1、开启另外两个线程获取测得数据
利用按钮,开启线程
Start()被调用后,直接转到对应线程的run()函数执行
2、信号关联
主线程定义两个slots槽函数,与两个over函数建立联系,另外两个线程在数据读取完成后分别发出信号给主线程,主线程分别执行两个数据处理函数
3、数据处理
定义线程对象,通过访问对象的变量来获取或改变温湿度、距离、标志位等信息
改变温湿度线程标志位、读取温湿度数据:
并在获取数据后,对数据进行处理:
–判断检验值是否出错
–判断数据是否在正常范围
–数据正常则调用函数来显示、写入数据库、绘制曲线(state_dis,writedata,drawline)
4、连接数据库、写入数据库
4、数据分析(人对温度影响)
1、温度数据分析
调用readdata函数对数据库的最新5个数据进行读取分析:
让最新的数据与前一个数据求差,差值保存;
保存最新的5个差值,差值求和,如果大于一个正的阈值,那么温度上升,如果小于一个负的阈值,那么温度下降;
设置阈值不直接用大于小于零,是因为相对于昼夜温差变化,人靠近和离开会造成温度变化较快,会在短期内累积差值超过一定阈值,而比如半夜里的降温则很缓慢,短期内的累积差值不会超过阈值,这就判断出了是人的出现造成的温度上升和下降,而不是自然温度变化。
写入数据库的数据包含:时间、温湿度、距离、有没有人、温度上升下降情况
2、距离数据分析
在距离线程里数据更新是100ms一次,直接取最新的5个数据存入数组并取平均,因为超声传感器就放在电脑旁,所以就判断阈值小于70cm则为人靠近
5、代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCharts/QChartView>//显示图表
#include <QtCharts/QLineSeries>//线系列
#include <QDoubleSpinBox>
#include <QGridLayout>
#include <QTimer>
#include <QtCharts/QSplineSeries>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>
#include <QtCharts/QDateTimeAxis>
#include<QThread>
#include"thread_1.h"
#include"thread_2.h
QT_CHARTS_USE_NAMESPACE
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
thread_1 thread_dht11;//温湿度读取线程对象
thread_2 thread_hcsr04;//距离读取线程对象
~MainWindow();
private:
Ui::MainWindow *ui;
double hum;//湿度
double tem;//温度
double lasthum;
double lasttem;
int records;//成功读取温湿度的次数
bool drawstart;//绘制曲线标志
bool humanflag;//有无人的标志
int tem_changeflag;//温度变化标志
qreal m_maxY1;//Y轴最大最小值(Y轴范围)
qreal m_minY1;
qreal m_maxY2;
qreal m_minY2;
QString recordstmp;//成功读取温湿度的次数QString
int interval;//写入数据库的时间间隔
double distance[5];//存最新5个距离
int dis_count;//当前循环到第几个距离数据
double temperature[6];//前5个是最新的温度数据,temperature[5]是当前循环到第几个温度数据
double difference[5];//5个最新的温差
int tem_count;//
QString S_checksum;//dht11校验:normal、error
QString S_human;//有没有人:man close、no one
QString S_temp;//温度状态:rising、normal、falling
QTimer m_timer;
QChart chart;//Qchart
// QLineSeries m_series;
// QSplineSeries m_series1;//temperature
QLineSeries m_series1;//temperature
QLineSeries m_series2;//humidity
QValueAxis my_axisY1;//Y1轴
QValueAxis my_axisY2;//Y2轴
QDateTimeAxis my_axisX;//横轴,时间轴
qreal m_x;
qreal m_y1;//y值,用于绘制曲线
qreal m_y2;
int axis_max;
void writedata(double tem,double hum,double distance);
void readdata();
void timerEvent( QTimerEvent *event );
void drawline(QLineSeries *series1, QLineSeries *series2, double temperature, double humidity);
void state_dis(QString checksum,QString human,QString temp);
private slots:
void on_pushButton_clicked();//开始按钮
void on_pushButton_2_clicked();//暂停按钮
void dht11data();//温湿度数据处理
void hcsr04data();//距离数据处理
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QSplineSeries>
#include <QChartView>
#include <QChart>
QT_CHARTS_USE_NAMESPACE
#include "ui_mainwindow.h"
#include <math.h>
#include <QTimer>
#include <math.h>
#include <QLayout>
#include <math.h>
#include <wiringPi.h>
#include <QSqlDatabase>
#include <QDebug>
#include <QMessageBox>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariantList>
#include <QtSql>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_x=0;
m_y1=0;
m_y2=0;
m_maxY1=0.1;
m_minY1=0;
m_maxY2=40;
m_minY2=80;
hum=0;//湿度
tem=0;//温度
records=0;
lasthum=0;
lasttem=0;
drawstart=0;
interval=0;
humanflag=0;
tem_changeflag=0;
dis_count=0;
tem_count=0;
S_human="no one";
S_temp="nomal";
for(int i = 0; i < 5; i++)
{
temperature[i]=0;
}
for(int i = 0; i < 5; i++)
{
difference[i]=0;
}
qDebug()<<QSqlDatabase::drivers();
qDebug()<<QCoreApplication::libraryPaths();//数据库驱动的文件位置
QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");//QMYSQL是采用QMYSQL数据库驱动
db.setHostName("127.0.0.1");
db.setUserName("noel"); //数据库账号
db.setPassword("123456");//数据库密码
db.setDatabaseName("noeldb"); //你的数据库名
if(!db.open()){
qDebug()<<"连接数据库失败";
return;
}else{
qDebug()<<"连接数据库成功";
}
chart.addSeries(&m_series1);//添加曲线m_series1
chart.addSeries(&m_series2);
m_series1.setName("temperature");//设置曲线名称
m_series2.setName("humidity");
// m_series1.setColor("red");
//m_series1.setColor("green");//设置曲线颜色
// my_axisX.setFormat("h:mm:ss");//设置横轴时间格式(时分秒)
my_axisX.setFormat("h:mm");//时分
my_axisY1.setMin(0);//设置Y轴最大最小值
my_axisY1.setMax(30);
my_axisY2.setMin(50);
my_axisY2.setMax(100);
my_axisY1.setTickCount(15);//将轴划分n格
my_axisY2.setTickCount(10);
my_axisX.setTickCount(10);
my_axisX.setTitleText("time-axis");//轴标题
my_axisY1.setTitleText("temperature");
my_axisY2.setTitleText("humidity");
my_axisY1.setLinePenColor(QColor(Qt::darkBlue));//画笔
my_axisY1.setGridLineColor(QColor(Qt::darkBlue));
my_axisY2.setLinePenColor(QColor(Qt::darkGreen));
my_axisY2.setGridLineColor(QColor(Qt::darkGreen));
my_axisY1.setGridLineVisible(false);//网格线不可见
my_axisY2.setGridLineVisible(false);
QPen penY1(Qt::darkBlue, 3,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin);
QPen penY2(Qt::darkGreen,3,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin);
my_axisY1.setLinePen(penY1);
my_axisY2.setLinePen(penY2);
chart.addAxis(&my_axisX,Qt::AlignBottom);//添加轴
chart.addAxis(&my_axisY1,Qt::AlignLeft);
chart.addAxis(&my_axisY2,Qt::AlignRight);
m_series1.attachAxis(&my_axisX);
m_series1.attachAxis(&my_axisY1);
m_series2.attachAxis(&my_axisX);
m_series2.attachAxis(&my_axisY2);
QChartView *chartView = new QChartView(&chart);
QGridLayout *baseLayout = new QGridLayout(); //便于显示,创建网格布局
chartView->setRenderHint(QPainter::Antialiasing);
baseLayout->addWidget(chartView, 0, 0);
ui->widget->setLayout(baseLayout); //显示到QWidget控件
connect(&thread_dht11,&thread_1::over1,this,&MainWindow::dht11data);//当开辟的线程内的复杂函数执行完后,发出over信号
connect(&thread_hcsr04,&thread_2::over2,this,&MainWindow::hcsr04data);//当开辟的线程内的复杂函数执行完后,发出over信号
}
void MainWindow::on_pushButton_clicked()
{
thread_dht11.dht11.pininit();
thread_hcsr04.hcsr04.pininit();//引脚初始化
delay(2000);
thread_dht11.thread1_start=1;//线程里的 while(thread1_start==1),进入循环
thread_dht11.start();//线程开始运行
thread_hcsr04.thread2_start=1;
thread_hcsr04.start();
}
void MainWindow::on_pushButton_2_clicked()
{
thread_dht11.thread1_start=0;//停止线程里的while循环
thread_dht11.finishflag=1;//任务完成标志
thread_hcsr04.thread2_start=0;
thread_hcsr04.finishflag2=1;
QThread::msleep(2500);
thread_hcsr04.quit();//退出线程
thread_dht11.quit();
}
void MainWindow::writedata(double tem,double hum,double distance)
{
//写数据进数据库
QSqlQuery query;
// query.exec("drop table data0608_1_lx;");//数据太多了就打开,删除表单dht11data_lx,下一条指令会新建
//时间、温湿度数据成功读取次数、温度、湿度、距离、人状态(1有人,0无人)、温度状态(1上升、0无变化、-1下降)
query.exec("create table data0608_3_lx(Time datetime, num int, Temperature double, Humidity double, Distance double, Human bool, Tempflag int);");//新建表单
QString sqlquery = QObject::tr("insert into data0608_3_lx(Time,num,Temperature,Humidity,Distance,Human,Tempflag) values(now(),'%1','%2','%3','%4','%5','%6')").arg(records).arg(tem).arg(hum).arg(distance).arg(humanflag).arg(tem_changeflag);//插入一个数据
query.exec(sqlquery);
}
void MainWindow::readdata()
{
//从数据库读取最新5个数据来分析
double current_temp=0;
double temp_difference=0;
QSqlQuery query;
bool success = query.exec("select * from data0608_3_lx order by Time desc limit 0,6");//访问最新的(6-1)=5个数据
if(!success){
qDebug() << "查询user失败";
}
QSqlRecord rec = query.record();
qDebug() << "user表的字段总数为:" << rec.count();
query.last();//最后的数据
while(query.previous()){//往前读取
//显示当前最新的数据库数据
qDebug() << query.value(0).toString()<< query.value(1).toString() << query.value(2).toString()<< query.value(3).toString()<< query.value(4).toString()<< query.value(5).toString()<< query.value(6).toString();
current_temp=query.value(2).toDouble();//数据取出到变量
}
temperature[(int)temperature[5]]=current_temp;//写进数组
//当前温度
qDebug() << "current_temp: "<< QString::number(temperature[(int)temperature[5]])<<QString::number((int)temperature[5]);
//最新5个温度
qDebug() << "temperature: "<< QString::number(temperature[0])<<QString::number(temperature[1])<<QString::number(temperature[2])<< QString::number(temperature[3])<< QString::number(temperature[4]);
//计算温差,最新数据减去上一个数据
if((int)temperature[5]==0)
{
temp_difference=temperature[0]-temperature[4];
}
else {
temp_difference=temperature[(int)temperature[5]]-temperature[(int)temperature[5]-1];
}
//保存最新温差进数组
difference[(int)temperature[5]]=temp_difference;
//当前温差
qDebug() << "current_dif: "<< QString::number(difference[(int)temperature[5]])<<QString::number((int)temperature[5]);
//
qDebug() << "difference: "<<QString::number(difference[0])<<QString::number(difference[1])<<QString::number(difference[2])<< QString::number(difference[3])<< QString::number(difference[4]);
temperature[5]++;
temp_difference=0;//清零
for(int i = 0; i < 5; i++)
{
temp_difference+=difference[i];//温差累积
}
qDebug() << "t_difference: "<<QString::number(temp_difference);//现实累积温差值
//阈值判定
if(temp_difference >= 0.3)//大于等于0.3判定为升温
{
tem_changeflag=1;
S_temp=" rising";
state_dis(S_checksum,S_human,S_temp);
}
else if(temp_difference <= -0.3)//小于等于-0.3判定为升降温
{
tem_changeflag=-1;
S_temp=" falling";
state_dis(S_checksum,S_human,S_temp);
}
else{//否则为温度未变化
tem_changeflag=0;
S_temp=" normal";
state_dis(S_checksum,S_human,S_temp);
}
if(((int)temperature[5])==5)
{
temperature[5]=0;//已更新完5个最新数据,清零再次更新
}
}
void MainWindow::timerEvent( QTimerEvent *event)
{
;
}
void MainWindow::drawline(QLineSeries *series1, QLineSeries *series2, double temperature, double humidity)
{
m_y1=temperature;//y值
m_y2=humidity;
QDateTime bjtime = QDateTime::currentDateTime();//时间
chart.axisX()->setMin(QDateTime::currentDateTime().addSecs(-28800*1));//8小时,(8×60×60=28800)
chart.axisX()->setMax(QDateTime::currentDateTime().addSecs(0));
series1->append(bjtime.toMSecsSinceEpoch(),m_y1);//绘制当前值
series2->append(bjtime.toMSecsSinceEpoch(),m_y2);
//曲线移动
if(series1->count()>10000)
{
series1->removePoints(0,series1->count()-10000);
}
if(series2->count()>10000)
{
series2->removePoints(0,series2->count()-10000);
}
//改变温度轴范围在当前值的+5 -5区间
m_maxY1 = m_y1 + 5;
m_minY1 = m_y1 - 5;
// chart.axisY()->setRange(m_minY1, m_maxY1);
my_axisY1.setMin(m_minY1);
my_axisY1.setMax(m_maxY1);
thread_dht11.finishflag=1;//处理完成标志
}
void MainWindow::hcsr04data()
{
double dis_ava=0;
thread_hcsr04.finishflag2=0;//开始出处理标志
while(thread_dht11.finishflag==0);//等待dht11数据处理完毕
QString distancetmp = QString::number((double)thread_hcsr04.out_distance);//double转QSTRING
ui->lineEdit_distance->setText(distancetmp);//显示
distance[dis_count]=(double)thread_hcsr04.out_distance;
dis_count++;
if(dis_count==5)
dis_count=0;
dis_ava=(distance[0]+distance[1]+distance[2]+distance[3]+distance[4])/5;//取5个最新数据的均值
if(dis_ava<=70)//阈值判定,小于70则判定有人
{
humanflag=1;
S_human="man close";
}
else {
humanflag=0;
S_human="no one";
}
state_dis(S_checksum,S_human,S_temp);//状态显示
thread_hcsr04.finishflag2=1;//处理完成标志
}
void MainWindow::state_dis(QString checksum,QString human,QString temp)
{
//状态显示函数
ui->lineEdit_state->setText("checksum:"+checksum+" records:"+recordstmp+" "+human+" temperature:"+temp);//dht11校验和错误
}
void MainWindow::dht11data()
{
thread_dht11.finishflag=0;//开始处理标志
interval++;//写数据间隔
// while(thread_hcsr04.finishflag2==0);//wait for hcsr04 done.
hum=thread_dht11.out_hum;//数据获取到主线程
tem=thread_dht11.out_tem;
if(thread_dht11.checkerrorflag==1)//dht11校验值判定
{
S_checksum="error";
state_dis(S_checksum,S_human,S_temp);
drawstart=0;//不绘图标志
thread_dht11.dht11.pininit();//重新初始化引脚
thread_dht11.finishflag=1;//处理完成标志
return;
}
QString humtmp = QString::number(hum);
ui->lineEdit_hum->setText(humtmp);//显示湿度
QString temtmp = QString::number(tem);
ui->lineEdit_tem->setText(temtmp);//显示温度
//阈值判定,不在阈值内的就是错误数据
if((tem<=40)&&(tem>=10)&&(hum<=100)&&(hum>=40))
{
lasttem=tem;
lasthum=hum;
drawstart=1;//可以绘图标志
}
else//error data
{
drawstart=0;
ui->lineEdit_state->setText("data error");//
thread_dht11.dht11.pininit();//重新初始化引脚``````````
thread_dht11.finishflag=1;
return;
}
records++;//正确读取数据的次数
recordstmp = QString::number(records);
S_checksum="normal";
// ui->lineEdit_state->setText("records:"+recordstmp);
state_dis(S_checksum,S_human,S_temp);
thread_dht11.dht11.pininit();
double distance=(double)thread_hcsr04.out_distance;//读取当前距离值
/*interval=1 min ,(30×2s) */
if(interval==1)
{
writedata(tem,hum,distance);
readdata();
}
if(interval>=30)
{
interval=1;
writedata(tem,hum,distance);
readdata();
}
if(drawstart==1)
{
drawline(&m_series1,&m_series2,tem,hum);//绘制曲线
}
}
MainWindow::~MainWindow()
{
delete ui;
thread_hcsr04.thread2_start=0;//停止线程里面的while循环
thread_dht11.thread1_start=0;
QThread::msleep(2500);//等待2.5s,保证线程的while循环已经停止
thread_hcsr04.quit();//退出线程
thread_dht11.quit();
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.ui
4、界面显示
1、曲线
在ui初始化时,设置两条曲线、两个y轴分别温湿度、x轴为时间轴;
设置曲线的属性,颜色、粗细、线型等等;
曲线随时间移动。
曲线初始化部分代码
绘制温湿度曲线
2、当前值、状态
温湿度:
距离:
状态:
5、运行结果
1、传感器放置:
2、软件界面:
点击getdata按钮开始获取数据、分析、绘图
如图,当前时刻温度29.2,湿度62,dht11校验值正常,正常读取了162次,距离49.742cm,有人状态;
最新的5个温度数据为28.9,28.9,28.9,28.9,29.2,温度上升状态
下图是人离开,温度下降状态
温度稳定状态:
3、数据库查看
倒数第二列有人是1,无人是0;最后一列,温度上升是1,下降是-1,无变化为0(一分钟记录一次):
长时段记录结果(正常运行并记录超过9小时):
1、23:44有人状态,温度升高:
2、0点人离开后,温度下降:
3、夜间温度自然下降,但是不是人引起的,所以温度下降标志无变化,符合预期
4、早上人有人状态,温度标志为1,温度又开始上升:
完
课程作业,边学边用,如有错漏,敬请指正
--------------------------------------------------------------------------------------------诺有缸的高飞鸟202007