用ESP8266通过MicroPython调用DHT11、DHT22、DHT20温湿度传感器制作水床孵化器

之前有购买ESP8266和RDA5807M收音机模块,以及一些OLED屏等模块,大人的玩具。。。

 

前段时间看到某夕夕的推送,鹌鹑蛋的受精蛋,突发奇想自己制作个水床孵化器来孵化鹌鹑玩玩。

说干就干 花¥20买了三十五颗

 

 

下面就是制作孵化器,

原理就是通过ESP8266来读取DHT11温湿度传感器的数值控制继电器的硅胶发热丝通断电来控制温度。

手机充电器USB口接ESP8266,然后8266插到面包板上,PIN5和PIN4接OLED的SDA和SCL,3.3v引脚供电

ESP8266的VIN脚和GND脚给继电器和DHT11供电,标的是5V电压

ESP8266 GPIO2输出高低电平控制继电器通断

ESP8266 GPIO5读取DHT11温湿度

 

因为DHT11的分辨率是个位,所以在37和38度之间控制比较麻烦,所以我用变量来得到达到某个温度的时长,为的是防止在37和38度之间来回跳转导致的频繁通断电

DHT11的库在MicroPython有内置,所以比较简单,代码如下:

 1 import dht
 2 import machine
 3 import time
 4 from machine import Pin, I2C
 5 from ssd1306 import SSD1306_I2C
 6 
 7 #定义我们屏幕的两个接口
 8 scl = Pin(5, Pin.OUT)
 9 sda = Pin(4, Pin.OUT)
10 #定义继电器电平输出口
11 jidianqi = Pin(2, Pin.OUT)
12 jidianqi.value(0)
13 #初始化一个I2C对象,指定SCL 以及SDA脚
14 i2c = I2C(scl=scl, sda=sda)
15 #初始化一个SSD1306对象,需要给定屏幕的尺寸,128*64
16 oled = SSD1306_I2C(128, 64, i2c)
17 #清除屏幕
18 oled.fill(0)
19 #定义DHT11传感器输入口
20 sensor = dht.DHT11(machine.Pin(14));
21 
22 jishuqi = 0
23 wendu = 0
24 kg1 = 0
25 kg2 = 0
26 t = 0
27 high = 0
28 low = 0
29 
30 while True:
31     sensor.measure();
32     wd = 'WD:' + str(sensor.temperature()) + ',SD:' + str(sensor.humidity());
33     
34     if(sensor.temperature() > high):
35         high = sensor.temperature()
36     if(sensor.temperature() < low):
37         low = sensor.temperature()
38     if(sensor.temperature() != wendu):
39         wendu = sensor.temperature()
40         jishuqi = 0
41     if(kg2 == 1):
42         low = sensor.temperature()
43         
44     if(sensor.temperature() < 38):
45         if(jidianqi.value() == 0):
46             jishuqi = jishuqi + 1
47             if(jishuqi > 10):
48                 jidianqi.value(1)
49                 jishuqi = 0
50                 kg1 = kg1 + 1
51     
52     if(sensor.temperature() >= 38):
53         if(jidianqi.value() == 1):
54             jishuqi = jishuqi + 1
55             if(jishuqi > 10):
56                 jidianqi.value(0)
57                 jishuqi = 0
58                 kg2 = kg2 + 1
59     
60     t = t + 2
61     
62     oled.fill(0)
63     oled.text(wd, 10, 0)
64     oled.text('JS:' + str(jishuqi), 10, 10)
65     oled.text('HIGH:' + str(high) + ',LOW:' + str(low), 10, 30)
66     oled.text('OP:' + str(kg1) + ',CL:' + str(kg2), 10, 40)
67     oled.text('TIME:' + str(t) ,10, 50)
68     oled.show()
69     time.sleep(2)

 

之后的几天运行都比较好温度基本在37-39度之间徘徊,但在第九天的时候,我在例行翻蛋的时候突然发现孵化器里面的温度烫手

回过头来看OLED屏,温度和湿度的数值卡住不动了,即使我打开了孵化器盖子和毯子,温度也毫无波动

