Micropython学习交流群 学习QQ群:786510434 提供多种固件下载和学习交流。
Micropython-扇贝物联 QQ群:31324057 扇贝物联是一个让你与智能设备沟通更方便的物联网云平台
Micropython学习交流群 学习QQ群:468985481 学习交流ESP8266、ESP32、ESP8285、wifi模块开发交流、物联网。
Micropython老哥俩的IT农场分享QQ群:929132891 为喜欢科创制作的小白们分享一些自制的计算机软硬件免费公益课程,由两位多年从事IT研发的中年大叔发起。
Micropython ESP32 C3连接GM12864屏幕ST7576驱动IC芯片
一、目的
这一节我们来学习如何使用合宙ESP32 C3,连接128x64点阵屏模块SPI接口液晶屏带字库,进行显示实验。
二、环境
ESP32 C3开发板(MicroPython v1.19.1 on 2022-06-18)+12864点阵屏模块 + 几根杜邦线 + Win10商业版
ESP32 C3和屏幕模块接线方法:
————————————————
main.py
from machine import Pin,SPI,PWM from st7567 import ST7567 from ufont import BMFont import time # 导入字库文件 font = BMFont("fonts/unifont-14-12888-16.v3.bmf") # 创建SPI对象 spi = SPI(1,baudrate = 40_000_000,sck = Pin(2),mosi = Pin(3),miso = None) # 波特率最大60兆 # 定义屏幕背光参数 blk = PWM(Pin(8),duty = (0),freq = (1000)) # 创建LCD屏幕对象。# invX内容反转,0x00或0x01 # invY显示反转,True或False lcd = ST7567(spi,dc = Pin(10,Pin.OUT),cs = Pin(7,Pin.OUT),rst = Pin(6,Pin.OUT),invX=0x00,invY=True,invdisp=0x00) # main函数 def main(): # 设置屏幕背光 num = 50 blk.duty(int(num/1000*1023)) # 显示中文 font.text(lcd,"魔都欢迎你",16,0,color=1,font_size=16,reverse=False,clear=False,show=True,half_char=True,auto_wrap=True) # 显示一条横线 lcd.hline(0,20,128,1) lcd.show() while True: # 动态化显示数值 for i in range(100): font.text(lcd,"数字:%.2d"%i,26,24,color=1,font_size=16,reverse=False,clear=False,show=True,half_char=True,auto_wrap=True) font.text(lcd,"Number:{0:2}".format(i),26,40,color=1,font_size=16,reverse=False,clear=False,show=True,half_char=True,auto_wrap=True) time.sleep(0.5) # 程序入口 if __name__ == "__main__": main()
st7567屏幕驱动
st7567.py
#Micro Python ST7567 128*64 lcd driver #You may need to set elecvolt and regratio to drive your screen properly from micropython import const import framebuf import time SET_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~0x0F class 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 port rst.init(rst.OUT,value=0)#reset device self.dc=dc self.cs=cs self.rst=rst self.spi=spi self.EV=elecvolt self.RR=regratio self.invX=0x00 if(invX==0) else 0x01#0x00:MX=0 normal dir, 0x01:MX=1 reverse dir self.invY=0x00 if(invY==0) else 0x08#0x00:MY=0 0x08:MY=1 self.invdisp=0x00 if(invdisp==0) else 0x01 self.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 done self.initscreen() time.sleep_ms(50) self.fill(0) self.show() self.write_cmd(DISP_ONOFF|0x01)#1:display on normal display mode def initscreen(self): self.write_cmd(SOFT_RST)#optional, I think it's useless self.write_cmd(SET_BOOST)#set booster mode self.write_cmd(0x00)#boost: 0x00:x4 0x01:x5 self.write_cmd(SET_BIAS|0x01)# 0:1/9 1:1/7 self.write_cmd(EVSET_MODE)#put device into EV setting mode self.write_cmd(self.EV)#0x00~0x3F set contrast to 0x1f with last command self.write_cmd(REGU_RATIO|self.RR)#0x00~0x07 3.0~6.5 self.write_cmd(POWER_CTRL|0x07)#7:{booster on,regulator on,follower on} self.write_cmd(INV_DISP|self.invdisp)#normal display self.write_cmd(ALL_PIX_ON|0x00)#0x00:normal display 0x01:all pixel on self.write_cmd(SEG_DIR|self.invX)#0:MX=0 normal dir, 1:MX=1 reverse dir self.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 port self.dc.value(0)#cmd mode self.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 port self.dc.value(1)#display data mode self.spi.write(data) #time.sleep_ms(1) self.cs.value(1)#disable device port def show(self): self.write_cmd(DISP_ONOFF|0x00) self.write_cmd(SRTLIN_SET|0x00) colcnt=0 pagcnt=0 while (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+=1 self.write_data(b"\x00") pagcnt+=1 self.write_cmd(DISP_ONOFF|0x01) def clear(self): self.fill(0) 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", 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 > 128 or y > 64: 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)
程序、字库文件以及屏幕资料下载
链接: https://pan.baidu.com/s/19gCH0w-6G6LkTredDdSlNQ 提取码: 75hh 复制这段内容后打开百度网盘手机App,操作更方便哦
版权声明:本文为CSDN博主「魔都飘雪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhusongziye/article/details/125455501
Copyright © 2014 ESP56.com All Rights Reserved
执行时间: 0.0085551738739014 seconds