物联网开发123 - Micropython ESP32 C3连接AHT30温湿度传感器模块

一、目的

        这一节我们来学习如何使用合宙ESP32 C3,连接AHT30温湿度传感器模块,在12864 LCD点阵屏(ST7567驱动)上显示温度和湿度的值。下面我们一起来学习一下吧!

二、环境

        ESP32 C3开发板(MicroPython v1.19.1 on 2022-06-18)+ AHT30传感器模块 + 12864 LCD点阵屏 + 几根杜邦线 + Win10商业版

        ESP32 C3和各模块接线方法:

三、示例代码

example.py

from machine import Pin,I2C,SPI,PWM
from sht30 import SHT30,SHT30Error
from st7567 import ST7567
from ufont import BMFont
import time# 创建I2C对象
i2c = I2C(0,scl = Pin(5),sda = Pin(4),freq = 1_000_000)
print(i2c.scan())  # 打印出i2c的地址
# 创建温湿度传感器对象
sht = SHT30(i2c,0,0,0x44)  # 0x44是模块的I2C地址"""duty = 0-1023"""
blk  = PWM(Pin(8),duty = (0),freq = 1000)  # 定义LCD显示屏的背光
font = BMFont("unifont-14.0.04.bmf")  # 定义字体文件
# 创建SPI对象
spi = SPI(1,baudrate = 40_000_000,polarity=0,sck = Pin(2),mosi = Pin(3),miso = None)
# 创建屏幕对象
lcd = ST7567(spi,dc = Pin(10,Pin.OUT),cs = Pin(7,Pin.OUT),rst  = Pin(6,Pin.OUT),invX=0x00,invY=True,invdisp=0x00)#print("%#x"%i2c.scan()[0])# 创建屏幕显示函数
def dispaly():try :# 判断温湿度传感器是否连接上if sht.is_present() != True:font.text(lcd,"传感器异常!",20,24,color=1,font_size = 16,reverse = False,clear = True,show = True,half_char = True,auto_wrap = True)else:temp,huml = sht.measure()  # 测量温湿度# 将温湿度的数值显示在屏幕上font.text(lcd,"温度: %.2f 度"%temp,8,24,color=1,font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = True)font.text(lcd,"湿度: %.2f "%huml + str("%"),8,44,color=1,font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = True)#print("温度: %.2f ℃"%temp)#print("湿度: %.2f "%huml + str("%"))time.sleep(1)except SHT30Error as ex:  # 捕获异常print(ex)RuntimeError# 创建主函数
def main():# 设置背光Blk = 100  blk.duty(int((Blk/1000)*1023))# 显示文字font.text(lcd,"sht30 module",16,0,color=1,font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = True)# 显示2个横线lcd.hline(0,18,128,1)lcd.hline(0,20,128,1)lcd.show()while True:dispaly()if __name__ == "__main__":main()

演示效果:

 

四、aht30驱动

aht30.py

