MicroPython 帧缓冲区库 framebuf 的使用方法

MicroPython 是为了在嵌入式系统中运行 Python 3 编程语言而设计的轻量级版本解释器。与常规 Python 相比,MicroPython 解释器体积小(仅100KB左右),通过编译成二进制 Executable 文件运行,执行效率较高。它使用了轻量级的垃圾回收机制并移除了大部分 Python 标准库,以适应资源限制的微控制器。

MicroPython 主要特点包括:
1、语法和功能与标准 Python 兼容,易学易用。支持 Python 大多数核心语法。
2、对硬件直接访问和控制,像 Arduino 一样控制 GPIO、I2C、SPI 等。
3、强大的模块系统,提供文件系统、网络、图形界面等功能。
4、支持交叉编译生成高效的原生代码,速度比解释器快 10-100 倍。
5、代码量少,内存占用小,适合运行在MCU和内存小的开发板上。
6、开源许可,免费使用。Shell 交互环境为开发测试提供便利。
7、内置 I/O 驱动支持大量微控制器平台,如 ESP8266、ESP32、STM32、micro:bit、掌控板和 pyBoard 等。有活跃的社区。

MicroPython 的 framebuf 模块是一个用于创建和操作位图图像的接口。它可以将一个字节数组作为一个像素缓冲区,然后使用不同的颜色格式和绘图方法来绘制像素、线条、矩形、文本等图形。它可以用于为显示器生成输出,或者将图像数据发送给其他设备。

framebuf 模块的主要特点有:
它基于著名的 BerkelyDB 库,版本 1.xx,具有成熟和稳定的性能。
它尽可能地模仿标准的 dict 类型的接口,方便用户使用。不过需要注意的是,键和值都必须是 bytes 类型的对象(如果要存储其他类型的对象,需要先序列化为 bytes)。
它支持多种不同的颜色格式,如单色、灰度、RGB565 等。不同的颜色格式有不同的位数和布局,影响着图像的质量和大小。
它支持一些高级的参数和方法,用于调整图像的操作,如页面大小、缓存大小、最小键数等。

framebuf 模块可以用于以下一些应用场景:
显示控制:利用 framebuf 模块,可以实现对显示器的控制和显示。例如,可以使用 framebuf 模块来显示一些文本、图标、动画等,并根据需要进行滚动、旋转、缩放等变换。
图像处理:利用 framebuf 模块,可以实现对图像的处理和转换。例如,可以使用 framebuf 模块来裁剪、旋转、缩放、镜像、反色等操作,并将结果保存为新的图像文件或发送给其他设备。
图形绘制:利用 framebuf 模块,可以实现对图形的绘制和生成。例如,可以使用 framebuf 模块来绘制一些简单的几何图形、曲线、填充等,并将结果显示在屏幕上或保存为新的图像文件。

使用 framebuf 模块时,需要注意以下事项:
在使用该模块上的任何其他方法之前,必须先调用 FrameBuffer 类的构造函数来创建一个 FrameBuffer 对象。创建时,需要传入一个字节数组作为缓冲区,以及指定图像的宽度、高度、颜色格式等参数。
在对图像进行修改操作后(如添加、删除或更新像素或图形),需要调用 flush 方法来将修改写入到缓冲区中。否则,修改可能会丢失或不一致。
在处理数据时,需要注意数据类型和长度的限制和转换。键和值都必须是 bytes 类型的对象,且长度不能超过 255 字节。如果要存储其他类型的对象,需要先序列化为 bytes 类型。

以下是一些使用 MicroPython 的 framebuf 模块的实际运用程序案例。

案例1:文本显示

这是一个使用 framebuf 模块来显示一些文本,并根据用户输入进行滚动或清除的程序案例。

# 导入 framebuf 和 machine 模块
import framebuf
import machine

