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


    一、测试环境

    我们同样使用在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)
    51. tem_Min=int(temp)
    52. if int(humi)>hum_Max:
    53. hum_Max=int(humi)
    54. if int(humi)
    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_Minand Warn_hum_Min
    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

  • 相关阅读:
    【计划书】软件项目计划书(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