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)