3. LCD显示基础:LCD驱动初始化、屏幕分辨率、颜色格式(RGB565)、清屏、绘制点线面等基本图形API

在K210视觉识别项目中,LCD屏幕是人与机器交互的核心窗口。无论是绘制人脸识别框、显示物体类别标签,还是呈现实时帧率与系统状态,所有视觉结果最终都需要通过LCD呈现给用户。本章将围绕K210常用LCD(以ST7789、ILI9341驱动芯片为代表)展开,系统讲解驱动初始化流程、分辨率与颜色格式(RGB565)的底层逻辑、清屏操作以及点、线、矩形、圆等基本图形API的使用方法。理解这些基础能力,是后续实现识别框绘制与多目标可视化的前提。

K210 LCD显示链路与图形API架构 K210 SPI主机 SCLK / MOSI / MISO CS / DC / RST / BL LCD驱动芯片 ST7789 / ILI9341 显存: 240×320×2B SPI命令/数据 像素格式 RGB565 R:5bit G:6bit B:5bit 2字节/像素 像素流 图形API层 lcd_clear() 清屏 lcd_draw_point() 画点 lcd_draw_line() 画线 lcd_draw_rect() 矩形 高级绘制能力 lcd_draw_circle() 圆 lcd_draw_string() 字符 lcd_draw_picture() 图片 lcd_fill_rect() 填充 识别框可视化 人脸框 / 物体框 标签 / 置信度 FPS / 系统状态 多目标叠加 初始化流程: 引脚配置 → SPI时钟(40MHz) → 复位时序 → 初始化命令序列 → 设置显示方向 → 清屏 → 绘制图形 关键参数: 分辨率240×320 | 颜色深度RGB565 | 帧缓冲约150KB

上图展示了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)等关键命令。

操作流程:

  1. 引脚映射:在代码中定义SPI引脚(SCLK、MOSI)以及DC、CS、RST、BL对应的GPIO编号。K210的MaixPy固件通常使用FPIOA(现场可编程IO阵列)进行引脚重映射。
  2. SPI主机初始化:设置SPI频率(典型值40MHz)、工作模式(模式0或模式3,取决于LCD芯片要求)。
  3. 硬件复位:将RST引脚拉低至少10ms,再拉高,确保芯片从干净状态启动。
  4. 发送初始化命令序列:按照芯片手册逐条发送命令和参数。每条命令发送时,DC引脚置低表示命令,置高表示数据。
  5. 设置显示方向:通过0x36命令的MADCTL参数控制扫描方向,决定屏幕的横竖显示。
  6. 开启显示并清屏:发送0x29开启显示,然后调用清屏函数将显存填充为背景色。
MaixPy初始化示例(简化):
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)     # 清屏为黑色
常见误区:很多初学者忘记设置DC引脚,导致LCD完全无响应或显示乱码。另外,SPI频率并非越高越好,超过芯片支持上限(如ST7789最高约62.5MHz)会导致数据错误。建议从20MHz开始调试,稳定后再提升频率。

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)适用场景
黑色0x0000000背景/文字
白色0xFFFF316331高亮/文字
红色0xF8003100警告/识别框
绿色0x07E00630正常/通过
蓝色0x001F0031信息/链接
黄色0xFFE031630警告/注意

颜色转换方法:在代码中,我们经常需要将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)函数自动处理缩放,但手动绘制框时仍需自行转换。

经验总结:建议在项目初始化时固定LCD方向,并在整个生命周期内不切换。频繁切换方向会导致屏幕闪烁,且需要重新清屏。如果必须支持横竖屏切换,应在切换后重新绘制所有静态UI元素。

3.5 性能优化与常见问题排查

LCD显示性能直接影响用户体验。在实时识别场景中,我们希望帧率尽可能高,同时画面不撕裂。

性能瓶颈分析:SPI传输是最大瓶颈。以40MHz SPI时钟计算,理论最大传输速率为5MB/s。绘制一个240×320全屏图像需要153,600字节,理论耗时约30ms,实际加上命令开销约40-50ms,即帧率上限约20-25FPS。如果使用RGB565格式,这个数字是固定的。

优化策略:

  1. 局部刷新:只更新识别框所在的区域,而不是全屏重绘。例如,上一帧人脸框在(80,60,120,150),下一帧移动到(90,65,118,148),只需重绘两个矩形区域的并集。
  2. 使用DMA传输:MaixPy的lcd.display()内部已使用DMA,但自定义绘制时尽量批量发送数据,避免逐点传输。
  3. 降低SPI频率:在信号完整性允许的情况下,适当降低频率可以减少误码率,反而提升整体效率。
  4. 双缓冲:在RAM中维护一个帧缓冲,绘制完成后一次性刷入LCD,避免屏幕闪烁。

常见故障排查表:

现象可能原因排查方法
屏幕全白/全黑初始化失败、背光未开启检查BL引脚电平,重新执行初始化序列
显示乱码/花屏SPI模式错误、DC引脚接反确认SPI模式(模式0或3),检查DC引脚映射
颜色偏色RGB565格式设置错误检查0x3A命令参数是否为0x05
画面闪烁清屏频率过高、SPI速率不足减少全屏清屏次数,使用局部刷新
坐标偏移显示方向设置错误重新调用lcd.direction()并校准原点
案例复盘:在某次人脸识别门禁项目中,我们遇到屏幕显示正常但识别框位置偏移的问题。排查发现,摄像头输出分辨率为320×240(QVGA),而LCD设置为竖屏240×320,导致坐标映射错误。解决方案是将LCD切换为横屏模式,并按照lcd_x = cam_x * 320 / 320、lcd_y = cam_y * 240 / 240进行等比映射,问题随即解决。这个案例说明,在项目初期就应统一摄像头与LCD的分辨率和方向,避免后期反复调整。