# 创建一个字节数组作为缓冲区
buffer = bytearray(128 * 64 // 8)
# 创建一个 FrameBuffer 对象,使用单色垂直最低有效位格式
fbuf = framebuf.FrameBuffer(buffer, 128, 64, framebuf.MONO_VLSB)
# 填充整个 FrameBuffer 为黑色
fbuf.fill(0)
# 在 FrameBuffer 上写入文本 "Hello, MicroPython!" ,使用白色
fbuf.text("Hello, MicroPython!", 0, 0, 1)

# 创建一个 SPI 对象,连接到 SSD1306 OLED 显示器
spi = machine.SPI(1, baudrate=10000000, polarity=0, phase=0)
# 创建一个 Pin 对象,用于控制显示器的数据/命令选择
dc = machine.Pin(2)
# 创建一个 Pin 对象,用于控制显示器的复位
rst = machine.Pin(4)
# 创建一个 Pin 对象,用于控制显示器的片选
cs = machine.Pin(15)
# 创建一个 SSD1306_SPI 对象,用于控制显示器
oled = framebuf.SSD1306_SPI(128, 64, spi, dc, rst, cs)

# 将 FrameBuffer 的内容显示在 OLED 上
oled.blit(fbuf, 0, 0)
# 刷新 OLED
oled.show()

# 创建一个 Pin 对象,用于接收用户的按键输入
button = machine.Pin(0, machine.Pin.IN)

# 定义一个变量,用于记录文本的水平偏移量
offset = 0

# 定义一个无限循环,用于处理用户的输入
while True:
    # 如果用户按下了按键
    if button.value() == 1:
        # 将文本的水平偏移量增加 8 像素
        offset += 8
        # 如果文本的水平偏移量超过了 FrameBuffer 的宽度
        if offset >= fbuf.width:
            # 将文本的水平偏移量重置为 0
            offset = 0
            # 填充整个 FrameBuffer 为黑色
            fbuf.fill(0)
        # 在 FrameBuffer 上写入文本 "Hello, MicroPython!" ,使用白色,并根据偏移量进行滚动
        fbuf.text("Hello, MicroPython!", -offset, 0, 1)
        # 将 FrameBuffer 的内容显示在 OLED 上
        oled.blit(fbuf, 0, 0)
        # 刷新 OLED
        oled.show()

案例2:图像转换

这是一个使用 framebuf 模块来将一个 BMP 图像文件转换为 RGB565 格式,并将结果保存为新的 BMP 图像文件的程序案例。

# 导入 framebuf 和 ubinascii 模块
import framebuf
import ubinascii

# 定义一个函数,用于读取 BMP 图像文件的头部信息,并返回宽度、高度和颜色格式等参数
def read_bmp_header(filename):
    # 打开 BMP 图像文件,以二进制模式读取
    with open(filename, "rb") as f:
        # 跳过前两个字节(文件类型标识符)
        f.read(2)
        # 读取四个字节(文件大小),并转换为整数类型
        file_size = int.from_bytes(f.read(4), "little")
        # 跳过四个字节(保留字段)
        f.read(4)
        # 读取四个字节(数据偏移量),并转换为整数类型
        data_offset = int.from_bytes(f.read(4), "little")
        # 跳过四个字节(信息头大小)
        f.read(4)
        # 读取四个字节(图像宽度),并转换为整数类型
        width = int.from_bytes(f.read(4), "little")
        # 读取四个字节(图像高度),并转换为整数类型
        height = int.from_bytes(f.read(4), "little")
        # 跳过两个字节(颜色平面数)
        f.read(2)
        # 读取两个字节(颜色位数),并转换为整数类型
        bit_count = int.from_bytes(f.read(2), "little")
    # 返回图像文件的参数
    return file_size, data_offset, width, height, bit_count

# 定义一个函数,用于将 RGB888 颜色格式转换为 RGB565 颜色格式,并返回转换后的颜色值
def rgb888_to_rgb565(color):
    # 将颜色值分解为三个分量:红、绿、蓝
    r, g, b = color[0], color[1], color[2]
    # 将红色分量右移 3 位,保留最低 5 位
    r = r >> 3
    # 将绿色分量右移 2 位,保留最低 6 位
    g = g >> 2
    # 将蓝色分量右移 3 位,保留最低 5 位
    b = b >> 3
    # 将三个分量合并为一个 16 位的整数,按照 RGB565 的布局
    rgb565 = (r << 11) | (g << 5) | b
    # 返回转换后的颜色值
    return rgb565

# 定义一个函数,用于将 RGB565 颜色格式转换为 RGB888 颜色格式,并返回转换后的颜色值
def rgb565_to_rgb888(color):
    # 将颜色值分解为三个分量:红、绿、蓝
    r = (color >> 11) & 0x1F
    g = (color >> 5) & 0x3F
    b = color & 0x1F
    # 将红色分量左移 3 位,补齐最高位
    r = r << 3 | r >> 2
    # 将绿色分量左移 2 位,补齐最高位
    g = g << 2 | g >> 4
    # 将蓝色分量左移 3 位,补齐最高位
    b = b << 3 | b >> 2
    # 将三个分量合并为一个 3 字节的 bytes 对象,按照 RGB888 的布局
    rgb888 = bytes([r, g, b])
    # 返回转换后的颜色值
    return rgb888

# 定义一个函数,用于将一个 BMP 图像文件转换为 RGB565 格式,并将结果保存为新的 BMP 图像文件
def convert_bmp_to_rgb565(in_file, out_file):
    # 读取输入文件的头部信息,获取宽度、高度和颜色格式等参数
    file_size, data_offset, width, height, bit_count = read_bmp_header(in_file)
    # 打开输入文件和输出文件,以二进制模式读写
    with open(in_file, "rb") as fin, open(out_file, "wb") as fout:
        # 将输入文件的前 data_offset 个字节(包括头部信息)复制到输出文件中
        fout.write(fin.read(data_offset))
        # 创建一个字节数组作为缓冲区,大小为 width * height * 2(每个像素占 2 字节)
        buffer = bytearray(width * height * 2)
        # 创建一个 FrameBuffer 对象,使用 RGB565 格式
        fbuf = framebuf.FrameBuffer(buffer, width, height, framebuf.RGB565)
        # 填充整个 FrameBuffer 为黑色
        fbuf.fill(0)
        # 根据输入文件的颜色格式,进行不同的处理
        if bit_count == 24: # 如果是 RGB888 格式
            # 从第 data_offset 个字节开始,循环读取输入文件中的数据,每次读取 width * 3 个字节(一行像素)
            for y in range(height):
                row = fin.read(width * 3)
                # 遍历每一行像素中的每个像素
                for x in range(width):
                    # 获取当前像素的颜色值(3 字节)
                    color = row[x * 3 : x * 3 + 3]
                    # 将颜色值转换为 RGB565 格式
                    color = rgb888_to_rgb565(color)
                    # 在 FrameBuffer 上绘制当前像素,注意 y 坐标需要反转
                    fbuf.pixel(x, height - y - 1, color)
        elif bit_count == 16: # 如果是 RGB565 格式
            # 直接将输入文件中的数据复制到缓冲区中
            buffer[:] = fin.read()
        else: # 如果是其他格式,不支持转换
            raise ValueError("Unsupported bit count: {}".format(bit_count))
        # 将缓冲区中的数据写入输出文件中
        fout.write(buffer)

# 调用函数,将一个 BMP 图像文件转换为 RGB565 格式,并将结果保存为新的 BMP 图像文件
convert_bmp_to_rgb565("in.bmp", "out.bmp")

案例3:LCD 显示屏

import framebuf

# 定义屏幕尺寸和颜色模式
width = 128
height = 64
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_VLSB)

