6. LCD显示

我们的鲁班猫板卡上支持各种各样的显示设备,像前面支持的小尺寸OLED屏幕, 以及中等尺寸的RGB屏幕,乃至HDMI接口接入大尺寸液晶显示屏。

6.1. LCD实验

在一些场景中,我们期望通过一些简单的方式,去控制显示设备的显示内容。 那么我们可以用Python来编写一些代码来实现。

6.2. Pygame库

6.2.1. Pygame库简介

Pygame是Python库中用于开发游戏的一种工具,或许这么说有点限制Pygame的用法。 Pygame不仅可以用于游戏开发,还可以用于显示处理,多媒体设备处理等等方面, 该库提供了许多多媒体、显示设备的操作功能。 我们可以在鲁班猫板卡上安装Python-Pygame库,并通过编写一些测试代码来使用该库。

6.3. 实验准备

6.3.1. 添加LCD资源

在板卡上的部分资源可能默认未被开启,在使用前请根据需要修改 /boot/uEnv.txt 文件, 可添加对应设备树插件的加载,重启系统,以在系统中添加对应资源。

如本节实验中,通常情况下在鲁班猫系统中默认使能 LCD 的功能, 如大家发现LCD的设备树插件未加载,请做相应修改。

同时如果大家在使用中发现LCD功能引脚被复用或有冲突,请要将对应占用LCD引脚资源的设备树插件取消加载, 否则LCD资源可能无法使用。若已开启对应资源,忽略以下步骤。

方法参考如下:

broken

添加LCD设备树插件,以使系统支持LCD功能,如下:

broken
# 以鲁班猫i.MX6ULL MINI板卡LCD设备树插件及触摸设备树插件内容为例:
dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-lcd.dtbo,clock-frequency_0=9000000,hactive_0=480,vactive_0=272,hfront-porch_0=8,hback-porch_0=2,hsync-len_0=41,vback-porch_0=4,vfront-porch_0=4,vsync-len_0=10,bits-per-pixel_0=24
dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-touch-capacitive-goodix.dtbo

如若运行代码时出现“Device or resource busy”或者运行代码卡死等等现象, 请按上述情况检查并按上述步骤操作。

如出现 Permission denied 或类似字样,请注意用户权限,大部分操作硬件外设的功能,几乎都需要root用户权限,简单的解决方案是在执行语句前加入sudo或以root用户运行程序。

# 在终端中输入如下命令,可以查看到显示设备资源:
ls /dev/fb*

板卡上的显示设备资源示例,仅供参考:

broken

6.3.2. 硬件连接

硬件连接小节,需要大家根据自身开发环境等情况对本章内容进行参考调整。

将LCD显示屏与鲁班猫板卡连接即可。

6.3.3. Pygame库安装

我们使用apt工具安装。

# 在终端中输入如下命令,安装Pygame库:
sudo apt -y install python3-pygame

等等安装完成后即可。

6.3.4. Pygame库使用

安装好对应的库之后,我们就可以利用安装好的Pygame库编写一下测试代码。

测试前,我们可以简单地理解本节实验中的一些技术要点, Pygame库利用Linux Framebuffer机制实现了调整显示设备的功能, Linux Framebuffer把屏幕上的每个点映射成一段线性内存空间, 程序可以简单的改变这段内存的值来改变屏幕上某一点的颜色。 可以使用以下命令不断地往 /dev/fb0 写入随机数据,使得屏幕花屏。

# 在终端中输入如下命令测试:
cat /dev/urandom > /dev/fb0

我们也可以通过fbset工具,在用户空间查看显示设备相关参数:

#安装fbset工具
sudo apt update
sudo apt -y install fbset

安装完fbset工具之后可以使用 fbset命令查看显示屏相关参数

broken

fbset工具很强大不仅可以插件显示设备相关参数,同时也能够在用户空间修改lcd参数。

关于FB子系统相关内容,参考 《Linux Framebuffer》

6.4. 测试代码一

测试代码如下:

配套代码 libdemo/lcd_test1.py文件内容
 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
""" 使用pygame进行屏幕测试 """
import os
import time
import pygame

# 设置系统环境,无鼠标
os.environ["SDL_NOMOUSE"] = "1"

# 初始化显示设备
pygame.display.init()

