跳转至

LCD屏驱动

一、LCD 概述:

LCD(Liquid Crystal Display,液晶显示器)是嵌入式系统中常用的显示设备,广泛应用于智能家居、工业控制、医疗设备、消费电子等领域。以下是 LCD 的详细介绍:

1.1 嵌入式 LCD 的基本原理

LCD 通过控制液晶分子的排列来改变光的透过率,从而显示图像或文字。其核心组成部分包括:

  • 液晶层:通过电场控制液晶分子的排列
  • 背光模块:提供光源(如 LED 背光)
  • 驱动电路:控制液晶分子的电场和像素的显示
  • 控制芯片:负责处理图像数据并发送给驱动电路

1.2 接口类型

  • SPI(串行接口,适合低引脚数场景)。
  • 8080 并行接口(8/9/16/18 位数据总线,高速传输)
  • RGB 接口(直接驱动 RGB 数据,需搭配时序控制器)
  • MIPI DSI(部分型号支持,用于高性能移动设备)

注意: 780EPM 目前只支持 SPI 接口的 LCD。

1.3 硬件连接示例(SPI 模式)

二、演示功能概述

本例程将使用 Air780EPM 的 LCD 功能,配合 Air780EPM V1.2开发板配套的 LCD 屏幕显示内容。

三、准备硬件环境

参考:硬件环境清单第二章节内容,准备以及组装好硬件环境。

3.1 ST7796 LCD 屏幕一个

3.2 780EPM 与 ST7796 LCD 屏幕 接线图如下

3.3 780EPM V1.2开发板与ST7796 LCD屏幕实物接线图

四、软件环境

“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。

1. Luatools 工具

2. 内核固件文件(底层 core 固件文件):LuatOS-SoC_V2003_Air780EPM;参考项目使用的内核固件

3. luatos 需要的脚本和资源文件

脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air780EPM/tree/master/demo/lcd

lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;

准备好软件环境之后,接下来查看如何烧录项目文件到 Air780EPM 开发板,将本篇文章中演示使用的项目文件烧录到 Air780EPM V1.2开发板中。

4. LuatOS 工程文件:lcd_20250328.luatos

五、使用 LCD 软硬件资料:

5.1 LCD 硬件参考资料

Air780EPM 支持 LCD 接口参考:LCD 参考电路和选型推荐

5.2 API 接口介绍

api 链接地址:lcd-api 地址

lcd.init(tp, args, spi_dev, init_in_service)

lcd 显示屏初始化

参数

传入值类型
解释
string

lcd类型,当前支持:
st7796
st7789
st7735
st7735v
st7735s
gc9a01
gc9106l
gc9306x
ili9486
custom
table
附加参数,与具体设备有关:
pin_pwr(背光)为可选项,可不设置
port:驱动端口,rgb:lcd.RGB spi:例如0,1,2...如果为device方式则为"device"
pin_dc:lcd数据/命令选择引脚
pin_rst:lcd复位引脚
pin_pwr:lcd背光引脚 可选项,可不设置
direction:lcd屏幕方向 0:0° 1:180° 2:270° 3:90°
w:lcd 水平分辨率
h:lcd 竖直分辨率
xoffset:x偏移(不同屏幕ic 不同屏幕方向会有差异)
yoffset:y偏移(不同屏幕ic 不同屏幕方向会有差异)
direction0:0°方向命令,(不同屏幕ic会有差异)
direction90:90°方向命令,(不同屏幕ic会有差异)
direction180:180°方向命令,(不同屏幕ic会有差异)
direction270:270°方向命令,(不同屏幕ic会有差异)
sleepcmd:睡眠命令,默认0X10
wakecmd:唤醒命令,默认0X11
interface_mode lcd模式,默认lcd.WIRE_4_BIT_8_INTERFACE_I
bus_speed:qspi/rgb总线速率
hbp:水平后廊
hspw:水平同步脉冲宽度
hfp:水平前廊
vbp:垂直后廊
vspw:垂直同步脉冲宽度
vfp:垂直前廊

返回值

例子

lcd.init("st7796", {
    port = port,
    pin_dc = pin_dc,
    pin_pwr = bl,
    pin_rst = pin_reset,
    direction = 0,
    -- direction0 = 0x00,
    w = 320,
    h = 480,
    xoffset = 0,
    yoffset = 0,
    sleepcmd = 0x10,
    wakecmd = 0x11,
})

lcd.clear(color)

lcd 清屏

