在树莓派上使用Python实现对温度,湿度以及光照强度的实施测量

准备

最近接到一个任务,要实现对环境温度,湿度以及光照强度的动态测量并用实时曲线来表示出来。我选择了在树莓派3上使用Python开发这个程序。所采用的器件如下:

  1. 温度湿度传感器DHT11
  2. 光照强度传感器GY30
  3. 树莓派3 

在开发的过程中我参考了一下DHT11和GY30器件的驱动代码:

DHT11:http://blog.csdn.net/u010900754/article/details/53078615?locationNum=13&fps=1

GY30:http://blog.csdn.net/weixiazailaide/article/details/52782458

另外绘制动态曲线图也参考了以下这个链接的代码:

http://blog.sina.com.cn/s/blog_6baac06c0101g7sd.html

需要注意的是这个链接的代码有一点问题,可自行修改。

硬件接线

树莓派2的GPIO引脚图如下所示:
在树莓派上使用Python实现对温度,湿度以及光照强度的实施测量_第1张图片
DTH11的接线:
GND 34脚
DAT 40脚
VCC 04脚
GY30的接线:
VCC 01脚
SCL 05脚
SDA 03脚
AD0 不接
GND 09脚

代码修改

本次开发基于绘制动态曲线的python程序(见上面的链接):
例程的第6行后面的"\"符号在运行时python提示出错,将其删除并下面的一行提到import后就可以了。
另外该例程的作者对第44行的代码的注释为 
# force a draw on the canvas()   
# trick to show the grid and the legend 
我猜作者的意思是避免每次更新时都要重画网格和图例以节省时间。但是这会引起每次更新时的重绘偏移了位置,见下面的说明:
错误的情况:
在树莓派上使用Python实现对温度,湿度以及光照强度的实施测量_第2张图片
可以看到最上方的图例上面有一条横线,另外我用于测试的初始值是10,可以明显地看到图像向下偏移了。
正确的情况:
在树莓派上使用Python实现对温度,湿度以及光照强度的实施测量_第3张图片
偏移已经消除,最上方的多余横线已经消失,曲线刚好在10的位置。
解决这个小问题的方法接下来会提到。

包含模块

import wx  
from matplotlib.figure import Figure  
import matplotlib.font_manager as font_manager  
import numpy as np  
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import smbus
import time
import RPi.GPIO as GPIO

包含的模块除了需要画图的模块之外,还需要smbus,time以及Rpi.GPIO这三个模块。
在运行这个例程时需要事先安装wxPython以及matplotlib。
注意安装完wxPython之后最好重启一下树莓派。

将DHT11以及GY30驱动代码定义的全局变量添加到PlotFigure类中

class PlotFigure(wx.Frame):  
    """Matplotlib wxFrame with animation effect"""  
    def __init__(self):
    	#自定义变量,保存湿度和温度值
        self.Humi=0
        self.Temp=0
        
        #DHT11的变量
        #BH1750(DHT11)地址
        self.__DEV_ADDR = 0x23
        #控制字
        self.__CMD_PWR_OFF=0x00  #关机
        self.__CMD_PWR_ON=0x01   #开机
        self.__CMD_RESET=0x07    #重置
        self.__CMD_CHRES=0x10    #持续高分辨率检测
        self.__CMD_CHRES2=0x11   #持续高分辨率模式2检测
        self.__CMD_CLHRES=0x13   #持续低分辨率检测
        self.__CMD_THRES=0x20    #一次高分辨率
        self.__CMD_THRES2=0x21   #一次高分辨率模式2
        self.__CMD_TLRES=0x23    #一次分辨率
        self.__CMD_SEN100H=0x42  #灵敏度100%,高位
        self.__CMD_SEN100L=0X65  #灵敏度100%,低位
        self.__CMD_SEN50H=0x44   #50%
        self.__CMD_SEN50L=0x6A   #50%
        self.__CMD_SEN200H=0x41  #200%
        self.__CMD_SEN200L=0x73  #200%

初始化部分

