跳转至

作者:江访

一、矢量字库

一、演示功能概述

AirFONT_1000 是合宙设计生产的一款 SPI 接口支持 16-192 矢量字体读取的配件板;

本 demo 演示的核心功能为:

Air8000 核心板 +AirFONT_1000 配件板,从 16-192 矢量字体各颜色字体的显示;

二、核心板 + 配件板资料

Air8000 核心板 + 配件板相关资料

三、演示硬件环境

1、接线图片

2、物料清单

1、Air8000 核心板

2、AirFONT_1000 配件板

3、AirLCD_1060 触摸屏

4、母对母的杜邦线 6 根,一定要使用配套的 5cm 长的杜邦线相连,杜邦线太长的话,会出现 spi 通信不稳定的现象;

5、Air8000 核心板和 AirFONT_1000 配件板的硬件接线方式为

  • Air8000 核心板通过 TYPE-C USB 口供电(核心板背面的功耗测试开关拨到 OFF 一端),此种供电方式下,VDD_EXT 引脚为 3.3V,可以直接给 AirFONT_1000 配件板供电;
  • 为了演示方便,所以 Air8000 核心板上电后直接通过 vbat 引脚给 AirFONT_1000 配件板提供了 3.3V 的供电;
  • 客户在设计实际项目时,一般来说,需要通过一个 GPIO 来控制 LDO 给配件板供电,这样可以灵活地控制配件板的供电,可以使项目的整体功耗降到最低;

3、接线方式

1、Air8000 核心板与 AirFONT_1000 配件板

Air8000核心板 AirFONT_1000配件板
VDD_EXT 3V3
GND GND
SPI1_MOSI MOSI
SPI1_MISO MISO
SPI1_CS CS
SPI1_SCLK CLK

2、Air8000 核心板与 AirLCD_1060 屏幕

Air8000核心板 AirLCD_1060触摸屏
VBAT VBAT
GND GND
LCD_RST LCD_RST
LCD_SDA LCD_SDA
LCD_RS LCD_RS
LCD_CS LCD_CS
LCD_CLK LCD_CLK
WAKEUP6 TP_INT
I2C0_SDA I2C0_SDA
I2C0_SCL I2C0_SCL

四、演示软件环境

1、Luatools 下载调试工具

2、Air8000 最新版本的内核固件

3、使用 demo 脚本

1、main.lua

---------------------------------------------功能说明---------------------------------------------
--[[
@module  main
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
@version 1.0
@date    2025.08.07
@author  江访
@usage
本demo演示的核心功能为:
主入口模块
核心功能:
1. 定义项目名称和版本号
2. 初始化系统各功能模块
3. 启动用户界面系统
4. 管理整体应用生命周期
更多说明参考本目录下的readme.md文件
]]
---------------------------------------------模块结构---------------------------------------------
--[[
- main.lua                      --主函数,只负责require
  - ui_main.lua                 --用户界面主模块,负责UI相关的初始化,主循环
    - airlcd.lua                --显示屏初始化程序
    - AirFONTS_1000.lua         --高通矢量字体
]]
---------------------------------------------使用说明---------------------------------------------
--[[
1. 定义PROJECT和VERSION全局变量
2. 根据所接设备配置屏幕型号(ui_main),屏幕尺寸(airlcd),配置LCD供电引脚(airlcd)
3. 加载系统服务和用户界面
4. 调用sys.run()启动系统
]]
---------------------------------------------注意事项---------------------------------------------
--[[
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
PROJECT:项目名,ascii string类型
        可以随便定义,只要不使用,就行
VERSION:项目版本号,ascii string类型
        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
]]
---------------------------------------------相关代码---------------------------------------------
-- 项目定义(必须)
PROJECT = "AirFONTS_1000_demo"  -- 项目名称
VERSION = "1.0.0"       -- 项目版本

-- 在日志中打印项目名和项目版本号
log.info("main", PROJECT, VERSION)

-- log.style(2) --调试日志风格

-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
if wdt then
    --配置喂狗超时时间为9秒钟
    wdt.init(9000)
    --启动一个循环定时器,每隔3秒钟喂一次狗
    sys.timerLoopStart(wdt.feed, 3000)
end

-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
-- 启动errDump日志存储并且上传功能,600秒上传一次
-- if errDump then
--     errDump.config(true, 600)
-- end