# 在屏幕上绘制图形
fb.fill(0)  # 清空屏幕
fb.rect(10, 10, 50, 30, 1)  # 绘制矩形
fb.line(0, 0, width - 1, height - 1, 1)  # 绘制线条
fb.text("Hello", 20, 40, 1)  # 绘制文本

# 将图形显示在LCD屏幕上
lcd = LCD()  # 假设已经初始化了LCD对象
lcd.show_framebuffer(fb)

print("图形显示成功!")

在这个例子中,我们使用 framebuf.FrameBuffer() 函数创建一个帧缓冲对象,用于在 LCD 显示屏上绘制图形。可以使用 fill() 方法清空屏幕,rect() 方法绘制矩形,line() 方法绘制线条,text() 方法绘制文本。最后,使用 lcd.show_framebuffer() 方法将图形显示在 LCD 屏幕上。

案例4:LED 矩阵显示

import framebuf

# 定义LED矩阵尺寸和颜色模式
width = 8
height = 8
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_HLSB)

# 在LED矩阵上绘制图案
fb.fill(0)  # 清空LED矩阵
fb.pixel(3, 3, 1)  # 设置像素点
fb.line(0, 0, width - 1, height - 1, 1)  # 绘制线条
fb.text("Hi", 1, 4, 1)  # 绘制文本