"""
https://space.bilibili.com/1349435951?spm_id_from=333.1007.0.0"""
from machine import Pin,I2C
import time# I2C address B 0x44 ADDR (pin 2) connected to GND
DEFAULT_I2C_ADDRESS = 0x44class SHT30:POLYNOMIAL = 0x131  # P(x) = x^8 + x^5 + x^4 + 1 = 100110001ALERT_PENDING_MASK = 0x8000     # 15HEATER_MASK = 0x2000            # 13RH_ALERT_MASK = 0x0800          # 11T_ALERT_MASK = 0x0400           # 10RESET_MASK = 0x0010             # 4CMD_STATUS_MASK = 0x0002        # 1WRITE_STATUS_MASK = 0x0001      # 0# MSB = 0x2C LSB = 0x06 Repeatability = High, Clock stretching = enabledMEASURE_CMD = b'\x2C\x10'STATUS_CMD = b'\xF3\x2D'RESET_CMD = b'\x30\xA2'CLEAR_STATUS_CMD = b'\x30\x41'ENABLE_HEATER_CMD = b'\x30\x6D'DISABLE_HEATER_CMD = b'\x30\x66'def __init__(self, i2c=None, delta_temp=0, delta_hum=0, i2c_address=None):if i2c is None:raise ValueError('An I2C object is required.')self.i2c = i2cself.i2c_addr = i2c_addressself.set_delta(delta_temp, delta_hum)time.sleep_ms(50)def is_present(self):"""Return true if the sensor is correctly conneced, False otherwise"""return self.i2c_addr in self.i2c.scan()def set_delta(self, delta_temp=0, delta_hum=0):"""Apply a delta value on the future measurements of temperature and/or humidityThe units are Celsius for temperature and percent for humidity (can be negative values)"""self.delta_temp = delta_tempself.delta_hum = delta_humdef _check_crc(self, data):# calculates 8-Bit checksum with given polynomialcrc = 0xFFfor b in data[:-1]:crc ^= bfor _ in range(8, 0, -1):if crc & 0x80:crc = (crc << 1) ^ SHT30.POLYNOMIALelse:crc <<= 1crc_to_check = data[-1]return crc_to_check == crcdef send_cmd(self, cmd_request, response_size=6, read_delay_ms=100):"""Send a command to the sensor and read (optionally) the responseThe responsed data is validated by CRC"""try:self.i2c.writeto(self.i2c_addr, cmd_request)if not response_size:returntime.sleep_ms(read_delay_ms)data = self.i2c.readfrom(self.i2c_addr, response_size)for i in range(response_size//3):if not self._check_crc(data[i*3:(i+1)*3]):  # pos 2 and 5 are CRCraise SHT30Error(SHT30Error.CRC_ERROR)if data == bytearray(response_size):raise SHT30Error(SHT30Error.DATA_ERROR)return dataexcept OSError:raise SHT30Error(SHT30Error.BUS_ERROR)except Exception as ex:raise exdef clear_status(self):"""Clear the status register"""return self.send_cmd(SHT30.CLEAR_STATUS_CMD, None)def reset(self):"""Send a soft-reset to the sensor"""return self.send_cmd(SHT30.RESET_CMD, None)def status(self, raw=False):"""Get the sensor status register.It returns a int value or the bytearray(3) if raw==True"""data = self.send_cmd(SHT30.STATUS_CMD, 3, read_delay_ms=20)if raw:return datastatus_register = data[0] << 8 | data[1]return status_registerdef measure(self, raw=False):"""If raw==True returns a bytearrya(6) with sensor direct measurement otherwiseIt gets the temperature (T) and humidity (RH) measurement and return them.The units are Celsius and percent"""data = self.send_cmd(SHT30.MEASURE_CMD, 6)if raw:return datat_celsius = (((data[0] << 8 |  data[1]) * 175) / 0xFFFF) - 45 + self.delta_temprh = (((data[3] << 8 | data[4]) * 100.0) / 0xFFFF) + self.delta_humreturn t_celsius, rhdef measure_int(self, raw=False):"""Get the temperature (T) and humidity (RH) measurement using integers.If raw==True returns a bytearrya(6) with sensor direct measurement otherwiseIt returns a tuple with 4 values: T integer, T decimal, H integer, H decimalFor instance to return T=24.0512 and RH= 34.662 This method will return(24, 5, 34, 66) Only 2 decimal digits are returned, .05 becomes 5Delta values are not applied in this methodThe units are Celsius and percent."""data = self.send_cmd(SHT30.MEASURE_CMD, 6)if raw:return dataaux = (data[0] << 8 | data[1]) * 175t_int = (aux // 0xffff) - 45t_dec = (aux % 0xffff * 100) // 0xffffaux = (data[3] << 8 | data[4]) * 100h_int = aux // 0xffffh_dec = (aux % 0xffff * 100) // 0xffffreturn t_int, t_dec, h_int, h_decclass SHT30Error(Exception):"""Custom exception for errors on sensor management"""BUS_ERROR = 0x01DATA_ERROR = 0x02CRC_ERROR = 0x03def __init__(self, error_code=None):self.error_code = error_codesuper().__init__(self.get_message())def get_message(self):if self.error_code == SHT30Error.BUS_ERROR:return "Bus error"elif self.error_code == SHT30Error.DATA_ERROR:return "Data error"elif self.error_code == SHT30Error.CRC_ERROR:return "CRC error"else:return "Unknown error"

