这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 树莓派5开发方案创意赛--03过程贴:点亮电子墨水屏

共2条 1/1 1 跳转至

树莓派5开发方案创意赛--03过程贴:点亮电子墨水屏

助工
2025-12-27 16:47:50     打赏
DFR0591 电子墨水屏介绍这款树莓派电子墨水屏模块配备一块2.13英寸屏幕,分辨率为250×122,采用SPI接口与树莓派通信。它引出了树莓派的引脚,因此如果您需要同时使用电子墨水屏和树莓派的引脚,不会出现冲突。该显示屏支持自定义字体。模块上有两个触摸开关,可扩展更多应用。这款电子墨水屏尺寸小巧、布局紧凑、即插即用且功耗低。即使在阳光下也能提供清晰的显示效果。断电后,电子墨水屏会继续显示上次的屏幕内容。由于屏幕刷新需要较长时间,因此我们不建议将其用于需要频繁刷新显示数据的应用场景。规格
  • 工作电压:3.3V

  • 按钮:2个
    • 按钮A,占用树莓派的GPIO29和P40

    • 按钮B,占用树莓派的GPIO28和P38

  • 分辨率:250x122 (逻辑分辨率 250x128)

  • 通信接口:SPI

  • 显示颜色:黑白

  • 灰度等级:2

  • 刷新方式:完全刷新和部分刷新

  • 刷新时间:全刷新需要3秒,部分刷新需要0.5秒

  • 可视角度:>170°

引脚图

image.png

image.png


树莓派5设置由于电子墨水屏通信方式为 SPI,所以树莓派5 需要使能SPI。

输入命令 sudo raspi-config 打开树莓派设置界面,进入选项 3 Interface Options,使能SPI。

image.png

image.png

image.png


确认,并保存,然后输入 sudo reboot 重启树莓派5.


电子墨水屏驱动我当前使用的是 gitee 上的驱动代码 https://gitee.com/dfrobot/DFRobot_RPi_Eink_Display这个驱动代码在树莓派3/4上验证过,没有在树莓派5上验证过。RPi.GPIO 报错运行电子墨水屏的示例程序,直接报错,如下所示,没有 RPi 模块。

(.venv) lintex9527@pi:~/workspace/eepw/elem_rpi5_contest/DFRobot_RPi_Eink_Display/examples $ python3 display_bitmap.py 
Traceback (most recent call last):
  File "/home/lintex9527/workspace/eepw/elem_rpi5_contest/DFRobot_RPi_Eink_Display/examples/display_bitmap.py", line 21, in <module>
    from DFRobot_RPi_Eink_Display import DFRobot_RPi_Eink_Display, THIS_BOARD_TYPE
  File "/home/lintex9527/workspace/eepw/elem_rpi5_contest/DFRobot_RPi_Eink_Display/DFRobot_RPi_Eink_Display.py", line 32, in <module>
    import RPi.GPIO as RPIGPIO
ModuleNotFoundError: No module named 'RPi'


lgpio 适配这是因为到2024年底,官方 RPi.GPIO 库对树莓派5的支持仍不完善,树莓派5 使用了新的 GPIO 控制器,而 RPi.GPIO 尚未完全适配。


替代方案是使用 gpiozero 或者 lgpio。这里我选择了用 lgpio。


RPi.GPIO 报错的代码如下,在判定当前开发板为树莓派是,引入 RPi.GPIO 库,否则引入 mraa 库。


image.png

后续用到 RPIGPIO 的代码都是在 class GPIO 中,即用 RPi.GPIO 实现了 GPIO 类,实现了set_out()/set_interrupt()/read() 等函数。那么只需要用 lgpio 实现对应的功能即可。


image.png

在安装了 lgpio 库之后,使用 lgpio 实现 GPIO 类,关键代码如下:


全局变量尝试引用 lgpio 库重命名为 sbc,并设置全局变量 USING_LGPIO=True

image.png

GPIO 类中使用的常量 HIGH, LOW 等用 lgpio 库重新定义

image.png


GPIO.__init__() 方法用 lgpio 重新实现

image.png


GPIO.set_out() 方法用 lgpio 重新实现

image.png

GPIO.set_interrupt() 方法由 lgpio 重新实现

image.png


GPIO.read() 和 cleanup() 方法也由 lgpio 重新实现

image.png


