基于esp32 C3的micropython星座风格的桌面时钟制作保姆级教程(4)

这一节,我们来说说st7789怎么显示图片,我这边是参考的王铭东王老师的方法(某站上学习的),我放下他的网站链接:it项目网www.itprojects.cn

st7789的驱动图片程序,st7789_itprojects.py:

import ustruct
import utime


_NOP = const(0x00)
_SWRESET = const(0x01)
_RDDID = const(0x04)
_RDDST = const(0x09)

_SLPIN = const(0x10)
_SLPOUT = const(0x11)
_PTLON = const(0x12)
_NORON = const(0x13)

_INVOFF = const(0x20)
_INVON = const(0x21)
_DISPOFF = const(0x28)
_DISPON = const(0x29)
_CASET = const(0x2A)
_RASET = const(0x2B)
_RAMWR = const(0x2C)
_RAMRD = const(0x2E)

_PTLAR = const(0x30)
_COLMOD = const(0x3A)
_MADCTL = const(0x36)

_FRMCTR1 = const(0xB1)
_FRMCTR2 = const(0xB2)
_FRMCTR3 = const(0xB3)
_INVCTR = const(0xB4)
_DISSET5 = const(0xB6)
_GCTRL = const(0xB7)
_VCOMS  =  const(0xBB)
_FRCTR2 = const(0xC6)
_D6H = const(0xD6)
_PWCTRL1 = const(0xD0)
_GATECTRL = const(0xE4)

_PWCTR1 = const(0xC0)
_PWCTR2 = const(0xC1)
_PWCTR3 = const(0xC2)
_PWCTR4 = const(0xC3)
_PWCTR5 = const(0xC4)
_VMCTR1 = const(0xC5)

_RDID1 = const(0xDA)
_RDID2 = const(0xDB)
_RDID3 = const(0xDC)
_RDID4 = const(0xDD)

_PWCTR6 = const(0xFC)

_GMCTRP1 = const(0xE0)
_GMCTRN1 = const(0xE1)


def color565(r, g, b):
    return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3


class DummyPin:
    """A fake gpio pin for when you want to skip pins."""

    OUT = 0
    IN = 0
    PULL_UP = 0
    PULL_DOWN = 0
    OPEN_DRAIN = 0
    ALT = 0
    ALT_OPEN_DRAIN = 0
    LOW_POWER = 0
    MED_POWER = 0
    HIGH_PWER = 0
    IRQ_FALLING = 0
    IRQ_RISING = 0
    IRQ_LOW_LEVEL = 0
    IRQ_HIGH_LEVEL = 0

    def __call__(self, *args, **kwargs):
        return False

    init = __call__
    value = __call__
    out_value = __call__
    toggle = __call__
    high = __call__
    low = __call__
    on = __call__
    off = __call__
    mode = __call__
    pull = __call__
    drive = __call__
    irq = __call__


class Display:
    _PAGE_SET = None
    _COLUMN_SET = None
    _RAM_WRITE = None
    _RAM_READ = None
    _INIT = ()
    _ENCODE_PIXEL = ">H"
    _ENCODE_POS = ">HH"
    _DECODE_PIXEL = ">BBB"

    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.init()

    def init(self):
        """Run the initialization commands."""
        for command, data in self._INIT:
            self._write(command, data)

    def _block(self, x0, y0, x1, y1, data=None):
        """Read or write a block of data."""
        self._write(self._COLUMN_SET, self._encode_pos(x0, x1))
        self._write(self._PAGE_SET, self._encode_pos(y0+80, y1+80))
        if data is None:
            size = ustruct.calcsize(self._DECODE_PIXEL)
            return self._read(self._RAM_READ, (x1 - x0 + 1) * (y1 - y0 + 1) * size)
    
        self._write(self._RAM_WRITE, data)

    def _encode_pos(self, a, b):
        """Encode a postion into bytes."""
        return ustruct.pack(self._ENCODE_POS, a, b)

    def _encode_pixel(self, color):
        """Encode a pixel color into bytes."""
        return ustruct.pack(self._ENCODE_PIXEL, color)

    def _decode_pixel(self, data):
        """Decode bytes into a pixel color."""
        return color565(*ustruct.unpack(self._DECODE_PIXEL, data))

    def pixel(self, x, y, color=None):
        """Read or write a pixel."""
        if color is None:
            return self._decode_pixel(self._block(x, y, x, y))
        if not 0 <= x < self.width or not 0 <= y < self.height:
            return
        self._block(x, y, x, y, self._encode_pixel(color))

    def fill_rectangle(self, x, y, width, height, color):
        """Draw a filled rectangle."""
        x = min(self.width - 1, max(0, x))
        y = min(self.height - 1, max(0, y))
        w = min(self.width - x, max(1, width))
        h = min(self.height - y, max(1, height))
        self._block(x, y, x + w - 1, y + h - 1, b'')
        chunks, rest = divmod(w * h, 512)
        print("color:", color)
        pixel = self._encode_pixel(color)
        print("decode:", pixel)
        if chunks:
            data = pixel * 512
            for count in range(chunks):
                self._write(None, data)
        if rest:
            self._write(None, pixel * rest)

    def fill(self, color=0):
        """Fill whole screen."""
        self.fill_rectangle(0, 0, self.width, self.height, color)

    def hline(self, x, y, width, color):
        """Draw a horizontal line."""
        self.fill_rectangle(x, y, width, 1, color)

    def vline(self, x, y, height, color):
        """Draw a vertical line."""
        self.fill_rectangle(x, y, 1, height, color)

    def blit_buffer(self, buffer, x, y, width, height):
        """Copy pixels from a buffer."""
        if (not 0 <= x < self.width or
            not 0 <= y < self.height or
            not 0 < x + width <= self.width or
            not 0 < y + height <= self.height):
                raise ValueError("out of bounds")
        self._block(x, y, x + width - 1, y + height - 1, buffer)