参数

传入值类型
解释
int
屏幕颜色 可选参数,默认背景色

返回值

例子

lcd清屏lcd.clear()

lcd.drawLine(x0,y0,x1,y1,color)

在两点之间画一条线.

参数

传入值类型
解释
int
第一个点的X位置.
int
第一个点的Y位置.
int
第二个点的X位置.
int
第二个点的Y位置.
int
绘画颜色 可选参数,默认前景色

返回值

例子

lcd.drawLine(100, 240, 240, 240, 0x001F)

lcd.drawRectangle(x0,y0,x1,y1,color)

从 x / y 位置(左上边缘)开始绘制一个框

参数

传入值类型
解释
int
左上边缘的X位置.
int
左上边缘的Y位置.
int
右下边缘的X位置.
int
右下边缘的Y位置.
int
绘画颜色 可选参数,默认前景色

返回值

例子

lcd.drawRectangle(100, 240, 240, 70, 0xF800)

lcd.drawCircle(x0,y0,r,color)

从 x / y 位置(圆心)开始绘制一个圆

参数

传入值类型
解释
int
圆心的X位置.
int
圆心的Y位置.
int
半径.
int
绘画颜色 可选参数,默认前景色

返回值

例子

lcd.drawCircle(150, 240, 100, 0x0CE0)

lcd.setFont(font, indentation)

设置字体

参数

传入值类型
解释
int
font lcd.font_XXX 请查阅常量表
int
indentation, 等宽字体ascii右侧缩进0~127个pixel,等宽字体的ascii字符可能在右侧有大片空白,用户可以选择删除部分。留空或者超过127则直接删除右半边, 非等宽字体无效

返回值

例子

lcd.setFont(lcd.font_opposansm32)
lcd.drawStr(60,240,"hello hezhou") --显示字符

lcd.drawStr(x,y,str,fg_color)

显示字符串

参数

传入值类型
解释
int
x 横坐标
int
y 竖坐标 注意:此(x,y)为左下起始坐标
string
str 文件内容
int
fg_color str颜色 注意:此参数可选,如不填写则使用之前设置的颜色,绘制只会绘制字体部分,背景需要自己清除

返回值

例子

lcd.setFont(lcd.font_opposansm32)
lcd.drawStr(60,240,"hello hezhou") --显示字符

lcd.showImage(x, y, file)

显示图片,当前只支持 jpg,jpeg

参数

传入值类型
解释
int
X坐标
int
y坐标
string
文件路径

返回值

例子

lcd.showImage(0,0,"/luadb/logo.jpg")

lcd.flush()

主动刷新数据到界面, 仅设置 buff 且禁用自动属性后使用

参数

返回值

返回值类型
解释
bool
成功返回true, 否则返回nil/false

例子

--本API与 lcd.setupBuff lcd.autoFlush 配合使用
lcd.flush()

lcd.setupBuff(conf, onheap)

设置显示缓冲区, 所需内存大小为 2× 宽 × 高 字节. 请衡量内存需求与业务所需的刷新频次.

参数

传入值类型
解释
userdata
conf指针, 不需要传
bool
true使用heap内存, false使用vm内存, 默认使用vm内存, 不需要主动传

返回值

返回值类型
解释
bool
是否成功

例子

-- 初始化lcd的buff缓冲区, 可理解为FrameBuffer区域
lcd.setupBuff()

lcd.autoFlush(enable)

设置自动刷新, 需配合 lcd.setupBuff 使用

参数

传入值类型
解释
bool
是否自动刷新,默认为true

返回值

例子

-- 设置buff 并禁用自动更新
lcd.setupBuff()
lcd.autoFlush(false)
-- 禁止自动更新后, 需要使用 lcd.flush() 主动刷新数据到屏幕

六、代码示例介绍

6.1 代码介绍

PROJECT = "lcddemo"
VERSION = "1.0.0"

log.info("main", PROJECT, VERSION)

-- sys库是标配
sys = require("sys")

-- 添加硬狗防止程序卡死
if wdt then
    wdt.init(9000) -- 初始化watchdog设置为9s
    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
end

pm.ioVol(pm.IOVOL_ALL_GPIO, 3000)--所有IO电平开到3V,电平匹配
-- 注意:V1.2的开发板需要打开GPIO28,V1.3的开发板需要打开GPIO29
gpio.setup(28, 1) -- GPIO28打开给lcd电源供电 
-- gpio.setup(29, 1) -- GPIO29打开给lcd电源供电

