一、项目介绍

    本实验通过 DHT11 模块测量大气中温湿度,利用树莓派多功能的用途,将温湿度测量结果显示到网页,并包含历史数据、实时折线图表示。

二、 实验介绍

1. 实验原材料

树莓派 Raspberry 4 Model B,DHT11 v1.3,电阻,杜邦线,面包板。

2. 流程图

三、硬件部分

DHT11 传感器实验相关知识

1.1 DHT11引脚说明
下图为GPIO引脚对照表

本次实验使用的DHT11有3个引脚:VCC、DATA、GND。
VCC接 5V PIN 02;DATA接 PIN 08;GND接地 PIN 06。
硬件连接图如下:右上角40引脚的2、6、8所连的三条线为DHT11所连的线。下面的13、14引脚所连的线为温度阈值报警小灯所用(此为附加功能所用)。

1.2 外设读取步骤
主机和从机之间的通信可通过如下几个步骤完成((外设(如微处理器)读取DHT11的数据的步骤)。
步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:
微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。发送信号如下图所示:
步骤三:
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的 DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知 外设准备接收数据,微处理器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号) 后,等待87微秒的高电平后的数据接收,发送信号下图所示:

步骤四:
由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据 “0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低 电平加68-74微秒的高电平。位数据“0”、“1”格式信号如下图所示:

结束信号:
DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电 阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。

1.3. DHT11单总线传送数据位定义
DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。
数据格式:

8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验位,其中湿度小数部分为 0

示例一:接收到的40位数据为:
0011 0101 / 0000 0000 / 0001 1000 / 0000 0100 / 0101 0001
湿度高8位 / 湿度低8位 / 温度高8位 / 温度低8位 / 校验位
计算:
00110101+00000000+00011000+00000100=01010001
接收数据正确:
湿度:00110101(整数)=35H=53%RH00000000(小数)=00H=0.0%RH=>53%RH+0.0%RH=53.0%RH
温度:00011000(整数)=18H=24℃00000100(小数)=04H=0.4℃=>24℃+0.4℃=24.4℃

实验中dht11.py所读取的温度显示为整数,欲将其变为带有一位小数的输出,只需将return值处理一下,将温度的小数部分the_bytes[3]加上就可以了

return DHT11Result(DHT11Result.ERR_NO_ERROR, the_bytes[2]+float(the_bytes[3])/10, the_bytes[0])

四、软件部分

1. 设计流程

相关参数调用关系

本实验中参数调用主要围绕app.py文件进行,app.py运行后,首先读取dht11读取到的当前温湿度参数,把参数存到数据库中,创建数组调用数据生成折线图。生成的图片通过存到对应路径上。html文件调用路径上存的文件显示到网页上,同时调用style.css文件进行网页美化。

文件夹路径关系:

主文件app.py位于WebServer文件夹
第三级目录中:
templates用于放html文件;
statics用于存放,css文件和其他的图片(可自选,例如背景图、温度湿度曲线图等便于调用);
history用于放dht11.py文件(因为我的树莓派B4无法使用Adafruit库,所以是使用硬件直接读取温湿度数据的。)

2. 树莓派学习笔记

树莓派相关下载过程此处不再赘述,这里只总结一些我在实验中遇到的问题以及解决的方法。

  1. SSH 远程连接树莓派 使用SSH远程连接后,可以在另外一台PC机上操控树莓派

    这个问题的出现的很普遍,因为大家对这个操作平台都还不是很熟悉,这个问题出现的原因是树莓派 SSH 服务没有打开,在树莓派桌面左上角树莓派图标上单击-> Preferences-> Raspberry Pi Configuration-> Interfaces -> SSH Enabled 选中 -> OK,重启PUTTY就可以解决了。
  2. 树莓派远程桌面 在实现远程连接时,要保证两个设备处在同一个网络中。 而且要确认好目前设备开的端口是哪一个,树莓派的IP地址是哪一个,确定好了才可以连接。

3. 代码程序报错记录