# 获取显示设备信息,并打印其中的宽度和高度
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
# 构造rgb色彩中的黑色
black = 0, 0, 0
# 设置显示窗口的范围为屏幕大小,并返回一个屏幕对象
screen = pygame.display.set_mode(size)
# 使用pygame image模块加载图片
ball = pygame.image.load("test.png")
# 获取图片大小矩形信息
ballrect = ball.get_rect()
# 对屏幕对象进行填充,填充色彩为黑色
screen.fill(black)
# 将图片按位拷贝到屏幕上
screen.blit(ball, ballrect)
# 更新屏幕以显示内容
pygame.display.flip()

time.sleep(5)
exit()

以上代码会将下图显示到LCD显示屏上:

broken

6.4.1. 实验步骤

将配套代码 libdemo\Pygame_Lcd目录中的测试代码及测试图片,一并上传至开发板同一目录下:

# 在终端中输入如下命令,因为访问硬件注意sudo权限:
sudo python3 lcd_test1.py

6.5. 测试代码二

配套代码 libdemo/lcd_test2.py文件内容
 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
""" 使用pygame进行屏幕测试 """
import os
import time
import pygame


class PyScope:
    """ 定义一个PyScope类,进行屏幕测试 """

    screen = None

    def __init__(self):
        "PyScope类的初始化方法,使用framebuffer构造pygame会使用到的图像缓冲区"
        # Based on "Python GUI in Linux frame buffer"
        # http://www.karoltomala.com/blog/?p=679
        # 尝试获取环境目录下定义的显示设备
        disp_no = os.getenv("DISPLAY")
        if disp_no:
            print("I'm running under X display = {0}".format(disp_no))

        # 检查何种驱动方式可用
        # 从fbcon开始,因为directfb会挂起复合输出
        drivers = ["fbcon", "directfb", "svgalib"]
        # 设置系统环境为无鼠标模式
        os.environ["SDL_NOMOUSE"] = "1"
        found = False
        # 根据枚举的framebuffer设备类型适配驱动
        for driver in drivers:
            # 确保环境变量SDL_VIDEODRIVER被设置
            if not os.getenv("SDL_VIDEODRIVER"):
                os.putenv("SDL_VIDEODRIVER", driver)
            try:
                print("Driver: {0} is checking now...".format(driver))
                # 尝试初始化显示设备功能
                pygame.display.init()
            except pygame.error:
                # 出错,打印提示
                print("Driver: {0} failed.".format(driver))
                continue
            print("Driver: {0} is suitable.".format(driver))
            found = True
            break

        if not found:
            raise Exception("No suitable video driver found!")

        # 获取显示设备的大小
        size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
        # 打印显示设备的大小
        print("Framebuffer size: %d x %d" % (size[0], size[1]))
        # 设置pygame使用的窗口显示为全屏幕
        self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
        # 清屏
        self.screen.fill((0, 0, 0))
        # 初始化字体库
        pygame.font.init()
        # 更新屏幕,以显示写入缓冲区的内容
        pygame.display.update()

    def __del__(self):
        "退出pygame库的时候会调用该方法,可以在此添加资源释放操作"

    def test(self):
        "PyScope类的测试方法,使屏幕填充为红色"
        # 填充屏幕为红色,其rgb值为(255, 0, 0)
        red = (255, 0, 0)
        # 填充
        self.screen.fill(red)
        # 更新屏幕,以显示写入缓冲区的内容
        pygame.display.update()


# 创建一个测试实例,开始测试
scope = PyScope()
# 调用scope类的测试方法
scope.test()
time.sleep(3)
exit()

代码功能注释已给出。以上代码值得一提的是__init__方法中,会检查系统当前设备所处平台, 并根据设备情况匹配驱动方式,最终该代码会在对应设备上全屏填充红色像素。

6.5.1. 实验步骤

将配套代码 libdemo\Pygame_Lcd目录中的测试代码上传至开发板任一目录下:

# 在终端中输入如下命令:
sudo python3 lcd_test2.py

命令执行后终端打印出的信息如下:

broken

其中可以看到 Driver: fbcon is suitable. 字样,说明我们的LCD屏幕是以framebuffer形式驱动的。 同时也打印出了屏幕大小的信息,屏幕也被填充了红色像素。

自此pygame库的使用测试结束。

更多关于Python Pygame库的使用,可参考 Pygame 教程 。 关于Pygame display,可参考 Pygame display