当前位置:   article > 正文

物联网开发笔记(9)- 使用Wokwi仿真MicroPython on ESP32开发板实现温度和湿度检测并使用屏幕显示_wokwi仿真平台

wokwi仿真平台

一、测试环境

我们同样使用在Wokwi网站上选择Micropython with ESP32进行仿真,来进行温度和湿度的检测。

ESP32官方技术参考手册:

https://www.espressif.com.cn/sites/default/files/documentation/esp32_technical_reference_manual_en.pdfhttps://www.espressif.com.cn/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf中文资料可查看乐鑫官网:

技术文档 | 乐鑫科技Downloads: SDK & Demos, APKs, Tools and Documents for Espressif Systems products and solutionshttps://www.espressif.com.cn/zh-hans/support/documents/technical-documents

二、硬件环境

温度湿度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

  1. '''
  2. oled温湿度报警,
  3. 可手动设定警戒值的报警装置,可以用于一些特定环境的温湿度控制
  4. 可以自己设定间隔时间
  5. 可以通过串口进行最高最低温度的设置等,省的设置一堆按钮显得乱
  6. '''
  7. from machine import Pin,PWM,I2C,Timer,UART
  8. import time,machine,ssd1306,dht
  9. uart1=UART(1,115200) #调用串口uart1
  10. uart1.init(115200,bits=8,parity=None,stop=1) #初始化串口相关参数
  11. Tim_S=Timer(0) #定时器对象,很怪,有了这个定时器,下面的蜂鸣器没有了短促的鸣叫
  12. key=Pin(27, Pin.OUT) # 蜂鸣器接GPIO27口
  13. Buzzer= PWM(key) #定义蜂鸣器
  14. Buzzer.duty(0) #控制蜂鸣器初始关闭状态
  15. global data
  16. data = dht.DHT22(Pin(15)) #实例化15号管脚,21被占用了
  17. i2c = I2C(0, scl=Pin(22), sda=Pin(21)) #对应管脚
  18. oled_width = 128 ##画幅大小。oled屏幕宽度128
  19. oled_height = 64 #画幅大小。oled屏幕高度64
  20. oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) #调用,设置像素大小
  21. i=0
  22. space=3000 #设置数据更新时间,默认三秒,可修改但是要为整型。
  23. point=['','.','..','...'] #oled显示“...”动态,表示在工作
  24. Warn_tem_Max=29.0 # 设置最高温度。可修改为浮点型
  25. Warn_tem_Min=26.0 # 设置最高温度。可修改为浮点型
  26. Warn_hum_Max=60.0 # 设置最大湿度。可修改为浮点型
  27. Warn_hum_Min=40.0 # 设置最小湿度。可修改为浮点型
  28. L_Blue=Pin(2,Pin.OUT) #内置小灯,判断状态,命令设置成功闪亮
  29. def Voice_On(): #开启调用
  30. Buzzer.duty(512) #设置蜂鸣器占空比
  31. Buzzer.freq(2000) #设置蜂鸣器频率
  32. time.sleep(0.5)
  33. Buzzer.duty(0)
  34. time.sleep(0.5)
  35. def Voice_Off(): #关闭调用
  36. Buzzer.duty(0) #蜂鸣器关闭
  37. def Open_Test(t):
  38. data.measure() #先调用测量函数,获取温湿度
  39. global temp
  40. temp=data.temperature()
  41. global humi
  42. humi=data.humidity()
  43. def max_or_min():
  44. global tem_Max
  45. global tem_Min
  46. global hum_Max
  47. global hum_Min
  48. if int(temp)>tem_Max:
  49. tem_Max=int(temp)
  50. if int(temp)<tem_Min:
  51. tem_Min=int(temp)
  52. if int(humi)>hum_Max:
  53. hum_Max=int(humi)
  54. if int(humi)<tem_Max:
  55. hum_Min=int(humi)
  56. def Print():
  57. global i
  58. oled.text('Temp:'+str(temp), 0, 12)
  59. oled.text('Max:'+str(tem_Max), 0, 26) #空一段,最大最小
  60. oled.text('Min:'+str(tem_Min), 64, 26)
  61. oled.text('Humi:'+str(humi), 0,40)
  62. oled.text('Max:'+str(hum_Max), 0, 57)
  63. oled.text('Min:'+str(hum_Min), 64, 57)
  64. oled.text('working'+point[i%4], 25, 0)
  65. oled.show()
  66. time.sleep(0.2)
  67. oled.fill(0)
  68. i=i+1
  69. def Is_Int(Dir): #异常处理。整型
  70. try:
  71. int(Dir)
  72. return True
  73. except ValueError:
  74. pass
  75. def Is_Float(Dir): #异常处理。浮点型
  76. try:
  77. float(Dir)
  78. return True
  79. except ValueError:
  80. pass
  81. def twink():
  82. L_Blue.value(1)
  83. time.sleep(0.5)
  84. L_Blue.value(0)
  85. time.sleep(0.5)
  86. L_Blue.value(1)
  87. time.sleep(0.5)
  88. L_Blue.value(0)
  89. time.sleep(0.5)
  90. oled.fill(0) #清屏
  91. oled.text('Welcome!', 10, 10) #欢迎界面
  92. oled.show()
  93. time.sleep(0.5)
  94. oled.fill(0) #清屏
  95. Open_Test(0) #先调用,才能全局改变下面的变量
  96. Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
  97. #效果是到定义的时间就调用函数收集一下数据,但是程序依然在运行,到主函数后会因为未到指定时间
  98. #而不启用收集函数,导致主函数出错,所以需要在定时器之前先调用一下函数,
  99. #还有种办法,可以通过延时来达到等待函数运行后再去显示数据,但是因为后续会有自定义收集间隔
  100. #所以如果通过延时来处理还需要让延时时间变量与间隔相同
  101. #time.sleep(n)
  102. tem_Max=int(temp) #控制空间,整数,大概
  103. tem_Min=int(temp)
  104. hum_Max=int(humi)
  105. hum_Min=int(humi)
  106. #主程序负责数据的对比,定时器外部中断优先,保障间隔的准确
  107. while True: #循环获取温湿度
  108. if Warn_tem_Min<temp<Warn_tem_Max and Warn_hum_Min<humi<Warn_hum_Max:
  109. Voice_Off()
  110. else:
  111. Voice_On()
  112. max_or_min()
  113. Print()
  114. #大概有几个口令:警报最大最小温度,湿度;采集时间间隔就这五个,
  115. #注意判断类型,命令或类型不正确的不予理会,设置成功有闪灯提醒
  116. if uart1.any()>0: #考虑放在定时器中,因为循环内很难监测到
  117. Dir=uart1.read()
  118. Dir=str(Dir) #转换为字符串型
  119. #Dir=Dir.lower(),字符小写就涉及到回车的问题,无法转变,会异常,所以我可以提前切出来想要的部分
  120. Dir=Dir[2:-3] #提前切掉b'...\n'这个东西,在让这个正常的字符串去变小写
  121. if Dir.find('space')>=0:
  122. Dir=Dir[5:]
  123. if Is_Int(Dir)==True:
  124. space=int(Dir)
  125. Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
  126. twink()
  127. elif Dir.find('tmax')>=0:
  128. Dir=Dir[4:]
  129. if Is_Float(Dir)==True:
  130. Warn_tem_Max=float(Dir)
  131. twink()
  132. elif Dir.find('tmin')>=0:
  133. Dir=Dir[4:]
  134. if Is_Float(Dir)==True:
  135. Warn_tem_Min=float(Dir)
  136. twink()
  137. elif Dir.find('hmax')>=0:
  138. Dir=Dir[4:]
  139. if Is_Float(Dir)==True:
  140. Warn_hum_Max=float(Dir)
  141. twink()
  142. elif Dir.find('hmin')>=0:
  143. Dir=Dir[4:]
  144. if Is_Float(Dir)==True:
  145. Warn_hum_Min=float(Dir)
  146. twink()
  147. #串口这部分也可以考虑写成函数,看起来能简洁些