我才知道,完了,传感器卡死了!温度刚好在加温的37,导致继电器一直接通一直加热。

第一次孵化全军覆没。

 

定下来想了想可能是之前买的DHT11传感器不是奥松正品吧,后来又在某夕夕花¥18块买了个DHT22

想的是DHT22一个是分辨率到小数后一位,并且应该稳定的多吧

说干就干,又买了一批种蛋

在等待种蛋回来的几天,把代码改为了适配DHT22的,并且对算法进行了调整和优化

DHT22的库在MicroPython也有内置,所以也比较简单,调用即可,代码如下:

 1 import dht
 2 import machine
 3 import time
 4 from machine import Pin, I2C
 5 from ssd1306 import SSD1306_I2C
 6 
 7 #定义我们屏幕的两个接口
 8 scl = Pin(5, Pin.OUT)
 9 sda = Pin(4, Pin.OUT)
10 #定义继电器电平输出口
11 jidianqi = Pin(2, Pin.OUT)
12 jidianqi.value(0)
13 #初始化一个I2C对象,指定SCL 以及SDA脚
14 i2c = I2C(scl=scl, sda=sda)
15 #初始化一个SSD1306对象,需要给定屏幕的尺寸,128*64
16 oled = SSD1306_I2C(128, 64, i2c)
17 #清除屏幕
18 oled.fill(0)
19 #定义DHT11传感器输入口
20 sensor = dht.DHT22(machine.Pin(14))
21 
22 jishuqi = 0
23 wendu = 0
24 kg1 = 0
25 kg2 = 0
26 t = 0
27 high = 0
28 low = 0
29 
30 while True:
31     sensor.measure();
32     temperature = sensor.temperature();
33     wd = 'WD:' + str(temperature) + ',SD:' + str(sensor.humidity());
34     
35     if(temperature > high):
36         high = temperature
37     if(temperature < low):
38         low = temperature
39     if(temperature != wendu):
40         wendu = temperature
41         jishuqi = 0
42     else:
43         jishuqi += 1
44 
45     if(kg2 == 1):
46         low = temperature
47         
48     if(temperature < 37.8):
49         if(jidianqi.value() == 0):
50             jidianqi.value(1)
51             kg1 = kg1 + 1
52     
53     if(temperature >= 38.2):
54         if(jidianqi.value() == 1):
55             jidianqi.value(0)
56             kg2 = kg2 + 1
57     
58     t = t + 5
59     
60     oled.fill(0)
61     oled.text(wd, 0, 0)
62     oled.text('JS:' + str(jishuqi), 0, 10)
63     oled.text('HI:' + str(high) + ',LO:' + str(low), 0, 30)
64     oled.text('OP:' + str(kg1) + ',CL:' + str(kg2), 0, 40)
65     oled.text('TIME:' + str(t) ,0, 50)
66     oled.show()
67     time.sleep(5)

因为DHT22的刷新时间是2秒,到货后的一两天运行中HI的高温记录,有时会飚到50多度,但是检查水床温度并不是

因此怀疑是频繁读取导致的数值异常,之后把等待时间换为了5秒读一次,之后没有莫名高温了

但是在之后的一两天,还是出现过之前的问题,就是偶尔温度会卡死

我就纳闷了,为什么不同的传感器一样的问题

我又优化了部分程序算法记录了同一温度下的时长,以避免温度卡死了我不知道,以后看数值大小就知道这个温度多久了,是否异常

 

因为用万用表量了下ESP8266几个电源引脚的电压,vin的根本没达到5V,测得只有4.49V   而其它本该3.3V的也只有2.9左右

之后怀疑是继电器通断时产生的电压波动导致DHT22卡死,在esp8266的VIN 和 GND引脚间加了电容,防止继电器开合的电流波动影响传感器

 

可悲的是后期运行中依然有卡死现象,不过这次卡死的不是温度传感器,是ESP8266卡死了,因为屏幕数值全部不动了,温度卡在了37.8

而温度一直在加温,拔掉电源重新插上后是42度,好在发现的早。