五、LCD屏幕驱动

st7567.py

#Micro Python ST7567 128*64 lcd driver
#You may need to set elecvolt and regratio to drive your screen properlyfrom micropython import const
import framebuf
import timeSET_BIAS  =const(0xA2)
POWER_CTRL=const(0x28)
SET_BOOST =const(0xF8)
SOFT_RST  =const(0xE2)
SEG_DIR   =const(0xA0)
COM_DIR   =const(0xC0)
REGU_RATIO=const(0x20)
EVSET_MODE=const(0x81)
DISP_ONOFF=const(0xAE)
INV_DISP  =const(0xA6)#0:normal display 1:inverse
ALL_PIX_ON=const(0xA4)
SRTLIN_SET=const(0x40)#40~7F
PAGEAD_SET=const(0xB0)#b0~b8
COLHAD_SET=const(0x10)#0x10~0x1F
COLLAD_SET=const(0x00)#0x00~0x0Fclass ST7567(framebuf.FrameBuffer):def __init__(self,spi,dc,cs,rst,elecvolt=0x1F,regratio=0x03,invX=0x00,invY=0x00,invdisp=0x00):dc.init(dc.OUT,value=0)cs.init(cs.OUT,value=1)#disable device portrst.init(rst.OUT,value=0)#reset deviceself.dc=dcself.cs=csself.rst=rstself.spi=spiself.EV=elecvoltself.RR=regratioself.invX=0x00 if(invX==0) else 0x01#0x00:MX=0 normal dir, 0x01:MX=1 reverse dirself.invY=0x00 if(invY==0) else 0x08#0x00:MY=0 0x08:MY=1self.invdisp=0x00 if(invdisp==0) else 0x01self.buffer=bytearray(128*64//8)super().__init__(self.buffer,128,64,framebuf.MONO_VLSB)time.sleep_ms(1)self.rst.value(1)time.sleep_ms(1)#reset doneself.initscreen()time.sleep_ms(50)self.fill(0)self.show()self.write_cmd(DISP_ONOFF|0x01)#1:display on normal display modedef initscreen(self):self.write_cmd(SOFT_RST)#optional, I think it's uselessself.write_cmd(SET_BOOST)#set booster modeself.write_cmd(0x00)#boost: 0x00:x4 0x01:x5self.write_cmd(SET_BIAS|0x01)# 0:1/9 1:1/7self.write_cmd(EVSET_MODE)#put device into EV setting modeself.write_cmd(self.EV)#0x00~0x3F set contrast to 0x1f with last commandself.write_cmd(REGU_RATIO|self.RR)#0x00~0x07 3.0~6.5self.write_cmd(POWER_CTRL|0x07)#7:{booster on,regulator on,follower on}self.write_cmd(INV_DISP|self.invdisp)#normal displayself.write_cmd(ALL_PIX_ON|0x00)#0x00:normal display 0x01:all pixel onself.write_cmd(SEG_DIR|self.invX)#0:MX=0 normal dir, 1:MX=1 reverse dirself.write_cmd(COM_DIR|self.invY)#0x00:MY=0 0x08:MY=1 (may change to reverse y)def write_cmd(self,cmd):self.cs.value(0)#enable device portself.dc.value(0)#cmd modeself.spi.write(bytearray([cmd]))#time.sleep_ms(1)self.cs.value(1)#disable device port def write_data(self,data):self.cs.value(0)#enable device portself.dc.value(1)#display data modeself.spi.write(data)#time.sleep_ms(1)self.cs.value(1)#disable device portdef show(self):self.write_cmd(DISP_ONOFF|0x00)self.write_cmd(SRTLIN_SET|0x00)colcnt=0pagcnt=0while (pagcnt<9):self.write_cmd(PAGEAD_SET|pagcnt)self.write_cmd(COLHAD_SET|0x00)self.write_cmd(COLLAD_SET|0x00)if(pagcnt<8):self.write_data(self.buffer[(128*pagcnt):(128*pagcnt+128)])else:while (colcnt<128):colcnt+=1self.write_data(b"\x00")pagcnt+=1self.write_cmd(DISP_ONOFF|0x01)def clear(self):self.fill(0)self.show()

