用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的分辨率既然能达到小数位以下四位,真不错! 可惜我用不上。。。

浙公网安备 33010602011771号