修复驱动中的24位图颜色深度(默认只支持1比特深度)官方的驱动程序有错误,虽然写着支持24bit深度的位图,但实际在电子墨水屏上无法显示。我进行了修复,bitmap_file() 加载制定的位图到显示屏制定的坐标。修复前的代码


    def bitmap_file(self, x, y, path):
        """!
          @brief Draw a bitmap
          @param x Starting x-coordinate of the bitmap
          @param y Starting y-coordinate of the bitmap
          @param path  Bitmap file path
        """
        try:
            f = open(path, "rb")
        except:
            print("open file error")
            return
        c = bytearray(f.read())
        f.close()

        # 确定是否是有效的BMP文件(包含 'BM')
        if c[0] != 0x42 and c[1] != 0x4d:
            print("file error")
            print(c[0])
            print(c[1])
            return

        dib_offset = self._bytes_to_number(c[10:14])
        width = self._bytes_to_number(c[18:22])
        height = self._bytes_to_number(c[22:26])
        color_bits = self._bytes_to_number(c[28:30])
        compression = self._bytes_to_number(c[30:32])
        # print("w: %d, h: %d, color_bits: %d" %(width, height, color_bits))

        if color_bits == 24:
            width3 = width * 3
            for i in range(height):
                self.start_draw_bitmap_file(x, y + height - i)
                buf = []
                left = dib_offset + i * width3
                i = 0
                while i < width3:
                    buf.append(c[left + i + 2])
                    buf.append(c[left + i + 1])
                    buf.append(c[left + i + 0])
                    i += 3
                self.bitmap_file_helper(buf)
            self.end_draw_bitmap_file()

        elif color_bits == 1:
            quads = self._get_quads(c, 2)
            addr = dib_offset
            if compression == self.BITMAP_COMPRESSION_NO:
                addr_count_complement = (width // 8 + 1) % 4
                if addr_count_complement != 0:
                    addr_count_complement = 4 - addr_count_complement
                for i in range(height):
                    w = width
                    addr_count = 0
                    self.start_draw_bitmap_file(x, y + height - i - 1)
                    buf = []
                    while w > 0:
                        d = c[addr + addr_count]
                        addr_count = addr_count + 1
                        j = 8
                        while w > 0 and j > 0:
                            j -= 1
                            quad = d & (0x01 << j)
                            if quad > 0:
                                quad = 1
                            buf.append(quads[quad][2])
                            buf.append(quads[quad][1])
                            buf.append(quads[quad][0])
                            w -= 1
                    self.bitmap_file_helper(buf)
                    addr_count += addr_count_complement
                    addr += addr_count
                self.end_draw_bitmap_file()
        else:
            print("dont support this bitmap file format yet")


修复后的代码:


    def bitmap_file(self, x, y, path):
        """!
          @brief Draw a bitmap
          @param x Starting x-coordinate of the bitmap
          @param y Starting y-coordinate of the bitmap
          @param path  Bitmap file path
        """
        try:
            f = open(path, "rb")
        except:
            print("open file error")
            return
        c = bytearray(f.read())
        f.close()

        # 检查BMP文件签名
        if c[0] != 0x42 or c[1] != 0x4d:
            print("Not a valid BMP file")
            return

        # 读取BMP头信息
        dib_offset = self._bytes_to_number(c[10:14])
        width = self._bytes_to_number(c[18:22])
        height = self._bytes_to_number(c[22:26])
        color_bits = self._bytes_to_number(c[28:30])
        compression = self._bytes_to_number(c[30:34])

        if color_bits == 24:
            self._draw_24bit_bmp(x, y, c, dib_offset, width, height)
            # self._draw_24bit_bmp_optimized(x, y, c, dib_offset, width, height)
        elif color_bits == 1:
            self._draw_1bit_bmp(x, y, c, dib_offset, width, height, compression)
        else:
            print(f"Unsupported BMP format: {color_bits}-bit")

    def _draw_24bit_bmp(self, x, y, file_data, data_offset, width, height):
        """处理24位BMP文件"""
        # 计算每行的字节数(4字节对齐)
        row_size = (width * 3 + 3) & ~3  # 对齐到4字节

        self.start_draw_bitmap_file(x, y)

        # BMP是从下到上存储的,需要反转
        for row in range(height):
            # 计算当前行在文件中的位置
            row_pos = data_offset + (height - 1 - row) * row_size

            buf = []
            for col in range(width):
                # 读取BGR像素
                pixel_pos = row_pos + col * 3
                blue = file_data[pixel_pos]
                green = file_data[pixel_pos + 1]
                red = file_data[pixel_pos + 2]

                # 转换为灰度值来判断黑白
                # 使用常见的灰度转换公式: 0.299*R + 0.587*G + 0.114*B
                gray = int(0.299 * red + 0.587 * green + 0.114 * blue)

                # 根据灰度值决定显示黑色还是白色
                # 阈值可以调整,这里使用128作为中间值
                if gray < 128:
                    buf.extend([0, 0, 0])  # 黑色
                else:
                    buf.extend([255, 255, 255])  # 白色

            self.bitmap_file_helper(buf)
            self._bitmap_file_start_y += 1

        self.end_draw_bitmap_file()

    def _draw_1bit_bmp(self, x, y, file_data, data_offset, width, height, compression):
        """处理1位BMP文件(原有的逻辑)"""
        quads = self._get_quads(file_data, 2)
        addr = data_offset

        if compression == self.BITMAP_COMPRESSION_NO:
            row_size = ((width + 31) // 32) * 4  # 1位BMP的行对齐计算

            for i in range(height):
                w = width
                self.start_draw_bitmap_file(x, y + height - i - 1)
                buf = []

                for byte_pos in range(row_size):
                    if w <= 0:
                        break

                    d = file_data[addr + byte_pos]
                    bits_remaining = min(8, w)

                    for bit in range(bits_remaining):
                        quad_index = (d >> (7 - bit)) & 0x01
                        buf.extend(quads[quad_index][:3])  # 只取RGB部分
                        w -= 1

                self.bitmap_file_helper(buf)
                addr += row_size

            self.end_draw_bitmap_file()


修复驱动,成功显示图像

把任意一种图片转换为 24bit 深度的 BMP 图片就可以在电子墨水屏上显示,如下图所示:

image.png

image.png








关键词: 树莓派5     电子墨水屏    

院士
2025-12-27 19:57:03     打赏
2楼

这个电子墨水屏看着真是漂亮啊


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]