内容
本文介绍:使用树莓派3B Qt+dht11读取温湿度,以一定时间间隔更新数据,显示于界面,并写入数据库
硬件:树莓派3B,温湿度传感器dht11,杜邦线
1、建工程
建立工程后点击mainwindow.ui设计界面
5个label和1个button,红框里的5个控件均是label:
接着为Getdata按钮添加点击响应函数
建立工程、使用控件有问题请挪步:
树莓派3B使用Qt+MySQL创建、写入、修改、显示数据(7).
2、配置
1、pro文件加代码
QT += core gui sql //SQL
LIBS += -lwiringPi //GPIO库函数
2、添加自己的类
在项目上点击右键,add new
添加一个c++类
输名字(自己随意取)
接着项目里生成dht11_lx3.h和dht11_lx3.cpp
3、上代码
必要说明我写在了注释上,直接贴:
xxx.pro
#-------------------------------------------------
#
# Project created by QtCreator 2020-05-13T19:56:28
#
#-------------------------------------------------
QT += core gui
QT += core gui sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qt_dht11_mysql_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_lx3.cpp
HEADERS += \
mainwindow.h \
dht11_lx3.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
dht11_lx3.h
#ifndef DHT11_LX3_H
#define DHT11_LX3_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <wiringPi.h>
#define uchar unsigned char
#define dht11_pin 7 //wiringPi方式的引脚,dht11信号线接引脚7
class dht11_lx3
{
public:
dht11_lx3();
// ~dht11_lx3();
void pininit();
void dht11_reset(void);
uint dht11_read_bit(void);
uint dht11_read_byte(void);
uint dht11_read_data(uchar buffer[5]);
};
#endif // DHT11_LX3_H
dht11_lx3.cpp
更正:之前上传代码的时候,为了好看清晰,删掉了一些调试的代码和不必要的注释,不小心把红框这里的分号删掉了。结果这次用dht11的时候直接来博客复制代码,发现用不了,找半天到这个问题,自己把自己坑惨。下面的代码已经加上了,并且加了几句代码,基本解决dht11在这里经常死掉的问题。
#include "dht11_lx3.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
dht11_lx3::dht11_lx3()
{
}
//dht11_lx3::~dht11_lx3()
//{
//}
void dht11_lx3::pininit()
{
wiringPiSetup();
pinMode(dht11_pin,OUTPUT);//设置Pin 0为输出模式,若为’INPUT‘则为输入模式,编码格式为wiringpi
digitalWrite( dht11_pin, HIGH );//拉高
}
void dht11_lx3::dht11_reset(void)
{
digitalWrite( dht11_pin, LOW );
delay(20);
digitalWrite( dht11_pin, HIGH );
delayMicroseconds(30);
pinMode(dht11_pin,INPUT);//设为输入在这里插入代码片
pullUpDnControl(dht11_pin,PUD_UP);//上拉
}
uint dht11_lx3::dht11_read_bit(void)
{
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_lx3::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_lx3::dht11_read_data(uchar buffer[5])
{
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;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void writedata(double tem,double hum);
protected:
void timerEvent( QTimerEvent *event );
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
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.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dht11_lx3.h"
#include <QSqlDatabase>
#include <QDebug>
#include <QMessageBox>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariantList>
#include <wiringPi.h>
int a=0,b=0;//调试用
int m_nTimerId;//定时器id
double hum=0;//湿度
double tem=0;//温度
dht11_lx3 dht11;//用dht11_lx3 类定义一个变量dht11
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//数据库配置
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()<<"连接数据库成功";
}
dht11.pininit();//引脚初始化
delay(2500);//dht11上电需等待2秒
}
MainWindow::~MainWindow()
{
delete ui;
if ( m_nTimerId != 0 )
{
killTimer(m_nTimerId);//kill定时器
}
}
void MainWindow::timerEvent( QTimerEvent *event )
{
b++;//读取次数
QString btmp = QString::number(b);
ui->label_3->setText(btmp);//显示次数
uchar buffer[5];
if (dht11.dht11_read_data(buffer) == 0)
{
hum = buffer[0] + buffer[1] / 10.0;//整数位+小数位
tem = buffer[2] + buffer[3] / 10.0;
}
else
{
ui->label_3->setText("checksum error:");//dht11校验和错误
dht11.pininit();//重新初始化引脚
return;
}
QString humtmp = QString::number(hum);
ui->humlabel->setText(humtmp);//显示湿度
QString temtmp = QString::number(tem);
ui->temlabel->setText(temtmp);//显示温度
writedata(tem,hum);//写数据进数据库
pinMode(dht11_pin,OUTPUT);//设置Pin 0为输出模式,若为’INPUT‘则为输入模式,编码格式为wiringpi
digitalWrite( dht11_pin, HIGH );//拉高引脚备下次用
}
//点击按钮开始获取数据
void MainWindow::on_pushButton_clicked()
{
ui->label_3->setText("Initializing:");
dht11.pininit();//引脚初始化
m_nTimerId=startTimer(3000);//设置3秒的定时器,每次时间一到就去timerEvent函数执行
}
void MainWindow::writedata(double tem,double hum)
{
QSqlQuery query;
// query.exec("drop table dht11data_lx;");//数据太多了就打开,删除表单dht11data_lx,下一条指令会新建
query.exec("create table dht11data_lx(Time datetime, Temperature double, Humidity double);");//新建表单dht11data_lx
QString sqlquery = QObject::tr("insert into dht11data_lx(Time,Temperature,Humidity) values(now(),'%1','%2')").arg(tem).arg(hum);//插入一个数据
query.exec(sqlquery);
}
4、上结果
运行后等待2-3秒,点击getdata,如图,每隔3秒记录一次,当前记录38次,数据库以及内容查看不会的见:
树莓派3B&MySQL-学习使用笔记202004(5).
有时候会checksum错误(不清楚的挪步百度dht11的说明):
之前有说过有时候会卡死,这是因为读取dht11时序的时候,while循环一直没出来,经常是下图这里,因为dht11本来该主动拉低引脚,但是却没有。这次把问题解决了,首先看dht11时序:
1、总时序:
2、主机给信号,dht11应答准备:
总线空闲状态为高,读取数据时,把总线拉低大于18ms,使DHT11能检测到开始。DHT11接收到信号后,等信号结束接着发80us低电平。单片机发送起始信号结束后,延时20-40us,然后检测DHT11的应答。如果检测到总线为低电平,说明DHT11发送应答信号,DHT11发送响应信号后,再把总线拉高80us。
3、dht11发数据:
发送数据:每位数据以50us低电平开始,高电平时间决定数据位是0还是1。格式如下图。最后一位数据传送完毕后,DHT11拉低总线 50us,随后总线进入空闲状态。
再看下面这段程序:
uint dht11_lx3::dht11_read_bit(void)
{
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;
}
}
造成运行异常的原因是这句被屏蔽的代码
//while (digitalRead( dht11_pin ) == 1);
由上面的时序,本来26-28us或者70us以后,dht11开始下一bit,但是如果dht11没有拉低,那么就会一直执行while。
那么,就得加个超时的判定,如果超过70us都还是高,那么肯定会出问题
delayMicroseconds(35);
上面这句代码是延时35us,正常情况下,如果延时35us后还是高,因为发送数据1的时序是70us,那么说明发送的数据是1;如果延时35us后已经变成低电平,那么说明是数据0。
那么,在数据1的情况下,前面已经延时35,如果在这里面每次延时1us并计数,当计数值大于50,也就是35+50=85us,而且加上指令运行的时间,这就绝对地大于正常的70us,这个时候就得用break来退出while,解决死循环的问题。
while (digitalRead( dht11_pin ) == 1)
{
delayMicroseconds(1);
count1++;
if(count1>50)
break;
}
完
课程作业,边学边用,如有错漏,敬请指正
--------------------------------------------------------------------------------------------诺有缸的高飞鸟202005