class DisplaySPI(Display):
    def __init__(self, spi, dc, cs=None, rst=None, width=1, height=1):
        self.spi = spi
        self.cs = cs
        self.dc = dc
        self.rst = rst
        if self.rst is None:
            self.rst = DummyPin()
        if self.cs is None:
            self.cs = DummyPin()
        self.cs.init(self.cs.OUT, value=1)
        self.dc.init(self.dc.OUT, value=0)
        self.rst.init(self.rst.OUT, value=1)
        self.reset()
        super().__init__(width, height)

    def reset(self):
        self.rst(0)
        utime.sleep_ms(50)
        self.rst(1)
        utime.sleep_ms(50)

    def _write(self, command=None, data=None):
        if command is not None:
            self.dc(0)
            self.cs(0)
            self.spi.write(bytearray([command]))
            self.cs(1)
        if data:
            self.dc(1)
            self.cs(0)
            self.spi.write(data)
            self.cs(1)

    def _read(self, command=None, count=0):
        self.dc(0)
        self.cs(0)
        if command is not None:
            self.spi.write(bytearray([command]))
        if count:
            data = self.spi.read(count)
        self.cs(1)
        return data


class ST7789(DisplaySPI):
    """
    A simple driver for the ST7789-based displays.
    >>> from machine import Pin, SPI
    >>> import st7789
    >>> display = st7789.ST7789(SPI(1), dc=Pin(12), cs=Pin(15), rst=Pin(16))
    >>> display = st7789.ST7789R(SPI(1, baudrate=40000000), dc=Pin(12), cs=Pin(15), rst=Pin(16))
    >>> display.fill(0x7521)
    >>> display.pixel(64, 64, 0)
    """
    _COLUMN_SET = _CASET
    _PAGE_SET = _RASET
    _RAM_WRITE = _RAMWR
    _RAM_READ = _RAMRD
    _INIT = (
        (_SWRESET, None),
        (_SLPOUT, None),
        (_COLMOD, b"\x55"),  # 16bit color
        (_MADCTL, b"\x08"),
    )

    def __init__(self, spi, dc, cs, rst=None, width=240, height=240):
        super().__init__(spi, dc, cs, rst, width, height)

    def init(self):

        super().init()
        cols = ustruct.pack(">HH", 0, self.width)
        rows = ustruct.pack(">HH", 0, self.height)
        # ctr2p= ustruct.pack(">BBBBB", b"\x1F\x1F\x00\x33\x33")
        ctr2p= b"\x1F\x1F\x00\x33\x33"
        # ctr1p= ustruct.pack(">BB", b"\xA4\xA1")
        ctr1p= b"\xA4\xA1"
        # e0p= ustruct.pack(">BBBBBBBBBBBBBB", b"\xF0\x08\x0E\x09\x08\x04\x2F\x33\x45\x36\x13\x12\x2A\x2D")
        e0p= b"\xF0\x08\x0E\x09\x08\x04\x2F\x33\x45\x36\x13\x12\x2A\x2D"
        # e1p= ustruct.pack(">BBBBBBBBBBBBBB", b"\xF0\x0E\x12\x0C\x0A\x15\x2E\x32\x44\x39\x17\x18\x2B\x2F")
        e1p= b"\xF0\x0E\x12\x0C\x0A\x15\x2E\x32\x44\x39\x17\x18\x2B\x2F"
        # gatep= ustruct.pack(">BBB", b"\x1d\x00\x00")
        gatep= b"\x1d\x00\x00"
        for command, data in (
            (_CASET, cols),
            (_RASET, rows),
            (_FRMCTR2,ctr2p),
            (_GCTRL, b"\x00"),
            (_VCOMS, b"\x36"),
            (_PWCTR3, b"\x01"),
            (_PWCTR4, b"\x13"),
            (_PWCTR5, b"\x20"),
            (_FRCTR2, b"\x13"),
            (_D6H, b"\xA1"),
            (_PWCTRL1, ctr1p),
            (_GMCTRP1, e0p),
            (_GMCTRN1, e1p),
            (_GATECTRL, gatep),
            (_INVON, None),
            (_NORON, None),
            (_DISPON, None),
            (_MADCTL, b"\xc0"),  # Set rotation to 0 and use RGB
        ):
            self._write(command, data)