六、字体库

ufont.py

__version__ = 3import time
import structimport framebufDEBUG = Falsedef timeit(f, *args, **kwargs):try:myname = str(f).split(' ')[1]except:myname = "UNKONW"def new_func(*args, **kwargs):if DEBUG:try:t = time.ticks_us()result = f(*args, **kwargs)delta = time.ticks_diff(time.ticks_us(), t)print('Function {} Time = {:6.3f}ms'.format(myname, delta / 1000))except AttributeError:t = time.perf_counter_ns()result = f(*args, **kwargs)delta = time.perf_counter_ns() - tprint('Function {} Time = {:6.3f}ms'.format(myname, delta / 1000000))return resultelse:return f(*args, **kwargs)return new_funcclass BMFont:@staticmethoddef _list_to_byte(arr):b = 0for a in arr:b = (b << 1) + areturn bytes([b])@timeitdef _bit_list_to_byte_data(self, bit_list):"""将点阵转换为字节数据Args:bit_list:Returns:"""byte_data = b''for _col in bit_list:for i in range(0, len(_col), 8):byte_data += self._list_to_byte(_col[i:i + 8])return byte_data@timeitdef __init__(self, font_file):self.font_file = font_fileself.font = open(font_file, "rb", buffering=0xff)self.bmf_info = self.font.read(16)if self.bmf_info[0:2] != b"BM":raise TypeError("字体文件格式不正确: " + font_file)self.version = self.bmf_info[2]if self.version != 3:raise TypeError("字体文件版本不正确: " + str(self.version))self.map_mode = self.bmf_info[3]  # 映射方式self.start_bitmap = struct.unpack(">I", b'\x00' + self.bmf_info[4:7])[0]  # 位图开始字节self.font_size = self.bmf_info[7]  # 字体大小self.bitmap_size = self.bmf_info[8]  # 点阵所占字节@timeitdef _to_bit_list(self, byte_data, font_size, *, _height=None, _width=None):"""将字节数据转换为点阵数据Args:byte_data: 字节数据font_size: 字号大小_height: 字体原高度_width: 字体原宽度Returns:"""_height = _height or self.font_size_width = _width or self.bitmap_size // self.font_size * 8new_bitarray = [[0 for j in range(font_size)] for i in range(font_size)]for _col in range(len(new_bitarray)):for _row in range(len(new_bitarray[_col])):_index = int(_col / (font_size / _height)) * _width + int(_row / (font_size / _width))new_bitarray[_col][_row] = byte_data[_index // 8] >> (7 - _index % 8) & 1return new_bitarray@timeitdef _color_render(self, bit_list, color):"""将二值点阵图像转换为 RGB565 彩色字节图像Args:bit_list:color:Returns:"""color_array = b""for _col in range(len(bit_list)):for _row in range(len(bit_list)):color_array += struct.pack("H", self.font.read(2))[0]if word_code == target_code:return (mid - 16) >> 1elif word_code < target_code:end = mid - 2else:start = mid + 2return -1@timeitdef get_bitmap(self, word):"""获取点阵图Args:word: 字符Returns:bytes 字符点阵"""index = self._get_index(word)if index == -1:return b'\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x0f\xcf\xf3\xcf\xf3\xff\xf3\xff\xcf\xff?\xff?\xff\xff\xff' \b'?\xff?\xff\xff\xff\xff'self.font.seek(self.start_bitmap + index * self.bitmap_size, 0)return self.font.read(self.bitmap_size)@timeitdef text(self, display, string, x, y, color=1, *, font_size=None, reverse=False, clear=False, show=False,half_char=True, auto_wrap=False, **kwargs):"""通过显示屏显示文字使用此函数显示文字,必须先确认显示对象是否继承与 framebuf.FrameBuffer。如果显示对象没有 clear 方法,需要自行调用 fill 清屏Args:display: 显示实例string: 字符串x: 字体左上角 x 轴y: 字体左上角 y 轴color: 颜色font_size: 字号reverse: 是否反转背景clear: 是否清除之前显示的内容show: 是否立刻显示half_char: 是否半字节显示 ASCII 字符auto_wrap: 自动换行**kwargs:Returns:None"""font_size = font_size or self.font_sizeinitial_x = x# 清屏try:display.clear() if clear else 0except AttributeError:print("请自行调用 display.fill(*) 清屏")for char in range(len(string)):# 是否自动换行if auto_wrap:if auto_wrap and ((x + font_size // 2 >= 128 and ord(string[char]) < 128 and half_char) or(x + font_size >= 128 and (not half_char or ord(string[char]) > 128))):y += font_sizex = initial_x# 回车if string[char] == '\n':y += font_sizex = initial_xcontinue# Tabelif string[char] == '\t':x = ((x // font_size) + 1) * font_size + initial_x % font_sizecontinue# 其它的控制字符不显示elif ord(string[char]) < 16:continue# 超过范围的字符不会显示*if x > 128 or y > 64:continuebyte_data = list(self.get_bitmap(string[char]))# 反转if reverse:for _pixel in range(len(byte_data)):byte_data[_pixel] = ~byte_data[_pixel] & 0xff# 缩放和色彩*if color > 1 or font_size != self.font_size:bit_data = self._to_bit_list(byte_data, font_size)if color > 1:display.blit(framebuf.FrameBuffer(bytearray(self._color_render(bit_data, color)), font_size, font_size,framebuf.RGB565), x, y)else:display.blit(framebuf.FrameBuffer(bytearray(self._bit_list_to_byte_data(bit_data)), font_size, font_size,framebuf.MONO_HLSB), x, y)else:display.blit(framebuf.FrameBuffer(bytearray(byte_data), font_size, font_size, framebuf.MONO_HLSB), x, y)# 英文字符半格显示if ord(string[char]) < 128 and half_char:x += font_size // 2else:x += font_sizedisplay.show() if show else 0def char(self, char, color=1, font_size=None, reverse=False):""" 获取字体字节数据在没有继承 framebuf.FrameBuffer 的显示驱动,或者内存不足以将一整个屏幕载入缓存帧时可以直接获取单字的字节数据,局部更新Args:char: 单个字符color: 颜色font_size: 字体大小reverse: 反转Returns:bytearray"""font_size = font_size or self.font_sizebyte_data = list(self.get_bitmap(char))# 反转if reverse:for _pixel in range(len(byte_data)):byte_data[_pixel] = ~byte_data[_pixel] & 0xffif color > 1 or font_size != self.font_size:bit_data = self._to_bit_list(byte_data, font_size)if color > 1:return self._color_render(bit_data, color)else:return self._bit_list_to_byte_data(bit_data)else:return bytearray(byte_data)

七、bmf字体文件

请从下面下载哈。

链接: https://pan.baidu.com/s/12FZy0V4PAtyrCUZuCzn0PQ 提取码: 53g4 复制这段内容后打开百度网盘手机App,操作更方便哦

八、模块购买

1,AHT30温湿度传感器模块I2C通讯数字型 宽电压 传感器

资料下载链接: 百度网盘 请输入提取码https://pan.baidu.com/s/1J2n_odDFC5PQgYqbn8NQ1Q百度网盘 请输入提取码 提取码: ikmk

2,12864点阵屏12864模块SPI接口LCD点阵屏12864液晶屏带字库金逸晨

https://item.taobao.com/item.htm?spm=a1z09.2.0.0.2df52e8dfgvOlJ&id=687093213593&_u=kp01rch1506https://item.taobao.com/item.htm?spm=a1z09.2.0.0.2df52e8dfgvOlJ&id=687093213593&_u=kp01rch1506


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部