local rtos_bsp = rtos.bsp()
-- local chip_type = hmeta.chip()
-- 根据不同的BSP返回不同的值
-- 根据不同的BSP返回不同的值
-- spi_id,pin_reset,pin_dc,pin_cs,bl
local function lcd_pin()
    local rtos_bsp = rtos.bsp()
    if string.find(rtos_bsp, "780EPM") then
        return lcd.HWID_0, 36, 0xff, 0xff, 25 -- 注意:EC718P有硬件lcd驱动接口, 无需使用spi,当然spi驱动也支持
    else
        log.info("main", "没找到合适的cat.1芯片", rtos_bsp)
        return
    end
end

local spi_id, pin_reset, pin_dc, pin_cs, bl = lcd_pin()
if spi_id ~= lcd.HWID_0 then
    spi_lcd = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 0)
    port = "device"
else
    port = spi_id
end

lcd.init("st7796", {
    port = port,
    pin_dc = pin_dc,
    pin_pwr = bl,
    pin_rst = pin_reset,
    direction = 0,
    -- direction0 = 0x00,
    w = 320,
    h = 480,
    xoffset = 0,
    yoffset = 0,
    sleepcmd = 0x10,
    wakecmd = 0x11,
})

-- 不在内置驱动的, 看demo/lcd_custom

sys.taskInit(function()
    -- 开启缓冲区, 刷屏速度回加快, 但也消耗2倍屏幕分辨率的内存
    -- lcd.setupBuff()          -- 使用lua内存
    lcd.setupBuff(nil, true) -- 使用sys内存, 只需要选一种
    lcd.autoFlush(false)

    while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        -- log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        -- log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        -- log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        -- lcd.setFont(lcd.font_opposansm32)
        -- lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end
end)

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

6.2 结果演示

1.使用 Air780EPM V1.2开发板 + 分辨率为 320*480 的 LCD 屏幕显示图片

代码里打开图片注释:

while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        -- log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        -- log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        -- log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        -- lcd.setFont(lcd.font_opposansm32)
        -- lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end

效果如下图所示:

2.使用 Air780EPM V1.2开发板 + 分辨率为 320*480 的 LCD 屏幕画线

代码里打开画线注释:

while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            -- lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        -- log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        -- log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        -- lcd.setFont(lcd.font_opposansm32)
        -- lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end

效果如下图所示:

3.使用 Air780EPM V1.2开发板 + 分辨率为 320*480 的 LCD 屏幕画框

代码里打开画框注释:

while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            -- lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        -- log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        -- log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        -- lcd.setFont(lcd.font_opposansm32)
        -- lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end

效果如下图所示:

3.使用 Air780EPM V1.2开发板 + 分辨率为 320*480 的 LCD 屏幕画圆

代码里打开画圆注释:

while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            -- lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        -- log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        -- log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        -- lcd.setFont(lcd.font_opposansm32)
        -- lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end

效果如下图所示:

4.使用 Air780EPM V1.2开发板 + 分辨率为 320*480 的 LCD 屏幕字符显示

代码里打开字符注释:

while 1 do
        lcd.clear()
        log.info("合宙 780EPM LCD演示")
        -- API 文档 https://wiki.luatos.com/api/lcd.html
        if lcd.showImage then
            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
            -- lcd.showImage(0, 0, "/luadb/picture.jpg") --显示图片
            sys.wait(100)
        end
        -- log.info("lcd.drawLine", lcd.drawLine(100, 240, 240, 240, 0x001F)) -- 画线
        -- log.info("lcd.drawRectangle", lcd.drawRectangle(100, 240, 240, 70, 0xF800)) -- 画框
        -- log.info("lcd.drawCircle", lcd.drawCircle(150, 240, 100, 0x0CE0)) -- 画圆

        lcd.setFont(lcd.font_opposansm32)
        lcd.drawStr(60,240,"hello hezhou") --显示字符
        lcd.flush()
        sys.wait(1000)
    end

效果如下图所示:

6.3 烧录代码注意事项

因为烧录脚本区可用空间有限,所以烧录时仅放置自己所用照片即可

七、总结

本文演示如何在 Air780EPM V1.2开发板上实现 LCD 屏幕显示图片、字符和画线,框,圆的功能。

八、常见问题

8.1 注意:字符显示 可以选择选择大小

例如想选择 32 号字体,在代码中可以 lcd.setFont(lcd.font_opposansm32)