树莓派3B Qt+dht11读取温湿度并写入数据库202005(8)

内容

本文介绍:使用树莓派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的说明):
在这里插入图片描述

202006问题更新:

之前有说过有时候会卡死,这是因为读取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

  • 9
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
要在树莓派上使用C语言读取DHT11温湿度传感器的值,可以通过GPIO接口进行读取。下面是一个示例程序: ```c #include <wiringPi.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #define MAX_TIMINGS 85 #define DHT_PIN 7 int data[5] = { 0, 0, 0, 0, 0 }; void read_dht_data() { uint8_t laststate = HIGH; uint8_t counter = 0; uint8_t j = 0; data[0] = data[1] = data[2] = data[3] = data[4] = 0; pinMode(DHT_PIN, OUTPUT); digitalWrite(DHT_PIN, LOW); delay(18); digitalWrite(DHT_PIN, HIGH); delayMicroseconds(40); pinMode(DHT_PIN, INPUT); for (uint8_t i = 0; i < MAX_TIMINGS; i++) { counter = 0; while (digitalRead(DHT_PIN) == laststate) { counter++; delayMicroseconds(1); if (counter == 255) { break; } } laststate = digitalRead(DHT_PIN); if (counter == 255) break; if ((i >= 4) && (i % 2 == 0)) { data[j / 8] <<= 1; if (counter > 16) data[j / 8] |= 1; j++; } } } int main(void) { if (wiringPiSetup() == -1) exit(1); while (1) { read_dht_data(); printf("Humidity = %d.%d %% Temperature = %d.%d *C \n", data[0], data[1], data[2], data[3]); delay(2000); } return 0; } ``` 在上面的代码中,我们使用了wiringPi库来访问GPIO口。它提供了一组用于读写GPIO的函数,以及其他一些实用的功能。在代码中,我们首先定义了一些常量和变量,然后定义了一个read_dht_data()函数来读取DHT11传感器的数据。在函数中,我们先发送一个18ms的低电平信号,然后再发送一个40us的高电平信号。接着转换GPIO口为输入模式,开始读取数据。我们使用循环来读取每个位的值,最后将温度和湿度的值存储在data数组中。最后,在主函数中,我们不断调用read_dht_data()函数来读取传感器数据,并打印出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺有缸的高飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值