-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
-- 可以使用合宙的iot.openluat.com平台进行远程升级
-- 也可以使用客户自己搭建的平台进行远程升级
-- 远程升级的详细用法,可以参考fota的demo进行使用

-- 启动一个循环定时器
-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
-- 方便分析内存使用是否有异常
-- sys.timerLoopStart(function()
--     log.info("mem.lua", rtos.meminfo())
--     log.info("mem.sys", rtos.meminfo("sys"))
-- end, 3000)

-- 加载用户界面主模块
require "ui_main"

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

2、ui_main.lua

---------------------------------------------功能说明---------------------------------------------
--[[
本文件为用户界面主模块
核心功能:
1. 协调各UI子文件
2. 初始化显示、触摸和页面管理
3. 管理主循环和事件分发

执行流程:
1. 初始化矢量字库
2. 初始化显示屏
3. 进入主循环显示
]]
---------------------------------------------相关代码---------------------------------------------
local ui_main = {}

--加载AirFONTS_1000驱动文件
local air_vetor_fonts = require "AirFONTS_1000"
--加载AirLCD_1001驱动文件
local airlcd = require "airlcd"           -- LCD驱动
local LCD_MODEL = "co5300"           -- LCD型号
local spi_id = 1 -- 接到模组的spi端口号,sip0就写0,spi1就写1
local spi_cs = 12 -- 字库所借spi片选引脚所对应的GPIO端口号

-- lcd显示矢量字体的task
-- AirFONTS_1000矢量字库,使用gtfont灰度显示UTF8字符串,支持16-192号大小字体
-- 自动刷新显示16到192字号的字体显示效果(非灰度显示以及灰度显示)

sys.taskInit(function()
    -- 初始化外置AirFONTS_1000矢量字库,使用gtfont灰度显示UTF8字符串,支持16-192号大小字体
    air_vetor_fonts.init(spi_id,spi_cs)                    --设置初始化AirFONTS_1000矢量字体
    lcd.setFont(lcd.drawGtfontUtf8)           --设置使用高通矢量字体

    -- 按所配置的型号参数初始化显示屏
    -- 注意:在airlcd内是按核心板和AirLCD_1001参数设置的,实际使用过程中按实际参数在airlcd和page_data_table内修改配置。
    airlcd.lcd_init(LCD_MODEL)

-- 开启显示缓冲区, 刷屏速度会加快, 但也消耗2倍屏幕分辨率的内存(2*宽*高 字节)
    -- 第一个参数无意义,直接填nil即可
    -- 第二个参数true表示使用sys中的内存
    lcd.setupBuff(nil, true)
    --禁止自动刷新
    --需要刷新时需要主动调用lcd.flush()接口,才能将缓冲区中的数据显示到lcd上
    lcd.autoFlush(false)

    while true do
        -- 显示AirFONTS_1000的总体特性
        -- 目前还有两个问题:
        -- 1、字母显示宽度不正常
        -- 2、颜色设置接口还没生效
        for i=5,1,-1 do
            --清屏
            lcd.clear()

            --设置背景色为白色,文字的前景色为黑色
            lcd.setColor(0xFFFF, 0x0000)
            lcd.drawGtfontUtf8("AirFONTS_1000配件板",32,50,150)

            --设置背景色为白色,文字的前景色为红色
            lcd.setColor(0xFFFF, 0xF800)
            lcd.drawGtfontUtf8("支持16到192号的黑体字体",32,50-8,191)

            --设置背景色为白色,文字的前景色为绿色
            lcd.setColor(0xFFFF, 0x07E0)
            lcd.drawGtfontUtf8("支持GBK中文和ASCII码字符集",32,50-20,232)

            --设置背景色为白色,文字的前景色为蓝色
            lcd.setColor(0xFFFF, 0x001F)
            lcd.drawGtfontUtf8("支持灰度显示,字体边缘更平滑",32,20,273)

            lcd.drawGtfontUtf8("倒计时:"..i,32,150,313)

            --刷屏显示
            lcd.flush()

            --等待1秒
            sys.wait(1000)
        end

        -- 16号到192号不支持灰度的显示效果演示

        --设置背景色为白色,文字的前景色为黑色
        lcd.setColor(0xFFFF, 0x0000)
        for i=16,64,1 do
            --清屏
            lcd.clear()

            lcd.drawGtfontUtf8(i.."号:合宙AirFONTS_1000",i,60,100)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        --设置背景色为白色,文字的前景色为红色
        lcd.setColor(0xFFFF, 0xF800)
        for i=65,96,1 do
            --清屏
            lcd.clear()

            lcd.drawGtfontUtf8(i.."号",i,60,100)
            lcd.drawGtfontUtf8("AirFONTS_1000",i,60,100+i+5)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        --设置背景色为白色,文字的前景色为绿色
        lcd.setColor(0xFFFF, 0x07E0)
        for i=97,128,1 do
            --清屏
            lcd.clear()

            lcd.drawGtfontUtf8(i.."号",i,60,20)
            lcd.drawGtfontUtf8("合宙",i,60,20+i+5)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        --设置背景色为白色,文字的前景色为蓝色
        lcd.setColor(0xFFFF, 0x001F)
        for i=129,192,1 do
            --清屏
            lcd.clear()

            lcd.drawGtfontUtf8(i.."号",i,60,20)
            lcd.drawGtfontUtf8("合宙",i,60,20+i+5)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        -- 16号到192号支持灰度的显示效果演示

        --设置背景色为白色,文字的前景色为黑色
        lcd.setColor(0xFFFF, 0x0000)
        for i=16,48,1 do
            --清屏
            lcd.clear()
            lcd.drawGtfontUtf8Gray(i.."号灰度:合宙AirFONTS_1000",i,4,60,100)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        --设置背景色为白色,文字的前景色为红色
        lcd.setColor(0xFFFF, 0xF800)
        for i=49,80,1 do
            --清屏
            lcd.clear()
            lcd.drawGtfontUtf8Gray(i.."号灰度",i,4,60,100)
            lcd.drawGtfontUtf8Gray("合宙AirFONTS_1000",i,4,60,100+i+5)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end

        --设置背景色为白色,文字的前景色为绿色
        lcd.setColor(0xFFFF, 0x07E0)
        for i=81,128,1 do
            --清屏
            lcd.clear()
            lcd.drawGtfontUtf8Gray(i.."号",i,4,60,20)
            lcd.drawGtfontUtf8Gray("合宙",i,4,60,20+i+5)

            --刷屏显示
            lcd.flush()

            --等待20毫秒
            sys.wait(20)
        end


        --设置背景色为白色,文字的前景色为蓝色
        lcd.setColor(0xFFFF, 0x001F)
        for i=129,192,1 do
            --清屏
            lcd.clear()

            lcd.drawGtfontUtf8(i.."号",i,60,20)
            lcd.drawGtfontUtf8("合宙",i,60,20+i+5)

            --刷屏显示
            lcd.flush()
            sys.wait(20)
        end
    end
end)

