3. LCD显示基础:LCD驱动初始化、屏幕分辨率、颜色格式(RGB565)、清屏、绘制点线面等基本图形API
在K210视觉识别项目中,LCD屏幕是人与机器交互的核心窗口。无论是绘制人脸识别框、显示物体类别标签,还是呈现实时帧率与系统状态,所有视觉结果最终都需要通过LCD呈现给用户。本章将围绕K210常用LCD(以ST7789、ILI9341驱动芯片为代表)展开,系统讲解驱动初始化流程、分辨率与颜色格式(RGB565)的底层逻辑、清屏操作以及点、线、矩形、圆等基本图形API的使用方法。理解这些基础能力,是后续实现识别框绘制与多目标可视化的前提。
上图展示了K210与LCD之间的完整工程链路。从左侧的SPI主机到中间的驱动芯片,再到右侧的像素格式与图形API层,最后落到识别框可视化应用。整个链路中,驱动初始化是第一步,它决定了屏幕能否正常显示;而图形API则是我们与屏幕交互的“画笔”。下面我们将逐一拆解每个环节。
3.1 LCD驱动初始化:从引脚到显示的核心流程
LCD驱动初始化是项目启动时最先执行的硬件配置步骤。K210通常通过SPI接口与LCD模块通信,但不同于普通SPI设备,LCD还需要额外的控制引脚来区分命令与数据(DC)、片选(CS)、复位(RST)以及背光控制(BL)。初始化不成功,后续所有绘制操作都将无效。
核心原理:LCD驱动芯片内部有一个指令寄存器组和显存(GRAM)。初始化过程本质上是按照芯片手册的时序要求,向寄存器写入正确的配置值,使芯片进入可用的显示模式。以ST7789为例,初始化序列通常包含:软件复位(0x01)、睡眠退出(0x11)、颜色格式设置(0x3A,设为0x05表示RGB565)、显示方向设置(0x36)、显示开启(0x29)等关键命令。
操作流程:
- 引脚映射:在代码中定义SPI引脚(SCLK、MOSI)以及DC、CS、RST、BL对应的GPIO编号。K210的MaixPy固件通常使用FPIOA(现场可编程IO阵列)进行引脚重映射。
- SPI主机初始化:设置SPI频率(典型值40MHz)、工作模式(模式0或模式3,取决于LCD芯片要求)。
- 硬件复位:将RST引脚拉低至少10ms,再拉高,确保芯片从干净状态启动。
- 发送初始化命令序列:按照芯片手册逐条发送命令和参数。每条命令发送时,DC引脚置低表示命令,置高表示数据。
- 设置显示方向:通过0x36命令的MADCTL参数控制扫描方向,决定屏幕的横竖显示。
- 开启显示并清屏:发送0x29开启显示,然后调用清屏函数将显存填充为背景色。
from Maix import GPIO, Fpioa, I2C, SPI
from fpioa_manager import fm
from lcd import lcd
# 引脚映射
fm.register(27, fm.fpioa.GPIO0, fm.fpioa.OUT) # DC
fm.register(28, fm.fpioa.GPIO1, fm.fpioa.OUT) # RST
fm.register(29, fm.fpioa.GPIO2, fm.fpioa.OUT) # BL
fm.register(30, fm.fpioa.SPI0_SCLK)
fm.register(31, fm.fpioa.SPI0_MOSI)
fm.register(32, fm.fpioa.SPI0_CS0)
# 初始化LCD
lcd.init(type=1, freq=40000000, color=lcd.RED)
lcd.direction(lcd.AUTO) # 自动检测方向
lcd.clear(lcd.BLACK) # 清屏为黑色
3.2 屏幕分辨率与颜色格式(RGB565)
分辨率决定了屏幕的像素网格大小,而颜色格式决定了每个像素点用多少位来表示颜色。K210常用LCD模块的分辨率为240×320(竖屏),即横向240个像素点,纵向320个像素点。总像素数为240×320=76,800个。
RGB565格式解析:RGB565是一种16位颜色编码方式,其中红色占高5位(bit15-bit11),绿色占中间6位(bit10-bit5),蓝色占低5位(bit4-bit0)。绿色多1位是因为人眼对绿色最敏感。因此,每个像素占用2字节(16位),整个屏幕的显存需求为:240×320×2 = 153,600字节 ≈ 150KB。这个大小对于K210的6MB RAM来说完全可承受。
| 颜色名称 | RGB565值(十六进制) | R(5bit) | G(6bit) | B(5bit) | 适用场景 |
|---|---|---|---|---|---|
| 黑色 | 0x0000 | 0 | 0 | 0 | 背景/文字 |
| 白色 | 0xFFFF | 31 | 63 | 31 | 高亮/文字 |
| 红色 | 0xF800 | 31 | 0 | 0 | 警告/识别框 |
| 绿色 | 0x07E0 | 0 | 63 | 0 | 正常/通过 |
| 蓝色 | 0x001F | 0 | 0 | 31 | 信息/链接 |
| 黄色 | 0xFFE0 | 31 | 63 | 0 | 警告/注意 |
颜色转换方法:在代码中,我们经常需要将RGB888(如从摄像头获取的颜色)转换为RGB565。转换公式为:rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)。其中r、g、b分别为8位颜色分量。
3.3 清屏操作与基本图形API实战
清屏是每次刷新画面时的基础操作,而点、线、矩形、圆等基本图形API则是构建复杂UI的积木。在识别框绘制中,我们最常用的是矩形绘制和填充。
清屏原理:清屏的本质是向LCD显存的所有地址写入同一个颜色值。MaixPy的lcd.clear(color)函数会设置显示窗口为全屏,然后连续写入颜色数据。由于SPI传输速度限制,清屏一次约需10-20ms(取决于SPI频率),在实时视频流中,我们通常不会每帧都全屏清空,而是只更新变化区域。
基本图形API列表:
lcd.draw_point(x, y, color):在坐标(x,y)处绘制一个像素点。lcd.draw_line(x1, y1, x2, y2, color):从点(x1,y1)到点(x2,y2)绘制直线。lcd.draw_rect(x, y, w, h, color):绘制空心矩形,左上角为(x,y),宽w,高h。lcd.fill_rect(x, y, w, h, color):绘制实心矩形,常用于填充背景或绘制色块。lcd.draw_circle(x, y, r, color):绘制空心圆,圆心(x,y),半径r。lcd.draw_string(x, y, text, color, scale):在(x,y)处绘制字符串,scale为缩放倍数。
案例拆解:绘制人脸识别框
假设我们通过K210的AI加速器检测到一个人脸,其边界框坐标为(x=80, y=60, w=120, h=150)。我们需要在LCD上绘制一个红色矩形框,并在框上方显示“face:0.95”的置信度标签。
# 假设已获取人脸框坐标
face_x, face_y, face_w, face_h = 80, 60, 120, 150
confidence = 0.95
# 绘制红色识别框(线宽2像素,通过绘制4条粗线实现)
for i in range(2):
lcd.draw_line(face_x+i, face_y, face_x+face_w+i, face_y, lcd.RED) # 上边
lcd.draw_line(face_x+i, face_y+face_h, face_x+face_w+i, face_y+face_h, lcd.RED) # 下边
lcd.draw_line(face_x, face_y+i, face_x, face_y+face_h+i, lcd.RED) # 左边
lcd.draw_line(face_x+face_w, face_y+i, face_x+face_w, face_y+face_h+i, lcd.RED) # 右边
# 在框上方绘制标签
label = "face:{:.2f}".format(confidence)
lcd.draw_string(face_x, face_y-16, label, lcd.WHITE, scale=2)
性能考量:上述代码中,绘制4条线需要4次SPI传输。如果每帧有多个目标,传输次数会线性增加。优化策略包括:使用lcd.fill_rect()先绘制一个半透明背景块再叠加文字,或者将多个绘制命令合并到一次DMA传输中(MaixPy的lcd.draw_image支持)。
lcd.draw_rect(),线宽固定为1像素,在320×240分辨率下可能不够醒目。上述案例通过循环偏移绘制多条线来模拟粗线框,但要注意坐标边界,避免绘制到屏幕外导致异常。
3.4 显示方向与坐标系统
LCD的显示方向直接影响坐标映射。K210的MaixPy通过lcd.direction()函数设置扫描方向,支持横屏(LANDSCAPE)和竖屏(PORTRAIT)两种模式。默认竖屏时,坐标原点在左上角,x轴向右,y轴向下。
方向切换的影响:当从竖屏切换为横屏时,屏幕的宽高会互换(变为320×240),且坐标原点可能移动到右上角或左下角(取决于MADCTL参数)。在视觉识别项目中,通常建议使用横屏模式,因为摄像头画面是横向的,可以减少图像旋转的开销。
| 方向模式 | 分辨率 | 坐标原点 | 适用场景 |
|---|---|---|---|
| 竖屏(默认) | 240×320 | 左上角 | 文字阅读、列表显示 |
| 横屏(90°) | 320×240 | 左上角 | 视频监控、图像识别 |
| 横屏(270°) | 320×240 | 右下角 | 特殊安装方向 |
坐标转换技巧:在识别框绘制中,摄像头输出的坐标通常基于图像分辨率(如QVGA 320×240),而LCD显示可能经过缩放。如果摄像头分辨率与LCD分辨率不一致,需要按比例映射:lcd_x = cam_x * lcd_width / cam_width。K210的MaixPy提供了lcd.display(img)函数自动处理缩放,但手动绘制框时仍需自行转换。
3.5 性能优化与常见问题排查
LCD显示性能直接影响用户体验。在实时识别场景中,我们希望帧率尽可能高,同时画面不撕裂。
性能瓶颈分析:SPI传输是最大瓶颈。以40MHz SPI时钟计算,理论最大传输速率为5MB/s。绘制一个240×320全屏图像需要153,600字节,理论耗时约30ms,实际加上命令开销约40-50ms,即帧率上限约20-25FPS。如果使用RGB565格式,这个数字是固定的。
优化策略:
- 局部刷新:只更新识别框所在的区域,而不是全屏重绘。例如,上一帧人脸框在(80,60,120,150),下一帧移动到(90,65,118,148),只需重绘两个矩形区域的并集。
- 使用DMA传输:MaixPy的
lcd.display()内部已使用DMA,但自定义绘制时尽量批量发送数据,避免逐点传输。 - 降低SPI频率:在信号完整性允许的情况下,适当降低频率可以减少误码率,反而提升整体效率。
- 双缓冲:在RAM中维护一个帧缓冲,绘制完成后一次性刷入LCD,避免屏幕闪烁。
常见故障排查表:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 屏幕全白/全黑 | 初始化失败、背光未开启 | 检查BL引脚电平,重新执行初始化序列 |
| 显示乱码/花屏 | SPI模式错误、DC引脚接反 | 确认SPI模式(模式0或3),检查DC引脚映射 |
| 颜色偏色 | RGB565格式设置错误 | 检查0x3A命令参数是否为0x05 |
| 画面闪烁 | 清屏频率过高、SPI速率不足 | 减少全屏清屏次数,使用局部刷新 |
| 坐标偏移 | 显示方向设置错误 | 重新调用lcd.direction()并校准原点 |
lcd_x = cam_x * 320 / 320、lcd_y = cam_y * 240 / 240进行等比映射,问题随即解决。这个案例说明,在项目初期就应统一摄像头与LCD的分辨率和方向,避免后期反复调整。