在运行这几个py文件时,遇到的几个主要的报错以及出现原因、处理方法如下:

  1. 报错:SyntaxError: invalid syntax
    这句话的意思是Python代码语法有问题。Python对语法的要求非常严格,有时候代码是网上直接找来复制粘贴的,就有可能导致明明看上去没错,但就一直报语法错误,可以尝试清空格式后重新输入一遍。
    另外需要注意的是Python2和Python3的语法有区别,比如Python2的print后面不用加括号,而Python3中就会报错。
  2. 报错:ModuleNotFoundError: No module named 'Adafruit_DHT’
    “import Adafruit_DHT ”语句错误,提示找不到Adafruit_DHT模块,但是在terminal里输入“import Adafruit_DHT”不报错,并且已经下载了相关库。可能是python版本的问题,先明确你运行程序时使用的是哪个Python版本。
    使用的是Python2使用的语句是:sudo pip install Adafruit_Python_DHT; sudo python setup.py install,
    但使用的是Python3使用的语句是:sudo pip3 install Adafruit_Python_DHT; sudo python3 setup.py install
    注意一定要用pip3
  3. 报错:ImportError: cannot import name ‘Beaglebone_Black_Driver’ from 'Adafruit_DHT’
    通过报错信息,发现是库中的common.py里引用get_platform有问题,再去platform_detect.py里查看发现树莓派的版本定义里没有4B,由于我们使用的是4B树莓派,所以导致返回了None
    解决:出现这个原因是AdaFruit不再更新这个旧的Adafruit_DHT库,所以里面没有更新树莓派4B对应的cpu。有两种解决方法,使用这个传感器的新库“Adafruit_CircuitPython_DHT”,或者在你原来的Adadruit_DHT库中自己手动更新,具体操作如下:
    (1)找到Adafruit_DHT文件夹, “/usr/local/lib/python3.7/dist-packages/Adafruit_DHT/”,
    (2)打开文件夹里的platform_detect.py文件,可以看到把下面这两行代码添加到最后。

    其中BCM2711是树莓派4B的CPU,它是四核Cortex-A72 64位。其它的BCMxxxx是其它树莓派版本的CPU。
  4. Adafruit库无法使用
    在根据讲义下载DHT库Adafruit库时,下载到的库中缺少Raspberry_Pi_2driver.py文件,导致执行DHT11_test测试文件时就没能读出数据,经过原因排查和多次下载,我们推断猜测可能是因为树莓派的问题,因为我们使用的是树莓派B4,可能是版本更新了的问题。
    对此我们的解决方案是:不使用Adafruit读取温湿度数据,而是用我们之前用过的DHT11.py文件进行读取,这个文件是通过GPIO端口直接读取数据的,并具有CRC纠检错功能,足够实验的功能实现。
    实际操作:WebServer文件夹下添加新文件夹:library,将dht11.py文件放在其中作调用功能,并在app.py文件加调用语言from library import dht11,将接下来的变量名重置。

4. 代码

基础功能的代码:使用dht11.py读取温度后,将温湿度显示到网页上。

(1)数据读取部分dht11.py

用于通过传感器读取数据的文件