return ui_main

3、AirFONTS_1000 .lua

local AirFONTS_1000 = {}

--初始化AirFONTS_1000的SPI配置
--AirFONTS_1000通过SPI接口(SCK CS MOSI MISO)和主控相连
--主控设备为SPI主设备,AirFONTS_1000为SPI从设备

--spi_id:number类型;
--     表示主设备的SPI ID;
--     取值范围:主控产品上有效的SPI ID值,例如Air8101上的取值范围为0和1;
--     如果没有传入此参数或者传入了nil,则使用默认值1;
--spi_cs:number类型;
--     表示cs引脚的GPIO ID;
--     取值范围:主控产品上有效的GPIO ID值,例如Air8101上的取值范围为0到9,12,14到55;
--     如果没有传入此参数或者传入了nil,则使用默认值12;

--返回值:成功返回true,失败返回false
function AirFONTS_1000.init(spi_id, spi_cs)
    --创建一个SPI设备对象
    AirFONTS_1000.spi_gtfont = spi.deviceSetup(spi_id or 1, spi_cs or 12, 0, 0, 8, 20*1000*1000, spi.MSB, 1, 0)
    log.error("AirFONTS_1000.init", "spi.deviceSetup", type(AirFONTS_1000.spi_gtfont))
    --检查SPI设备对象是否创建成功
    if type(AirFONTS_1000.spi_gtfont) ~= "userdata" then
        log.error("AirFONTS_1000.init", "spi.deviceSetup error", type(AirFONTS_1000.spi_gtfont))
        return false
    end

    --初始化矢量字库
    if not gtfont.init(AirFONTS_1000.spi_gtfont) then
        log.error("AirFONTS_1000.init", "gtfont.init error")
        return false
    end

    return true
end

return AirFONTS_1000

4、airlcd.lua

