一、测试环境
我们同样使用在Wokwi网站上选择Micropython with ESP32进行仿真,来进行温度和湿度的检测。
ESP32官方技术参考手册:
二、硬件环境
温度湿度DHT22使用说明和显示屏ssd1366使用说明
wokwi-dht22 Reference | Wokwi DocsDigital Humidity and Temperature sensor.https://docs.wokwi.com/parts/wokwi-dht22board-ssd1306 Reference | Wokwi DocsMonochrome 128x64 OLED display with I2C interfacehttps://docs.wokwi.com/parts/board-ssd1306三、代码说明
main.py
- '''
- oled温湿度报警,
- 可手动设定警戒值的报警装置,可以用于一些特定环境的温湿度控制
- 可以自己设定间隔时间
- 可以通过串口进行最高最低温度的设置等,省的设置一堆按钮显得乱
- '''
- from machine import Pin,PWM,I2C,Timer,UART
- import time,machine,ssd1306,dht
-
- uart1=UART(1,115200) #调用串口uart1
- uart1.init(115200,bits=8,parity=None,stop=1) #初始化串口相关参数
- Tim_S=Timer(0) #定时器对象,很怪,有了这个定时器,下面的蜂鸣器没有了短促的鸣叫
- key=Pin(27, Pin.OUT) # 蜂鸣器接GPIO27口
- Buzzer= PWM(key) #定义蜂鸣器
- Buzzer.duty(0) #控制蜂鸣器初始关闭状态
- global data
- data = dht.DHT22(Pin(15)) #实例化15号管脚,21被占用了
- i2c = I2C(0, scl=Pin(22), sda=Pin(21)) #对应管脚
- oled_width = 128 ##画幅大小。oled屏幕宽度128
- oled_height = 64 #画幅大小。oled屏幕高度64
- oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) #调用,设置像素大小
- i=0
- space=3000 #设置数据更新时间,默认三秒,可修改但是要为整型。
- point=['','.','..','...'] #oled显示“...”动态,表示在工作
- Warn_tem_Max=29.0 # 设置最高温度。可修改为浮点型
- Warn_tem_Min=26.0 # 设置最高温度。可修改为浮点型
- Warn_hum_Max=60.0 # 设置最大湿度。可修改为浮点型
- Warn_hum_Min=40.0 # 设置最小湿度。可修改为浮点型
- L_Blue=Pin(2,Pin.OUT) #内置小灯,判断状态,命令设置成功闪亮
-
- def Voice_On(): #开启调用
- Buzzer.duty(512) #设置蜂鸣器占空比
- Buzzer.freq(2000) #设置蜂鸣器频率
- time.sleep(0.5)
- Buzzer.duty(0)
- time.sleep(0.5)
-
- def Voice_Off(): #关闭调用
- Buzzer.duty(0) #蜂鸣器关闭
-
- def Open_Test(t):
- data.measure() #先调用测量函数,获取温湿度
- global temp
- temp=data.temperature()
- global humi
- humi=data.humidity()
-
- def max_or_min():
- global tem_Max
- global tem_Min
- global hum_Max
- global hum_Min
- if int(temp)>tem_Max:
- tem_Max=int(temp)
- if int(temp)
- tem_Min=int(temp)
- if int(humi)>hum_Max:
- hum_Max=int(humi)
- if int(humi)
- hum_Min=int(humi)
-
- def Print():
- global i
- oled.text('Temp:'+str(temp), 0, 12)
- oled.text('Max:'+str(tem_Max), 0, 26) #空一段,最大最小
- oled.text('Min:'+str(tem_Min), 64, 26)
- oled.text('Humi:'+str(humi), 0,40)
- oled.text('Max:'+str(hum_Max), 0, 57)
- oled.text('Min:'+str(hum_Min), 64, 57)
- oled.text('working'+point[i%4], 25, 0)
- oled.show()
- time.sleep(0.2)
- oled.fill(0)
- i=i+1
-
- def Is_Int(Dir): #异常处理。整型
- try:
- int(Dir)
- return True
- except ValueError:
- pass
-
- def Is_Float(Dir): #异常处理。浮点型
- try:
- float(Dir)
- return True
- except ValueError:
- pass
-
- def twink():
- L_Blue.value(1)
- time.sleep(0.5)
- L_Blue.value(0)
- time.sleep(0.5)
- L_Blue.value(1)
- time.sleep(0.5)
- L_Blue.value(0)
- time.sleep(0.5)
-
- oled.fill(0) #清屏
- oled.text('Welcome!', 10, 10) #欢迎界面
- oled.show()
- time.sleep(0.5)
- oled.fill(0) #清屏
-
- Open_Test(0) #先调用,才能全局改变下面的变量
- Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
- #效果是到定义的时间就调用函数收集一下数据,但是程序依然在运行,到主函数后会因为未到指定时间
- #而不启用收集函数,导致主函数出错,所以需要在定时器之前先调用一下函数,
- #还有种办法,可以通过延时来达到等待函数运行后再去显示数据,但是因为后续会有自定义收集间隔
- #所以如果通过延时来处理还需要让延时时间变量与间隔相同
- #time.sleep(n)
-
- tem_Max=int(temp) #控制空间,整数,大概
- tem_Min=int(temp)
- hum_Max=int(humi)
- hum_Min=int(humi)
-
- #主程序负责数据的对比,定时器外部中断优先,保障间隔的准确
- while True: #循环获取温湿度
- if Warn_tem_Min
and Warn_hum_Min - Voice_Off()
- else:
- Voice_On()
- max_or_min()
- Print()
- #大概有几个口令:警报最大最小温度,湿度;采集时间间隔就这五个,
- #注意判断类型,命令或类型不正确的不予理会,设置成功有闪灯提醒
- if uart1.any()>0: #考虑放在定时器中,因为循环内很难监测到
- Dir=uart1.read()
- Dir=str(Dir) #转换为字符串型
- #Dir=Dir.lower(),字符小写就涉及到回车的问题,无法转变,会异常,所以我可以提前切出来想要的部分
- Dir=Dir[2:-3] #提前切掉b'...\n'这个东西,在让这个正常的字符串去变小写
- if Dir.find('space')>=0:
- Dir=Dir[5:]
- if Is_Int(Dir)==True:
- space=int(Dir)
- Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
- twink()
- elif Dir.find('tmax')>=0:
- Dir=Dir[4:]
- if Is_Float(Dir)==True:
- Warn_tem_Max=float(Dir)
- twink()
- elif Dir.find('tmin')>=0:
- Dir=Dir[4:]
- if Is_Float(Dir)==True:
- Warn_tem_Min=float(Dir)
- twink()
- elif Dir.find('hmax')>=0:
- Dir=Dir[4:]
- if Is_Float(Dir)==True:
- Warn_hum_Max=float(Dir)
- twink()
- elif Dir.find('hmin')>=0:
- Dir=Dir[4:]
- if Is_Float(Dir)==True:
- Warn_hum_Min=float(Dir)
- twink()
- #串口这部分也可以考虑写成函数,看起来能简洁些
diagram.json
- {
- "version": 1,
- "author": "魔都飘雪",
- "editor": "wokwi",
- "parts": [
- { "type": "wokwi-esp32-devkit-v1", "id": "esp", "top": -68.61, "left": -8.02, "attrs": {} },
- { "type": "wokwi-dht22", "id": "dht1", "top": -71.8, "left": 118.28, "attrs": {} },
- { "type": "board-ssd1306", "id": "oled1", "top": 23.53, "left": -135.32, "attrs": {} },
- {
- "type": "wokwi-buzzer",
- "id": "bz1",
- "top": -81.64,
- "left": -146.94,
- "attrs": { "volume": "0.5" }
- }
- ],
- "connections": [
- [ "esp:TX0", "$serialMonitor:RX", "", [] ],
- [ "esp:RX0", "$serialMonitor:TX", "", [] ],
- [ "dht1:VCC", "esp:3V3", "red", [ "v0" ] ],
- [ "dht1:SDA", "esp:D15", "green", [ "v0" ] ],
- [ "dht1:GND", "esp:GND.1", "black", [ "v0" ] ],
- [ "oled1:VCC", "esp:3V3", "red", [ "v-12.04", "h-51.43", "v113.03", "h241.73", "v-40.86" ] ],
- [
- "oled1:GND",
- "esp:GND.2",
- "black",
- [ "v-12.72", "h-41.98", "v114.4", "h127.33", "v-50.39" ]
- ],
- [ "oled1:SDA", "esp:D21", "green", [ "v-103.15", "h173.6", "v86.85" ] ],
- [ "bz1:1", "esp:GND.2", "green", [ "v8.67", "h101.46", "v72.79" ] ],
- [ "bz1:2", "esp:D27", "green", [ "v8.67", "h96.78", "v53.56" ] ],
- [ "oled1:SCL", "esp:D22", "green", [ "v-108.86", "h178.16", "v59.06" ] ]
- ],
- "serialMonitor": { "display": "plotter", "newline": "lf" }
- }
ssd1366.py(ssd1306屏幕的驱动)
- # MicroPython SSD1306 OLED driver, I2C and SPI interfaces
-
- from micropython import const
- import framebuf
- import math
-
-
- # register definitions
- SET_CONTRAST = const(0x81)
- SET_ENTIRE_ON = const(0xa4)
- SET_NORM_INV = const(0xa6)
- SET_DISP = const(0xae)
- SET_MEM_ADDR = const(0x20)
- SET_COL_ADDR = const(0x21)
- SET_PAGE_ADDR = const(0x22)
- SET_DISP_START_LINE = const(0x40)
- SET_SEG_REMAP = const(0xa0)
- SET_MUX_RATIO = const(0xa8)
- SET_COM_OUT_DIR = const(0xc0)
- SET_DISP_OFFSET = const(0xd3)
- SET_COM_PIN_CFG = const(0xda)
- SET_DISP_CLK_DIV = const(0xd5)
- SET_PRECHARGE = const(0xd9)
- SET_VCOM_DESEL = const(0xdb)
- SET_CHARGE_PUMP = const(0x8d)
-
-
- class SSD1306:
- def __init__(self, width, height, external_vcc, color=framebuf.MONO_VLSB):
- self.width = width
- self.height = height
- self.external_vcc = external_vcc
- self.pages = self.height // 8
- self.buffer = bytearray(self.pages * self.width)
- fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, color)
- self.framebuf = fb
- # Provide methods for accessing FrameBuffer graphics primitives. This is a
- # workround because inheritance from a native class is currently unsupported.
- # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
- self.fill = fb.fill
- self.pixel = fb.pixel
- self.hline = fb.hline
- self.vline = fb.vline
- self.line = fb.line
- self.rect = fb.rect
- self.fill_rect = fb.fill_rect
- self.text = fb.text
- self.scroll = fb.scroll
- self.blit = fb.blit
- self.init_display()
-
- def init_display(self):
- for cmd in (
- SET_DISP | 0x00, # off
- # address setting
- SET_MEM_ADDR, 0x00, # horizontal
- # resolution and layout
- SET_DISP_START_LINE | 0x00,
- SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
- SET_MUX_RATIO, self.height - 1,
- SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
- SET_DISP_OFFSET, 0x00,
- SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
- # timing and driving scheme
- SET_DISP_CLK_DIV, 0x80,
- SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
- SET_VCOM_DESEL, 0x30, # 0.83*Vcc
- # display
- SET_CONTRAST, 0xff, # maximum
- SET_ENTIRE_ON, # output follows RAM contents
- SET_NORM_INV, # not inverted
- # charge pump
- SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
- SET_DISP | 0x01): # on
- self.write_cmd(cmd)
- self.fill(0)
- self.show()
-
- def poweroff(self):
- self.write_cmd(SET_DISP | 0x00)
-
- def poweron(self):
- self.write_cmd(SET_DISP | 0x01)
-
- def contrast(self, contrast):
- self.write_cmd(SET_CONTRAST)
- self.write_cmd(contrast)
-
- def invert(self, invert):
- self.write_cmd(SET_NORM_INV | (invert & 1))
-
- def show(self):
- x0 = 0
- x1 = self.width - 1
- if self.width == 64:
- # displays with width of 64 pixels are shifted by 32
- x0 += 32
- x1 += 32
- self.write_cmd(SET_COL_ADDR)
- self.write_cmd(x0)
- self.write_cmd(x1)
- self.write_cmd(SET_PAGE_ADDR)
- self.write_cmd(0)
- self.write_cmd(self.pages - 1)
- self.write_data(self.buffer)
- #下面函数为添加的功能,根据pyboard板子厂商提供的例程修改
-
- def show_hanzi(self, row, col, charlist1):
- data = bytearray(charlist1)
- fbuf = framebuf.FrameBuffer(data, 16, 16, framebuf.MONO_VLSB)
- self.blit(fbuf,col,(row-1)*16)
- del fbuf
-
- def show_image(self, image_list):
- data = bytearray(image_list)
- fbuf = framebuf.FrameBuffer(data, 128, 96, framebuf.MONO_VLSB)
- self.blit(fbuf, 0, 0)
- del fbuf
-
-
- class SSD1306_I2C(SSD1306):
- def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False, color=framebuf.MONO_VLSB):
- self.i2c = i2c
- self.addr = addr
- self.temp = bytearray(2)
- super().__init__(width, height, external_vcc, color)
-
- def write_cmd(self, cmd):
- self.temp[0] = 0x80 # Co=1, D/C#=0
- self.temp[1] = cmd
- self.i2c.writeto(self.addr, self.temp)
-
- def write_data(self, buf):
- self.i2c.writeto(self.addr, b'\x40' + buf)
-
-
- class SSD1306_SPI(SSD1306):
- def __init__(self, width, height, spi, dc, res, cs, external_vcc=False, color=framebuf.MONO_VLSB):
- self.rate = 10 * 1024 * 1024
- dc.init(dc.OUT, value=0)
- res.init(res.OUT, value=0)
- cs.init(cs.OUT, value=1)
- self.spi = spi
- self.dc = dc
- self.res = res
- self.cs = cs
- import time
- self.res(1)
- time.sleep_ms(1)
- self.res(0)
- time.sleep_ms(10)
- self.res(1)
- super().__init__(width, height, external_vcc, color)
-
- def write_cmd(self, cmd):
- self.spi.init(baudrate=self.rate, polarity=0, phase=0)
- self.cs(1)
- self.dc(0)
- self.cs(0)
- self.spi.write(bytearray([cmd]))
- self.cs(1)
-
- def write_data(self, buf):
- self.spi.init(baudrate=self.rate, polarity=0, phase=0)
- self.cs(1)
- self.dc(1)
- self.cs(0)
- self.spi.write(buf)
- self.cs(1)
是不是,很简单!来看看效果:
也可以在网页上查看实际效果:
Wokwi Arduino and ESP32 Simulatorhttps://wokwi.com/projects/341771399848788563
-
相关阅读:
【计划书】软件项目计划书(Word原件直接套用)
Vue一些你不知道的东西
随机森林算法深入浅出
用nodejs爬虫台湾痞客邦相册
Visual Studio部署C++矩阵库Armadillo的方法
面向面试编程:分布式ID生成策略(二)
Python自动化测试实战 真实项目-Web自动化测试从方案到实战落地(二)
深度学习Course2第一周Practical aspects of Deep Learning习题整理
java Boolean 比较
新版TCGA的甲基化数据分析
-
原文地址:https://blog.csdn.net/zhusongziye/article/details/126682077