当前位置:   article > 正文

【雕爷学编程】MicroPython手册之特定的库 framebuf —帧缓冲区操作

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的应用场景包括:
1、为嵌入式产品快速构建原型和用户交互。
2、制作一些小型的可 programmable 硬件项目。
3、作为教育工具,帮助初学者学习Python和物联网编程。
4、构建智能设备固件,实现高级控制和云连接。
5、各种微控制器应用如物联网、嵌入式智能、机器人等。

使用MicroPython需要注意:
1、内存和Flash空间有限。
2、解释执行效率不如C语言。
3、部分库函数与标准版有差异。
4、针对平台优化语法,订正与标准Python的差异。
5、合理使用内存资源,避免频繁分配大内存块。
6、利用原生代码提升速度关键部位的性能。
7、适当使用抽象来封装底层硬件操作。

总体来说,MicroPython让Python进入了微控制器领域,是一项重要的创新,既降低了编程门槛,又提供了良好的硬件控制能力。非常适合各类物联网和智能硬件的开发。

在这里插入图片描述

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

案例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")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

案例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("图形显示成功!")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这个例子中,我们使用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("图案显示成功!")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这个例子中,我们使用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这个例子中,我们使用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

案例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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

案例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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/278268
推荐阅读
相关标签
  

闽ICP备14008679号