import time
import RPiclass DHT11Result:'DHT11 sensor result returned by DHT11.read() method'ERR_NO_ERROR = 0ERR_MISSING_DATA = 1ERR_CRC = 2error_code = ERR_NO_ERRORtemperature = -1humidity = -1def __init__(self, error_code, temperature, humidity):self.error_code = error_codeself.temperature = temperatureself.humidity = humiditydef is_valid(self):return self.error_code == DHT11Result.ERR_NO_ERRORclass DHT11:'DHT11 sensor reader class for Raspberry'__pin = 0def __init__(self, pin):self.__pin = pindef read(self):RPi.GPIO.setup(self.__pin, RPi.GPIO.OUT)# send initial highself.__send_and_sleep(RPi.GPIO.HIGH, 0.05)# pull down to lowself.__send_and_sleep(RPi.GPIO.LOW, 0.02)# change to input using pull upRPi.GPIO.setup(self.__pin, RPi.GPIO.IN, RPi.GPIO.PUD_UP)# collect data into an arraydata = self.__collect_input()# parse lengths of all data pull up periodspull_up_lengths = self.__parse_data_pull_up_lengths(data)# if bit count mismatch, return error (4 byte data + 1 byte checksum)if len(pull_up_lengths) != 40:return DHT11Result(DHT11Result.ERR_MISSING_DATA, 0, 0)# calculate bits from lengths of the pull up periodsbits = self.__calculate_bits(pull_up_lengths)# we have the bits, calculate bytesthe_bytes = self.__bits_to_bytes(bits)# calculate checksum and checkchecksum = self.__calculate_checksum(the_bytes)if the_bytes[4] != checksum:return DHT11Result(DHT11Result.ERR_CRC, 0, 0)# ok, we have valid data, return itreturn DHT11Result(DHT11Result.ERR_NO_ERROR, the_bytes[2]+float(the_bytes[3])/10, the_bytes[0]+float(the_bytes[1])/10)def __send_and_sleep(self, output, sleep):RPi.GPIO.output(self.__pin, output)time.sleep(sleep)def __collect_input(self):# collect the data while unchanged foundunchanged_count = 0# this is used to determine where is the end of the datamax_unchanged_count = 100last = -1data = []while True:current = RPi.GPIO.input(self.__pin)data.append(current)if last != current:unchanged_count = 0last = currentelse:unchanged_count += 1if unchanged_count > max_unchanged_count:breakreturn datadef __parse_data_pull_up_lengths(self, data):STATE_INIT_PULL_DOWN = 1STATE_INIT_PULL_UP = 2STATE_DATA_FIRST_PULL_DOWN = 3STATE_DATA_PULL_UP = 4STATE_DATA_PULL_DOWN = 5state = STATE_INIT_PULL_DOWNlengths = [] # will contain the lengths of data pull up periodscurrent_length = 0 # will contain the length of the previous periodfor i in range(len(data)):current = data[i]current_length += 1if state == STATE_INIT_PULL_DOWN:if current == RPi.GPIO.LOW:# ok, we got the initial pull downstate = STATE_INIT_PULL_UPcontinueelse:continueif state == STATE_INIT_PULL_UP:if current == RPi.GPIO.HIGH:# ok, we got the initial pull upstate = STATE_DATA_FIRST_PULL_DOWNcontinueelse:continueif state == STATE_DATA_FIRST_PULL_DOWN:if current == RPi.GPIO.LOW:# we have the initial pull down, the next will be the data pull upstate = STATE_DATA_PULL_UPcontinueelse:continueif state == STATE_DATA_PULL_UP:if current == RPi.GPIO.HIGH:# data pulled up, the length of this pull up will determine whether it is 0 or 1current_length = 0state = STATE_DATA_PULL_DOWNcontinueelse:continueif state == STATE_DATA_PULL_DOWN:if current == RPi.GPIO.LOW:# pulled down, we store the length of the previous pull up periodlengths.append(current_length)state = STATE_DATA_PULL_UPcontinueelse:continuereturn lengthsdef __calculate_bits(self, pull_up_lengths):# find shortest and longest periodshortest_pull_up = 1000longest_pull_up = 0for i in range(0, len(pull_up_lengths)):length = pull_up_lengths[i]if length < shortest_pull_up:shortest_pull_up = lengthif length > longest_pull_up:longest_pull_up = length# use the halfway to determine whether the period it is long or shorthalfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2bits = []for i in range(0, len(pull_up_lengths)):bit = Falseif pull_up_lengths[i] > halfway:bit = Truebits.append(bit)return bitsdef __bits_to_bytes(self, bits):the_bytes = []byte = 0for i in range(0, len(bits)):byte = byte << 1if (bits[i]):byte = byte | 1else:byte = byte | 0if ((i + 1) % 8 == 0):the_bytes.append(byte)byte = 0return the_bytesdef __calculate_checksum(self, the_bytes):return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255

(2)主文件app.py

  1. 这里要注意地址需要修改成自己主机的地址,查看树莓派地址的方式:在终端输入ifconfig然后回车。
  2. from-import是用来引用文件中的文件内容的。 title中的内容"Sensor Data"和html中的代码</>Sensor Data</>是对应的,如果想要修改,需要两边同时修改。
  3. time.sleep(1)的用处是让程序间隔一秒读取数据。这里的timesleep是python自带的一个函数,在编写程序时候,我们有时需要将程序短暂的停顿一下,这个时候就需要用到time包下面的sleep。
  4. 有的时候运行报错可能是因为端口的问题,尝试把port=50改成80/5080/8080之类的就好了。
from flask import Flask ,render_template
from library import dht11
import RPi.GPIO as GPIOapp = Flask(__name__)
# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()#read data using pin 14
instance = dht11.DHT11(pin=14)@app.route("/")
def hello():result = instance.read()time.sleep(1)temperature = result.temperaturehumidity = result.humiditytemplateData={'title': "Sensor Data",'temp': temperature,'hum': humidity,}       return render_template("index.html", **templateData)if __name__ == "__main__":app.run(host="192.168.1.xxx", port=50, debug=True)

(3)index.html

<!DOCTYPE html><head><html><head><title>{{title}}</title><link rel="stylesheet" href='../static/style.css'/></head><body><h1>Sensor Data</h1><h2>TEMPERATURE ==> {{ temp }} oC</h2><h3>HUMIDITY (Rel.) ==> {{ hum }} %</h3></body></html>

(4)style.css:用于美化html背景和字体颜色

body{background: blue;color: yellow;padding:1%
}
.button {font: bold 15px Arial;text-decoration: none;background-color: #EEEEEE;color: #333333;padding: 2px 6px 2px 6px;border-top: 1px solid #CCCCCC;border-right: 1px solid #333333;border-bottom: 1px solid #333333;border-left: 1px solid #CCCCCC;
}