diagram.json

  1. {
  2. "version": 1,
  3. "author": "魔都飘雪",
  4. "editor": "wokwi",
  5. "parts": [
  6. { "type": "wokwi-esp32-devkit-v1", "id": "esp", "top": -68.61, "left": -8.02, "attrs": {} },
  7. { "type": "wokwi-dht22", "id": "dht1", "top": -71.8, "left": 118.28, "attrs": {} },
  8. { "type": "board-ssd1306", "id": "oled1", "top": 23.53, "left": -135.32, "attrs": {} },
  9. {
  10. "type": "wokwi-buzzer",
  11. "id": "bz1",
  12. "top": -81.64,
  13. "left": -146.94,
  14. "attrs": { "volume": "0.5" }
  15. }
  16. ],
  17. "connections": [
  18. [ "esp:TX0", "$serialMonitor:RX", "", [] ],
  19. [ "esp:RX0", "$serialMonitor:TX", "", [] ],
  20. [ "dht1:VCC", "esp:3V3", "red", [ "v0" ] ],
  21. [ "dht1:SDA", "esp:D15", "green", [ "v0" ] ],
  22. [ "dht1:GND", "esp:GND.1", "black", [ "v0" ] ],
  23. [ "oled1:VCC", "esp:3V3", "red", [ "v-12.04", "h-51.43", "v113.03", "h241.73", "v-40.86" ] ],
  24. [
  25. "oled1:GND",
  26. "esp:GND.2",
  27. "black",
  28. [ "v-12.72", "h-41.98", "v114.4", "h127.33", "v-50.39" ]
  29. ],
  30. [ "oled1:SDA", "esp:D21", "green", [ "v-103.15", "h173.6", "v86.85" ] ],
  31. [ "bz1:1", "esp:GND.2", "green", [ "v8.67", "h101.46", "v72.79" ] ],
  32. [ "bz1:2", "esp:D27", "green", [ "v8.67", "h96.78", "v53.56" ] ],
  33. [ "oled1:SCL", "esp:D22", "green", [ "v-108.86", "h178.16", "v59.06" ] ]
  34. ],
  35. "serialMonitor": { "display": "plotter", "newline": "lf" }
  36. }