-- airlcd.lua
--[[
LCD显示屏驱动模块
核心功能:
1. 支持多种型号LCD的初始化配置
2. 提供统一的LCD初始化接口
3. 特殊型号特殊处理的初始化流程

支持的LCD型号:
- AirLCD_1000: 320x480, ST7796控制器
- AirLCD_1001: 320x480, ST7796控制器
- AirLCD_1002: 480x480, R395435T01控制器
- co5300: 480x466, 自定义初始化流程

对外接口:
1. lcd_init(sn): 初始化指定型号的LCD
   - sn: LCD型号字符串

注意:SPI引脚、供电引脚、RST引脚都需要与实际接线端口进行匹配
   ]]

local airLCD = {}

-- 必须在task里用,自发光屏幕不需要背光控制
function co5300_init(lcd_cfg)
    lcd.qspi(0x02, 0x32, 0x12)
    lcd.init("user", lcd_cfg)
    gpio.set(lcd_cfg.pin_rst, 0)
    sys.wait(300)
    gpio.set(lcd_cfg.pin_rst, 1)
    sys.wait(200)
    lcd.cmd(0xfe, 0x00)
    lcd.cmd(0xc4, 0x80)
    lcd.cmd(0x3a, 0x55)
    lcd.cmd(0x35, 0x00)
    lcd.cmd(0x53, 0x20)
    lcd.cmd(0x51, 0x7a)
    lcd.cmd(0x63, 0xaa)
    lcd.cmd(0x36, 0x00) --方向
    lcd.wakeup()
    sys.wait(200)
    lcd.cmd(0x29)
end

function airLCD.lcd_init(sn)
    local width, height, lcd_ic

    if sn == "AirLCD_1000" then
        width = 320
        height = 480
        lcd_ic = "st7796"
    elseif sn == "AirLCD_1001" then
        width = 320
        height = 480
        lcd_ic = "st7796"
    elseif  sn == "AirLCD_1002" then
        width = 480
        height = 480
        lcd_ic = "R395435T01"
    elseif sn == "co5300" then  -- 新增co5300支持
        width = 480
        height = 466
        lcd_ic = "user"
    else
        log.info("lcd", "没有找到合适的LCD")
        return
    end

    -- 公共初始化参数
    local lcd_param = {
        port = lcd.HWID_0,      -- 使用的spi id 号
        --pin_dc = -1,            -- QSPI模式不需要DC引脚
        --pin_rst = 36,           -- 复位引脚
        pin_dc = 0xff,            -- 命令选择硬件,不设置
        pin_rst = 2,             -- 屏幕reset 管脚  
        direction = 0,            -- 屏幕方向
        w = width,                -- 屏幕宽度
        h = height,               -- 屏幕高度
        xoffset = 0,              -- X轴偏移像素
        yoffset = 0,              -- Y轴偏移像素
        sleepcmd = 0x10,          -- LCD睡眠命令
        wakecmd = 0x11,           -- LCD唤醒命令
    }

    -- 如果是co5300添加QSPI专用参数
    if sn == "co5300" then
        lcd_param.interface_mode = lcd.QSPI_MODE
        lcd_param.bus_speed = 60000000  -- 60MHz
        lcd_param.rb_swap = true
        lcd_param.pin_pwr = -1         -- 自发光屏不需要背光控制
        lcd_param.pin_dc = -1
        lcd_param.pin_rst = 36
        gpio.setup(17, 0, gpio.PULLUP)-- CO5300电源
        sys.wait(100)
        gpio.setup(17, 1, gpio.PULLUP)
        sys.wait(1000)
    elseif sn == "AirLCD_1001" then
        lcd_param.pin_dc = 0xff
        lcd_param.pin_rst = 2
        gpio.setup(164, 1, gpio.PULLUP)
        gpio.setup(141, 1, gpio.PULLUP)
        sys.wait(1000)
        lcd.init(lcd_ic, lcd_param)
    end

    -- 特殊初始化流程
    if sn == "co5300" then
        co5300_init(lcd_param)
    else
        lcd.init(lcd_ic, lcd_param)
    end

    -- 公用设置
    lcd.setupBuff(nil, true)
    lcd.autoFlush(false)
    lcd.user_done()
    lcd.clear()
    lcd.flush()

end

return airLCD

五、演示操作步骤

1、搭建好演示硬件环境

2、不需要修改 demo 脚本代码

3、Luatools 烧录内核固件和 demo 脚本代码

4、烧录成功后,自动开机运行

5、屏幕出现以下显示,就表示测试正常