class ST7889_Image(ST7789):
    
    def _set_columns(self, start, end):
        if start <= end:
            self._write(_CASET, self._encode_pos(start, end))
            
    def _set_rows(self, start, end):
        if start <= end:
            self._write(_RASET, self._encode_pos(start, end))
    
    def _set_window(self, x0, y0, x1, y1):
        """
    
        """
        self._set_columns(x0, x1)
        self._set_rows(y0, y1)
        self._write(_RAMWR)
        
    def show_img(self, x0, y0, x1, y1, img_data):
        self._set_window(x0, y0 + 80, x1, y1 + 80)
        self._write(None, img_data)
    


王铭东老师的显示原理是,将png图片转化为包含颜色信息的bmp图片,再将bmp文件转化为dat文件,在st7789上面显示出来

这里先附一下png转化为bmp的程序:

from PIL import Image

def convert_png_to_bgm(input_path, output_path):
    # 打开PNG图片
    image = Image.open(input_path)
    
    # 将图片转换为BGM格式
    image.save(output_path, "BMP")

然后是bmp转化为dat文件的程序:

import os
import sys
from PIL import Image
import numpy as np
import struct

Bytes = 4 #Every line have Bytes bytes
DataAddr = 512

file_name=r'bmp文件的路径'

img=Image.open(file_name)

merge_array = np.array(img)

file_name1 = "输出dat文件的路径"

def color565(r, g, b):
    return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3

#转成dat文件的主要操作
with open(file_name1, "wb") as f:
        for line in merge_array:
            for dot in line:
                f.write(struct.pack("H", color565(*dot))[::-1])

我们来看个最简单的例子:

from machine import Pin, SPI
import st7789_itprojects


tft = st7789_itprojects.ST7889_Image(SPI(1,baudrate = 80_000_000,polarity = 1,sck = Pin(2),mosi = Pin(3),miso = None), dc=Pin(6), cs=None, rst=Pin(10))
tft.fill(st7789_itprojects.color565(0,0, 0))  # 背景设置为黑色



def show_img(m):
    with open("selwe_dat/"+str(m)+".dat", "rb") as f:
        for row in range(64):
            buffer = f.read(128)
            tft.show_img(160,row+30,224,row+30, buffer)


show_img('yeFair')

我显示的图片是64*64像素的,王铭东老师的显示方法是一行一行读取dat文件里面的数据,64*64的图片就有64行,因此range里面是64,为什么read里面是128?因为每一个像素点的信息包括它的位置信息和颜色信息,都需要在st7789上面表达出来。160表示在第160例开始显示,224表示在第224列显示结束。row+30代表在第30行开始显示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!为了制作一个时钟,你将需要以下硬件和软件: 硬件: 1. ESP32 C3 开发板:ESP32 C3 是一款低成本、低功耗的Wi-Fi和蓝牙芯片,非常适合物联网应用。 2. DS3231SN 实时时钟模块:DS3231SN 是一款高精度的实时时钟模块,可以提供准确的时间信息。 3. SSD1306 OLED 显示屏:SSD1306 是一款0.96英寸的OLED显示屏,可以显示时钟和其他信息。 4. 连接线:用于连接 ESP32、DS3231SN 和 SSD1306。 软件: 1. MicroPythonMicroPython 是一种精简版的 Python 解释器,可以在嵌入式系统上运行。 下面是制作时钟的步骤: 1. 连接硬件: - 将 ESP32 C3 与 DS3231SN 和 SSD1306 连接起来。确保连接正确,参考硬件连接图。 - 将 DS3231SN 和 SSD1306 分别连接到 ESP32 的 I2C 接口。 2. 安装 MicroPython: - 在你的计算机上下载并安装 MicroPython。 - 使用 USB 数据线将 ESP32 C3 连接到计算机。 3. 编写 MicroPython 代码: - 打开一个文本编辑器,创建一个新的 MicroPython 脚本。 - 导入必要的库,例如 machine、ssd1306 和 ds3231。 - 初始化 I2C 总线和 DS3231SN 模块。 - 设置 SSD1306 OLED 显示屏的参数。 - 使用 DS3231SN 模块获取当前时间。 - 在 OLED 显示屏上显示时间。 4. 上传代码到 ESP32 C3: - 将编写好的 MicroPython 代码保存为 main.py 文件。 - 使用 MicroPython 工具将 main.py 上传到 ESP32 C3 开发板上。 5. 测试和调试: - 断开 ESP32 C3 与计算机的连接。 - 将 ESP32 C3 与电源连接,启动时钟程序。 - 监视 SSD1306 OLED 显示屏,确保时间正确显示。 这是一个基本的框架,你可以根据自己的需求进行进一步的扩展和美化。希望对你有所帮助!如果你有任何问题,请随时向我提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大初哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值