ssd1366.py(ssd1306屏幕的驱动)

  1. # MicroPython SSD1306 OLED driver, I2C and SPI interfaces
  2. from micropython import const
  3. import framebuf
  4. import math
  5. # register definitions
  6. SET_CONTRAST = const(0x81)
  7. SET_ENTIRE_ON = const(0xa4)
  8. SET_NORM_INV = const(0xa6)
  9. SET_DISP = const(0xae)
  10. SET_MEM_ADDR = const(0x20)
  11. SET_COL_ADDR = const(0x21)
  12. SET_PAGE_ADDR = const(0x22)
  13. SET_DISP_START_LINE = const(0x40)
  14. SET_SEG_REMAP = const(0xa0)
  15. SET_MUX_RATIO = const(0xa8)
  16. SET_COM_OUT_DIR = const(0xc0)
  17. SET_DISP_OFFSET = const(0xd3)
  18. SET_COM_PIN_CFG = const(0xda)
  19. SET_DISP_CLK_DIV = const(0xd5)
  20. SET_PRECHARGE = const(0xd9)
  21. SET_VCOM_DESEL = const(0xdb)
  22. SET_CHARGE_PUMP = const(0x8d)
  23. class SSD1306:
  24. def __init__(self, width, height, external_vcc, color=framebuf.MONO_VLSB):
  25. self.width = width
  26. self.height = height
  27. self.external_vcc = external_vcc
  28. self.pages = self.height // 8
  29. self.buffer = bytearray(self.pages * self.width)
  30. fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, color)
  31. self.framebuf = fb
  32. # Provide methods for accessing FrameBuffer graphics primitives. This is a
  33. # workround because inheritance from a native class is currently unsupported.
  34. # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
  35. self.fill = fb.fill
  36. self.pixel = fb.pixel
  37. self.hline = fb.hline
  38. self.vline = fb.vline
  39. self.line = fb.line
  40. self.rect = fb.rect
  41. self.fill_rect = fb.fill_rect
  42. self.text = fb.text
  43. self.scroll = fb.scroll
  44. self.blit = fb.blit
  45. self.init_display()
  46. def init_display(self):
  47. for cmd in (
  48. SET_DISP | 0x00, # off
  49. # address setting
  50. SET_MEM_ADDR, 0x00, # horizontal
  51. # resolution and layout
  52. SET_DISP_START_LINE | 0x00,
  53. SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
  54. SET_MUX_RATIO, self.height - 1,
  55. SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
  56. SET_DISP_OFFSET, 0x00,
  57. SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
  58. # timing and driving scheme
  59. SET_DISP_CLK_DIV, 0x80,
  60. SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
  61. SET_VCOM_DESEL, 0x30, # 0.83*Vcc
  62. # display
  63. SET_CONTRAST, 0xff, # maximum
  64. SET_ENTIRE_ON, # output follows RAM contents
  65. SET_NORM_INV, # not inverted
  66. # charge pump
  67. SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
  68. SET_DISP | 0x01): # on
  69. self.write_cmd(cmd)
  70. self.fill(0)
  71. self.show()
  72. def poweroff(self):
  73. self.write_cmd(SET_DISP | 0x00)
  74. def poweron(self):
  75. self.write_cmd(SET_DISP | 0x01)
  76. def contrast(self, contrast):
  77. self.write_cmd(SET_CONTRAST)
  78. self.write_cmd(contrast)
  79. def invert(self, invert):
  80. self.write_cmd(SET_NORM_INV | (invert & 1))
  81. def show(self):
  82. x0 = 0
  83. x1 = self.width - 1
  84. if self.width == 64:
  85. # displays with width of 64 pixels are shifted by 32
  86. x0 += 32
  87. x1 += 32
  88. self.write_cmd(SET_COL_ADDR)
  89. self.write_cmd(x0)
  90. self.write_cmd(x1)
  91. self.write_cmd(SET_PAGE_ADDR)
  92. self.write_cmd(0)
  93. self.write_cmd(self.pages - 1)
  94. self.write_data(self.buffer)
  95. #下面函数为添加的功能,根据pyboard板子厂商提供的例程修改
  96. def show_hanzi(self, row, col, charlist1):
  97. data = bytearray(charlist1)
  98. fbuf = framebuf.FrameBuffer(data, 16, 16, framebuf.MONO_VLSB)
  99. self.blit(fbuf,col,(row-1)*16)
  100. del fbuf
  101. def show_image(self, image_list):
  102. data = bytearray(image_list)
  103. fbuf = framebuf.FrameBuffer(data, 128, 96, framebuf.MONO_VLSB)
  104. self.blit(fbuf, 0, 0)
  105. del fbuf
  106. class SSD1306_I2C(SSD1306):
  107. def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False, color=framebuf.MONO_VLSB):
  108. self.i2c = i2c
  109. self.addr = addr
  110. self.temp = bytearray(2)
  111. super().__init__(width, height, external_vcc, color)
  112. def write_cmd(self, cmd):
  113. self.temp[0] = 0x80 # Co=1, D/C#=0
  114. self.temp[1] = cmd
  115. self.i2c.writeto(self.addr, self.temp)
  116. def write_data(self, buf):
  117. self.i2c.writeto(self.addr, b'\x40' + buf)
  118. class SSD1306_SPI(SSD1306):
  119. def __init__(self, width, height, spi, dc, res, cs, external_vcc=False, color=framebuf.MONO_VLSB):
  120. self.rate = 10 * 1024 * 1024
  121. dc.init(dc.OUT, value=0)
  122. res.init(res.OUT, value=0)
  123. cs.init(cs.OUT, value=1)
  124. self.spi = spi
  125. self.dc = dc
  126. self.res = res
  127. self.cs = cs
  128. import time
  129. self.res(1)
  130. time.sleep_ms(1)
  131. self.res(0)
  132. time.sleep_ms(10)
  133. self.res(1)
  134. super().__init__(width, height, external_vcc, color)
  135. def write_cmd(self, cmd):
  136. self.spi.init(baudrate=self.rate, polarity=0, phase=0)
  137. self.cs(1)
  138. self.dc(0)
  139. self.cs(0)
  140. self.spi.write(bytearray([cmd]))
  141. self.cs(1)
  142. def write_data(self, buf):
  143. self.spi.init(baudrate=self.rate, polarity=0, phase=0)
  144. self.cs(1)
  145. self.dc(1)
  146. self.cs(0)
  147. self.spi.write(buf)
  148. self.cs(1)

 是不是,很简单!来看看效果:

也可以在网页上查看实际效果:

Wokwi Arduino and ESP32 Simulatoricon-default.png?t=M7J4https://wokwi.com/projects/341771399848788563

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/378723
推荐阅读
相关标签
  

闽ICP备14008679号