现在怀疑是USB电源稳定性问题,以及8266的导致的电源损耗而达不到5V,索性换了个光电转换器用的5V 5.5*2.5接口的那种电源,

把线绞断后正负极接到了继电器的电源口,在通过继电器电源口回传到面包板上给传感器和8266供电

目前运行了两天,还算稳定,观察中。。。。

 

之前买的DHT22,收到的时候胶壳上没有丝印,也就是仿品吧,联系卖家也不回消息,十几块钱也懒得退了

随后闲逛,看到正品奥松新的DHT20传感器也才四五块钱还包邮

又买了个,不过这个不像之前的DHT11和DHT22那样有底座,它就光的模块,四个针脚

后来网上搜索MicroPython的DHT20库,懵逼了,没有。。。

到处找MicroPython的DHT20代码,国内居然没有!(PS:这也是发这篇博客的初衷!)

最后FQ出去找到了几个,从中找了个简单的来改了部分算法和逻辑分享出来,库代码如下:

 1 '''''''''
 2 本代码参考于以下页面
 3 http://47.106.166.129/Embeded/pico-micropython-grove
 4 '''''''''
 5 from machine import I2C
 6 from time import sleep_ms
 7 class DHT20(object):
 8     def __init__(self, i2c):
 9         self.i2c = i2c
10         if (self.read_status() & 0x80) == 0x80:
11             self.dht20_init()  
12             
13     def measure(self):
14         self.i2c.writeto(0x38, bytes([0xac,0x33,0x00]))
15         sleep_ms(80)
16         cnt = 0
17         while (self.read_status() & 0x80) == 0x80:
18             sleep_ms(1)
19             if cnt >= 100:
20                 cnt += 1
21                 break
22         data = self.i2c.readfrom(0x38, 7, True)
23         n = []
24         for i in data[:]:
25             n.append(i)
26         self.data = n
27         
28     def read_status(self):
29         data = self.i2c.readfrom(0x38, 1, True)
30         return data[0]
31     
32     def dht20_init(self):
33         i2c.writeto(0x38, bytes([0xa8,0x00,0x00]))
34         sleep_ms(10)
35         i2c.writeto(0x38, bytes([0xbe,0x08,0x00]))
36         
37     def calc_crc8(self,data):
38         crc = 0xff
39         for i in data[:-1]:
40             crc ^= i
41             for j in range(8):
42                 if crc & 0x80:
43                     crc = (crc << 1) ^ 0x31
44                 else:
45                     crc = (crc << 1)
46         return crc
47     
48     def temperature(self):
49         data = self.data
50         Temper = 0
51         if 1:
52             Temper = (Temper | data[3]) << 8
53             Temper = (Temper | data[4]) << 8
54             Temper = Temper | data[5]
55             Temper = Temper & 0xfffff
56             Temper = Temper / 1048576) * 200 - 50
57         return Temper
58         
59     def humidity(self):
60         data = self.data
61         humidity = 0
62         if 1:
63             humidity = (humidity | data[1]) << 8
64             humidity = (humidity | data[2]) << 8
65             humidity = humidity | data[3]
66             humidity = humidity >> 4
67             humidity = humidity / 1048576 * 100
68         return humidity

将上面的代码保存为DHT20.py  与调用代码放在一起,调用的话,用以下代码:

 1 import machine
 2 import time
 3 from machine import Pin, I2C
 4 from DHT20 import DHT20
 5 
 6 
 7 #定义我们DHT20的两个接口
 8 scl = Pin(5, Pin.OUT)
 9 sda = Pin(4, Pin.OUT)
10 
11 #初始化一个I2C对象,指定SCL 以及SDA脚
12 i2c = I2C(scl=scl, sda=sda)
13 
14 #初始化DHT20传感器
15 sensor = DHT20(i2c)
16 
17 while True:
18     sensor.measure()
19     print("温度:",str(sensor.temperature()))
20     print("湿度:",str(sensor.humidity()))
21     time.sleep(1)

DHT20的分辨率既然能达到小数位以下四位,真不错!          可惜我用不上。。。

 

posted @ 2022-08-08 22:23  孤灯空明  阅读(332)  评论(0)    收藏  举报