基于 WEB 的室内温湿度监测系统(树莓派)相关推荐

  1. 基于物联网的远程温湿度监测系统 --- ESP8266 + 机智云

    基于物联网的远程温湿度监测系统 一.ESP-8266 烧录固件 二.机智云创建产品 三.手机端安装机智云 APP 四.编写 DHT11 驱动 五.机智云工程代码移植 六.采集数据的上发 七.控制数据的 ...

  2. 室内温湿度监测系统解决方案

    应用背景 我们正处于一个机械化.信息化的时代,各式各样的机械.仪器都需要处在一个合适的环境中才能良好运行,一些实验与生产性工作对环境也有特殊需求,对温湿度等指标进行监管和控制,才能保证生产生活的良好秩 ...

  3. ZigBee网络数据传递流程_基于ZigBee—WSN的温湿度监测系统

    摘要:针对环境监测系统布线复杂.数据的实时性和准确性低等问题,提出了一种基于ZigBee技术的分布式传感器网络平台.选用SHT75传感器实现对监测点温湿度信息的精准采集,并通过由CC2530芯片和CC ...

  4. 基于MQTT应用层协议的物联网家庭温湿度监测系统

    引言 出生于互联网时代的我们,见证了智能手机和个人电脑通过计算机网络互相进行连接,把每个人紧密地连接在一起,形成了一个地球村.而今,我们即将迈入5G时代,在通信技术不断发展的今天,连接到互联网的将不仅 ...

  5. 基于NB-IoT技术的环境温湿度监测系统的研制

    摘要 针对传统环境监测系统功耗高.维护成本高.不能实时监测的弊端,研制了一种以单片机为主控制芯片的基于 NB-IoT 技术的环境温湿度监测系统,并对主控制器的工作流程及通信模块的工作方式进行优化,降低 ...

  6. 基于arduino的温湿度监测系统的设计与实现

    以arduino开发板为控制器平台,采用dth11传感器采集温湿度数据,液晶显示屏显示温湿度数据,并对超出规定范围的数据用蜂鸣器报警提示,并实现与手机的基本交互. 一.需求分析 a.  温湿度的实时检 ...

  7. 基于STC89C51单片机的温湿度检测系统

    基于STC89C51单片机的温湿度检测系统 摘 要:设计一种计算机教室温度.湿度检测系统,用于控制机房的温.湿度.整个系统采用STC89C51微处理器作为主控系统,硬件电路主要包括51单片机.DHT1 ...

  8. java采集温湿度水浸_配电室水浸及温湿度监测系统可加强环境保障

    配电室水浸及温湿度监测系统有两大监测对象,一是管道.门窗等位置的漏水现象,二是室内各个位置的温度.湿度变化值,实现这两方面监测,能有效加强环境保障,降低漏水.高温.潮湿而引起的电力系统故障.设备损坏问 ...

  9. 温湿度服务器系统软件,无线温湿度监测系统

    系统介绍 无线温湿度监测系统有无线温湿度采集器(监测终端).无线温湿度接收管理主机(接收器)和本地软件.云服务器软件.手机APP组成,系统利用各类传输技术(433M.WIFI.TCP/IP.GPRS) ...

最新文章

  1. python *args 元组 **kargs 字典
  2. 大数据视域下网络涉军舆情管控研究
  3. docker 安装 oracle 11g
  4. 网路流程图 TCP/IP
  5. 如何检索Python函数的源代码
  6. Python学习笔记11:标准库之文件管理(os包,shutil包)
  7. ECMAScript 基础--原始值和引用值
  8. html+div+css+jquery+javascript的关系
  9. c语言获取pmbus之pec值
  10. KVM虚拟机迁移具体步骤
  11. 梵语和藏语_《百字明》梵文和藏文发音区分
  12. java表格居中_让表格水平垂直居中
  13. PostgreSQL文本搜索(七)——自定义配置
  14. 遇到问题--python--BLOB/TEXT column 'code' used in key specification without a key length
  15. 计算机类软件工程与测绘类遥感专业的薪水,2018遥感科学与技术专业就业前景和就业方向分析...
  16. java 线程的构造函数_深入理解Thread构造函数
  17. Oracle 错误总结及问题解决 ORA
  18. html中出现弹窗偏右,打印机打印某些网页时,右边总是打印不全,怎么办
  19. 华为服务器gpu芯片怎么样,云服务器gpu有多大
  20. 卡迪夫大数据专业排名_2019QS排名出炉啦!看看卡迪夫大学那些世界前百强的学科...

热门文章

  1. 建议保留:两个星期整理IO必学内容
  2. Android 单元测试之Mockito
  3. 【Android -- 学习笔记】ListView 详解
  4. grbl学习之旅---protocol篇
  5. 黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第五章 WEB黑客(3)暴力破解目录与文件位置
  6. pytorch学习-从入门到mnist(一)
  7. 使用国密函数读取金税盘信息-Delphi 版
  8. 进程间的通信--无名管道
  9. 王晓刚:深度学习在图像识别中的研究进展与展望
  10. 某信服EDR任意用户登陆漏洞分析