一、目的
这一节我们来学习如何使用合宙ESP32 C3,连接AHT20温湿传感器模块和BMP280压力传感器模块,使用ST7735屏幕进行显示。下面我们一起来学习一下吧!
二、环境
ESP32 C3开发板(MicroPython v1.19.1 on 2022-06-18)+ AHT20温湿度模块 + BMP280压力传感器模块 + TFT ST7735屏幕 + 几根杜邦线 + Win10商业版
ESP32 C3和各模块接线方法:
三、示例代码
example.py
from machine import Pin,I2C,SPI
from ahtx0 import AHT20
from bmp280 import BMP280
from st7735 import ST7735,color
from ufont import BMFont
import time
font = BMFont("fonts/unifont-14.0.04.bmf")
spi = SPI(1,baudrate = 60_000_000,polarity = 0,sck = Pin(2),mosi = Pin(3),miso = None)
tft = ST7735(spi,rst = 10,dc = 6,cs = 7,bl = 8, width = 160, height = 80,rotate = 1,rgb = True)
i2c = I2C(0,scl = Pin(5),sda = Pin(4),freq = 800_000)
bmp = BMP280(i2c,0x77)
aht = AHT20(i2c,0X38)
def dispaly():
try:
"""BMP280压力传感器信息"""
font.text(tft,"温度: %.2f ℃"%bmp.getTemp(),0,0,color(0,255,0),font_size = 16, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
font.text(tft,"压力: %.2f Pa"%bmp.getPress(),0,16,color(0,255,0),font_size = 16, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
font.text(tft,"海拔: %.2f m"%bmp.getAltitude(),0,32,color(0,255,0),font_size = 16, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
"""AHT20传感器信息"""
font.text(tft,"AHT20湿度: %.2f"%aht.relative_humidity + str(' ') + str('%'),0,48,color(255,255,255),font_size = 16, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
font.text(tft,"AHT20温度: %.2f ℃"%aht.temperature,0,64,color(255,255,255),font_size = 16, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
except:
RuntimeError
font.text(tft,"传感器异常!",50,24,color(0,255,0),font_size = 24, reverse = True,clear = False,show = True,half_char = True,auto_wrap = False)
def main():
for i in i2c.scan():
print("%#x "%i)
tft.back_light(200)
font.text(tft,"下班后实验室",8,24,color(0,255,0),font_size = 24, reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
time.sleep(2)
tft.clear()
tft.fill(color(255,0,0))
tft.show()
time.sleep(2)
tft.clear()
while True:
dispaly()
if __name__ == "__main__":
main()
四、AHT20驱动
ahtx0.py
# The MIT License (MIT)
#
# Copyright (c) 2020 Kattni Rembor for Adafruit Industries
# Copyright (c) 2020 Andreas Bühl
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
MicroPython driver for the AHT10 and AHT20 Humidity and Temperature Sensor
Author(s): Andreas Bühl, Kattni Rembor
"""
import utime
from micropython import const
class AHT10:
"""Interface library for AHT10/AHT20 temperature+humidity sensors"""
AHTX0_I2CADDR_DEFAULT = const(0x38) # Default I2C address
AHTX0_CMD_INITIALIZE = 0xE1 # Initialization command
AHTX0_CMD_TRIGGER = const(0xAC) # Trigger reading command
AHTX0_CMD_SOFTRESET = const(0xBA) # Soft reset command
AHTX0_STATUS_BUSY = const(0x80) # Status bit for busy
AHTX0_STATUS_CALIBRATED = const(0x08) # Status bit for calibrated
def __init__(self, i2c, address = None):
utime.sleep_ms(20) # 20ms delay to wake up
self._i2c = i2c
self._address = address
self._buf = bytearray(6)
self.reset()
if not self.initialize():
raise RuntimeError("Could not initialize")
self._temp = None
self._humidity = None
def reset(self):
"""Perform a soft-reset of the AHT"""
self._buf[0] = self.AHTX0_CMD_SOFTRESET
self._i2c.writeto(self._address, self._buf[0:1])
utime.sleep_ms(20) # 20ms delay to wake up
def initialize(self):
"""Ask the sensor to self-initialize. Returns True on success, False otherwise"""
self._buf[0] = self.AHTX0_CMD_INITIALIZE
self._buf[1] = 0x08
self._buf[2] = 0x00
self._i2c.writeto(self._address, self._buf[0:3])
self._wait_for_idle()
if not self.status & self.AHTX0_STATUS_CALIBRATED:
return False
return True
@property
def status(self):
"""The status byte initially returned from the sensor, see datasheet for details"""
self._read_to_buffer()
return self._buf[0]
@property
def relative_humidity(self):
"""The measured relative humidity in percent."""
self._perform_measurement()
self._humidity = (
(self._buf[1] << 12) | (self._buf[2] << 4) | (self._buf[3] >> 4)
)
self._humidity = (self._humidity * 100) / 0x100000
return self._humidity
@property
def temperature(self):
"""The measured temperature in degrees Celcius."""
self._perform_measurement()
self._temp = ((self._buf[3] & 0xF) << 16) | (self._buf[4] << 8) | self._buf[5]
self._temp = ((self._temp * 200.0) / 0x100000) - 50
return self._temp
def _read_to_buffer(self):
"""Read sensor data to buffer"""
self._i2c.readfrom_into(self._address, self._buf)
def _trigger_measurement(self):
"""Internal function for triggering the AHT to read temp/humidity"""
self._buf[0] = self.AHTX0_CMD_TRIGGER
self._buf[1] = 0x33
self._buf[2] = 0x00
self._i2c.writeto(self._address, self._buf[0:3])
def _wait_for_idle(self):
"""Wait until sensor can receive a new command"""
while self.status & self.AHTX0_STATUS_BUSY:
utime.sleep_ms(5)
def _perform_measurement(self):
"""Trigger measurement and write result to buffer"""
self._trigger_measurement()
self._wait_for_idle()
self._read_to_buffer()
class AHT20(AHT10):
AHTX0_CMD_INITIALIZE = 0xBE # Calibration command
五、bmp280驱动
bmp280.py
"""下班后实验室 https://space.bilibili.com/1349435951?spm_id_from=333.999.0.0"""
from micropython import const
from machine import I2C
class BMP280():
def __init__(self, i2c,address = None):
self.i2c = i2c
self.address = address
self.tb = bytearray(1)
self.rb = bytearray(1)
self.dig_T1 = self.get2Reg(0x88)
self.dig_T2 = self.short(self.get2Reg(0x8A))
self.dig_T3 = self.short(self.get2Reg(0x8C))
self.dig_P1 = self.get2Reg(0x8E)
self.dig_P2 = self.short(self.get2Reg(0x90))
self.dig_P3 = self.short(self.get2Reg(0x92))
self.dig_P4 = self.short(self.get2Reg(0x94))
self.dig_P5 = self.short(self.get2Reg(0x96))
self.dig_P6 = self.short(self.get2Reg(0x98))
self.dig_P7 = self.short(self.get2Reg(0x9A))
self.dig_P8 = self.short(self.get2Reg(0x9C))
self.dig_P9 = self.short(self.get2Reg(0x9E))
self.mode = 3
self.osrs_p = 3
self.osrs_t = 1
self.setReg(0xF4, 0x2F)
self.setReg(0xF5, 0x0C)
self.filter = 3
self.T = 0
self.P = 0
self.version = '1.0'
def short(self, dat):
if dat > 32767:
return dat - 65536
else:
return dat
# set reg
def setReg(self, reg, dat):
self.tb[0] = dat
self.i2c.writeto_mem(self.address, reg, self.tb)
# get reg
def getReg(self, reg):
self.i2c.readfrom_mem_into(self.address, reg, self.rb)
return self.rb[0]
# get two reg
def get2Reg(self, reg):
return self.getReg(reg) + self.getReg(reg+1) * 256
def get(self):
adc_T = (self.getReg(0xFA)<<12) + (self.getReg(0xFB)<<4) + (self.getReg(0xFC)>>4)
var1 = (((adc_T>>3)-(self.dig_T1<<1))*self.dig_T2)>>11
var2 = (((((adc_T>>4)-self.dig_T1)*((adc_T>>4) - self.dig_T1))>>12)*self.dig_T3)>>14
t = var1+var2
self.T = ((t * 5 + 128) >> 8)/100
var1 = (t>>1) - 64000
var2 = (((var1>>2) * (var1>>2)) >> 11 ) * self.dig_P6
var2 = var2 + ((var1*self.dig_P5)<<1)
var2 = (var2>>2)+(self.dig_P4<<16)
var1 = (((self.dig_P3*((var1>>2)*(var1>>2))>>13)>>3) + (((self.dig_P2) * var1)>>1))>>18
var1 = ((32768+var1)*self.dig_P1)>>15
if var1 == 0:
return # avoid exception caused by division by zero
adc_P = (self.getReg(0xF7)<<12) + (self.getReg(0xF8)<<4) + (self.getReg(0xF9)>>4)
p=((1048576-adc_P)-(var2>>12))*3125
if p < 0x80000000:
p = (p << 1) // var1
else:
p = (p // var1) * 2
var1 = (self.dig_P9 * (((p>>3)*(p>>3))>>13))>>12
var2 = (((p>>2)) * self.dig_P8)>>13
self.P = p + ((var1 + var2 + self.dig_P7) >> 4)
return [self.T, self.P]
# get Temperature in Celsius
def getTemp(self):
self.get()
return self.T
# get Pressure in Pa
def getPress(self):
self.get()
return self.P
# Calculating absolute altitude
def getAltitude(self):
return 44330*(1-(self.getPress()/101325)**(1/5.255))
# sleep mode
def poweroff(self):
self.setReg(0xF4, 0)
# normal mode
def poweron(self):
self.setReg(0xF4, 0x2F)
六、st7735屏幕驱动
st7735.py
"""
合宙 Air10x 系列屏幕扩展板驱动
160(H)RGB x 80(V)
使用方法(以合宙ESP32C3为例):
from machine import SPI, Pin
from st7735 import ST7735
spi = SPI(1, 30000000, sck=Pin(2), mosi=Pin(3))
ST7735(spi, rst=10, dc=6, cs=7, bl=11, width=160, height=80, rotate=1) # 直插横屏显示
ST7735(spi, rst=10, dc=6, cs=7, bl=11, width=160, height=80, rotate=0) # 直插竖屏显示
本款LCD使用的内置控制器为ST7735S,是一款162 x RGB x 132像素的LCD控制器,而本LCD本身的像素为160(H)RGB x 80(V)。由于LCD的显示
起始位置与控制器的原点不一致,因此在使用控制器初始化显示全屏显示区域时需要对做偏移处理:水平方向从第二个像素点开始显示,垂直方向从第27个像素点
开始。这样就可以保证显示的LCD中RAM对应的位置与实际一致。(https://www.waveshare.net/wiki/Pico-LCD-0.96)
屏幕详细信息: https://wiki.luatos.com/peripherals/lcd_air10x/index.html
ST7735S文档: https://www.waveshare.net/w/upload/e/e2/ST7735S_V1.1_20111121.pdf
FrameBuf文档: https://docs.micropython.org/en/latest/library/framebuf.html
"""
import gc
import time
import math
import machine
import framebuf
from micropython import const
SWRESET = const(0x01)
SLPOUT = const(0x11)
NORON = const(0x13)
INVOFF = const(0x20)
DISPON = const(0x29)
CASET = const(0x2A)
RASET = const(0x2B)
RAMWR = const(0x2C)
MADCTL = const(0x36)
COLMOD = const(0x3A)
FRMCTR1 = const(0xB1)
FRMCTR2 = const(0xB2)
FRMCTR3 = const(0xB3)
INVCTR = const(0xB4)
PWCTR1 = const(0xC0)
PWCTR2 = const(0xC1)
PWCTR3 = const(0xC2)
PWCTR4 = const(0xC3)
PWCTR5 = const(0xC4)
VMCTR1 = const(0xC5)
GMCTRP1 = const(0xE0)
GMCTRN1 = const(0xE1)
ROTATIONS = [0x00,0x60] # 只给了两个旋转方向
def color(r, g, b):
i = (((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3)).to_bytes(2, "little")
return (i[0] << 8) + i[1]
RED = color(255, 0, 0)
GREEN = color(0, 255, 0)
BLUE = color(0, 0, 255)
WHITE = color(255, 255, 255)
BLACK = color(0, 0, 0)
class ST7735(framebuf.FrameBuffer):
def __init__(self, spi, rst, dc, cs, bl=None, width=None, height=None, offset=None, rotate=1, rgb=True):
"""
:param spi:
:param rst:
:param dc:
:param cs: 使能
:param bl: 背光
:param width: 宽度
:param height: 高度
:param offset: 偏移 (x, y): (23, -1)|(-1, 23)
:param rotate: 旋转 0 横屏 1 竖屏
:param rgb: RGB 色彩模式
"""
# 根据方向自动设置偏移
self.rotate = rotate
self.offset = offset
self.rgb = rgb
if offset is None and rotate == 1:
self.offset = (-1, 23)
elif offset is None and rotate == 0:
self.offset = (23, -1)
self.width = width
self.height = height
self.spi = spi
self.rst = machine.Pin(rst, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.dc = machine.Pin(dc, machine.Pin.OUT, machine.Pin.PULL_DOWN)
self.cs = machine.Pin(cs, machine.Pin.OUT, machine.Pin.PULL_DOWN)
if bl is not None:
self.bl = machine.PWM(machine.Pin(bl))
gc.collect()
self.buffer = bytearray(self.height * self.width * 2)
super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
self.init()
self.set_windows()
self.clear()
def set_windows(self, x_start=None, y_start=None, x_end=None, y_end=None):
"""
设置窗口
:return:
"""
x_start = (x_start + self.offset[0] + 1) if x_start is not None else (self.offset[0] + 1)
x_end = x_end + self.rotate + self.offset[0] if x_end is not None else self.width + self.rotate + \
self.offset[0]
y_start = y_start + self.offset[1] + 1 if y_start is not None else self.offset[1] + 1
y_end = y_end + self.rotate + self.offset[1] if y_end is not None else self.height + self.rotate + \
self.offset[1]
self.write_cmd(CASET)
self.write_data(bytearray([0x00, x_start, 0x00, x_end]))
self.write_cmd(RASET)
self.write_data(bytearray([0x00, y_start, 0x00, y_end]))
self.write_cmd(RAMWR)
def init(self):
self.reset()
self.write_cmd(SWRESET)
time.sleep_us(150)
self.write_cmd(SLPOUT)
time.sleep_us(300)
self.write_cmd(FRMCTR1)
self.write_data(bytearray([0x01, 0x2C, 0x2D]))
self.write_cmd(FRMCTR2)
self.write_data(bytearray([0x01, 0x2C, 0x2D]))
self.write_cmd(FRMCTR3)
self.write_data(bytearray([0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D]))
time.sleep_us(10)
self.write_cmd(INVCTR)
self.write_data(bytearray([0x07]))
self.write_cmd(PWCTR1)
self.write_data(bytearray([0xA2, 0x02, 0x84]))
self.write_cmd(PWCTR2)
self.write_data(bytearray([0xC5]))
self.write_cmd(PWCTR3)
self.write_data(bytearray([0x0A, 0x00]))
self.write_cmd(PWCTR4)
self.write_data(bytearray([0x8A, 0x2A]))
self.write_cmd(PWCTR5)
self.write_data(bytearray([0x8A, 0xEE]))
self.write_cmd(VMCTR1)
self.write_data(bytearray([0x0E]))
self.write_cmd(INVOFF)
self.write_cmd(MADCTL)
self.write_data(bytearray([ROTATIONS[self.rotate] | 0x00 if self.rgb else 0x08]))
self.write_cmd(COLMOD)
self.write_data(bytearray([0x05]))
self.write_cmd(GMCTRP1)
self.write_data(
bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10]))
self.write_cmd(GMCTRN1)
self.write_data(
bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e, 0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10]))
self.write_cmd(NORON)
time.sleep_us(10)
self.write_cmd(DISPON)
time.sleep_us(100)
self.cs(1)
def reset(self):
"""
设备重置
:return:
"""
self.rst(1)
time.sleep(0.2)
self.rst(0)
time.sleep(0.2)
self.rst(1)
time.sleep(0.2)
def write_cmd(self, cmd):
self.dc(0)
self.cs(0)
self.spi.write(bytearray([cmd]))
self.cs(1)
def write_data(self, buf):
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
def back_light(self, value):
"""
背光调节
:param value: 背光等级 0 ~ 256
:return:
"""
self.bl.freq(1000)
if value >= 0xff:
value = 0xff
data = value * 0xffff >> 8
self.bl.duty_u16(data)
def clear(self):
"""
清屏
:return:
"""
self.fill(0)
self.show()
def show(self):
"""
显示
:return:
"""
self.set_windows() # 如果没有这行就会偏移
self.write_data(self.buffer)
def circle(self, center, radius, c=color(255, 255, 255), section=100):
"""
画圆
:param c: 颜色
:param center: 中心(x, y)
:param radius: 半径
:param section: 分段
:return:
"""
arr = []
for m in range(section + 1):
x = round(radius * math.cos((2 * math.pi / section) * m - math.pi) + center[0])
y = round(radius * math.sin((2 * math.pi / section) * m - math.pi) + center[1])
arr.append([x, y])
for i in range(len(arr) - 1):
self.line(*arr[i], *arr[i + 1], c)
def image(self, file_name):
with open(file_name, "rb") as bmp:
for b in range(0, 80 * 160 * 2, 1024):
self.buffer[b:b + 1024] = bmp.read(1024)
self.show()
七、操作字体文件方法库
ufont.py
__version__ = 3
import time
import struct
import framebuf
DEBUG = False
def 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() - t
print('Function {} Time = {:6.3f}ms'.format(myname, delta / 1000000))
return result
else:
return f(*args, **kwargs)
return new_func
class BMFont:
@staticmethod
def _list_to_byte(arr):
b = 0
for a in arr:
b = (b << 1) + a
return bytes([b])
@timeit
def _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
@timeit
def __init__(self, font_file):
self.font_file = font_file
self.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] # 点阵所占字节
@timeit
def _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 * 8
new_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) & 1
return new_bitarray
@timeit
def _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", color) if bit_list[_col][_row] else b'\x00\x00'
return color_array
@timeit
def _get_index(self, word):
"""获取索引
Args:
word: 字符
Returns:
"""
word_code = ord(word)
start = 0x10
end = self.start_bitmap
while start <= end:
mid = ((start + end) // 4) * 2
self.font.seek(mid, 0)
target_code = struct.unpack(">H", self.font.read(2))[0]
if word_code == target_code:
return (mid - 16) >> 1
elif word_code < target_code:
end = mid - 2
else:
start = mid + 2
return -1
@timeit
def 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)
@timeit
def 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_size
initial_x = x
# 清屏
try:
display.clear() if clear else 0
except 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_size
x = initial_x
# 回车
if string[char] == '\n':
y += font_size
x = initial_x
continue
# Tab
elif string[char] == '\t':
x = ((x // font_size) + 1) * font_size + initial_x % font_size
continue
# 其它的控制字符不显示
elif ord(string[char]) < 16:
continue
# 超过范围的字符不会显示*
if x > 160 or y > 80:
continue
byte_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 // 2
else:
x += font_size
display.show() if show else 0
def 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_size
byte_data = list(self.get_bitmap(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:
return self._color_render(bit_data, color)
else:
return self._bit_list_to_byte_data(bit_data)
else:
return bytearray(byte_data)
字体:
unifont-14.0.04.bmf
链接: https://pan.baidu.com/s/1YJi0oD0Bx3yQni02cDs0Kw 提取码: 59nd 复制这段内容后打开百度网盘手机App,操作更方便哦
八、模块购买
1,AHT20温湿度模块
2,bmp280压力传感器模块