初始化部分基本上就是为绘制实时曲线图的做准备,不过这个应用是同时对三个变量同时监测,因此需要多个子图。我在原来的程序上稍微修改了一下,多添加了两个子图:
wx.Frame.__init__(self, None, wx.ID_ANY, title="illumination,tempature and humidity Monitor", size=(600, 600))  
        # Matplotlib Figure  
        self.fig = Figure((6, 6), 100)  
        # bind the Figure to the backend specific canvas  
        self.canvas = FigureCanvas(self, wx.ID_ANY, self.fig)

        # subplot 0 
        self.ax = self.fig.add_subplot(311)    
        self.ax.set_ylim([0, 100])  
        self.ax.set_xlim([0, POINTS])  
        self.ax.set_autoscale_on(False)  
        self.ax.set_xticks([])   
        self.ax.set_yticks(range(0, 2020, 200))  
        self.ax.grid(True)  
        self.user = [None] * POINTS  
        self.l_user,=self.ax.plot(range(POINTS),self.user,label='illumination lx')  
        self.ax.legend(loc='upper center', ncol=4, prop=font_manager.FontProperties(size=10))  
      
        # subplot 1
        self.ax1=self.fig.add_subplot(312)
        self.ax1.set_ylim([0, 100])  
        self.ax1.set_xlim([0, POINTS])
        self.ax1.set_autoscale_on(False)  
        self.ax1.set_xticks([])   
        self.ax1.set_yticks(range(0, 101, 10))   
        self.ax1.grid(True)   
        self.user1 = [None] * POINTS  
        self.l_user1,=self.ax1.plot(range(POINTS),self.user1,label='tempature *C')
        self.ax1.legend(loc='upper center', ncol=4, prop=font_manager.FontProperties(size=10))

        # subplot 2
        self.ax2=self.fig.add_subplot(313)
        self.ax2.set_ylim([0, 100])  
        self.ax2.set_xlim([0, POINTS])
        self.ax2.set_autoscale_on(False)  
        self.ax2.set_xticks([])  
        self.ax2.set_yticks(range(0, 101, 10))  
        self.ax2.grid(True)  
        self.user2 = [None] * POINTS  
        self.l_user2,=self.ax2.plot(range(POINTS),self.user2,label='humidity %RH')
        self.ax2.legend(loc='upper center', ncol=4, prop=font_manager.FontProperties(size=10)) 
      	
        # save the clean background - everything but the line  
        # is drawn and saved in the pixel buffer background  
        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)
        self.bg1 = self.canvas.copy_from_bbox(self.ax1.bbox)
        self.bg2 = self.canvas.copy_from_bbox(self.ax2.bbox)
        
        # bind events coming from timer with id = TIMER_ID  
        # to the onTimer callback function
        wx.EVT_TIMER(self, TIMER_ID, self.onTimer

对温湿度模块DHT11代码的调整

   while j < 40:
            k = 0
            while GPIO.input(channel) == GPIO.LOW:
                continue
            while GPIO.input(channel) == GPIO.HIGH:
                k += 1
                if k > 140:
                    break
            if k < 15:
                data.append(0)
            else:
                data.append(1)
            j += 1
不得不说温湿度模块DHT11是一个非常不灵敏的模块,每次获得数据都要经过1.2秒左右,而且结果还可能是错误的。1秒是为了略过不稳定的状态,0.2毫秒是用于保持GPIO脚低电平,然后再拉高。我对这个模块的代码仅仅修改了k的下限和上限,DHT11的例程提供的k的下限原来为3,上限原来为100,而DHT11文档建议的k值是20。如果下限值过小,那么判决的接收到的每一位都是0,结果就是全0;如果下限值过大,那么判决的接收到的每一位都是1,结果就是全1即255。另外上限值140是估计是为了防止发生异常而设置的。对于k下限值的设置可以自己调整一下,已达到最好的效果。上限值影响不大。

对定时器回调函数的修改

def onTimer(self, evt):    
	#subplot 0
        self.canvas.restore_region(self.bg)  #恢复原来的背景
        lx=self.getIlluminance()	#获取光照强度
        self.user = self.user[1:] + [lx] 
        self.l_user.set_ydata(self.user)
        self.ax.draw_artist(self.l_user)
        self.canvas.draw() #更新标题和网格
        self.canvas.blit(self.ax.bbox) #绘制到画布上
				
	#subplot1
        self.GetTempHumi()    #获取温度和湿度
        self.canvas.restore_region(self.bg1)
        self.user1 = self.user1[1:] + [self.Temp]
        self.l_user1.set_ydata(self.user1) #subplot 1
        self.ax1.draw_artist(self.l_user1)
        self.canvas.draw()
        self.canvas.blit(self.ax1.bbox) 
				
	#subplot2
        self.canvas.restore_region(self.bg2)
        self.l_user2.set_ydata(self.user2) #subplot 2  
        self.user2 = self.user2[1:] + [self.Humi]
        self.ax2.draw_artist(self.l_user2)
        self.canvas.draw()
        self.canvas.blit(self.ax2.bbox)
前面已经说过绘制实时折线图的时候图像会向下偏移。经过测试我发现调用
restore_region
函数的结果是正确的,那么这就说明了是对blit函数的调用出错了。联想到出错的地方与网格(grid)和图例(legend)显示有关,又想起作者提到的那个trick,于是我就将对
draw
的调用放到对
blit
的调用之前,这样问题就解决了:例程的作者估计是为了节省开销而不多次调用draw,实际上这是不可以的,会出现绘图偏移的错误。

不足

  1. 鉴于DHT11这个模块的性能,这个程序的更新时间大约为1.2秒,实在有点慢。
  2. 对Figure((6,6),100)这个函数调用还不是很清楚。不能理解第一个参数的意义。
  3. 程序有时会不稳定。
由于本人对Python不是非常的熟悉,如果遇到有错误的地方请多指教。












你可能感兴趣的:(在树莓派上使用Python实现对温度,湿度以及光照强度的实施测量)