# 将图案显示在LED矩阵上
led_matrix = LEDMatrix()  # 假设已经初始化了LEDMatrix对象
led_matrix.show_framebuffer(fb)

print("图案显示成功!")
在这个例子中,我们使用 framebuf.FrameBuffer() 函数创建一个帧缓冲对象,用于在 LED 矩阵上绘制图案。可以使用 fill() 方法清空 LED 矩阵,pixel() 方法设置像素点,line() 方法绘制线条,text() 方法绘制文本。最后,使用 led_matrix.show_framebuffer() 方法将图案显示在LED矩阵上。

案例5:游戏开发

import framebuf

# 定义游戏窗口尺寸和颜色模式
width = 128
height = 64
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_VLSB)

# 游戏循环
while True:
    fb.fill(0)  # 清空屏幕
    # 在屏幕上绘制游戏图形和角色
    # 处理用户输入
    # 更新游戏状态
    # 显示更新后的图像
    lcd = LCD()  # 假设已经初始化了LCD对象
    lcd.show_framebuffer(fb)

在这个例子中,我们使用 framebuf.FrameBuffer() 函数创建一个帧缓冲对象,用于在游戏窗口上绘制游戏图形和角色。在游戏循环中,可以使用 fill() 方法清空屏幕,绘制游戏图形和角色,处理用户输入,更新游戏状态,并使用 lcd.show_framebuffer() 方法将更新后的图像显示在屏幕上。

案例6:显示文本

使用 framebuf 模块在屏幕上显示文本信息。

import framebuf

# 创建帧缓冲区
width = 128
height = 64
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_VLSB)

# 清空屏幕
fb.fill(0)

# 设置字体和颜色
font = framebuf.FONT8x8
color = 1

# 在屏幕上绘制文本
fb.text("Hello, World!", 0, 0, color, font)

# 显示帧缓冲区内容
display.show(fb)

案例7:绘制图形

使用 framebuf 模块在屏幕上绘制简单的图形,如线条、矩形和圆形。

import framebuf

# 创建帧缓冲区
width = 128
height = 64
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_VLSB)

# 清空屏幕
fb.fill(0)

# 设置颜色
color = 1

# 绘制线条
fb.line(0, 0, 127, 63, color)

# 绘制矩形
fb.rect(10, 10, 50, 30, color)

# 绘制圆形
fb.circle(64, 32, 20, color)

# 显示帧缓冲区内容
display.show(fb)

案例8:显示图像

使用 framebuf 模块加载和显示图像文件。

import framebuf

# 加载图像文件
with open('image.pbm', 'rb') as f:
    f.readline()  # 读取PBM文件头
    f.readline()  # 读取图像尺寸
    data = bytearray(f.read())

# 创建帧缓冲区
width = 128
height = 64
buf = bytearray(width * height // 8)
fb = framebuf.FrameBuffer(buf, width, height, framebuf.MONO_VLSB)

# 清空屏幕
fb.fill(0)

# 在帧缓冲区中绘制图像
fb.blit(data, 0, 0, width, height, 0, 0)

# 显示帧缓冲区内容
display.show(fb)

这些案例展示了 MicroPython 的 framebuf 模块的一些实际运用程序。通过使用 framebuf 模块,可以在 MicroPython 设备上显示文本、绘制图形和显示图像等操作。你可以根据具体的应用需求进一步扩展和优化这些案例。请注意,在使用 framebuf 模块时,需要根据具体的硬件和显示设备进行相应的配置和适配。

转自:https://blog.csdn.net/weixin_41659040/article/details/132835872



坐沙发

发表评论

你的邮件地址不会公开


*