init: Air780EPM 官方 LuatOS 项目代码基线
- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码 - 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等) - 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
--[[
|
||||
@module hw_default_font_drv
|
||||
@summary LCD初始化和内置点阵字体驱动模块
|
||||
@version 1.0
|
||||
@date 2026.01.06
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为LCD初始化和内置字体硬件驱动模块,核心业务逻辑为:
|
||||
1、初始化ST7567单色点阵屏(128x64分辨率);
|
||||
2、配置SPI通信参数和显示参数;
|
||||
3、设置内置字体显示模式;
|
||||
4、显示开机信息并开启背光;
|
||||
|
||||
本文件无对外接口,模块加载时自动执行初始化;
|
||||
]]
|
||||
|
||||
-- ST7567 SPI引脚配置
|
||||
local spi_id, spi_res, spi_dc, spi_cs = 1, 24, 14, 12
|
||||
|
||||
local function init()
|
||||
-- 初始化U8G2显示屏 - ST7567, 128x64
|
||||
local result = u8g2.begin(
|
||||
{
|
||||
ic = "custom", -- 使用自定义IC
|
||||
direction = 0, -- 显示方向
|
||||
mode = "spi_hw_4pin", -- SPI硬件4线模式
|
||||
spi_id = spi_id, -- SPI端口号
|
||||
spi_res = spi_res, -- 复位引脚
|
||||
spi_dc = spi_dc, -- 数据/命令选择引脚
|
||||
spi_cs = spi_cs -- 片选引脚
|
||||
},
|
||||
{
|
||||
width = 128, -- 分辨率宽度,128像素
|
||||
height = 64, -- 分辨率高度,64像素
|
||||
|
||||
-- 初始化命令表,根据ST7567芯片手册配置
|
||||
initcmd = {
|
||||
0xE2, -- 系统复位
|
||||
0x82, -- 设置偏压比
|
||||
0x2F, -- 电源控制(开启内部电荷泵)
|
||||
0x26, -- 电阻比率设置
|
||||
0xF8, 0x00, -- 设置显示偏移(垂直偏移量为0)
|
||||
0x81, 0x09, -- 设置对比度(0x09为对比度值)
|
||||
0x40, -- 设置显示起始行(第0行)
|
||||
0xC8, -- COM扫描方向(反向)
|
||||
0xA4, -- 正常显示模式
|
||||
0xAF, -- 开启显示
|
||||
},
|
||||
sleepcmd = 0xAE, -- 休眠命令
|
||||
wakecmd = 0xAF, -- 唤醒命令
|
||||
}
|
||||
)
|
||||
|
||||
if result == 1 then
|
||||
-- SPI接口屏幕才能获取初始化成功后屏幕的长宽,I2C接口无法获取的屏幕初始化成功后的长宽
|
||||
local width = u8g2.GetDisplayWidth()
|
||||
local height = u8g2.GetDisplayHeight()
|
||||
log.info("u8g2", "ST7567 init success" .. width .. "x" .. height)
|
||||
|
||||
-- 设置字体显示模式为透明
|
||||
u8g2.SetFontMode(1)
|
||||
|
||||
-- 显示开机信息
|
||||
u8g2.ClearBuffer()
|
||||
u8g2.DrawUTF8("U8G2 Demo Start", 10, 30)
|
||||
u8g2.SendBuffer()
|
||||
|
||||
-- 打开背光,若采用GPIO控制
|
||||
gpio.setup(1, 1)
|
||||
else
|
||||
log.error("u8g2", "Init failed, error code:", result)
|
||||
end
|
||||
end
|
||||
|
||||
init()
|
||||
@@ -0,0 +1,62 @@
|
||||
--[[
|
||||
@module key_drv
|
||||
@summary 按键驱动模块
|
||||
@version 1.0
|
||||
@date 2025.12.11
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为按键驱动功能模块,核心业务逻辑为:
|
||||
1、初始化BOOT键和PWR键的GPIO;
|
||||
2、配置按键事件的中断处理函数;
|
||||
3、实现按键防抖功能,防止误触发;
|
||||
4、对外发布按键消息;
|
||||
|
||||
本文件没有对外接口,直接在main.lua中require "key_drv"就可以加载运行;
|
||||
]]
|
||||
|
||||
-- 按键定义
|
||||
local key_boot = 0 -- GPIO0按键(BOOT键)
|
||||
local key_pwr = gpio.PWR_KEY -- 电源按键
|
||||
|
||||
|
||||
-- 按键事件处理函数
|
||||
local function handle_boot_key(val)
|
||||
-- print("key_boot", val)
|
||||
if val == 1 then
|
||||
sys.publish("KEY_EVENT", "boot_down")
|
||||
else
|
||||
sys.publish("KEY_EVENT", "boot_up")
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_pwr_key(val)
|
||||
-- print("key_pwr", val)
|
||||
if val == 1 then
|
||||
sys.publish("KEY_EVENT", "pwr_up")
|
||||
else
|
||||
sys.publish("KEY_EVENT", "pwr_down")
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
初始化按键GPIO;
|
||||
配置BOOT键和PWR键的GPIO中断;
|
||||
|
||||
@api init()
|
||||
@summary 配置BOOT键和PWR键的GPIO中断
|
||||
@return bool 初始化只会返回true
|
||||
@usage
|
||||
|
||||
]]
|
||||
local function init()
|
||||
gpio.setup(key_boot, handle_boot_key, gpio.PULLDOWN, gpio.BOTH)
|
||||
gpio.debounce(key_boot, 50, 0) -- 防抖,防止频繁触发
|
||||
|
||||
gpio.setup(key_pwr, handle_pwr_key, gpio.PULLUP, gpio.BOTH)
|
||||
gpio.debounce(key_pwr, 50, 0) -- 防抖,防止频繁触发
|
||||
|
||||
log.info("key_drv", "按键初始化完成")
|
||||
end
|
||||
|
||||
init()
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
--[[
|
||||
@module main
|
||||
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
|
||||
@version 1.0
|
||||
@date 2025.12.11
|
||||
@author 江访
|
||||
@usage
|
||||
本demo演示的核心功能为:
|
||||
1、使用U8G2图形库驱动ST7567单色点阵屏(128x64);
|
||||
2、提供两种显示模式选择:组件演示、内置字体显示;
|
||||
3、通过BOOT键和PWR键进行菜单导航和确认操作;
|
||||
4、支持按键防抖和看门狗机制,确保系统稳定运行;
|
||||
|
||||
本文件作为程序入口,主要完成以下初始化工作:
|
||||
1、定义项目名称和版本号;
|
||||
2、初始化看门狗定时器;
|
||||
3、加载硬件显示驱动(使用内置12号英文点阵字体);
|
||||
4、加载按键驱动模块;
|
||||
5、启动UI主模块;
|
||||
更多说明参考本目录下的readme.md文件
|
||||
]]
|
||||
|
||||
|
||||
--[[
|
||||
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
|
||||
PROJECT:项目名,ascii string类型
|
||||
可以随便定义,只要不使用,就行
|
||||
VERSION:项目版本号,ascii string类型
|
||||
如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
|
||||
X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
|
||||
因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为999
|
||||
如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
|
||||
]]
|
||||
|
||||
-- main.lua - 程序入口文件
|
||||
|
||||
|
||||
-- 项目名称和版本定义
|
||||
PROJECT = "u8g2_demo" -- 项目名称,用于标识当前工程
|
||||
VERSION = "001.999.000" -- 项目版本号
|
||||
|
||||
-- 在日志中打印项目名和项目版本号
|
||||
log.info("u8g2_demo", PROJECT, VERSION)
|
||||
|
||||
-- 设置日志输出风格为样式2(建议调试时开启)
|
||||
-- log.style(2)
|
||||
|
||||
|
||||
|
||||
-- 如果内核固件支持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("hw_default_font_drv") -- 使用内置12号英文点阵字体
|
||||
|
||||
-- 加载按键驱动
|
||||
require("key_drv")
|
||||
|
||||
-- 加载UI主模块
|
||||
require("ui_main")
|
||||
|
||||
-- 用户代码已结束
|
||||
-- 结尾总是这一句
|
||||
sys.run()
|
||||
-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行
|
||||
@@ -0,0 +1,192 @@
|
||||
# U8G2显示屏与按键演示系统
|
||||
|
||||
### 1.1 核心主程序模块
|
||||
|
||||
1. **main.lua** - 主程序入口,负责系统初始化和任务调度
|
||||
2. **ui_main.lua** - 用户界面主控模块,管理页面切换和事件分发
|
||||
|
||||
### 1.2 显示页面模块
|
||||
|
||||
1. **home_page.lua** - 主页模块,提供应用入口和导航功能
|
||||
2. **component_page.lua** - 组件演示模块,展示进度条和基本图形
|
||||
3. **default_font_page.lua** - 内置字体演示模块,展示U8G2内置字体效果
|
||||
|
||||
### 1.3 驱动模块
|
||||
|
||||
1. **hw_default_font_drv.lua** - LCD初始化和内置12号英文点阵字体驱动模块
|
||||
2. **key_drv.lua** - 按键驱动模块,管理BOOT键和PWR键
|
||||
|
||||
## 二、按键消息介绍
|
||||
|
||||
1. **"KEY_EVENT"** - 按键事件消息,包含按键类型和状态
|
||||
- boot 键事件:`boot_down`(按下)、`boot_up`(释放)
|
||||
- pwr 键事件:`pwr_down`(按下)、`pwr_up`(释放)
|
||||
- 按键功能定义:
|
||||
- 主页:boot 键(释放)选择/切换选项,pwr 键(释放)确认
|
||||
- 组件演示页面:boot 键(释放)切换选项,pwr 键(释放)确认(返回或进度 +10%)
|
||||
- 内置字体页面:boot 键(释放)切换选项(只有一个返回按钮,无实际效果),pwr 键(释放)返回
|
||||
|
||||
注意:当前代码中只处理按键的释放事件(boot_up 和 pwr_up),按下事件被忽略。
|
||||
|
||||
## 三、显示效果
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>主页<br/></td><td>组件演示页<br/></td><td>GTFont页面<br/></td></tr>
|
||||
<tr>
|
||||
<td rowspan="2"><img src="https://docs.openluat.com/cdn/image/Air780EPM_st7567_homepage.jpg" width="80" /><br/></td><td rowspan="2"><img src="https://docs.openluat.com/cdn/image/Air780EPM_ST7567_component_page.jpg" width="80" /><br/></td><td><img src="https://docs.openluat.com/cdn/image/Air780EPM_st7567_default_font_page.jpg" width="80" /><br/></td></tr>
|
||||
</table>
|
||||
|
||||
## 四、功能详细说明
|
||||
|
||||
1. **进度条显示** - 展示进度条,可通过"+10%"按钮增加进度(最大 100%)
|
||||
2. **基本图形绘制** - 展示圆形、实心圆、矩形、实心矩形、三角形
|
||||
3. **按钮交互** - 支持返回首页和调整进度两种功能
|
||||
|
||||
### 4.2 内置字体演示页面
|
||||
|
||||
1. **内置字体显示** - 展示 U8G2 内置12号英文点阵字体效果
|
||||
2. **时间显示** - 显示当前系统时间,支持实时更新
|
||||
3. **简洁界面** - 单按钮设计,便于快速返回
|
||||
|
||||
### 4.3 按键交互功能
|
||||
|
||||
1. **页面导航** - 支持多页面之间的流畅切换
|
||||
2. **防抖处理** - 按键驱动内置 50ms 防抖,防止误触发
|
||||
3. **事件分发** - 统一的事件分发机制,便于扩展
|
||||
|
||||
|
||||
## 五、演示硬件环境
|
||||
|
||||
### 5.1 硬件清单
|
||||
|
||||
- Air780EPM核心板 × 1
|
||||
- st7657 显示屏 × 1 [本demo演示使用的屏幕购买链接]( https://e.tb.cn/h.72oQitvwK2AJtDC?tk=ymJ3fuxC8L4)
|
||||
- 母对母杜邦线 × 8,杜邦线太长的话,会出现 spi 通信不稳定的现象;
|
||||
- TYPE-C 数据线 × 1
|
||||
- Air780EPM核心板和 ST7567单色点阵屏的硬件接线方式为
|
||||
|
||||
- Air780EPM核心板通过 TYPE-C USB 口供电(核心板正面开关拨到 ON 一端),此种供电方式下,VBAT 引脚为 3.3V,可以直接给 ST7567单色点阵屏供电;
|
||||
- 为了演示方便,所以 Air780EPM核心板上电后直接通过 VBAT 引脚给 ST7567单色点阵屏供电;
|
||||
- 客户在设计实际项目时,一般来说,需要通过一个 GPIO 来控制 LDO 给配件板供电,这样可以灵活地控制配件板的供电,可以使项目的整体功耗降到最低;
|
||||
|
||||
### 5.2 接线配置
|
||||
|
||||
#### 5.2.1 LCD 显示屏接线
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Air780EPM核心板<br/></td><td>st7567<br/></td></tr>
|
||||
<tr>
|
||||
<td>57/U3TXD<br/></td><td>SCL<br/></td></tr>
|
||||
<tr>
|
||||
<td>28/U2RXD<br/></td><td>CS<br/></td></tr>
|
||||
<tr>
|
||||
<td>20/GPIO24<br/></td><td>RST<br/></td></tr>
|
||||
<tr>
|
||||
<td>29/U2TXD<br/></td><td>SDA<br/></td></tr>
|
||||
<tr>
|
||||
<td>58/U3RXD<br/></td><td>DC<br/></td></tr>
|
||||
<tr>
|
||||
<td>22/GPIO1<br/></td><td>BL<br/></td></tr>
|
||||
<tr>
|
||||
<td>VBAT<br/></td><td>VCC<br/></td></tr>
|
||||
<tr>
|
||||
<td>GND<br/></td><td>GND<br/></td></tr>
|
||||
</table>
|
||||
|
||||
#### 5.2.2 接线图
|
||||

|
||||
|
||||
## 六、演示软件环境
|
||||
|
||||
### 6.1 开发工具
|
||||
|
||||
- [Luatools下载调试工具](https://docs.openluat.com/air780epm/luatos/common/download/) - 固件烧录和代码调试
|
||||
|
||||
### 6.2 内核固件
|
||||
|
||||
- [点击下载Air780EPM系列最新版本内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/),demo所使用的是LuatOS-SoC_V2014_Air780EPM 1号固件
|
||||
|
||||
## 七、演示核心步骤
|
||||
|
||||
### 7.1 硬件准备
|
||||
1. 按照硬件接线表连接所有设备
|
||||
2. 确保电源连接正确,通过TYPE-C USB口供电
|
||||
3. 检查所有接线无误,避免短路
|
||||
|
||||
### 7.2 软件配置
|
||||
在`main.lua`中选择加载对应的驱动模块:
|
||||
|
||||
```lua
|
||||
-- 加载显示和字体驱动模块
|
||||
require("hw_default_font_drv") -- 使用内置12号英文点阵字体
|
||||
|
||||
-- 加载按键驱动
|
||||
require("key_drv")
|
||||
|
||||
-- 加载UI主模块
|
||||
require("ui_main")
|
||||
```
|
||||
|
||||
### 7.3 软件烧录
|
||||
1. 使用Luatools烧录最新内核固件
|
||||
2. 下载并烧录本项目所有脚本文件
|
||||
3. 烧录成功后设备自动重启后开始运行
|
||||
|
||||
### 7.4 功能测试
|
||||
|
||||
#### 7.4.1 主页面操作
|
||||
|
||||
1. 设备启动后显示主页面,包含两个功能选项
|
||||
2. 使用 boot 键(释放)切换选择不同的菜单项
|
||||
3. 使用 pwr 键(释放)进入选中的演示页面
|
||||
|
||||
#### 7.4.2 组件演示页面
|
||||
|
||||
1. 查看进度条显示(初始 30%)
|
||||
2. 查看基本图形绘制效果
|
||||
3. 使用 boot 键切换按钮(返回、+10%)
|
||||
4. 使用 pwr 键执行当前选中按钮的功能
|
||||
|
||||
#### 7.4.3 内置字体演示页面
|
||||
|
||||
1. 查看内置字体显示效果
|
||||
2. 查看当前时间显示(每 300ms 更新一次)
|
||||
3. 使用 boot 键切换按钮(只有一个返回按钮)
|
||||
4. 按 pwr 键返回主页
|
||||
|
||||
### 7.5 预期效果
|
||||
|
||||
- **系统启动**:显示开机信息(内置字体进入/GTFont 进入),然后进入主页面
|
||||
- **主页面**:正常显示两个菜单项,boot 键切换选项,pwr 键确认
|
||||
- **组件演示页面**:进度条和图形显示正常,按键功能正常
|
||||
- **内置字体页面**:字体显示正常,时间更新正常,pwr 键返回
|
||||
- **按键响应**:所有按键操作响应及时准确,页面切换流畅
|
||||
|
||||
### 7.6 故障排除
|
||||
|
||||
1. **显示屏不亮**
|
||||
|
||||
- 检查电源接线是否正确
|
||||
- 确认 SPI 通信速率是否合适
|
||||
|
||||
2. **显示内容异常**
|
||||
|
||||
- 检查初始化参数和命令是否正确
|
||||
- 确认显示屏分辨率设置是否与自己的屏幕相同
|
||||
|
||||
3. **按键无响应**
|
||||
|
||||
- 检查按键 GPIO 引脚配置
|
||||
- 确认按键中断处理函数是否正确注册
|
||||
- 检查防抖参数是否合适
|
||||
|
||||
4. **系统卡顿或重启**
|
||||
|
||||
- 确认内存使用情况
|
||||
- 适当调整屏幕刷新频率
|
||||
|
||||
### 7.7 扩展建议
|
||||
|
||||
本demo所演示的接口都可以在[u8g2核心库](https://docs.openluat.com/osapi/core/u8g2)中找到,更丰富的使用方式可以参考u8g2核心库进行进一步开发。
|
||||
@@ -0,0 +1,146 @@
|
||||
--[[
|
||||
@module component_page
|
||||
@summary U8G2组件演示页面模块 - 128x64屏幕
|
||||
@version 1.0
|
||||
@date 2025.12.23
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为组件演示页面模块,核心业务逻辑为:
|
||||
1、展示U8G2图形组件的绘制能力;
|
||||
2、显示进度条和基本图形(圆形、矩形、三角形等);
|
||||
3、提供进度调整功能和返回首页功能;
|
||||
4、支持BOOT键和PWR键的导航操作;
|
||||
|
||||
本文件的对外接口有4个:
|
||||
1、component_page.draw():绘制页面内容;
|
||||
2、component_page.handle_key(key_type):处理按键事件;
|
||||
3、component_page.on_enter():页面进入回调;
|
||||
4、component_page.on_leave():页面离开回调;
|
||||
]]
|
||||
|
||||
local component_page = {}
|
||||
|
||||
-- 进度条当前值(0-100)
|
||||
local progress_value = 30
|
||||
|
||||
-- 当前选中按钮的索引(1:返回, 2:+10%)
|
||||
local selected_index = 1
|
||||
|
||||
--[[
|
||||
@api draw()
|
||||
@summary 绘制组件演示页面内容
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
component_page.draw()
|
||||
]]
|
||||
function component_page.draw()
|
||||
-- 标题
|
||||
u8g2.DrawUTF8("Component Page", 15, 10)
|
||||
|
||||
-- 进度条区域
|
||||
u8g2.DrawUTF8("PROG", 0, 25)
|
||||
|
||||
-- 进度条背景(更大)
|
||||
u8g2.DrawFrame(45, 15, 50, 12)
|
||||
|
||||
-- 进度条前景
|
||||
local fill_width = math.floor(50 * progress_value / 100)
|
||||
u8g2.DrawBox(44, 15, fill_width, 12)
|
||||
|
||||
-- 进度文本
|
||||
u8g2.DrawUTF8(progress_value .. "%", 100,25)
|
||||
|
||||
-- 图形演示区域
|
||||
u8g2.DrawUTF8("GRPX", 0, 40)
|
||||
|
||||
-- 绘制基本图形(增加间距)
|
||||
u8g2.DrawCircle(42, 36, 5, u8g2.DRAW_ALL)
|
||||
u8g2.DrawDisc(60, 36, 5, u8g2.DRAW_ALL)
|
||||
u8g2.DrawFrame(75, 31, 10, 10)
|
||||
u8g2.DrawBox(90, 31, 10, 10)
|
||||
u8g2.DrawTriangle(105, 40, 110, 30, 115, 40)
|
||||
|
||||
-- 按钮区域(布局更宽松)
|
||||
if selected_index == 1 then
|
||||
-- 返回按钮:选中状态
|
||||
u8g2.DrawButtonUTF8("Back", 20, 58, u8g2.BTN_INV + u8g2.BTN_BW1, 0, 2, 0)
|
||||
else
|
||||
-- 返回按钮:未选中状态
|
||||
u8g2.DrawButtonUTF8("Back", 20, 58, u8g2.BTN_BW1, 0, 2, 0)
|
||||
end
|
||||
|
||||
if selected_index == 2 then
|
||||
-- +10%按钮:选中状态
|
||||
u8g2.DrawButtonUTF8("+10%", 80, 58, u8g2.BTN_INV + u8g2.BTN_BW1, 0, 2, 0)
|
||||
else
|
||||
-- +10%按钮:未选中状态
|
||||
u8g2.DrawButtonUTF8("+10%", 80, 58, u8g2.BTN_BW1, 0, 2, 0)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@api handle_key(key_type)
|
||||
@summary 处理按键事件,实现进度调整和页面导航
|
||||
@param string key_type 按键类型,可选值:
|
||||
- "confirm":确认键,执行当前选中按钮的功能
|
||||
- "next":切换到下一个按钮
|
||||
- "prev":切换到上一个按钮
|
||||
@return bool 是否已处理该按键,true表示已处理
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
local handled = component_page.handle_key("confirm")
|
||||
]]
|
||||
function component_page.handle_key(key_type)
|
||||
log.info("component_page.handle_key", "key_type:", key_type)
|
||||
|
||||
if key_type == "confirm" then
|
||||
-- 确认键:执行当前选中按钮的功能
|
||||
if selected_index == 1 then
|
||||
-- 返回按钮:返回首页
|
||||
switch_page("home")
|
||||
elseif selected_index == 2 then
|
||||
-- +10%按钮:增加进度值,最大不超过100%
|
||||
progress_value = math.min(100, progress_value + 10)
|
||||
end
|
||||
return true
|
||||
elseif key_type == "next" then
|
||||
-- 切换到下一个按钮
|
||||
selected_index = selected_index % 2 + 1
|
||||
return true
|
||||
elseif key_type == "prev" then
|
||||
-- 切换到上一个按钮
|
||||
selected_index = (selected_index - 2) % 2 + 1
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_enter()
|
||||
@summary 页面进入时的初始化操作,重置选中项和进度值
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
component_page.on_enter()
|
||||
]]
|
||||
function component_page.on_enter()
|
||||
-- 页面进入时初始化
|
||||
selected_index = 1 -- 默认选中返回按钮
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_leave()
|
||||
@summary 页面离开时的清理操作
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
component_page.on_leave()
|
||||
]]
|
||||
function component_page.on_leave()
|
||||
-- 页面离开时的清理操作
|
||||
-- 当前无需特殊清理
|
||||
end
|
||||
|
||||
return component_page
|
||||
@@ -0,0 +1,110 @@
|
||||
--[[
|
||||
@module default_font_page
|
||||
@summary U8G2内置字体演示页面模块 - 128x64屏幕
|
||||
@version 1.0
|
||||
@date 2025.12.23
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为默认字体演示页面模块,核心业务逻辑为:
|
||||
1、展示U8G2内置字体的显示效果;
|
||||
2、显示固定文本内容和当前系统时间;
|
||||
3、提供返回首页的功能;
|
||||
4、支持BOOT键和PWR键的导航操作;
|
||||
|
||||
本文件的对外接口有4个:
|
||||
1、default_font_page.draw():绘制页面内容;
|
||||
2、default_font_page.handle_key(key_type):处理按键事件;
|
||||
3、default_font_page.on_enter():页面进入回调;
|
||||
4、default_font_page.on_leave():页面离开回调;
|
||||
]]
|
||||
|
||||
local default_font_page = {}
|
||||
|
||||
-- 当前选中项的索引(仅有一个返回按钮)
|
||||
local selected_index = 1
|
||||
|
||||
--[[
|
||||
@api draw()
|
||||
@summary 绘制默认字体演示页面内容
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
default_font_page.draw()
|
||||
]]
|
||||
function default_font_page.draw()
|
||||
-- 标题
|
||||
u8g2.DrawUTF8("Font Page", 37, 10)
|
||||
|
||||
-- 字体演示(居中显示)
|
||||
u8g2.DrawUTF8("LuatOS Demo", 30, 27)
|
||||
u8g2.DrawUTF8("U8G2 Graphics", 25, 42)
|
||||
u8g2.DrawUTF8(os.date("%Y-%m-%d %H:%M:%S"), 15, 58)
|
||||
|
||||
-- 按钮区域
|
||||
if selected_index == 1 then
|
||||
-- 返回按钮:选中状态
|
||||
u8g2.DrawButtonUTF8("Back", 5, 10, u8g2.BTN_INV + u8g2.BTN_BW1, 0, 2, 0)
|
||||
else
|
||||
-- 返回按钮:未选中状态
|
||||
u8g2.DrawButtonUTF8("Back", 5, 10, u8g2.BTN_BW1, 0, 2, 0)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@api handle_key(key_type)
|
||||
@summary 处理按键事件,实现页面导航
|
||||
@param string key_type 按键类型,可选值:
|
||||
- "confirm":确认键,返回首页
|
||||
- "next":切换选中状态(仅有一个按钮,无实际效果)
|
||||
- "prev":切换选中状态(仅有一个按钮,无实际效果)
|
||||
@return bool 是否已处理该按键,true表示已处理
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
local handled = default_font_page.handle_key("confirm")
|
||||
]]
|
||||
function default_font_page.handle_key(key_type)
|
||||
log.info("default_font_page.handle_key", "key_type:", key_type)
|
||||
|
||||
if key_type == "confirm" then
|
||||
-- 确认键:返回首页
|
||||
switch_page("home")
|
||||
return true
|
||||
elseif key_type == "next" or key_type == "prev" then
|
||||
-- 切换选中项(只有一个按钮,所以切换无实际效果)
|
||||
-- 但为了保持接口一致性,仍然返回true表示已处理
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_enter()
|
||||
@summary 页面进入时的初始化操作,重置选中项和设置帧更新时间
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
default_font_page.on_enter()
|
||||
]]
|
||||
function default_font_page.on_enter()
|
||||
-- 页面进入时初始化
|
||||
selected_index = 1
|
||||
-- 设置较短的帧更新时间,使时间显示能够实时更新
|
||||
frame_time = 300 -- 300ms
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_leave()
|
||||
@summary 页面离开时的清理操作,恢复默认帧更新时间
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
default_font_page.on_leave()
|
||||
]]
|
||||
function default_font_page.on_leave()
|
||||
-- 页面离开时的清理操作
|
||||
-- 恢复默认的帧更新时间(60秒)
|
||||
frame_time = 60 * 1000
|
||||
end
|
||||
|
||||
return default_font_page
|
||||
@@ -0,0 +1,112 @@
|
||||
--[[
|
||||
@module home_page
|
||||
@summary U8G2主页模块 - 128x64屏幕
|
||||
@version 1.0
|
||||
@date 2025.12.23
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为主页显示模块,核心业务逻辑为:
|
||||
1、显示主菜单,包含两个选项:组件演示、内置字体;
|
||||
2、处理BOOT键和PWR键的导航和确认操作;
|
||||
3、管理当前选中项状态;
|
||||
|
||||
本文件的对外接口有4个:
|
||||
1、home_page.draw():绘制页面内容;
|
||||
2、home_page.handle_key(key_type):处理按键事件;
|
||||
3、home_page.on_enter():页面进入回调;
|
||||
4、home_page.on_leave():页面离开回调;
|
||||
]]
|
||||
|
||||
local home_page = {}
|
||||
|
||||
-- 菜单项
|
||||
local menu_items = {
|
||||
{name = "component", text = "1.Component Demo", x = 10, y = 22},
|
||||
{name = "default_font", text = "2.Built-in Font", x = 10, y = 40}
|
||||
}
|
||||
|
||||
local selected_index = 1
|
||||
|
||||
--[[
|
||||
@api draw()
|
||||
@summary 绘制主页内容
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
home_page.draw()
|
||||
]]
|
||||
function home_page.draw()
|
||||
|
||||
-- 绘制按键提示
|
||||
u8g2.DrawUTF8("BOOT:Select", 0, 10)
|
||||
u8g2.DrawUTF8("PWR:Confirm", 0, 58)
|
||||
|
||||
-- 绘制菜单项
|
||||
for i, item in ipairs(menu_items) do
|
||||
if i == selected_index then
|
||||
-- 选中状态
|
||||
u8g2.DrawButtonUTF8(item.text, item.x, item.y,
|
||||
u8g2.BTN_INV + u8g2.BTN_BW1, 110, 2, 0)
|
||||
else
|
||||
-- 未选中状态
|
||||
u8g2.DrawButtonUTF8(item.text, item.x, item.y,
|
||||
u8g2.BTN_BW1, 110, 2, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@api handle_key(key_type)
|
||||
@summary 处理按键事件
|
||||
@param string key_type 按键类型,可选值:"confirm"、"next"、"prev"
|
||||
@return bool 是否已处理该按键
|
||||
@usage
|
||||
-- 在UI主循环中调用
|
||||
home_page.handle_key("confirm")
|
||||
]]
|
||||
function home_page.handle_key(key_type)
|
||||
log.info("home_page.handle_key", "key_type:", key_type, "selected_index:", selected_index)
|
||||
|
||||
if key_type == "confirm" then
|
||||
-- 确认键:切换到选中的页面
|
||||
local item = menu_items[selected_index]
|
||||
switch_page(item.name)
|
||||
return true
|
||||
elseif key_type == "next" then
|
||||
-- 向下选择
|
||||
selected_index = selected_index % #menu_items + 1
|
||||
return true
|
||||
elseif key_type == "prev" then
|
||||
-- 向上选择
|
||||
selected_index = (selected_index - 2) % #menu_items + 1
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_enter()
|
||||
@summary 页面进入时的初始化操作
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
home_page.on_enter()
|
||||
]]
|
||||
function home_page.on_enter()
|
||||
selected_index = 1 -- 重置选中项
|
||||
end
|
||||
|
||||
--[[
|
||||
@api on_leave()
|
||||
@summary 页面离开时的清理操作
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面切换时自动调用
|
||||
home_page.on_leave()
|
||||
]]
|
||||
function home_page.on_leave()
|
||||
-- 页面离开时的清理操作
|
||||
end
|
||||
|
||||
return home_page
|
||||
@@ -0,0 +1,148 @@
|
||||
--[[
|
||||
@module ui_main
|
||||
@summary U8G2主程序模块 - 128x64屏幕
|
||||
@version 1.0
|
||||
@date 2025.12.23
|
||||
@author 江访
|
||||
@usage
|
||||
本文件为U8G2图形界面的主控模块,核心业务逻辑为:
|
||||
1、管理三个页面:主页、组件演示页、内置字体页;
|
||||
2、处理按键事件并分发给当前页面;
|
||||
3、控制页面切换逻辑,调用页面的进入/离开回调函数;
|
||||
4、实现主渲染循环,定期更新屏幕显示;
|
||||
|
||||
本文件的对外接口有2个:
|
||||
1、switch_page(new_page):页面切换接口;
|
||||
2、handle_key_event(key_event):按键事件处理入口;
|
||||
]]
|
||||
|
||||
-- 加载页面
|
||||
local home_page = require("home_page")
|
||||
local component_page = require("component_page")
|
||||
local default_font_page = require("default_font_page")
|
||||
|
||||
-- 超时更新画面时间,默认60秒
|
||||
frame_time = 60 * 1000
|
||||
|
||||
-- 页面管理
|
||||
local PAGE_NAMES = {
|
||||
HOME = "home",
|
||||
COMPONENT = "component",
|
||||
DEFAULT_FONT = "default_font"
|
||||
}
|
||||
|
||||
-- 当前页面
|
||||
local current_page = PAGE_NAMES.HOME
|
||||
|
||||
--[[
|
||||
@api handle_key_event(key_event)
|
||||
@summary 处理按键事件
|
||||
@param string key_event 按键事件类型,可选值:"boot_up"、"boot_down"、"pwr_up"、"pwr_down"
|
||||
@return bool 是否已处理该按键事件
|
||||
@usage
|
||||
-- 在主循环中调用
|
||||
handle_key_event("boot_up")
|
||||
]]
|
||||
-- 按键处理函数
|
||||
local function handle_key_event(key_event)
|
||||
log.info("Key event", "event:", key_event, "Current page:", current_page)
|
||||
|
||||
-- 按键抬起生效
|
||||
if key_event == "boot_up" then
|
||||
-- BOOT键抬起:切换到下一个选项
|
||||
if current_page == PAGE_NAMES.HOME then
|
||||
return home_page.handle_key("next")
|
||||
elseif current_page == PAGE_NAMES.COMPONENT then
|
||||
return component_page.handle_key("next")
|
||||
elseif current_page == PAGE_NAMES.DEFAULT_FONT then
|
||||
return default_font_page.handle_key("next")
|
||||
end
|
||||
return false
|
||||
elseif key_event == "pwr_up" then
|
||||
-- PWR键抬起:确认/返回
|
||||
if current_page == PAGE_NAMES.HOME then
|
||||
return home_page.handle_key("confirm")
|
||||
elseif current_page == PAGE_NAMES.COMPONENT then
|
||||
return component_page.handle_key("confirm")
|
||||
elseif current_page == PAGE_NAMES.DEFAULT_FONT then
|
||||
return default_font_page.handle_key("confirm")
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@api switch_page(new_page)
|
||||
@summary 切换当前显示的页面
|
||||
@param string new_page 要切换到的页面名称,可选值:"home"、"component"、"default_font"
|
||||
@return 无返回值
|
||||
@usage
|
||||
-- 在页面处理函数中调用
|
||||
switch_page("home")
|
||||
]]
|
||||
-- 页面切换函数(供其他页面调用)
|
||||
function switch_page(new_page)
|
||||
log.info("switch_page", "From", current_page, "to", new_page)
|
||||
|
||||
-- 调用旧页面的离开函数
|
||||
if current_page == PAGE_NAMES.HOME and home_page.on_leave then
|
||||
home_page.on_leave()
|
||||
elseif current_page == PAGE_NAMES.COMPONENT and component_page.on_leave then
|
||||
component_page.on_leave()
|
||||
elseif current_page == PAGE_NAMES.DEFAULT_FONT and default_font_page.on_leave then
|
||||
default_font_page.on_leave()
|
||||
end
|
||||
|
||||
current_page = new_page
|
||||
|
||||
-- 调用新页面的进入函数
|
||||
if new_page == PAGE_NAMES.HOME and home_page.on_enter then
|
||||
home_page.on_enter()
|
||||
elseif new_page == PAGE_NAMES.COMPONENT and component_page.on_enter then
|
||||
component_page.on_enter()
|
||||
elseif new_page == PAGE_NAMES.DEFAULT_FONT and default_font_page.on_enter then
|
||||
default_font_page.on_enter()
|
||||
end
|
||||
|
||||
log.info("ui_main", "Switched to page:", current_page)
|
||||
end
|
||||
|
||||
-- 主UI任务
|
||||
local function ui_main()
|
||||
|
||||
-- 预留1S给开机信息显示
|
||||
sys.wait(1000)
|
||||
log.info("ui_main", "Start UI main loop")
|
||||
|
||||
-- 初始化主页
|
||||
home_page.on_enter()
|
||||
|
||||
-- 主渲染循环
|
||||
while true do
|
||||
-- 设置默认字体
|
||||
u8g2.SetFont(u8g2.font_6x10) -- 使用英文字体
|
||||
-- 清空缓冲区
|
||||
u8g2.ClearBuffer()
|
||||
|
||||
-- 根据当前页面绘制内容
|
||||
if current_page == PAGE_NAMES.HOME then
|
||||
home_page.draw()
|
||||
elseif current_page == PAGE_NAMES.COMPONENT then
|
||||
component_page.draw()
|
||||
elseif current_page == PAGE_NAMES.DEFAULT_FONT then
|
||||
default_font_page.draw()
|
||||
end
|
||||
|
||||
-- 刷新显示
|
||||
u8g2.SendBuffer()
|
||||
|
||||
-- 等待按键事件
|
||||
local result, key_event = sys.waitUntil("KEY_EVENT", frame_time)
|
||||
if result then
|
||||
handle_key_event(key_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 启动UI任务
|
||||
sys.taskInit(ui_main)
|
||||
Reference in New Issue
Block a user