Micropython学习交流群 学习QQ群:786510434 提供多种固件下载和学习交流。

Micropython-扇贝物联 QQ群:31324057 扇贝物联是一个让你与智能设备沟通更方便的物联网云平台

Micropython学习交流群 学习QQ群:468985481 学习交流ESP8266、ESP32、ESP8285、wifi模块开发交流、物联网。

Micropython老哥俩的IT农场分享QQ群:929132891 为喜欢科创制作的小白们分享一些自制的计算机软硬件免费公益课程,由两位多年从事IT研发的中年大叔发起。

Micropython ESP频道

Micropython ESP32 C3连接GM12864屏幕ST7576驱动IC芯片


Micropython ESP32 C3连接GM12864屏幕ST7576驱动IC芯片

652ba0d841d34e0ea92f368c1f2bf397.png

 一、目的


        这一节我们来学习如何使用合宙ESP32 C3,连接128x64点阵屏模块SPI接口液晶屏带字库,进行显示实验。


二、环境


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


        ESP32 C3和屏幕模块接线方法:

————————————————

9a30d1af98444d00b85cb6ac8d2559f9.png

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)


b9a6ceb3b3f948a5b5f0e748f91ac4e7.png

程序、字库文件以及屏幕资料下载

        链接: 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.0093979835510254 seconds