init: Air780EPM 官方 LuatOS 项目代码基线

- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码
- 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等)
- 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
wangfq
2026-08-31 08:53:49 +08:00
commit 173dd6874f
813 changed files with 125484 additions and 0 deletions
@@ -0,0 +1,129 @@
--[[
@module AirSHT30_1000
@summary AirSHT30_1000应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为AirSHT30_1000驱动配置文件,核心业务逻辑为:
1、打开AirSHT30_1000
2、读取温湿度数据;
本文件没有对外接口,直接require "AirSHT30_1000"就可以加载运行;
]]
-- 本文件中的主机是指I2C主机,具体指Air780EXX系列每个模组
-- 本文件中的从机是指I2C从机,具体指AirSHT30_1000配件板上的sht30温湿度传感器芯片
local AirSHT30_1000 =
{
-- i2c_id:主机的i2c id
}
-- 从机地址为0x44
local slave_addr = 0x44
-- 计算数据表data中所有数据元素的crc8校验值
local function crc8(data)
local crc = 0xFF
for i = 1, #data do
crc = bit.bxor(crc, data[i])
for j = 1, 8 do
crc = crc * 2
if crc >= 0x100 then
crc = bit.band(bit.bxor(crc, 0x31), 0xff)
end
end
end
return crc
end
-- 打开AirSHT30_1000
--i2c_idnumber类型;
-- 主机使用的I2C ID,用来控制AirSHT30_1000
-- 取值范围:仅支持0和1;
-- 如果没有传入此参数,则默认为0;
--返回值:成功返回true,失败返回false
function AirSHT30_1000.open(i2c_id)
--如果i2c_id为nil,则赋值为默认值0
if i2c_id==nil then i2c_id=0 end
--检查参数的合法性
if not (i2c_id == 0 or i2c_id == 1) then
log.error("AirSHT30_1000.open", "invalid i2c_id", i2c_id)
return false
end
AirSHT30_1000.i2c_id = i2c_id
--初始化I2C
if i2c.setup(i2c_id, i2c.FAST) ~= 1 then
log.error("AirSHT30_1000.open", "i2c.setup error", i2c_id)
return false
end
return true
end
-- 读取温湿度数据;
-- 返回值:失败返回false
-- 成功返回两个值,第一个为摄氏温度值(number类型,例如23.6表示23.6摄氏度),第二个为百分比湿度值(number类型,例如67表示67%的湿度)
function AirSHT30_1000.read()
-- 发送启动测量命令(高精度)
i2c.send(AirSHT30_1000.i2c_id, slave_addr, {0x24, 0x00})
-- 等待测量完成(SHT30高精度测量需~15ms)
sys.wait(20)
-- 读取6字节数据(温度高/低 + CRC,湿度高/低 + CRC
local data = i2c.recv(AirSHT30_1000.i2c_id, slave_addr, 6)
-- 如果没有读取到6字节数据
if type(data)~="string" or data:len()~=6 then
log.error("AirSHT30_1000.read", "i2c.recv error")
return false
end
-- log.info("AirSHT30_1000.read", data:toHex())
--如果校验值正确
if crc8({data:byte(1), data:byte(2)}) == data:byte(3) and crc8({data:byte(4), data:byte(5)}) == data:byte(6) then
-- 提取原始温度值
local temp_raw = (data:byte(1) << 8) | data:byte(2)
-- 提取原始湿度值
local hum_raw = (data:byte(4) << 8) | data:byte(5)
-- 转换为实际值(根据SHT30数据手册公式)
local temprature = (-45 + 175 * temp_raw / 65535.0)
local humidity = (100 * hum_raw / 65535.0)
-- 打印输出结果(保留2位小数)
-- log.info("AirSHT30_1000.read", "temprature", string.format("%.2f ℃", temprature))
-- log.info("AirSHT30_1000.read", "temprature", string.format("%.2f %%RH", humidity))
return temprature, humidity
else
log.error("AirSHT30_1000.read", "crc error", i2c_id)
return false
end
end
-- 关闭AirSHT30_1000
-- 返回值:成功返回true,失败返回false
function AirSHT30_1000.close()
--close接口没有返回值,理论上不会关闭失败
i2c.close(AirSHT30_1000.i2c_id)
return true
end
return AirSHT30_1000
@@ -0,0 +1,93 @@
--[[
@module take_photo
@summary 摄像头拍照控制模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本模块负责摄像头拍照控制,核心业务逻辑为:
1、摄像头初始化:根据配置参数初始化gc032a摄像头硬件
2、拍照执行:接收拍照指令,执行拍照操作
3、数据返回:拍照成功后发布照片数据
4、资源管理:拍照完成后关闭摄像头释放资源
对外接口:
1、事件发布:
- "CAMERA_TAKE_PHOTO_RSP":拍照完成时发布,携带照片数据
2、消息订阅:
- "CAMERA_TAKE_PHOTO_REQ":等待拍照指令
使用说明:
1、摄像头配置:支持gc032a型号
2、工作模式:拍照模式(work_mode=0
3、数据存储:使用ZBUFF格式存储照片数据
4、GPIO配置:支持摄像头使能、电源控制和补光灯控制
]]
require "gc032a"
-- 引入excamera扩展库模块
local excamera = require "excamera"
--[[
拍照功能task
@function camera_take_photo_task
@local
@return nil
]]
local function camera_take_photo_task()
-- 定义变量用于存储操作结果和数据
local result, data
-- 无限循环,持续等待拍照事件
while true do
--[[
配置gc032a摄像头参数表
@table spi_camera_param
@field id string 摄像头型号,支持"gc032a"、"gc0310"、"bf30a2"
@field i2c_id number I2C总线编号
@field work_mode number 工作模式,0为拍照模式,1为扫描模式
@field save_path string 拍照结果存储路径,"ZBUFF"表示由excamera库管理
@field camera_pwr number 摄像头使能管脚GPIO号,无则填nil
@field camera_pwdn number 摄像头pwdn开关脚GPIO号,无则填nil
@field camera_light number 摄像头补光灯控制管脚GPIO号,无则填nil
]]
local spi_camera_param = {
id = "gc032a", -- SPI摄像头型号
i2c_id = 1, -- 模块上使用的I2C编号
work_mode = 0, -- 工作模式:0为拍照模式,1为扫描模式
save_path = "ZBUFF", -- 拍照结果存储路径
camera_pwr = 2, -- 摄像头使能管脚GPIO号
camera_pwdn = 5, -- 摄像头pwdn开关脚GPIO号
camera_light = nil -- 摄像头补光灯控制管脚GPIO号
}
-- 等待外部触发拍照事件(CAMERA_TAKE_PHOTO_REQ)
sys.waitUntil("CAMERA_TAKE_PHOTO_REQ")
-- 打印内存信息
log.info("mem.lua", rtos.meminfo())
log.info("mem.sys", rtos.meminfo("sys"))
-- 初始化摄像头,传入配置参数
result = excamera.open(spi_camera_param)
-- 记录摄像头初始化状态
log.info("camera_take_photo_task excamera.open", result)
-- 判断摄像头初始化是否成功,不成功则直接关闭,成功则启动拍照
if result then
-- 执行拍照操作
result, data = excamera.photo()
log.info("camera_take_photo_task excamera.photo", result, type(data), data:used())
end
-- 发布拍照结果响应消息,携带操作结果和数据
sys.publish("CAMERA_TAKE_PHOTO_RSP", result, data)
-- 关闭摄像头,保留zbuff内存资源
excamera.close(true)
end
end
-- 创建拍照功能任务
sys.taskInit(camera_take_photo_task)
@@ -0,0 +1,143 @@
--[[
@module app_lpuart
@summary UART功能应用模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本模块负责低功耗UART应用,核心业务逻辑为:
1、初始化uart参数,设置波特率为9600,数据位8位,无校验位,1位停止位
2、配置uart发送与接收回调函数,用于处理发送完成和接收数据
3、对接收到的数据进行检测,当收到A0001指令时发布“CAMERA_TAKE_PHOTO_REQ”消息,通知拍照模块(例如app_camera.lua)执行拍照操作
4、拍照模块执行完拍照操作后,发布“CAMERA_TAKE_PHOTO_RSP”消息,携带操作结果和数据
5、收到“CAMERA_TAKE_PHOTO_RSP”消息后,根据操作结果和数据,判断是否需要将图像数据发送出去
6、需要将图像数据通过UART发送时,先关闭当前UART,重新设置波特率为115200,发送数据,发送完成后关闭UART,重新设置波特率为9600
]]
-- 使用UART1
local UART_ID = 1
-- 串口接收数据缓冲区
local read_buf = ""
-- false表示空闲,true表示正常处理拍照回传业务
local is_busy = false
-- 串口发送完成回调函数
local function uart_sent_callback()
sys.publish("SEND_PHOTO_DONE")
end
-- 处理拍照结果响应消息任务
local function camera_take_photo_rsp_task(data)
log.info("camera_take_photo_rsp_task", type(data), data:used())
local uart_tx_start = 0 -- 已发送数据的起始位置
local uart_tx_len = 102400 -- 每次发送的数据长度
uart.close(UART_ID)
uart.setup(UART_ID, 115200, 8, 1)
-- 循环发送数据,直到所有数据都发送完成
while true do
if data:used() - uart_tx_start >= 102400 then
uart_tx_len = 102400
elseif data:used() - uart_tx_start < 102400 then
uart_tx_len = data:used() - uart_tx_start
elseif data:used() - uart_tx_start == 0 then
break
end
uart.tx(UART_ID, data, uart_tx_start, uart_tx_len)
uart_tx_start = uart_tx_start + uart_tx_len
-- 等待发送完成(最多等待30秒)
local result = sys.waitUntil("SEND_PHOTO_DONE", 30 * 1000)
if not result then
log.error("uart.tx timeout")
break
end
end
uart.close(UART_ID)
uart.setup(UART_ID, 9600, 8, 1)
is_busy = false
end
-- 发布拍照结果响应消息
local function camera_take_photo_rsp(result, data)
if result then
log.info("camera_take_photo_rsp", result, type(data), data:used(), is_busy)
sys.taskInit(camera_take_photo_rsp_task, data)
else
log.info("camera_take_photo_rsp", result)
is_busy = false
end
end
-- 处理串口缓冲区数据超时函数
-- 防止将一大包数据拆分成多个小包来处理
local function concat_timeout_func()
log.info("concat_timeout_func", read_buf:len(), is_busy)
-- 如果存在尚未处理的串口缓冲区数据;
-- 将数据通过publish通知其他应用功能模块处理;
-- 然后清空本文件的串口缓冲区数据
if read_buf:len() > 0 then
if not is_busy then
-- 检查是否包含拍照指令
if read_buf:find("A0001") then
sys.publish("CAMERA_TAKE_PHOTO_REQ")
is_busy = true
end
end
read_buf = ""
end
end
-- UART1的数据接收中断处理函数,UART1接收到数据时,会执行此函数
local function read()
local s
while true do
-- 非阻塞读取UART1接收到的数据,最长读取1024字节
s = uart.read(UART_ID, 1024)
-- 如果从串口没有读到数据
if not s or s:len() == 0 then
-- 启动50毫秒的定时器,如果50毫秒内没收到新的数据,则处理当前收到的所有数据
-- 这样处理是为了防止将一大包数据拆分成多个小包来处理
-- 例如pc端串口工具下发1100字节的数据,可能会产生将近20次的中断进入到read函数,才能读取完整
-- 此处的50毫秒可以根据自己项目的需求做适当修改,在满足整包拼接完整的前提下,时间越短,处理越及时
sys.timerStart(concat_timeout_func, 50)
-- 跳出循环,退出本函数
break
end
log.info("uart_app.read len", s:len())
-- log.info("uart_app.read", s)
-- 将本次从串口读到的数据拼接到串口缓冲区read_buf中
read_buf = read_buf..s
end
end
-- 初始化UART1,波特率115200,数据位8,停止位1
uart.setup(UART_ID, 9600, 8, 1)
-- 注册UART1的数据接收中断处理函数,UART1接收到数据时,会执行read函数
uart.on(UART_ID, "receive", read)
-- 注册串口发送回调
uart.on(UART_ID, "sent", uart_sent_callback)
-- 订阅拍照结果响应消息
sys.subscribe("CAMERA_TAKE_PHOTO_RSP", camera_take_photo_rsp)
@@ -0,0 +1,287 @@
--[[
@module mqtt_main
@summary mqtt client 主应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为mqtt client 主应用功能模块,核心业务逻辑为:
1、创建一个mqtt client,连接server
2、处理连接/订阅/取消订阅/异常逻辑,出现异常后执行重连动作;
3、调用mqtt_receiver的外部接口mqtt_receiver.proc,对接收到的publish数据进行处理;
4、调用sys.sendMsg接口,发送"CONNECT OK"、"PUBLISH OK"和"DISCONNECTED"三种类型的"MQTT_EVENT"消息到mqtt_sender的task,控制publish数据发送逻辑;
5、收到MQTT心跳应答后,执行sys.publish("FEED_NETWORK_WATCHDOG") 对网络环境检测看门狗功能模块进行喂狗;
本文件没有对外接口,直接在main.lua中require "mqtt_main"就可以加载运行;
]]
-- 加载mqtt client数据接收功能模块
local mqtt_receiver = require "app_mqtt_receiver"
-- 加载mqtt client数据发送功能模块
local mqtt_sender = require "app_mqtt_sender"
-- mqtt服务器地址和端口
-- 这里使用的地址和端口,会不定期重启或维护,仅能用作测试用途,不可商用,说不定哪一天就关闭了
-- 用户开发项目时,替换为自己的商用服务器地址和端口
local SERVER_ADDR = "lbsmqtt.airm2m.com"
local SERVER_PORT = 1884
-- mqtt_main的任务名
local TASK_NAME = mqtt_sender.TASK_NAME_PREFIX.."main"
-- mqtt主题的前缀:IMEI号
local TOPIC_PREFIX = mobile.imei()
-- mqtt client的事件回调函数
local function mqtt_client_event_cbfunc(mqtt_client, event, data, payload, metas)
log.info("mqtt_client_event_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-- mqtt连接成功
if event == "conack" then
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-- 订阅单主题
-- 第二个参数表示qos,取值范围为0,1,2,如果不设置,默认为0
-- if not mqtt_client:subscribe(TOPIC_PREFIX .. "/down") then
-- sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-- end
-- 订阅多主题,如果有需要,打开注释
-- 表中的每一个订阅主题的格式为[topic]=qos
-- if not mqtt_client:subscribe(
-- {
-- [(TOPIC_PREFIX .. "/data"]=0,
-- [(TOPIC_PREFIX .. "/cmd"]=1
-- }
-- ) then
-- sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-- end
-- 订阅结果
-- data:订阅应答结果,true为成功,false为失败
-- payloadnumber类型;成功时表示qos,取值范围为0,1,2;失败时表示失败码,一般是0x80
elseif event == "suback" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", data, payload)
-- 取消订阅成功
elseif event == "unsuback" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "UNSUBSCRIBE", true)
-- 接收到服务器下发的publish数据
-- datastring类型,表示topic
-- payloadstring类型,表示payload
-- metastable类型,数据内容如下
-- {
-- qos: number类型,取值范围0,1,2
-- retainnumber类型,取值范围0,1
-- dupnumber类型,取值范围0,1
-- message_id: number类型
-- }
elseif event == "recv" then
-- 对接收到的publish数据处理
mqtt_receiver.proc(data, payload, metas)
-- 发送成功publish数据
-- datanumber类型,表示message id
elseif event == "sent" then
-- 发送消息通知 mqtt sender task
sys.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_OK", data)
-- 服务器断开mqtt连接
elseif event == "disconnect" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED", false)
-- 收到服务器的心跳应答
elseif event == "pong" then
-- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 严重异常,本地会主动断开连接
-- data:string类型,表示具体的异常,有以下几种:
-- "connect"tcp连接失败
-- "tx":数据发送失败
-- "conack"mqtt connect后,服务器应答CONNACK鉴权失败,失败码为payloadnumber类型)
-- "other":其他异常
elseif event == "error" then
if data == "connect" or data == "conack" then
-- 发送消息通知 mqtt main task,连接失败
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", false)
elseif data == "other" or data == "tx" then
-- 发送消息通知 mqtt main task,出现异常
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "ERROR")
end
end
end
-- mqtt main task 的任务处理函数
-- auto_reconnect:短连接还是长连接;长连接为true,表示断开连接后会自动重连;短连接为false,表示断开连接后,不会自动重连
local function mqtt_client_main_task_func(auto_reconnect)
local mqtt_client
local result, msg
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("mqtt_client_main_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息
log.info("mqtt_client_main_task_func", "recv IP_READY", socket.dft())
-- 清空此task绑定的消息队列中的未处理的消息
sys.cleanMsg(TASK_NAME)
-- 创建mqtt client对象
mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT)
-- 如果创建mqtt client对象失败
if not mqtt_client then
log.error("mqtt_client_main_task_func", "mqtt.create error")
goto EXCEPTION_PROC
end
-- 配置mqtt client对象的client idusernamepassword和clean session标志
result = mqtt_client:auth(TASK_NAME..mobile.imei(), "", "", true)
-- 如果配置失败
if not result then
log.error("mqtt_client_main_task_func", "mqtt_client:auth error")
goto EXCEPTION_PROC
end
-- 注册mqtt client对象的事件回调函数
mqtt_client:on(mqtt_client_event_cbfunc)
-- 设置mqtt keepalive时间为120秒
-- 如果没有设置,内核固件中默认为180秒
-- 有需要的话,可以打开注释
-- mqtt_client:keepalive(120)
-- 设置遗嘱消息,有需要的话,可以打开注释
-- mqtt_client:will(TOPIC_PREFIX .. "/status", "offline")
-- 连接server
result = mqtt_client:connect()
-- 如果连接server失败
if not result then
log.error("mqtt_client_main_task_func", "mqtt_client:connect error")
goto EXCEPTION_PROC
end
-- 连接、断开连接、订阅、取消订阅、异常等各种事件的处理调度逻辑
while true do
-- 等待"MQTT_EVENT"消息
msg = sys.waitMsg(TASK_NAME, "MQTT_EVENT")
log.info("mqtt_client_main_task_func waitMsg", msg[2], msg[3], msg[4])
-- connect连接结果
-- msg[3]表示连接结果,true为连接成功,false为连接失败
if msg[2] == "CONNECT" then
-- mqtt连接成功
if msg[3] then
log.info("mqtt_client_main_task_func", "connect success")
-- 通知mqtt sender数据发送应用模块的task,MQTT连接成功
sys.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "CONNECT_OK", mqtt_client)
-- mqtt连接失败
else
log.info("mqtt_client_main_task_func", "connect error")
-- 退出循环,发起重连
break
end
-- subscribe订阅结果
-- msg[3]表示订阅结果,true为订阅成功,false为订阅失败
elseif msg[2] == "SUBSCRIBE" then
-- 订阅成功
if msg[3] then
log.info("mqtt_client_main_task_func", "subscribe success", "qos: "..(msg[4] or "nil"))
-- 订阅失败
else
log.error("mqtt_client_main_task_func", "subscribe error", "code", msg[4])
-- 主动断开mqtt client连接
mqtt_client:disconnect()
-- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
sys.wait(1000)
break
end
-- unsubscribe取消订阅成功
elseif msg[2] == "UNSUBSCRIBE" then
log.info("mqtt_client_main_task_func", "unsubscribe success")
-- 需要主动关闭mqtt连接
-- 用户需要主动关闭mqtt连接时,可以调用sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CLOSE")
elseif msg[2] == "CLOSE" then
-- 主动断开mqtt client连接
mqtt_client:disconnect()
-- 发送disconnect之后,此处延时1秒,给数据发送预留一点儿时间,发送到服务器;
-- 即使1秒的时间不足以发送给服务器也没关系;对服务器来说,mqtt客户端只是没有优雅的断开,不影响什么实质功能;
-- sys.wait(1000)
break
-- 被动关闭了mqtt连接
-- 被网络或者服务器断开了连接
elseif msg[2] == "DISCONNECTED" then
break
-- 出现了其他异常
elseif msg[2] == "ERROR" then
break
end
end
-- 出现异常
::EXCEPTION_PROC::
-- 清空此task绑定的消息队列中的未处理的消息
sys.cleanMsg(TASK_NAME)
-- 通知mqtt sender数据发送应用模块的task,MQTT连接已经断开
sys.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "DISCONNECTED")
-- 如果存在mqtt client对象
if mqtt_client then
-- 关闭mqtt client,并且释放mqtt client对象
mqtt_client:close()
mqtt_client = nil
end
-- 根据是否需要自动重连标志,决定后续执行的动作
if auto_reconnect then
-- 5秒后跳转到循环体开始位置,自动发起重连
sys.wait(5000)
else
sys.publish("MQTT_CLIENT_CLOSE_RSP")
log.warn("mqtt_client_main_task_func", "exit")
break
end
end
-- 清除此task对应的管理表资源
sys.taskDel(TASK_NAME)
end
local function mqtt_client_run_req(connection_type)
--创建并且启动一个task
--运行这个task的处理函数mqtt_client_main_task_func
sys.taskInitEx(mqtt_client_main_task_func, TASK_NAME, nil, connection_type)
end
local function mqtt_client_close_req()
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CLOSE")
end
sys.subscribe("MQTT_CLIENT_RUN_REQ", mqtt_client_run_req)
sys.subscribe("MQTT_CLIENT_CLOSE_REQ", mqtt_client_close_req)
@@ -0,0 +1,63 @@
--[[
@module mqtt_receiver
@summary mqtt client数据接收处理应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为mqtt client 数据接收应用功能模块,核心业务逻辑为:
处理接收到的publish数据,同时将数据发送给其他应用功能模块做进一步处理;
本文件的对外接口有2个:
1、mqtt_receiver.proc(topic, payload, metas)publish数据处理入口,在mqtt_main.lua中调用;
2、sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt server: ", topic, payload)
将接收到的publish中的topic和payload数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
]]
local mqtt_receiver = {}
--[[
处理接收到的publish数据
@api mqtt_receiver.proc(topic, payload, metas)
@param1 topic string
表示publish主题
@param2 payload string
表示publish数据负载
@param2 payload string
表示publish数据负载
@param3 metas table
表示publish报文的一些参数;格式如下:
{
qos: number类型,取值范围0,1,2
retainnumber类型,取值范围0,1
dupnumber类型,取值范围0,1
message_id: number类型
}
@return1 result nil
@usage
mqtt_receiver.proc(topic, payload, metas)
]]
function mqtt_receiver.proc(topic, payload, metas)
log.info("mqtt_receiver.proc", topic, payload:len(), json.encode(metas))
-- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 将topic和payload通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
sys.publish("RECV_DATA_FROM_SERVER", "recv from mqtt server: ", topic, payload)
-- 也可以直接在此处编写代码,处理topic和payload
end
return mqtt_receiver
@@ -0,0 +1,155 @@
--[[
@module mqtt_sender
@summary mqtt client数据发送应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为mqtt client 数据发送应用功能模块,核心业务逻辑为:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
2、mqtt sender task接收"CONNECT OK"、"PUBLISH_REQ"、"PUBLISH OK"三种类型的"MQTT_EVENT"消息,遍历队列send_queue,逐条发送数据到server
3、mqtt sender task接收"DISCONNECTED"类型的"MQTT_EVENT"消息,丢弃掉队列send_queue中未发送的数据;
4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
本文件的对外接口有1个:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的topic,payload和qos以及回调函数和回调参数一起publish出去;
本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
]]
local mqtt_sender = {}
--[[
数据发送队列,数据结构为:
{
[1] = {topic="topic1", payload="payload1", qos=0, cb={func=callback_function1, para=callback_para1}},
[2] = {topic="topic2", payload="payload2", qos=1, cb={func=callback_function2, para=callback_para2}},
[3] = {topic="topic3", payload="payload3", qos=2, cb={func=callback_function3, para=callback_para3}},
}
topic的内容为publish的主题,string类型,必须存在;
payload的内容为publish的负载数据,string类型,必须存在;
qos的内容为publish的质量等级,number类型,取值范围0,1,2,可选,如果用户没有指定,默认为0;
cb.func的内容为数据发送结果的用户回调函数,可以不存在;
cb.para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
]]
local send_queue = {}
-- mqtt client的任务名前缀
mqtt_sender.TASK_NAME_PREFIX = "mqtt_"
-- mqtt_client_sender的任务名
mqtt_sender.TASK_NAME = mqtt_sender.TASK_NAME_PREFIX.."sender"
-- "SEND_DATA_REQ"消息的处理函数
local function send_data_req_proc_func(tag, topic, payload, qos, cb)
-- 将原始数据增加前缀,然后插入到发送队列send_queue中
table.insert(send_queue, {topic=topic, payload="send from "..tag..": "..payload, qos=qos or 0, cb=cb})
-- 发送消息通知 mqtt sender task,有新数据等待发送
sys.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_REQ")
end
-- 按照顺序发送send_queue中的数据
-- 如果调用publish接口成功,则返回当前正在发送的数据项
-- 如果调用publish接口失败,通知回调函数发送失败后,继续发送下一条数据
local function publish_item(mqtt_client)
local item
-- 如果发送队列中有数据等待发送
while #send_queue>0 do
-- 取出来第一条数据赋值给item
-- 同时从队列send_queue中删除这一条数据
item = table.remove(send_queue, 1)
-- publish数据
-- result表示调用publish接口的同步结果,返回值有以下几种:
-- 如果失败,返回nil
-- 如果成功,number类型,qos为0时直接返回0qos为1或者2时返回publish报文的message id
result = mqtt_client:publish(item.topic, item.payload, item.qos)
-- publish接口调用成功
if result then
return item
-- publish接口调用失败
else
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if item.cb and item.cb.func then
item.cb.func(false, item.cb.para)
end
end
end
end
local function publish_item_cbfunc(item, result)
if item then
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if item.cb and item.cb.func then
item.cb.func(result, item.cb.para)
end
end
end
-- mqtt client sender的任务处理函数
local function mqtt_client_sender_task_func()
local mqtt_client
local send_item
local result, msg
while true do
-- 等待"MQTT_EVENT"消息
msg = sys.waitMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT")
-- mqtt连接成功
-- msg[3]表示mqtt client对象
if msg[2] == "CONNECT_OK" then
mqtt_client = msg[3]
-- 发送send_queue中的数据
send_item = publish_item(mqtt_client)
-- mqtt publish数据请求
elseif msg[2] == "PUBLISH_REQ" then
-- 如果mqtt client对象存在,并且没有正在等待发送结果的发送数据项
if mqtt_client and not send_item then
-- 发送send_queue中的数据
send_item = publish_item(mqtt_client)
end
-- mqtt publish数据成功
elseif msg[2] == "PUBLISH_OK" then
-- publish成功,执行回调函数通知发送方
publish_item_cbfunc(send_item, true)
-- publish成功,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 发送send_queue中的数据
send_item = publish_item(mqtt_client)
-- mqtt断开连接
elseif msg[2] == "DISCONNECTED" then
-- 清空mqtt client对象
mqtt_client = nil
-- 如果存在正在等待发送结果的发送项,执行回调函数通知发送方失败
publish_item_cbfunc(send_item, false)
-- 如果发送队列中有数据等待发送
while #send_queue>0 do
-- 取出来第一条数据赋值给send_item
-- 同时从队列send_queue中删除这一条数据
send_item = table.remove(send_queue,1)
-- 执行回调函数通知发送方失败
publish_item_cbfunc(send_item, false)
end
-- 当前没有正在等待发送结果的发送项
send_item = nil
end
end
end
-- 订阅"SEND_DATA_REQ"消息;
-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
--创建并且启动一个task
--运行这个task的处理函数mqtt_client_sender_task_func
sys.taskInitEx(mqtt_client_sender_task_func, mqtt_sender.TASK_NAME)
return mqtt_sender
@@ -0,0 +1,48 @@
--[[
@module sht30_app
@summary sht30_app应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为sht30_app应用功能模块,核心业务逻辑为:
1、每隔1秒读取一次温湿度数据;
本文件没有对外接口,直接在main.lua中require "sht30_app"就可以加载运行;
]]
-- 加载AirSHT30_1000驱动文件
local air_sht30 = require "AirSHT30_1000"
-- 读取sht30温湿度数据任务
local function read_sht30_task()
--打开sht30硬件
air_sht30.open(1)
--读取温湿度数据
local temprature, humidity = air_sht30.read()
--读取结果
if temprature then
-- 打印输出结果(保留2位小数)
log.info("read_sht30_req", "temprature", string.format("%.2f ℃", temprature))
log.info("read_sht30_req", "humidity", string.format("%.2f %%RH", humidity))
else
log.error("read_sht30_task_func", "read error")
end
--关闭sht30硬件
air_sht30.close()
-- 发布读取结果
sys.publish("READ_SHT30_RSP", temprature~=nil, temprature, humidity)
end
-- 读取sht30数据请求消息处理函数
local function read_sht30_req()
sys.taskInit(read_sht30_task)
end
-- 订阅读取sht30数据请求消息
sys.subscribe("READ_SHT30_REQ", read_sht30_req)
@@ -0,0 +1,167 @@
--[[
@module tcp_client_main
@summary tcp client socket主应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为tcp client socket主应用功能模块,核心业务逻辑为:
1、创建一个tcp client socket,连接server
2、处理连接异常,出现异常后执行重连动作;
3、调用tcp_client_receiver和tcp_client_sender中的外部接口,进行数据收发处理;
本文件没有对外接口,直接在main.lua中require "tcp_client_main"就可以加载运行;
]]
local libnet = require "libnet"
-- 加载tcp client socket数据接收功能模块
local tcp_client_receiver = require "app_tcp_receiver"
-- 加载tcp client socket数据发送功能模块
local tcp_client_sender = require "app_tcp_sender"
-- 电脑访问:https://iot.luatos.com/#/page6/netlab
-- 本工具使用方法可以参考:https://docs.openluat.com/common/TCPUDP_Test/
-- 点击 打开TCP 按钮,会创建一个TCP server
-- 将server的地址和端口赋值给下面这两个变量
local SERVER_ADDR = "115.120.239.161"
local SERVER_PORT = 25485
-- tcp_client_main的任务名
local TASK_NAME = tcp_client_sender.TASK_NAME
-- 处理未识别的消息
local function tcp_client_main_cbfunc(msg)
log.info("tcp_client_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
end
-- tcp client socket的任务处理函数
-- auto_reconnect:短连接还是长连接;长连接为true,表示断开连接后会自动重连;短连接为false,表示断开连接后,不会自动重连
local auto_reconnect = true
local function tcp_client_main_task_func(auto_reconnect)
local socket_client
local result, para1, para2
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("tcp_client_main_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息
log.info("tcp_client_main_task_func", "recv IP_READY", socket.dft())
-- 创建socket client对象
socket_client = socket.create(nil, TASK_NAME)
-- 如果创建socket client对象失败
if not socket_client then
log.error("tcp_client_main_task_func", "socket.create error")
goto EXCEPTION_PROC
end
-- 配置socket client对象为tcp client
result = socket.config(socket_client)
-- 如果配置失败
if not result then
log.error("tcp_client_main_task_func", "socket.config error")
goto EXCEPTION_PROC
end
-- 连接server
result = libnet.connect(TASK_NAME, 30000, socket_client, SERVER_ADDR, SERVER_PORT)
-- 如果连接server失败
if not result then
log.error("tcp_client_main_task_func", "libnet.connect error")
goto EXCEPTION_PROC
end
log.info("tcp_client_main_task_func", "libnet.connect success")
-- 数据收发以及网络连接异常事件总处理逻辑
while true do
-- 数据接收处理(接收处理必须写在libnet.wait之前,因为老版本的内核固件要求必须这样,新版本的内核固件没这个要求,为了不出问题,写在libnet.wait之前就行了)
-- 如果处理失败,则退出循环
if not tcp_client_receiver.proc(socket_client) then
log.error("tcp_client_main_task_func", "tcp_client_receiver.proc error")
break
end
-- 数据发送处理
-- 如果处理失败,则退出循环
if not tcp_client_sender.proc(TASK_NAME, socket_client) then
log.error("tcp_client_main_task_func", "tcp_client_sender.proc error")
break
end
-- 阻塞等待socket.EVENT事件或者15秒钟超时
-- 以下三种业务逻辑会发布事件:
-- 1、socket client和server之间的连接出现异常(例如server主动断开,网络环境出现异常等),此时在内核固件中会发布事件socket.EVENT
-- 2、socket client接收到server发送过来的数据,此时在内核固件中会发布事件socket.EVENT
-- 3、socket client需要发送数据到server, 在tcp_client_sender.lua中会发布事件socket.EVENT
result, para1, para2 = libnet.wait(TASK_NAME, 360000, socket_client)
log.info("tcp_client_main_task_func", "libnet.wait", result, para1, para2)
-- 如果连接异常或者用户主动关闭,则退出循环
if not result then
log.warn("tcp_client_main_task_func", "connection exception")
break
end
end
-- 出现异常
::EXCEPTION_PROC::
-- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
tcp_client_sender.exception_proc()
-- 如果存在socket client对象
if socket_client then
-- 关闭socket client连接
libnet.close(TASK_NAME, 5000, socket_client)
-- 释放socket client对象
socket.release(socket_client)
socket_client = nil
end
-- 根据是否需要自动重连标志,决定后续执行的动作
if auto_reconnect then
-- 5秒后跳转到循环体开始位置,自动发起重连
sys.wait(5000)
else
sys.publish("TCP_CLIENT_CLOSE_RSP")
log.warn("tcp_client_main_task_func", "exit")
break
end
end
-- 清除此task对应的管理表资源
sys.taskDel(TASK_NAME)
end
local function tcp_client_run_req(connection_type)
--创建并且启动一个task
--运行这个task的主函数tcp_client_main_task_func
sys.taskInitEx(tcp_client_main_task_func, TASK_NAME, tcp_client_main_cbfunc, connection_type)
end
local function tcp_client_close_req()
sys.sendMsg(TASK_NAME, socket.EVENT, "CLOSE_REQ")
end
sys.subscribe("TCP_CLIENT_RUN_REQ", tcp_client_run_req)
sys.subscribe("TCP_CLIENT_CLOSE_REQ", tcp_client_close_req)
@@ -0,0 +1,90 @@
--[[
@module tcp_client_receiver
@summary tcp client socket数据接收应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为tcp client socket数据接收应用功能模块,核心业务逻辑为:
从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
本文件的对外接口有2个:
1、tcp_client_receiver.proc(socket_client):数据接收应用逻辑处理入口,在tcp_client_main.lua中调用;
2、sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data)
将接收到的数据通过消息"RECV_DATA_FROM_SERVER"发布出去;
需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
]]
local tcp_client_receiver = {}
-- socket数据接收缓冲区
local recv_buff = nil
--[[
检查socket client是否收到数据,如果收到数据,读取并且处理完所有数据
@api tcp_client_receiver.proc(socket_client)
@param1 socket_client userdata
表示由socket.create接口创建的socket client对象;
必须传入,不允许为空或者nil
@return1 result bool
表示处理结果,成功为true,失败为false
@usage
--
tcp_client_receiver.proc(socket_client)
]]
function tcp_client_receiver.proc(socket_client)
-- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
if recv_buff==nil then
recv_buff = zbuff.create(1024)
-- 当recv_buff不再使用时,不需要主动调用recv_buff:free()去释放
-- 因为Lua的垃圾处理器会自动释放recv_buff所申请的内存空间
-- 如果等不及垃圾处理器自动处理,在确定以后不会再使用recv_buff时,则可以主动调用recv_buff:free()释放内存空间
end
-- 循环从内核的缓冲区读取接收到的数据
-- 如果读取失败,返回false,退出
-- 如果读取成功,处理数据,并且继续循环读取
-- 如果读取成功,并且读出来的数据为空,表示已经没有数据可读,返回true,退出
while true do
-- 从内核的缓冲区中读取数据到recv_buff中
-- 如果recv_buff的存储空间不足,会自动扩容
local result = socket.rx(socket_client, recv_buff)
-- 读取数据失败
-- 有两种情况:
-- 1、recv_buff扩容失败
-- 2、socket client和server之间的连接断开
if not result then
log.error("tcp_client_receiver.proc", "socket.rx error")
return false
end
-- 如果读取到了数据, used()就必然大于0, 进行处理
if recv_buff:used() > 0 then
log.info("tcp_client_receiver.proc", "recv data len", recv_buff:used())
-- 读取socket数据接收缓冲区中的数据,赋值给data
local data = recv_buff:query()
-- 将数据data通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data)
-- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 清空socket数据接收缓冲区中的数据
recv_buff:del()
-- 读取成功,但是读出来的数据为空,表示已经没有数据可读,可以退出循环了
else
break
end
end
return true
end
return tcp_client_receiver
@@ -0,0 +1,138 @@
--[[
@module tcp_client_sender
@summary tcp client socket数据发送应用功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为tcp client socket数据发送应用功能模块,核心业务逻辑为:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
2、tcp_client_main主任务调用tcp_client_sender.proc接口,遍历队列send_queue,逐条发送数据到server
3、tcp client socket和server之间的连接如果出现异常,tcp_client_main主任务调用tcp_client_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
本文件的对外接口有3个:
1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
2、tcp_client_sender.proc:数据发送应用逻辑处理入口,在tcp_client_main.lua中调用;
3、tcp_client_sender.exception_proc:数据发送应用逻辑异常处理入口,在tcp_client_main.lua中调用;
]]
local tcp_client_sender = {}
local libnet = require "libnet"
--[[
数据发送队列,数据结构为:
{
[1] = {data="data1", cb={func=callback_function1, para=callback_para1}},
[2] = {data="data2", cb={func=callback_function2, para=callback_para2}},
}
data的内容为真正要发送的数据,必须存在;
func的内容为数据发送结果的用户回调函数,可以不存在
para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
]]
local send_queue = {}
-- tcp_client_main的任务名
tcp_client_sender.TASK_NAME = "tcp_client_main"
-- "SEND_DATA_REQ"消息的处理函数
local function send_data_req_proc_func(tag, data, cb)
-- 将原始数据增加前缀,然后插入到发送队列send_queue中
table.insert(send_queue, {data="send from "..tag..": "..data, cb=cb})
-- 通知tcp_client_main主任务有数据需要发送
-- tcp_client_main主任务如果处在libnet.wait调用的阻塞等待状态,就会退出阻塞状态
sys.sendMsg(tcp_client_sender.TASK_NAME, socket.EVENT, 0)
end
--[[
检查socket client是否需要发送数据,如果需要发送数据,读取并且发送完发送队列中的所有数据
@api tcp_client_sender.proc(task_name, socket_client)
@param1 task_name string
表示socket.create接口创建socket client对象时所处的task的name
必须传入,不允许为空或者nil
@param2 socket_client userdata
表示由socket.create接口创建的socket client对象;
必须传入,不允许为空或者nil
@return1 result bool
表示处理结果,成功为true,失败为false
@usage
tcp_client_sender.proc("tcp_client_main", socket_client)
]]
function tcp_client_sender.proc(task_name, socket_client)
local send_item
local result, buff_full
-- 遍历数据发送队列send_queue
while #send_queue>0 do
-- 取出来第一条数据赋值给send_item
-- 同时从队列send_queue中删除这一条数据
send_item = table.remove(send_queue,1)
-- 发送这条数据,超时时间15秒钟
result, buff_full = libnet.tx(task_name, 15000, socket_client, send_item.data)
-- 发送失败
if not result then
log.error("tcp_client_sender.proc", "libnet.tx error")
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
return false
end
-- 如果内核固件中缓冲区满了,则将send_item再次插入到send_queue的队首位置,等待下次尝试发送
if buff_full then
log.error("tcp_client_sender.proc", "buffer is full, wait for the next time")
table.insert(send_queue, 1, send_item)
return true
end
log.info("tcp_client_sender.proc", "send success")
-- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(true, send_item.cb.para)
end
-- 发送成功,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
end
return true
end
--[[
socket client连接出现异常时,清空等待发送的数据,并且执行发送方的回调函数
@api tcp_client_sender.exception_proc()
@usage
tcp_client_sender.exception_proc()
]]
function tcp_client_sender.exception_proc()
-- 遍历数据发送队列send_queue
while #send_queue>0 do
local send_item = table.remove(send_queue,1)
-- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
end
end
-- 订阅"SEND_DATA_REQ"消息;
-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
return tcp_client_sender
@@ -0,0 +1,676 @@
--[[
@module drv_lowpower
@summary 低功耗模式pm.power(pm.WORK_MODE, 1)驱动配置功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为低功耗模式pm.power(pm.WORK_MODE, 1)驱动配置功能模块,提供了低功耗模式的配置模板,包括以下几点:
1、在进入低功耗模式前,根据自己的实际项目需求,配置进入低功耗模式后的中断唤醒方式;详情参考set_lowpower_interrupt_wakeup()实现
2、在进入低功耗模式前,根据自己的实际项目需求,配置一些必要的功能项;可以在满足项目功能需求的背景下,让功耗降到最低;详情参考set_lowpower_func_item()实现
3、配置最低功耗模式为低功耗模式;pm.power(pm.WORK_MODE, 1)
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在低功耗模式示例代码中,并未对GPIO23进行配置,默认状态下为高电平,以此演示低功耗模式下的实际功耗表现;
Air780EHV模组内部包含有Audio Codec芯片ES8311GPIO20作为Audio Codec芯片ES8311的供电使能开关;
在本应用demo中无须单独对GPIO20进行配置,一般是结合对应的Audio功能代码进行操作;
如果在本应用demo中配置了GPIO20为输出高电平,此时Audio Codec芯片功耗表现为45uA左右;
在低功耗模式下,并未对GPIO20进行配置,默认状态下为输入高阻态,以此演示低功耗模式下的实际功耗表现;
Air780EXX 系列模组中,UART1 支持 LPUART,LPUART 是一种专为低功耗应用设计的串口,适合长时间运行的电池供电设备
1、如果需要使用 LPUART 的唤醒功能,可以参考下方代码进行配置;
2、如果不需要使用 LPUART 的唤醒功能,可以参考下方说明进行配置:
2.1 之前没有配置过 LPUART,那么就不需要进行任何配置;
2.2 之前配置过 LPUART,必须按照下方的说明进行软件和硬件的配置,缺一不可:
1) 软件上的配置说明:
uart.close(1)
pins.setup(16, "GPIO19") -- 把原有的uart改成其他功能, 或者gpio(此处仅为示例,实际项目中需要根据实际情况进行配置)
pins.setup(17, "GPIO18") -- 把原有的uart改成其他功能, 或者gpio(此处仅为示例,实际项目中需要根据实际情况进行配置)
gpio.close(19) -- 关闭对应的gpio(此处仅为示例,实际项目中需要根据实际情况进行配置)
gpio.close(18) -- 关闭对应的gpio(此处仅为示例,实际项目中需要根据实际情况进行配置)
2) 硬件上的配置说明:
将 UART1_TX 上拉一个 10K 电阻到 Vref,或者上拉到一个可以固定输出的 3.3V 电平(注意不能是 VDD_EXT
本文件的对外接口只有1个:
1、sys.subscribe("DRV_SET_LOWPOWER", set_drv_lowpower):订阅"DRV_SET_LOWPOWER"消息;
其他应用模块如果需要配置低功耗模式,直接sys.publish("DRV_SET_LOWPOWER")这个消息即可;
]]
-- 获取当前使用的模组型号
local module = hmeta.model()
log.info("drv_lowpower", "当前使用的模组是:", module)
-- Air780EGG/EGP模组WAKEUP2引脚内部用作GSensor中断信号,用户需要手动配置成中断方式才能实现GSensor的中断唤醒功能,除此之外不可作为其他功能使用
-- Air780EPM/EHM/EHU/EHN/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,可以作为普通中断功能
--
-- Air780EHV模组WAKEUP3引脚内部用作GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关,除此之外不可作为其他功能
-- Air780EPM/EHM/EHU/EHN/EGH/EGP/EGG模组WAKEUP3引脚并未被模组内部占用,可以作为普通中断功能
--
-- Air780EGH/EGP/EGG模组WAKEUP4引脚内部用作GPIO21功能,用于控制GNSS定位芯片的供电使能开关,除此之外不可作为其他功能
-- Air780EPM/EHM/EHU/EHN/EHV模组WAKEUP4引脚并未被模组内部占用,可以作为普通中断功能
--
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)功能
-- Air780EHU/EHN/EHV/EGH/EGP/EGG模组支持CHG_DETWAKEUP6)功能,可以作为普通中断功能
--
-- 在低功耗模式下,唤醒后会执行此处的中断处理函数
local function lowpower_wakeup_func(level, id)
local tag =
{
[gpio.PWR_KEY] = "PWR_KEY",
[gpio.CHG_DET] = "CHG_DET",
[gpio.WAKEUP0] = "WAKEUP0",
[gpio.WAKEUP1] = "WAKEUP1",
[gpio.WAKEUP2] = "WAKEUP2",
[gpio.WAKEUP3] = "WAKEUP3",
[gpio.WAKEUP4] = "WAKEUP4",
[gpio.WAKEUP5] = "WAKEUP5",
}
-- 注意:此处的level电平并不表示触发中断的边沿电平
-- 而是在触发中断后,某个时间点的电平状态
-- 可能和触发中断的边沿电平状态一致,也可能不一致
log.info("lowpower_wakeup_func", tag[id], level)
end
-- UART1的数据接收中断处理函数,UART1接收到数据时,会执行此函数
-- 此处仅仅简单的演示UART1唤醒后,读取UART1接收到的数据功能,更详细的用法参考单独的uart demo
--
-- 当配置波特率在9600及以下时,可正常接收每一包数据
--
-- 当配置波特率在9600以上时,模组在休眠状态下接收数据时会有丢失
-- 如何才能正确处理串口接收业务,建议采用以下操作流程:
-- 1、串口对端先发送1个字节的数据,例如发送“1”,此时会使模组唤醒,并触发UART1的数据接收中断回调(例如uart1_wakeup_read),回调函数中len为-1
-- 2、模组对“len == -1”进行判断,当len为-1时,切换到常规模式,开始准备接收数据,并向对端返回“lowpower wakeup\r\n”,用于告知对端模组已唤醒
-- 3、对端收到“lowpower wakeup\r\n”后,即可确认模组已唤醒,此时可以开始发送数据
-- 4、模组切换到常规模式后,通过while循环读取UART1接收到的数据,直到读取不到数据或者读取到的数据长度为0(回调中也做有拼接数据的处理,防止一包数据被拆分成多个小包)
-- 5、当业务处理完成后,可以通过调用 sys.publish("DRV_SET_LOWPOWER") 使其再次进入低功耗模式
--
-- 串口接收数据缓冲区
local read_buf = ""
local function concat_timeout_func()
if read_buf:len() > 0 then
-- uart.write(1, "len: " .. #read_buf .. " data: " .. read_buf .. "\r\n")
read_buf = ""
end
end
-- UART1的数据接收中断回调函数,UART1接收到数据时,会执行此函数
local function uart1_wakeup_read(_, len)
if len == -1 then
-- 切换到常规模式
pm.power(pm.WORK_MODE, 0)
-- 发送确认唤醒的消息
uart.write(1, "lowpower wakeup\r\n")
end
local s
while true do
-- 非阻塞读取UART1接收到的数据,最长读取1024字节
s = uart.read(1, 1024)
-- 如果从串口没有读到数据
if not s or s:len() == 0 then
-- 启动50毫秒的定时器,如果50毫秒内没收到新的数据,则处理当前收到的所有数据
-- 这样处理是为了防止将一大包数据拆分成多个小包来处理
-- 例如pc端串口工具下发1100字节的数据,可能会产生将近20次的中断进入到read函数,才能读取完整
-- 此处的50毫秒可以根据自己项目的需求做适当修改,在满足整包拼接完整的前提下,时间越短,处理越及时
sys.timerStart(concat_timeout_func, 50)
break
end
log.info("lowpower uart1_read len", s:len())
-- log.info("lowpower uart1_wakeup_read", s, s:toHex())
-- 拼接收到的数据到缓冲区
read_buf = read_buf .. s
end
end
-- 在进入低功耗模式前,根据自己的实际项目需求,配置低功耗模式下的中断唤醒方式
--
-- 低功耗模式下,Air780EPM/EHM支持以下几种类型的中断唤醒方式:
-- 1、PWR_KEY引脚中断
-- 2、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 3、VBUS(内部分压到WAKEUP1)引脚中断
-- 4、UART1_RXD引脚中断(需要将UART1配置为9600波特率)
--
-- Air780EHM/EHU/EHN支持以下几种类型的中断唤醒方式:
-- 1、PWR_KEY引脚中断
-- 2、CHG_DET(WAKEUP6)引脚中断
-- 3、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 4、VBUS(内部分压到WAKEUP1)引脚中断
-- 5、UART1_RXD引脚中断(需要将UART1配置为9600波特率)
--
-- Air780EHV支持以下几种类型的中断唤醒方式:
-- 1、PWR_KEY引脚中断
-- 2、CHG_DET(WAKEUP6)引脚中断
-- 3、WAKEUP0、WAKEUP2、WAKEUP4、WAKEUP5引脚中断
-- 4、VBUS(内部分压到WAKEUP1)引脚中断
-- 5、UART1_RXD引脚中断(需要将UART1配置为9600波特率)
--
-- Air780EGH支持以下几种类型的中断唤醒方式:
-- 1、PWR_KEY引脚中断
-- 2、CHG_DET(WAKEUP6)引脚中断
-- 3、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP5引脚中断
-- 4、VBUS(内部分压到WAKEUP1)引脚中断
-- 5、UART1_RXD引脚中断(需要将UART1配置为9600波特率)
--
-- Air780EGP/EGG支持以下几种类型的中断唤醒方式:
-- 1、PWR_KEY引脚中断
-- 2、CHG_DET(WAKEUP6)引脚中断
-- 3、WAKEUP0、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 4、VBUS(内部分压到WAKEUP1)引脚中断
-- 5、UART1_RXD引脚中断(需要将UART1配置为9600波特率)
--
-- 特别注意:当使用杜邦线短接/断开测试时,因为抖动因素,所以实际情况肯定会存在高低电平频繁跳变的情况!!!!!!
-- 所以测试表现和实际的短接/断开动作并不完全相符,这种测试方法仅仅简单验证一下功能即可!!!!!!
-- 最终自己设计的硬件产品并不会出现此问题
-- 特别注意:当配置引脚唤醒功能时,基于使用的硬件,配置之后,可能会增加系统功耗;本函数中基于Air780EXX系列每个模组的核心板给出了每项配置对功耗的影响数据
-- 当使用自己的硬件测试时,以自己的硬件实测数据为准;Air780EXX系列每个模组的核心板的实测数据可以用来参考
local function set_lowpower_interrupt_wakeup()
-- 配置PWR_KEY引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中三选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 由于PWR_KEY引脚内部已经拉高至VBAT电压,因此只能配置为gpio.PULLUP,不能配置为gpio.PULLDOWN
-- 当配置为gpio.PULLUP时,按下开机键产生下降沿,弹起开机键产生上升沿
-- 在实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.PWR_KEY, 200)
-- gpio.setup(gpio.PWR_KEY, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.PWR_KEY, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.PWR_KEY, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 在Air780EXX系列模组中,Air780EHN/EHU/EHV/EGH/EGG/EGP模组包含有CHG_DET(WAKEUP6)引脚,可以将此引脚配置为中断唤醒引脚
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)引脚的中断唤醒功能
-- 配置CHG_DET(WAKEUP6)引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中三选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试:
-- 由于CHG_DET(WAKEUP6)引脚内部已经拉高至VDD_1.8V,因此只能配置为gpio.PULLUP,不能配置为gpio.PULLDOWN
-- 当配置为gpio.PULLUP时,将CHG_DET(WAKEUP6)引脚(对应的丝印为75/CHG_DET)和GND短接产生下降沿,和GND断开产生上升沿
-- 在实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EHN" or module == "Air780EHU" or module == "Air780EHV" or module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
-- gpio.debounce(gpio.CHG_DET, 1000)
-- -- gpio.setup(gpio.CHG_DET, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- -- gpio.setup(gpio.CHG_DET, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- -- gpio.setup(gpio.CHG_DET, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- end
-- 配置WAKEUP0引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP0引脚(对应的丝印为101/WAKEUP0)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP0引脚(对应的丝印为101/WAKEUP0)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP0, 1000)
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 配置VBUS(WAKEUP1)引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试,将提供5V供电输入的USB线插入type-c座子,会产生上升沿,拔出会产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP1, 200)
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP1, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 在Air780EXX系列模组中,Air780EGP/EGG模组WAKEUP2引脚内部用作GSensor中断信号,
-- 如果需要在低功耗模式下使用GSensor的中断唤醒功能,则需要根据下方说明打开对应的代码
--
-- Air780EPM/EHM/EHN/EHU/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,可以作为普通中断功能使用,配置方式见下一个配置项
--
-- 配置WAKEUP2引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中三选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列内部包含GSensor的每个模组的核心板测试,WAKEUP2引脚已被模组内部用作GSensor中断信号,外部不可再用,否则会干扰GSensor的正常工作
-- 在实际测试时,需要先引用exvib模块,再通过exvib.open(1)打开Air780EXX系列内部包含的三轴加速度传感器DA221,最后配置WAKEUP2引脚的中断唤醒功能
-- 由于GSensor的电源开关通过Air780EXX系列内部包含GSensor的模组的GPIO23控制,因此切记不要在其他地方对GPIO23进行二次配置,否则会干扰GSensor的正常工作
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EGP" or module == "Air780EGG" then
-- -- 关于引用exvib模块,功耗数据变化的说明:
-- exvib = require("exvib") -- 引用exvib模块
-- exvib.open(1) -- 打开Air780EXX系列内部的三轴加速度传感器DA221
--
-- -- 在测试下面的配置代码时,同时也需要把上面两行代码打开
-- gpio.debounce(gpio.WAKEUP2, 200)
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, nil, gpio.FALLING) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, nil, gpio.RISING) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, nil, gpio.BOTH) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- end
--
--
-- 在Air780EXX系列模组中,除了Air780EGP/EGG模组WAKEUP2引脚内部用作GSensor中断信号外
-- Air780EPM/EHM/EHN/EHU/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,外部可以作为WAKEUP使用
-- 如果需要在低功耗模式下使用WAKEUP2引脚的中断唤醒功能,则需要根据下方说明打开对应的代码
--
-- 配置WAKEUP2引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组内部不包含GSensor的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP2引脚(对应的丝印为79/SIMDET)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP2引脚(对应的丝印为79/SIMDET)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EHV" or module == "Air780EGH" then
-- gpio.debounce(gpio.WAKEUP2, 1000)
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- end
-- 在Air780EXX系列模组中,Air780EHV模组内部将GPIO20引脚强制用作GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关
-- 除Air780EHV模组外,Air780EPM/EHM/EHN/EHU/EGH/EGG/EGP模组可以将GPIO20引脚配置为WAKEUP3引脚,用于中断唤醒功能
-- 配置WAKEUP3引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP3引脚(对应的丝印为102/GPIO20)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP3引脚(对应的丝印为102/GPIO20)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
-- gpio.debounce(gpio.WAKEUP3, 1000)
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- end
-- 在Air780EXX系列模组中,Air780EGH/EGP/EGG模组内部将GPIO21引脚强制用作GPIO21功能,用于控制GNSS定位芯片的供电使能开关
-- 除Air780EGH/EGP/EGG模组外,Air780EPM/EHM/EHN/EHU/EHV模组可以将GPIO21引脚配置为WAKEUP4引脚,用于中断唤醒功能
-- 配置WAKEUP4引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试:
-- 当配置为时gpio.PULLUP,将WAKEUP4引脚(对应的丝印为107/GPIO21)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为时gpio.PULLDOWN,将WAKEUP4引脚(对应的丝印为107/GPIO21)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EHV" then
-- gpio.debounce(gpio.WAKEUP4, 1000)
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- end
-- 配置WAKEUP5引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP5引脚(对应的丝印为19/GPIO22)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP5引脚(对应的丝印为19/GPIO22)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP5, 1000)
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, lowpower_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 配置9600波特率的UART1_RXD接收到数据唤醒(必须配置为9600波特率,这样可以保证唤醒的同时,还能接收到完整的数据)
-- 此处仅仅简单的演示UART1唤醒功能的配置,更详细的用法参考单独的uart demo
-- 初始化UART1,波特率9600,数据位8,停止位1
-- 基于合宙Air780EXX系列每个模组的核心板测试,将UART1引脚(对应的丝印为17/U1RXD、18/U1TXD、GND)通过USB转TTL串口线和电脑相连,电脑串口工具配置9600波特率,数据位8,停止位1,串口工具发送任何数据都可以唤醒模组
-- uart.setup(1, 9600, 8, 1)
-- 注册UART1的数据接收中断处理函数,UART1接收到数据时,会执行uart1_wakeup_read函数
-- uart.on(1, "receive", uart1_wakeup_read)
end
-- Air780EGG/EGP模组内部包含有GsensorAir780EGH/EGP/EGG模组内部包含有GNSS
-- Air780EHV模组内部包含有Audio Codec芯片ES8311Air780EHU/EHN/EHV/EGH/EGP/EGG模组支持CHG_DETWAKEUP6)功能
-- Air780EPM/EHM模组没有引出CHG_DETWAKEUP6)引脚,无法配置CHG_DETWAKEUP6)功能
-- set_lowpower_func_item()中会自动对模组型号进行判断,避免对不包含GNSS/Gsensor/Audio Codec芯片或者CHG_DETWAKEUP6)功能的模组进行误配置
-- 在进入低功耗模式前,根据自己的实际项目需求,配置一些必要的功能项,可以在满足项目功能需求的背景下,让功耗降到最低
--
-- 关于 WAKEUP0 ~ WAEKUP6、PWR_KEY 管脚如何配置才能正确关闭的说明:
-- 1、 要想让某个管脚关闭,我们一般需要在软件中将该管脚配置为输入模式,不过 WAKEUP0 ~ WAEKUP6、PWR_KEY 管脚在配置为输入模式时,需要特别注意;
-- 2、 WAKEUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY :这些管脚是独立的 WAEKUP 管脚,在使用 gpio.setup() 接口配置为输入模式时,可以只有输入功能,而没有唤醒功能
-- 在 V2046 及之前的版本中,WAEKUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- 在 V2048 及之后的版本中,WAEKUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,没有唤醒功能,只有输入功能;
-- 3、 WAKEUP3 ~ WAKEUP5 :这些管脚不仅是 AGPIOWAKEUP 管脚(对应 AGPIOWU0 ~ AGPIOWU2),也是 GPIO 管脚(对应 GPIO20 ~ GPIO22),使用 gpio.setup() 接口配置为输入模式时:
-- 如果第一个参数填写为 gpio.WAKEUP3/gpio.WAKEUP4/gpio.WAKEUP5 ,那么内核中统一会配置为 输入唤醒 功能,当 WAKEUP3 ~ WAKEUP5 引脚的电平发生变化时,会触发中断,导致模组唤醒,无法真正实现关闭;
-- 所以,在关闭 WAKEUP3 ~ WAKEUP5 管脚时,使用 gpio.setup() 接口配置为输入模式时,第一个参数应该填写为 20 ~ 22 ,即对应的 GPIO 号,这样才能真正关闭 WAKEUP3 ~ WAKEUP5 管脚,与内核固件版本无关。
local function set_lowpower_func_item()
-- 第一类功能配置项:飞行模式
-- 通过配置飞行模式可以有效关闭4G芯片的4G网络能力
--
-- 这个功能的特性是:
-- 1、在常规模式下,飞行模式默认是关闭的,可以根据项目需要显式的开启飞行模式,从而关闭4G网络能力
-- 2、在低功耗模式下,飞行模式默认也是关闭的,需要根据项目需要显式的开启飞行模式,从而关闭4G网络能力,关闭后可以有效降低功耗
-- 3、在PSM+模式下,飞行模式默认是开启的,不能显式的关闭飞行模式
-- 根据自己的项目需求决定:进入低功耗模式前,是否需要进入飞行模式
-- 一旦进入飞行模式,意味着无法使用4G网络,无法和自己的业务服务器保持连接和收发数据
-- 此处代码默认没有进入飞行模式;如果需要进入飞行模式,打开下面的一行代码
-- 在vbat供电3.8v的状态下,进入飞行模式,可以减少1mA到1.5mA的功耗(和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准)
-- 在关闭其他功能的情况下,飞行模式+低功耗状态,待机电流在40多uA到70多uA左右
-- mobile.flymode(0, true)
-- 第二类功能配置项:USB功能
-- 通过USB功能可以实现抓日志和业务数据通信等
--
-- 这个功能的特性是:
-- 1、在常规模式下,USB功能是默认开启的,通过USB虚拟串口进行抓日志和业务数据通信等
-- 2、在低功耗模式和PSM+模式下,此时USB功能默认是关闭的,无法使用USB虚拟串口进行抓日志和业务数据通信等
-- 根据自己的项目需求决定:进入低功耗模式前,是否需要关闭USB供电电源
-- 从2025年3月份发布的内核固件开始:
-- 1、在pm.power(pm.WORK_MODE, 1)和pm.power(pm.WORK_MODE, 3)中会自动执行pm.power(pm.USB, false)关闭USB功能
-- 2、在pm.power(pm.WORK_MODE, 0)会自动执行pm.power(pm.USB, true)打开USB功能
-- 所以,如果你使用的内核固件如果是2025年3月份之后发布的,则不再需要显式的关闭USB功能,在低功耗模式中会自动关闭USB功能
-- 此处代码默认没有显式的关闭USB功能,是因为在后续的pm.power(pm.WORK_MODE, 1)中会自动关闭USB功能
-- 如果由于某种原因,你必须使用2025年3月份之前的内核固件,则根据需求可以打开下面的一行代码
-- 在vbat供电3.8v的状态下,关闭USB功能,可以减少140uA到200uA左右的功耗
-- pm.power(pm.USB, false)
-- 第三类功能配置项:GNSS备电电源开关及Gsensor电源开关
-- 这一类功能配置项仅对Air780EGH/EGG/EGP模组有效(Air780EGH内部包含GNSSAir780EGG/EGP内部包含GNSS和Gsensor
-- Air780EPM/EHM/EHN/EHU/EHV模组内部不包含GNSS和Gsensor,无法使用该功能
-- Air780EGH/EGG/EGP模组通过GPIO23作为GNSS的备电电源开关和Gsensor的电源开关,默认为高电平输出
--
-- 这个功能引脚输出的电平状态,对GNSS和Gsensor功能的影响是:
-- GNSS:在低功耗模式或者PSM+模式下,
-- 如果GPIO23输出高电平,可以保证GNSS的定位数据不被丢失,
-- 并且在关闭GNSS后两个小时内,在室外空旷环境下,再次打开GNSS时,可以热启动3s左右快速获取到定位数据;
-- 但是如果超过两个小时之后,再次打开GNSS,就是冷启动状态,35s左右才能获取到定位数据;
-- 如果GPIO23输出低电平,此时GNSS的备电电源开关是关闭的,下次打开GNSS时,就是冷启动状态,35s左右才能获取到定位数据;
-- 客户可以根据项目需求来配置GPIO23的电平状态
-- Gsensor:在低功耗模式或者PSM+模式下,
-- 如果GPIO23输出高电平,Gsensor的电源开关处于打开状态,那么可以通过Gsensor的中断唤醒脚(WAKEUP2)来实现震动中断唤醒功能;
-- 如果GPIO23输出低电平,Gsensor的电源开关处于关闭状态,那么无法使用Gsensor的任何功能;
--
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,
-- 可能你会打开GNSS的备电电源开关和GSensor的电源开关,用于保存GNSS的定位数据和快速获取定位数据或者实现GSensor的震动中断唤醒功能
-- 根据自己的项目需求决定:进入低功耗模式前,是否需要关闭GNSS的备电电源开关和GSensor的电源开关
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码没有打开,这行代码打开后可以减少30uA左右的功耗
-- if module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
-- gpio.setup(23, nil, gpio.PULLDOWN)
-- end
-- 第四类功能配置项:通用AGPIOGPIO24、GPIO25、GPIO26、GPIO27、GPIO28
-- 这五个功能引脚在Air780EXX系列模组内部并没有被占用,所以用户在项目开发中可以根据自己的项目需求来使用任何一个引脚
--
-- 这些功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为普通的GPIO输出、输入、中断使用
-- 2、在低功耗模式和PSM+模式下,可以保持固定的高电平或者低电平输出
-- 3、如果在模组内部和模组外部都没有接其他元器件,无论软件上如何配置AGPIO,对功耗都没有影响
-- 4、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出低,让元器件彻底不工作,则对功耗都没有影响
-- 5、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出高,让元器件彻底不工作,并且AGPIO在硬件上也没有接下拉电阻,则对功耗都没有影响
-- 6、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出高,让元器件彻底不工作,但是AGPIO在硬件上接了下拉电阻,对功耗有影响
-- 例如接了100K的下拉电阻,当AGPIO输出的高电平是3.3V、下拉电阻是100K时,其电流影响的理论值大概是3.3V/100K=33uA,具体数据以实际硬件环境的测量为准
-- 7、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出电平可以让元器件正常工作,则对功耗有影响,影响大小取决于元器件本身的耗电,具体数据以实际硬件环境的测量为准
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下
-- 可能你会使用这些AGPIO来固定输出高电平,做为Vref,给其他外围硬件电路做上拉使用(例如模组的UART RX可以上拉到VrefSIM卡插入检测的USIM_DET可以上拉到Vref);也可能会有其他用途
-- 根据自己的项目需求决定:进入低功耗模式前,来关闭AGPIOGPIO24、GPIO25、GPIO26、GPIO27、GPIO28)控制的电路单元的功耗
-- 一旦关闭,如果你项目中使用了这些功能引脚,意味着这些功能引脚有关的功能将无法正常工作,例如无法为外围电路提供上拉
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输出低电平,输出高电平,close,输入下拉,输入上拉,六种方式中的一种);
-- 具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
-- gpio.setup(24, nil, gpio.PULLDOWN)
-- gpio.setup(25, nil, gpio.PULLDOWN)
-- gpio.setup(26, nil, gpio.PULLDOWN)
-- gpio.setup(27, nil, gpio.PULLDOWN)
-- gpio.setup(28, nil, gpio.PULLDOWN)
-- 第五类功能配置项:通用WAKEUPWAKEUP0
-- 这一个功能引脚在Air780EXX系列每个模组内部并没有被占用,所以用户在项目开发中可以根据自己的项目需求来使用这个引脚
--
-- 这些功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为中断使用,每个引脚可以配置独立的中断处理函数,用来区分是哪一个WAKEUP引脚产生的中断
-- 2、在低功耗模式下,也可以作为中断使用,每个引脚可以配置独立的中断处理函数,用来区分是哪一个WAKEUP引脚产生的中断
-- 3、在PSM+模式下,也可以作为中断使用,虽然每个引脚可以配置独立的中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数,无法区分是哪一个WAKEUP引脚唤醒
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这些WAKEUP引脚的中断唤醒功能
-- 根据自己的项目需求,决定是否需要关闭通用WAKEUP(WAKEUP0)功能,如果关闭,对功耗的影响可以降到最低
-- 一旦关闭,如果你项目中使用了这些功能引脚,意味着这些功能引脚有关的功能将无法正常工作,例如无法中断唤醒
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输入下拉,输入上拉,close,四种方式中的一种);具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.WAKEUP0, nil, gpio.PULLDOWN)
-- 第六类功能配置项:VBUSWAKEUP1
-- 这个是VBUS功能引脚,在Air780EXX系列每个模组内部经分压后接WAKEUP1,固定只能用作USB插入检测使用
--
-- 这个功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- 2、在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- 3、在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 根据自己的项目需求决定是否需要关闭VBUS(WAKEUP1)功能,如果关闭,对功耗的影响可以降到最低
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法检测USB插入、无法中断唤醒
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输入下拉,输入上拉,close,四种方式中的一种);具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.WAKEUP1, nil, gpio.PULLDOWN)
-- 第七类功能配置项:AGPIOWUGPIO20/WAKEUP3、GPIO21/WAKEUP4、GPIO22/WAKEUP5
-- 在Air780EXX系列模组中,Air780EHV模组内部将GPIO20/WAKEUP3引脚作为GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关
-- 除Air780EHV模组外,Air780EPM/EHM/EHU/EHN/EGH/EGP/EGG模组可以将GPIO20/WAKEUP3引脚作为WAKEUP3功能使用
--
-- 在Air780EXX系列模组中,Air780EGH/EGP/EGG模组内部将GPIO21/WAKEUP4引脚作为GPIO21功能,用于控制GNSS定位芯片的供电使能开关
-- 除Air780EGH/EGP/EGG模组外,Air780EPM/EHM/EHU/EHN/EHV模组可以将GPIO21/WAKEUP4引脚作为WAKEUP4功能使用
--
-- 只有GPIO22/WAKEUP5引脚在Air780EXX系列模组中没有被占用
--
-- 所以用户在项目开发中可以根据自己的项目需求以及选择的模组型号来合理使用任何一个引脚
--
-- 这些功能引脚的特性是:
-- 1、软件上既可以配置做为AGPIO使用,也可以配置做为WAKEUP使用
-- 2、做AGPIO使用时,功能特性以及如何配置可以将功耗降到最低,参考上文中“第三类功能配置项:通用AGPIO”的说明
-- 3、做WAKEUP使用时,功能特性以及如何配置可以将功耗降到最低,参考上文中“第四类功能配置项:通用WAKEUP”的说明
--
-- 特别注意:
-- 1、 在使用 gpio.setup() 接口配置为输入模式关闭 AGPIOWU 管脚时,需要将第一个参数填写为 GPIO 号,及 20/21/22,这样真能真正关闭 AGPIOWU 管脚;
-- 2、 如果第一个参数填写的是 gpio.WAEKUP3/WAKEUP4/WAKEUP5,那么会无法真正关闭 APGIOWU 管脚,当管脚电平发生变化时,还会触发唤醒功能;
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHU" or module == "Air780EHN" or module == "Air780EGH" or module == "Air780EGP" or module == "Air780EGG" then
-- gpio.setup(20, nil, gpio.PULLDOWN)
-- end
--
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHU" or module == "Air780EHN" or module == "Air780EHV" then
-- gpio.setup(21, nil, gpio.PULLDOWN)
-- end
--
-- gpio.setup(22, nil, gpio.PULLDOWN)
-- 第八类功能配置项:PWR_KEY
-- 这个是PWRKEY开机键功能引脚,这个功能引脚的特性是:
-- 1、如果PWRKEY接地,模组上电即开机;如果PWRKEY不接地,模组上电后,此引脚检测到下降沿就可以开机
-- 2、开机运行之后:
-- (1) 在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- (2) 在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- (3) 在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 需要提醒的是,PWR_KEY引脚如果硬件设计为接地自动开机,通常会增加系统功耗;以Air780EXX系列每个模组的核心板为例,如果一直按下开机键,则会增加系统功耗15uA左右
-- 根据自己的项目需求决定:进入低功耗模式前,是否需要关闭PWR_KEY功能
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法中断唤醒
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.PWR_KEY, nil, gpio.PULLDOWN)
-- 第九类功能配置项:CHG_DETWAKEUP6
-- 在Air780EXX系列模组中,Air780EHU/EHN/EHV/EGH/EGG/EGP模组支持CHG_DETWAKEUP6)功能
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)功能
--
-- 原始功能为充电器插入检测,目前只做跟PWR_KEY一样的功能使用
-- PWR_KEY引脚与CHG_DETWAKEUP6)引脚在硬件上的部分区别在于:
-- 1、PWR_KEY引脚内部上拉至VBATCHG_DET(WAKEUP6)引脚内部上拉至一个不对外开放的LDO_1.8V
-- 2、PWR_KEY引脚可以直接接地或者通过串联电阻接地,而CHG_DET(WAKEUP6)引脚只能直接接地,不能通过串联电阻接地
-- CHG_DETWAKEUP6)引脚的特性是:
-- 1、上电开机前,CHG_DET(WAKEUP6)引脚检测到下降沿(接地)就可以执行开机
-- 2、开机运行之后:
-- (1) 在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- (2) 在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- (3) 在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 根据自己的项目需求决定:进入低功耗模式前,是否需要关闭CHG_DET(WAKEUP6)功能
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法中断唤醒
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- if module == "Air780EHU" or module == "Air780EHN" or module == "Air780EHV" or module == "Air780EGH" or module == "Air780EGP" or module == "Air780EGG" then
-- gpio.close(gpio.CHG_DET)
-- end
end
local function lowpower_task()
log.info("lowpower_task enter")
-- 在进入低功耗模式前,根据自己的实际项目需求,配置进入低功耗模式后的中断唤醒方式
-- 一定要仔细阅读这个函数的代码注释说明,根据自己的项目需求来决定是否需要配置每一项功能
-- 注意:如果在此处配置了某些引脚,就不要在接下来的set_lowpower_func_item()函数中关闭对应的引脚功能,否则会导致配置失效
-- 例如,如果在此函数中配置了WAKEUP0引脚中断唤醒,则在set_lowpower_func_item()中就不要关闭WAKEUP0引脚功能
set_lowpower_interrupt_wakeup()
-- 在进入低功耗模式前,根据自己的实际项目需求,配置一些必要的功能项
-- 可以在满足项目功能需求的背景下,让功耗降到最低
-- 一定要仔细阅读这个函数的代码注释说明,根据自己的项目需求来决定是否需要配置每一项功能
set_lowpower_func_item()
-- 延时10秒钟,是为了使用USB抓取日志
-- 仅仅开发调试过程中需要,量产前不需要
-- sys.wait(10000)
-- 配置最低功耗模式为低功耗模式
-- 执行下面这行代码后,只是配置了允许系统进入低功耗模式
-- 并不是说,一定会立即进低功耗模式,最终进入低功耗模式的时间点,取决于内核固件中的任务和Lua脚本中task都处于阻塞状态
-- 也就是说,执行这一行代码时:
-- (1) 如果内核固件中的任务和Lua脚本中task都处于阻塞状态,理论上就会立即成功进入低功耗模式
-- (2) 否则,不会立即成功进入低功耗模式,而是等待所有运行中的任务处于阻塞状态;
-- 假设5秒钟之后,满足了条件,则5秒钟之后会成功进入低功耗模式;
--
-- 在配置最低功耗模式为低功耗模式之后,无论是否成功进入低功耗模式:
-- 用户编写的任何脚本代码的主动业务逻辑都会正常运行,代码运行过程中就会自动唤醒,代码阻塞后又会自动进入低功耗状态
--
-- 使用合宙核心板测试的低功耗模式功耗数据,在vbat供电3.8v状态下
-- 飞行模式+低功耗+配置set_lowpower_func_item()中的所有功能项:66uA左右(40uA到70uA左右都属于正常值)
-- 低功耗+set_lowpower_func_item()中的所有功能项(飞行模式除外):1mA到1.5mA左右(和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准)
pm.power(pm.WORK_MODE, 1)
-- 在低功耗模式下,默认会关闭USB功能,这样会降低140uA到200uA左右的功耗
-- 所以默认无法使用USB端口抓日志,可以使用DBG_UART(即UART0)端口+EPAT工具+USB转TTL高速线+6000000波特率来抓日志
-- 也可以在开发调试过程中,打开下面这行代码,重新打开USB功能,使用USB端口+Luatools抓日志,代价就是无法测量准确的功耗
-- 等到调试OK之后,项目软件量产前再关掉这行代码,完整测试一遍项目的所有功能,保证最终量产状态下的项目稳定性
-- pm.power(pm.USB, true)
end
local function set_drv_lowpower()
sys.taskInit(lowpower_task)
end
-- 根据项目的业务逻辑,在合适的位置sys.publish("DRV_SET_LOWPOWER")就可以配置最低功耗模式为低功耗模式
sys.subscribe("DRV_SET_LOWPOWER", set_drv_lowpower)
-- 如果项目启动之后,最低功耗模式需要一直配置为低功耗模式,则可以直接打开下面这一行代码,相当于开机初始化时,就配置最低功耗模式为低功耗模式
--
-- 如果项目不需要初始化为低功耗模式,或者在项目运行过程中,在不同的功耗模式之间手动切换,
-- 则可以根据需求,注释掉下面的一行代码,根据自己的业务逻辑,在合适的位置sys.publish("DRV_SET_LOWPOWER")即可配置为最低功耗模式为低功耗模式
-- sys.publish("DRV_SET_LOWPOWER")
@@ -0,0 +1,69 @@
--[[
@module drv_normal
@summary 常规模式pm.power(pm.WORK_MODE, 0)驱动配置功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为常规模式pm.power(pm.WORK_MODE, 0)驱动配置功能模块,提供了常规模式的配置模板,包括以下几点:
1、在进入常规模式前,根据自己的实际项目需求,配置是否需要退出飞行模式
2、配置最低功耗模式为常规模式;pm.power(pm.WORK_MODE, 0)
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在常规模式示例代码中,并未对GPIO23进行额外配置,默认状态下为高电平,以此演示常规模式下的实际功耗表现;
Air780EHV模组内部包含有Audio Codec芯片ES8311GPIO20作为Audio Codec芯片ES8311的供电使能开关;
在本应用demo中无须单独对GPIO20进行配置,一般是结合对应的Audio功能代码进行操作;
如果在本应用demo中配置了GPIO20为输出高电平,此时Audio Codec芯片功耗表现为45uA左右;
在常规模式下,并未对GPIO20进行配置,默认状态下为输入高阻态,以此演示常规模式下的实际功耗表现;
本文件的对外接口只有1个:
1、sys.subscribe("DRV_SET_NORMAL", set_drv_normal):订阅"DRV_SET_NORMAL"消息;
其他应用模块如果需要配置DRV_SET_NORMAL模式,直接sys.publish("DRV_SET_NORMAL")这个消息即可;
]]
local module = hmeta.model()
log.info("drv_normal", "当前使用的模组是:", module)
local function normal_task()
log.info("normal_task enter")
-- 根据自己的项目需求决定是否需要退出飞行模式
-- 一般来说,主动切换为常规模式时,如果系统处于飞行模式(例如在低功耗模式下自己主动设置了飞行模式)
-- 并且切换为常规模式后需要退出飞行模式时,才需要打开下面的一行代码
-- mobile.flymode(0, false)
-- Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
-- GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态为高电平
-- 如果在之前进入低功耗模式或者PSM+模式时关闭/拉低了GPIO23
-- 则在切换为常规模式后,需要重新拉高GPIO23,使GNSS和Gsensor正常工作
-- 根据自己的项目需求决定是否重新拉高GPIO23,需要时可以打开下面这行代码
if module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
gpio.setup(23, 1)
end
-- 配置最低功耗模式为常规模式
-- 执行此行代码后,就会立即主动进入常规模式
pm.power(pm.WORK_MODE, 0)
end
local function set_drv_normal()
sys.taskInit(normal_task)
end
-- 系统启动之后,最低功耗模式默认就是常规模式
-- 如果项目需求是一直工作在常规模式,则不需要做任何设置
-- 如果项目需求是在常规模式,低功耗模式,PSM+模式之间主动灵活切换,根据自己的业务逻辑,在合适的位置sys.publish("DRV_SET_NORMAL")即可配置为最低功耗模式为常规模式
-- 此处订阅"DRV_SET_NORMAL"消息,在消息处理函数中主动切换为常规模式;
-- 此处并不会因为异步消息处理机制导致sys.publish("DRV_SET_NORMAL")下一行代码运行在其他功耗模式,因为代码只要在运行,自动就是常规模式
sys.subscribe("DRV_SET_NORMAL", set_drv_normal)
@@ -0,0 +1,650 @@
--[[
@module drv_psm
@summary PSM+模式pm.power(pm.WORK_MODE, 3)驱动配置功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为PSM+模式pm.power(pm.WORK_MODE, 3)驱动配置功能模块,提供了PSM+模式的配置模板,包括以下几点:
1、在进入PSM+模式前,根据自己的实际项目需求,配置进入PSM+模式后的中断唤醒方式;详情参考set_psm_interrupt_wakeup()实现
2、在进入PSM+模式前,根据自己的实际项目需求,配置一些必要的功能项;可以在满足项目功能需求的背景下,让功耗降到最低;详情参考set_psm_func_item()实现
3、配置最低功耗模式为PSM+模式;pm.power(pm.WORK_MODE, 3)
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在PSM+模式示例代码中,默认配置GPIO23为输入下拉的方式来演示PSM+模式的功耗表现;
Air780EHV模组内部包含有Audio Codec芯片ES8311GPIO20作为Audio Codec芯片ES8311的供电使能开关;
在本应用demo中无须单独对GPIO20进行配置,一般是结合对应的Audio功能代码进行操作;
如果在本应用demo中配置了GPIO20为输出高电平,此时Audio Codec芯片功耗表现为45uA左右;
在PSM+模式下,并未对GPIO20进行配置,默认状态下为输入高阻态,以此演示PSM+模式下的实际功耗表现;
本文件的对外接口只有1个:
1、sys.subscribe("DRV_SET_PSM", set_drv_psm):订阅"DRV_SET_PSM"消息;
其他应用模块如果需要配置PSM+模式,直接sys.publish("DRV_SET_PSM")这个消息即可;
]]
-- 获取当前使用的模组型号
local module = hmeta.model()
log.info("drv_psm", "当前使用的模组是:", module)
-- Air780EGG/EGP模组WAKEUP2引脚内部用作GSensor中断信号,用户需要手动配置成中断方式才能实现GSensor的中断唤醒功能,除此之外不可作为其他功能使用
-- Air780EPM/EHM/EHU/EHN/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,可以作为普通中断功能
--
-- Air780EHV模组WAKEUP3引脚内部用作GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关,除此之外不可作为其他功能
-- Air780EPM/EHM/EHU/EHN/EGH/EGP/EGG模组WAKEUP3引脚并未被模组内部占用,可以作为普通中断功能
--
-- Air780EGH/EGP/EGG模组WAKEUP4引脚内部用作GPIO21功能,用于控制GNSS定位芯片的供电使能开关,除此之外不可作为其他功能
-- Air780EPM/EHM/EHU/EHN/EHV模组WAKEUP4引脚并未被模组内部占用,可以作为普通中断功能
--
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)功能
-- Air780EHU/EHN/EHV/EGH/EGP/EGG模组支持CHG_DETWAKEUP6)功能,可以作为普通中断功能
--
-- 在PSM+模式下,唤醒后会直接重启软件系统,并不会执行此处的中断处理函数
local function psm_wakeup_func(level, id)
local tag =
{
[gpio.PWR_KEY] = "PWR_KEY",
[gpio.CHG_DET] = "CHG_DET",
[gpio.WAKEUP0] = "WAKEUP0",
[gpio.WAKEUP1] = "WAKEUP1",
[gpio.WAKEUP2] = "WAKEUP2",
[gpio.WAKEUP3] = "WAKEUP3",
[gpio.WAKEUP4] = "WAKEUP4",
[gpio.WAKEUP5] = "WAKEUP5",
}
-- 注意:此处的level电平并不表示触发中断的边沿电平
-- 而是在触发中断后,某个时间点的电平状态
-- 可能和触发中断的边沿电平状态一致,也可能不一致
log.info("psm_wakeup_func", tag[id], level)
end
-- 在进入PSM+模式前,根据自己的实际项目需求,配置PSM+模式下的中断唤醒方式
--
-- PSM+模式下,Air780EPM/EHM支持以下几种类型的中断唤醒方式:
-- 1、深度休眠定时器(dtimer)
-- 2、PWR_KEY引脚中断
-- 3、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 4、VBUS(内部分压到WAKEUP1)引脚中断
-- 5、UART1_RXD引脚中断(可以将UART1配置为支持的任意波特率)
--
-- Air780EHM/EHU/EHN支持以下几种类型的中断唤醒方式:
-- 1、深度休眠定时器(dtimer)
-- 2、PWR_KEY引脚中断
-- 3、CHG_DET(WAKEUP6)引脚中断
-- 4、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 5、VBUS(内部分压到WAKEUP1)引脚中断
-- 6、UART1_RXD引脚中断(可以将UART1配置为支持的任意波特率)
--
-- Air780EHV支持以下几种类型的中断唤醒方式:
-- 1、深度休眠定时器(dtimer)
-- 2、PWR_KEY引脚中断
-- 3、CHG_DET(WAKEUP6)引脚中断
-- 4、WAKEUP0、WAKEUP2、WAKEUP4、WAKEUP5引脚中断
-- 5、VBUS(内部分压到WAKEUP1)引脚中断
-- 6、UART1_RXD引脚中断(可以将UART1配置为支持的任意波特率)
--
-- Air780EGH支持以下几种类型的中断唤醒方式:
-- 1、深度休眠定时器(dtimer)
-- 2、PWR_KEY引脚中断
-- 3、CHG_DET(WAKEUP6)引脚中断
-- 4、WAKEUP0、WAKEUP2、WAKEUP3、WAKEUP5引脚中断
-- 5、VBUS(内部分压到WAKEUP1)引脚中断
-- 6、UART1_RXD引脚中断(可以将UART1配置为支持的任意波特率)
--
-- Air780EGP/EGG支持以下几种类型的中断唤醒方式:
-- 1、深度休眠定时器(dtimer)
-- 2、PWR_KEY引脚中断
-- 3、CHG_DET(WAKEUP6)引脚中断
-- 4、WAKEUP0、WAKEUP3、WAKEUP4、WAKEUP5引脚中断
-- 5、VBUS(内部分压到WAKEUP1)引脚中断
-- 6、UART1_RXD引脚中断(可以将UART1配置为支持的任意波特率)
--
-- 特别注意:从PSM+模式唤醒后,软件系统会直接重启,重启过程中AGPIO的电平状态不会发生改变!!!!!!
-- 特别注意:当使用杜邦线短接/断开测试时,因为抖动因素,所以实际情况肯定会存在高低电平频繁跳变的情况!!!!!!
-- 所以测试表现和实际的短接/断开动作并不完全相符,这种测试方法仅仅简单验证一下功能即可!!!!!!
-- 最终自己设计的硬件产品并不会出现此问题
-- 特别注意:当配置引脚唤醒功能时,基于使用的硬件,配置之后,可能会增加系统功耗;本函数中基于Air780EXX系列每个模组的核心板给出了每项配置对功耗的影响数据
-- 当使用自己的硬件测试时,以自己的硬件实测数据为准;Air780EXX系列每个模组的核心板的实测数据可以用来参考
local function set_psm_interrupt_wakeup()
-- 配置深度休眠定时器唤醒
-- 定时器时长有讲究,此处的时长不要小于80秒
-- 因为如果满足进入PSM+模式的条件,内核固件最长需要75秒肯定可以进入PSM+模式
-- 如果此处设置的时间过短,在某些情况下,有可能还没有真正进入PSM+模式,就出现了深度休眠定时器超时
-- 此情况下的唤醒重启,pm.lastReson()的返回值为1,4,0,0,仅关注第一个返回值1即可
-- pm.dtimerStart(0, 60*60*1000) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 配置PWR_KEY引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 由于PWR_KEY引脚内部已经拉高至VBAT电压,因此只能配置为gpio.PULLUP,不能配置为gpio.PULLDOWN
-- 当配置为gpio.PULLUP时,按下开机键产生下降沿,弹起开机键产生上升沿
-- 在实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为5,4,0,256,仅关注第一个返回值5即可
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.PWR_KEY, 200)
-- gpio.setup(gpio.PWR_KEY, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.PWR_KEY, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.PWR_KEY, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 在Air780EXX系列模组中,Air780EHN/EHU/EHV/EGH/EGG/EGP模组包含有CHG_DET(WAKEUP6)引脚,可以将此引脚配置为中断唤醒引脚
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)引脚的中断唤醒功能
-- 配置CHG_DET(WAKEUP6)引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中三选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试:
-- 由于CHG_DET(WAKEUP6)引脚内部已经拉高至VDD_1.8V,因此只能配置为gpio.PULLUP,不能配置为gpio.PULLDOWN
-- 当配置为gpio.PULLUP时,将CHG_DET(WAKEUP6)引脚(对应的丝印为75/CHG_DET)和GND短接产生下降沿,和GND断开产生上升沿
-- 在实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为6,4,0,512,仅关注第一个返回值6即可
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.CHG_DET, 1000)
-- gpio.setup(gpio.CHG_DET, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- gpio.setup(gpio.CHG_DET, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- gpio.setup(gpio.CHG_DET, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持CHG_DET(WAKEUP6)引脚的模组核心板测试,没有增加功耗
-- 配置WAKEUP0引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP0引脚(对应的丝印为101/WAKEUP0)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP0引脚(对应的丝印为101/WAKEUP0)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,1,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP0表示幂次为0,第四个返回值为2^0=1
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP0, 1000)
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP0, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 配置VBUS(WAKEUP1)引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试,将提供5V供电输入的USB线插入type-c座子,会产生上升沿,拔出会产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,2,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP1表示幂次为1,第四个返回值为2^1=2
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP1, 200)
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,增加17uA功耗
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP1, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 在Air780EXX系列模组中,Air780EGP/EGG模组WAKEUP2引脚内部用作GSensor中断信号,
-- 如果需要在低功耗模式下使用GSensor的中断唤醒功能,则需要根据下方说明打开对应的代码
--
-- Air780EPM/EHM/EHN/EHU/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,可以作为普通中断功能使用,配置方式见下一个配置项
--
-- 配置WAKEUP2引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中三选一)
-- 防抖配置:200ms时长防抖,冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列内部包含GSensor的每个模组的核心板测试,WAKEUP2引脚已被模组内部用作GSensor中断信号,外部不可再用,否则会干扰GSensor的正常工作
-- 在实际测试时,需要先引用exvib模块,再通过exvib.open(1)打开Air780EXX系列内部包含的三轴加速度传感器DA221,最后配置WAKEUP2引脚的中断唤醒功能
-- 由于GSensor的电源开关通过Air780EXX系列内部包含GSensor的模组的GPIO23控制,因此切记不要在其他地方对GPIO23进行二次配置,否则会干扰GSensor的正常工作
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,4,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP2表示幂次为2,第四个返回值为2^2=4
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EGP" or module == "Air780EGG" then
-- -- 关于引用exvib模块,功耗数据变化的说明:
-- exvib = require("exvib") -- 引用exvib模块
-- exvib.open(1) -- 打开Air780EXX系列内部的三轴加速度传感器DA221
-- -- 执行完pm.power(pm.WORK_MODE, 3)函数之后并不会立即进去休眠,而是等内核固件中的任务和Lua脚本中task都处于阻塞状态时才会进入休眠;
-- -- 此处在调用exvib.open(1)函数时,exvib.open(1)内部自动执行了一个tasksys.taskInit(da221_init)),da221_init函数内部包含多个sys.wait函数;
-- -- 由于da221_init和psm_task函数不在同一个task,于是da221_init和pm.power(pm.WORK_MODE, 3)会同时执行;
-- -- 当执行完pm.power(pm.WORK_MODE, 3)函数之后,da221_init函数内部执行到某个sys.wait后会立即进入休眠模式,此时后续代码并不会执行;
-- -- 最终会导致WAKEUP2引脚实际没有配置成功,因此需要在下方添加一个延时1秒左右的函数,待exvib.open(1)函数执行完成后再执行pm.power(pm.WORK_MODE, 3)
-- sys.wait(1000)
-- -- 在测试下面的配置代码时,同时也需要把上面两行代码打开
-- gpio.debounce(gpio.WAKEUP2, 200)
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, nil, gpio.FALLING) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, nil, gpio.RISING) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, nil, gpio.BOTH) -- Air780EXX系列内部包含GSensor的每个模组的核心板测试,没有增加功耗
-- end
--
--
-- 在Air780EXX系列模组中,除了Air780EGP/EGG模组WAKEUP2引脚内部用作GSensor中断信号外
-- Air780EPM/EHM/EHN/EHU/EHV/EGH模组WAKEUP2引脚并未被模组内部用作GSensor中断信号,外部可以作为WAKEUP使用
-- 如果需要在PSM+模式下使用WAKEUP2引脚的中断唤醒功能,则需要根据下方说明打开对应的代码
--
-- 配置WAKEUP2引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组内部不包含GSensor的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP2引脚(对应的丝印为79/SIMDET)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP2引脚(对应的丝印为79/SIMDET)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,4,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP2表示幂次为2,第四个返回值为2^2=4
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EHV" or module == "Air780EGH" then
-- gpio.debounce(gpio.WAKEUP2, 1000)
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP2, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列内部不包含GSensor的每个模组的核心板测试,没有增加功耗
-- end
-- 在Air780EXX系列模组中,Air780EHV模组内部将GPIO20引脚强制用作GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关
-- 除Air780EHV模组外,Air780EPM/EHM/EHN/EHU/EGH/EGG/EGP模组可以将GPIO20引脚配置为WAKEUP3引脚,用于中断唤醒功能
-- 配置WAKEUP3引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP3引脚(对应的丝印为102/GPIO20)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP3引脚(对应的丝印为102/GPIO20)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,8,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP3表示幂次为3,第四个返回值为2^3=8
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
-- gpio.debounce(gpio.WAKEUP3, 1000)
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP3, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列支持将GPIO20引脚配置为WAKEUP3引脚的模组的核心板测试,没有增加功耗
-- end
-- 在Air780EXX系列模组中,Air780EGH/EGP/EGG模组内部将GPIO21引脚强制用作GPIO21功能,用于控制GNSS定位芯片的供电使能开关
-- 除Air780EGH/EGP/EGG模组外,Air780EPM/EHM/EHN/EHU/EHV模组可以将GPIO21引脚配置为WAKEUP4引脚,用于中断唤醒功能
-- 配置WAKEUP4引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP4引脚(对应的丝印为107/GPIO21)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP4引脚(对应的丝印为107/GPIO21)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,16,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP4表示幂次为4,第四个返回值为2^4=16
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHN" or module == "Air780EHU" or module == "Air780EHV" then
-- gpio.debounce(gpio.WAKEUP4, 1000)
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- -- gpio.setup(gpio.WAKEUP4, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列支持将GPIO21引脚配置为WAKEUP4引脚的模组的核心板测试,没有增加功耗
-- end
-- 配置WAKEUP5引脚下降沿、上升沿、双边沿中断唤醒(根据硬件设计原理以及项目需求,配置防抖之后,从中断唤醒方式中六选一)
-- 防抖配置,目前是1000ms防抖(因为在核心板上使用杜邦线插拔测试,电平状态跳变频繁,所以防抖时间设置的较长,实际项目中根据自己的硬件设计和项目需求修改),冷却模式(根据项目需求可以修改)
-- 此处的代码基于合宙Air780EXX系列每个模组的核心板测试:
-- 当配置为gpio.PULLUP时,将WAKEUP5引脚(对应的丝印为19/GPIO22)和GND短接产生下降沿,和GND断开产生上升沿
-- 当配置为gpio.PULLDOWN时,将WAKEUP5引脚(对应的丝印为19/GPIO22)和3V3引脚短接产生上升沿,和3V3引脚断开产生下降沿
-- 在客户实际的项目中,可以根据自己的硬件设计原理以及项目需求,对此处的代码做适当修改
-- 此情况下的唤醒重启,pm.lastReson()的返回值为2,4,0,32,仅关注第一个返回值2表示此时为WAKEUP唤醒
-- 通过第四个返回值可以判断WAKEUP的序号,其中返回值表示2的幂,序号表示2的幂次
-- 例如:WAKEUP5表示幂次为5,第四个返回值为2^5=32
--
-- 特别注意:gpio.debounce接口设置的防抖功能,在不同功耗模式下表现不同:
-- 1、在常规模式0下,防抖功能有效,可以参考API详细说明,配置自己需要的防抖模式,实现“有效避免误触发”的效果
-- 2、在低功耗模式1下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且执行中断处理函数
-- 3、在PSM+模式3下,休眠之后,防抖功能无效,根据自己配置的中断触发类型,只要满足条件就会立即触发中断,自动唤醒,并且重启软件
-- gpio.debounce(gpio.WAKEUP5, 1000)
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLUP, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLUP, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLUP, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLDOWN, gpio.FALLING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLDOWN, gpio.RISING) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- gpio.setup(gpio.WAKEUP5, psm_wakeup_func, gpio.PULLDOWN, gpio.BOTH) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
-- 配置UART1_RXD接收到数据唤醒(模组配置为任意支持的波特率都可以,对端串口配置任意的波特率也可以,二者波特率不必一致)
-- 此处仅仅简单的演示UART1唤醒功能的配置,更详细的用法参考单独的uart demo
-- 初始化UART1,波特率9600,数据位8,停止位1
-- 基于合宙Air780EXX系列每个模组的核心板测试,将UART1引脚(对应的丝印为17/U1RXD、18/U1TXD、GND)通过USB转TTL串口线和电脑相连,电脑串口工具配置任意波特率,数据位8,停止位1,串口工具发送任何数据都可以唤醒模组
-- 此情况下的唤醒重启,pm.lastReson()的返回值为3,4,0,64,仅关注第一个返回值3即可
-- uart.setup(1, 9600, 8, 1) -- Air780EXX系列每个模组的核心板测试,没有增加功耗
end
-- Air780EGG/EGP模组内部包含有GsensorAir780EGH/EGP/EGG模组内部包含有GNSS
-- Air780EHV模组内部包含有Audio Codec芯片ES8311Air780EHU/EHN/EHV/EGH/EGP/EGG模组支持CHG_DETWAKEUP6)功能
-- Air780EPM/EHM模组没有引出CHG_DETWAKEUP6)引脚,无法配置CHG_DETWAKEUP6)功能
-- set_psm_func_item()中会自动对模组型号进行判断,避免对不包含GNSS/Gsensor/Audio Codec芯片或者CHG_DETWAKEUP6)功能的模组进行误配置
-- 在进入PSM+模式前,根据自己的实际项目需求,配置一些必要的功能项,可以在满足项目功能需求的背景下,让功耗降到最低
--
-- 关于 WAKEUP0 ~ WAEKUP6、PWR_KEY 管脚如何配置才能正确关闭的说明:
-- 1、 要想让某个管脚关闭,我们一般需要在软件中将该管脚配置为输入模式,不过 WAKEUP0 ~ WAEKUP6、PWR_KEY 管脚在配置为输入模式时,需要特别注意;
-- 2、 WAKEUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY :这些管脚是独立的 WAEKUP 管脚,在使用 gpio.setup() 接口配置为输入模式时,可以只有输入功能,而没有唤醒功能
-- 在 V2046 及之前的版本中,WAEKUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- 在 V2048 及之后的版本中,WAEKUP0 ~ WAEKUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,没有唤醒功能,只有输入功能;
-- 3、 WAKEUP3 ~ WAKEUP5 :这些管脚不仅是 AGPIOWAKEUP 管脚(对应 AGPIOWU0 ~ AGPIOWU2),也是 GPIO 管脚(对应 GPIO20 ~ GPIO22),使用 gpio.setup() 接口配置为输入模式时:
-- 如果第一个参数填写为 gpio.WAKEUP3/gpio.WAKEUP4/gpio.WAKEUP5 ,那么内核中统一会配置为 输入唤醒 功能,当 WAKEUP3 ~ WAKEUP5 引脚的电平发生变化时,会触发中断,导致模组唤醒,无法真正实现关闭;
-- 所以,在关闭 WAKEUP3 ~ WAKEUP5 管脚时,使用 gpio.setup() 接口配置为输入模式时,第一个参数应该填写为 20 ~ 22 ,即对应的 GPIO 号,这样才能真正关闭 WAKEUP3 ~ WAKEUP5 管脚,与内核固件版本无关。
local function set_psm_func_item()
-- 第一类功能配置项:飞行模式
-- 通过配置飞行模式可以有效关闭4G芯片的4G网络能力
--
-- 这个功能的特性是:
-- 1、在常规模式下,飞行模式默认是关闭的,可以根据项目需要显式的开启飞行模式,从而关闭4G网络能力
-- 2、在低功耗模式下,飞行模式默认也是关闭的,需要根据项目需要显式的开启飞行模式,从而关闭4G网络能力,关闭后可以有效降低功耗
-- 3、在PSM+模式下,飞行模式默认是开启的,不能显式的关闭飞行模式
-- 从2025年3月份发布的内核固件开始:
-- 1、在pm.power(pm.WORK_MODE, 3)中会自动执行mobile.flymode(0, true)进入飞行模式
-- 2、从PSM+模式唤醒重启后,重启后飞行模式的状态和重启前用户是否显式执行mobile.flymode控制的飞行模式的状态一致;
-- 3、其余原因的重启或者开机,重启或者开机后,自动退出飞行模式;
-- 根据自己的项目需求决定:进入PSM+模式前,是否需要显式的进入飞行模式;如果需要,则打开下面这行代码
-- 是否打开下面这行代码,最终不会影响PSM+模式的功耗,仅仅影响从PSM+模式唤醒重启后的默认飞行模式状态
-- 如果打开了下面这行代码,进入PSM+模式后,被唤醒会自动重启软件,重启后,默认仍然处于飞行模式状态
-- 轻易不要打开这行代码,因为这行代码和具体项目的业务逻辑关联性会比较强,在这里加上这行代码仅仅是为了解释:显式进行飞行模式后,下次重启后的默认飞行状态
-- mobile.flymode(0, true)
-- 第二类功能配置项:USB功能
-- 通过USB功能可以实现抓日志和业务数据通信等
--
-- 这个功能的特性是:
-- 1、在常规模式下,USB功能是默认开启的,通过USB虚拟串口进行抓日志和业务数据通信等
-- 2、在低功耗模式和PSM+模式下,此时USB功能默认是关闭的,无法使用USB虚拟串口进行抓日志和业务数据通信等
-- 根据自己的项目需求决定:进入PSM+模式前,是否需要关闭USB功能
-- 从2025年3月份发布的内核固件开始:
-- 1、在pm.power(pm.WORK_MODE, 1)和pm.power(pm.WORK_MODE, 3)中会自动执行pm.power(pm.USB, false)关闭USB功能
-- 2、在pm.power(pm.WORK_MODE, 0)会自动执行pm.power(pm.USB, true)打开USB功能
-- 所以,如果你使用的内核固件如果是2025年3月份之后发布的,则不再需要显示的关闭USB功能,在PSM+模式中会自动关闭USB功能
-- 此处代码默认没有显式的关闭USB功能,是因为在后续的pm.power(pm.WORK_MODE, 1)中会自动关闭USB功能
-- 如果由于某种原因,你必须使用2025年3月份之前的内核固件,则根据需求可以打开下面的一行代码
-- 在vbat供电3.8v的状态下,关闭USB功能,可以减少140uA到200uA左右的功耗
-- pm.power(pm.USB, false)
-- 第三类功能配置项:GNSS备电电源开关及Gsensor电源开关
-- 这一类功能配置项仅对Air780EGH/EGG/EGP模组有效(Air780EGH内部包含GNSSAir780EGG/EGP内部包含GNSS和Gsensor
-- Air780EPM/EHM/EHN/EHU/EHV模组内部不包含GNSS和Gsensor,无法使用该功能
-- Air780EGH/EGG/EGP模组通过GPIO23作为GNSS的备电电源开关和Gsensor的电源开关,默认为高电平输出
--
-- 这个功能引脚输出的电平状态,对GNSS和Gsensor功能的影响是:
-- GNSS:在低功耗模式或者PSM+模式下,
-- 如果GPIO23输出高电平,可以保证GNSS的定位数据不被丢失,
-- 并且在关闭GNSS后两个小时内,在室外空旷环境下,再次打开GNSS时,可以热启动3s左右快速获取到定位数据;
-- 但是如果超过两个小时之后,再次打开GNSS,就是冷启动状态,35s左右才能获取到定位数据;
-- 如果GPIO23输出低电平,此时GNSS的备电电源开关是关闭的,下次打开GNSS时,就是冷启动状态,35s左右才能获取到定位数据;
-- 客户可以根据项目需求来配置GPIO23的电平状态
-- Gsensor:在低功耗模式或者PSM+模式下,
-- 如果GPIO23输出高电平,Gsensor的电源开关处于打开状态,那么可以通过Gsensor的中断唤醒脚(WAKEUP2)来实现震动中断唤醒功能;
-- 如果GPIO23输出低电平,Gsensor的电源开关处于关闭状态,那么无法使用Gsensor的任何功能;
--
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,
-- 可能你会打开GNSS的备电电源开关和GSensor的电源开关,用于保存GNSS的定位数据和快速获取定位数据或者实现GSensor的震动中断唤醒功能
-- 根据自己的项目需求决定:进入PSM+模式前,是否需要关闭GNSS的备电电源开关和GSensor的电源开关
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经打开,可以减少30uA左右的功耗
if module == "Air780EGH" or module == "Air780EGG" or module == "Air780EGP" then
gpio.setup(23, nil, gpio.PULLDOWN)
end
-- 第四类功能配置项:通用AGPIOGPIO24、GPIO25、GPIO26、GPIO27、GPIO28
-- 这五个功能引脚在Air780EXX系列模组内部并没有被占用,所以用户在项目开发中可以根据自己的项目需求来使用任何一个引脚
--
-- 这些功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为普通的GPIO输出、输入、中断使用
-- 2、在低功耗模式和PSM+模式下,可以保持固定的高电平或者低电平输出
-- 3、如果在模组内部和模组外部都没有接其他元器件,无论软件上如何配置AGPIO,对功耗都没有影响
-- 4、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出低,让元器件彻底不工作,则对功耗都没有影响
-- 5、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出高,让元器件彻底不工作,并且AGPIO在硬件上也没有接下拉电阻,则对功耗都没有影响
-- 6、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出高,让元器件彻底不工作,但是AGPIO在硬件上接了下拉电阻,对功耗有影响
-- 例如接了100K的下拉电阻,当AGPIO输出的高电平是3.3V、下拉电阻是100K时,其电流影响的理论值大概是3.3V/100K=33uA,具体数据以实际硬件环境的测量为准
-- 7、如果在模组内部或者模组外部接了其他元器件,当软件配置的AGPIO输出电平可以让元器件正常工作,则对功耗有影响,影响大小取决于元器件本身的耗电,具体数据以实际硬件环境的测量为准
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下
-- 可能你会使用这些AGPIO来固定输出高电平,做为Vref,给其他外围硬件电路做上拉使用(例如模组的UART RX可以上拉到VrefSIM卡插入检测的USIM_DET可以上拉到Vref);也可能会有其他用途
-- 根据自己的项目需求决定:进入PSM+模式前,来关闭AGPIOGPIO24、GPIO25、GPIO26、GPIO27、GPIO28)控制的电路单元的功耗
-- 一旦关闭,如果你项目中使用了这些功能引脚,意味着这些功能引脚有关的功能将无法正常工作,例如无法为外围电路提供上拉
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输出低电平,输出高电平,close,输入下拉,输入上拉,六种方式中的一种);
-- 具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
-- gpio.setup(24, nil, gpio.PULLDOWN)
-- gpio.setup(25, nil, gpio.PULLDOWN)
-- gpio.setup(26, nil, gpio.PULLDOWN)
-- gpio.setup(27, nil, gpio.PULLDOWN)
-- gpio.setup(28, nil, gpio.PULLDOWN)
-- 第五类功能配置项:通用WAKEUPWAKEUP0
-- 这一个功能引脚在Air780EXX系列每个模组内部并没有被占用,所以用户在项目开发中可以根据自己的项目需求来使用这个引脚
--
-- 这些功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为中断使用,每个引脚可以配置独立的中断处理函数,用来区分是哪一个WAKEUP引脚产生的中断
-- 2、在低功耗模式下,也可以作为中断使用,每个引脚可以配置独立的中断处理函数,用来区分是哪一个WAKEUP引脚产生的中断
-- 3、在PSM+模式下,也可以作为中断使用,虽然每个引脚可以配置独立的中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数,无法区分是哪一个WAKEUP引脚唤醒
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这些WAKEUP引脚的中断唤醒功能
-- 根据自己的项目需求,决定是否需要关闭通用WAKEUP(WAKEUP0)功能,如果关闭,对功耗的影响可以降到最低
-- 一旦关闭,如果你项目中使用了这些功能引脚,意味着这些功能引脚有关的功能将无法正常工作,例如无法中断唤醒
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输入下拉,输入上拉,close,四种方式中的一种);具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.WAKEUP0, nil, gpio.PULLDOWN)
-- 第六类功能配置项:VBUSWAKEUP1
-- 这个是VBUS功能引脚,在Air780EXX系列每个模组内部经分压后接WAKEUP1,固定只能用作USB插入检测使用
--
-- 这个功能引脚的特性是:
-- 1、在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- 2、在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- 3、在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 根据自己的项目需求决定是否需要关闭VBUS(WAKEUP1)功能,如果关闭,对功耗的影响可以降到最低
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法检测USB插入、无法中断唤醒
-- 此处默认使用的是配置为输入下拉的方式来关闭,默认代码已经注释掉了,如果默认不配置的状态可以满足需求(实际测试一下功耗),就可以不用代码控制,默认什么动作都不处理即可
-- 如果打开这里的默认配置代码可以满足需求(实际测试一下功耗),就可以直接打开使用
-- 如果无法满足需求,需要根据自己的电路设计,来决定如何关闭(什么都不处理,输入下拉,输入上拉,close,四种方式中的一种);具体使用何种方式,需要结合自己的硬件来实际测试,选取功耗最低的一种即可
-- 可以在此处关闭,也可以在具体的外围电路软件功能模块代码文件中关闭
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.WAKEUP1, nil, gpio.PULLDOWN)
-- 第七类功能配置项:AGPIOWUGPIO20/WAKEUP3、GPIO21/WAKEUP4、GPIO22/WAKEUP5
-- 在Air780EXX系列模组中,Air780EHV模组内部将GPIO20/WAKEUP3引脚作为GPIO20功能,用于控制Audio Codec芯片ES8311的供电使能开关
-- 除Air780EHV模组外,Air780EPM/EHM/EHU/EHN/EGH/EGP/EGG模组可以将GPIO20/WAKEUP3引脚作为WAKEUP3功能使用
--
-- 在Air780EXX系列模组中,Air780EGH/EGP/EGG模组内部将GPIO21/WAKEUP4引脚作为GPIO21功能,用于控制GNSS定位芯片的供电使能开关
-- 除Air780EGH/EGP/EGG模组外,Air780EPM/EHM/EHU/EHN/EHV模组可以将GPIO21/WAKEUP4引脚作为WAKEUP4功能使用
--
-- 只有GPIO22/WAKEUP5引脚在Air780EXX系列模组中没有被占用
--
-- 所以用户在项目开发中可以根据自己的项目需求以及选择的模组型号来合理使用任何一个引脚
--
-- 这些功能引脚的特性是:
-- 1、软件上既可以配置做为AGPIO使用,也可以配置做为WAKEUP使用
-- 2、做AGPIO使用时,功能特性以及如何配置可以将功耗降到最低,参考上文中“第三类功能配置项:通用AGPIO”的说明
-- 3、做WAKEUP使用时,功能特性以及如何配置可以将功耗降到最低,参考上文中“第四类功能配置项:通用WAKEUP”的说明
--
-- 特别注意:
-- 1、 在使用 gpio.setup() 接口配置为输入模式关闭 AGPIOWU 管脚时,需要将第一个参数填写为 GPIO 号,及 20/21/22,这样真能真正关闭 AGPIOWU 管脚;
-- 2、 如果第一个参数填写的是 gpio.WAEKUP3/WAKEUP4/WAKEUP5,那么会无法真正关闭 APGIOWU 管脚,当管脚电平发生变化时,还会触发唤醒功能;
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHU" or module == "Air780EHN" or module == "Air780EGH" or module == "Air780EGP" or module == "Air780EGG" then
-- gpio.setup(20, nil, gpio.PULLDOWN)
-- end
--
-- if module == "Air780EPM" or module == "Air780EHM" or module == "Air780EHU" or module == "Air780EHN" or module == "Air780EHV" then
-- gpio.setup(21, nil, gpio.PULLDOWN)
-- end
--
-- gpio.setup(22, nil, gpio.PULLDOWN)
-- 第八类功能配置项:PWR_KEY
-- 这个是PWRKEY开机键功能引脚,这个功能引脚的特性是:
-- 1、如果PWRKEY接地,模组上电即开机;如果PWRKEY不接地,模组上电后,此引脚检测到下降沿就可以开机
-- 2、开机运行之后:
-- (1) 在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- (2) 在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- (3) 在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 需要提醒的是,PWR_KEY引脚如果硬件设计为接地自动开机,通常会增加系统功耗;以Air780EXX系列每个模组的核心板为例,如果一直按下开机键,则会增加系统功耗15uA左右
-- 根据自己的项目需求决定:进入PSM+模式前,是否需要关闭PWR_KEY功能
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法中断唤醒
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- gpio.setup(gpio.PWR_KEY, nil, gpio.PULLDOWN)
-- 第九类功能配置项:CHG_DETWAKEUP6
-- 在Air780EXX系列模组中,Air780EHU/EHN/EHV/EGH/EGG/EGP模组支持CHG_DETWAKEUP6)功能
-- Air780EPM/EHM模组没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)功能
--
-- 原始功能为充电器插入检测,目前只做跟PWR_KEY一样的功能使用
-- PWR_KEY引脚与CHG_DETWAKEUP6)引脚在硬件上的部分区别在于:
-- 1、PWR_KEY引脚内部上拉至VBATCHG_DET(WAKEUP6)引脚内部上拉至一个不对外开放的LDO_1.8V
-- 2、PWR_KEY引脚可以直接接地或者通过串联电阻接地,而CHG_DET(WAKEUP6)引脚只能直接接地,不能通过串联电阻接地
-- CHG_DETWAKEUP6)引脚的特性是:
-- 1、上电开机前,CHG_DET(WAKEUP6)引脚检测到下降沿(接地)就可以执行开机
-- 2、开机运行之后:
-- (1) 在常规功耗模式下,可以做为中断使用,可以配置中断处理函数处理业务逻辑
-- (2) 在低功耗模式下,也可以作为中断使用,可以配置中断处理函数处理业务逻辑
-- (3) 在PSM+模式下,也可以作为中断使用,虽然可以配置中断处理函数,但是仅仅做为唤醒功能使用,一旦唤醒,软件系统会直接重启,并不会执行中断处理函数
-- 所以,在实际的项目设计中,如果需要工作在低功耗模式或者PSM+模式下,可能你会使用这个引脚的中断唤醒功能
-- 根据自己的项目需求决定:进入PSM+模式前,是否需要关闭CHG_DETWAKEUP6)功能
-- 一旦关闭,如果你项目中使用了这个功能引脚,意味着这个功能引脚有关的功能将无法正常工作,例如无法中断唤醒
--
-- 特别注意:
-- 1、 WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 管脚在配置为输入模式时,由于内核固件的不同,需要注意
-- V2046 及之前的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,不仅有输入功能,还有唤醒功能;
-- V2048 及之后的版本中,WAEKUP0 ~ WAKEUP2、WAEKUP6、PWR_KEY 在配置为输入模式时,没有唤醒功能,只有输入功能;
-- if module == "Air780EHU" or module == "Air780EHN" or module == "Air780EHV" or module == "Air780EGH" or module == "Air780EGP" or module == "Air780EGG" then
-- gpio.close(gpio.CHG_DET)
-- end
end
local function psm_task()
log.info("psm_task enter")
-- 在进入PSM+模式前,根据自己的实际项目需求,配置进入PSM+模式后的唤醒方式
-- 一定要仔细阅读这个函数的代码注释说明,根据自己的项目需求来决定是否需要配置每一项功能
-- 注意:如果在此处配置了某些引脚,就不要在接下来的set_psm_func_item()函数中关闭对应的引脚功能,否则会导致配置失效
-- 例如,如果在此函数中配置了WAKEUP0引脚中断唤醒,则在set_psm_func_item()中就不要关闭WAKEUP0引脚功能
set_psm_interrupt_wakeup()
-- 在进入PSM+模式前,根据自己的实际项目需求,配置一些必要的功能项
-- 可以在满足项目功能需求的背景下,让功耗降到最低
-- 一定要仔细阅读这个函数的代码注释说明,根据自己的项目需求来决定是否需要配置每一项功能
set_psm_func_item()
-- 延时10秒钟,是为了使用USB抓取日志
-- 仅仅开发调试过程中需要,量产前不需要
-- sys.wait(10000)
-- 配置最低功耗模式为PSM+模式
-- 执行下面这行代码后,只是配置了允许系统进入PSM+模式
-- 并不是说,一定会立即进入PSM+模式,最终进入PSM+模式的时间点,取决于内核固件中的任务和Lua脚本中task都处于阻塞状态
-- 也就是说,执行这一行代码时:
-- (1) 如果内核固件中的任务和Lua脚本中task都处于阻塞状态,理论上就会立即成功进入PSM+模式
-- (2) 否则,不会立即成功进入PSM+模式,而是等待所有运行中的任务处于阻塞状态;
-- 假设5秒钟之后,满足了条件,则5秒钟之后会成功进入PSM+模式;这种情况下,执行到这一行代码时仅仅是配置了一下,还会接着执行后续其他脚本代码,等5秒钟之后,内核固件就会自动控制成功进入PSM+模式
--
-- 一旦成功进入PSM+模式,则从进入的那一刻起,RAM掉电,后续不再执行任何脚本代码
-- 使用合宙核心板测试的PSM+模式功耗数据,在vbat供电3.8v状态下,配置set_psm_func_item()中的所有功能项:3.3uA左右(3uA到10uA都属于正常值)
pm.power(pm.WORK_MODE, 3)
-- 下面几行代码实现的功能是:延时等待80秒,然后软件重启;
--
-- 为什么要写下面三行代码,分以下两种情况介绍:
-- 1、当上面执行pm.power(pm.WORK_MODE, 3)时,如果立即成功进入到PSM+模式,则没有机会执行此处的三行代码
-- 2、当上面执行pm.power(pm.WORK_MODE, 3)时,如果没有立即成功进入到PSM+模式,则会接着执行此处的三行代码
-- 在此处最多等待80秒,80秒内,如果成功进入了PSM+模式,则没有机会运行此处的rtos.reboot()软件重启代码
-- 如果超过了80秒,都没有成功进入PSM+模式,则此处会控制软件重启,
-- 重启后,根据本demo项目写的业务逻辑,会再次执行进入PSM+模式的逻辑
--
-- 此处为什么延时等待80秒,是因为从2025年3月份开始,对外发布的内核固件,在脚本中执行pm.power(pm.WORK_MODE, 3)时,
-- 如果满足进入PSM+模式的条件,理论上会立即成功进入PSM+模式,
-- 虽然如此,为了防止出现不可预知的错误,所以在内核固件中多加了一层保护机制,最长等待75秒钟一定会成功进入PSM+模式
-- 所以在此处延时等待80秒,比75秒稍微长个5秒钟,为了让内核固件的这一层保护机制有时间运行,而不必执行此处的软件重启脚本代码
-- 减少不必要的重启规避逻辑而带来的多余功耗
--
-- 这个是设置允许进入PSM+模式的标准操作,必须要与demo保持一致,加入这三行代码
sys.wait(80000)
log.info("psm_task", "进入PSM+失败,重启")
rtos.reboot()
end
local function set_drv_psm()
sys.taskInit(psm_task)
end
-- 根据项目的业务逻辑,在合适的位置sys.publish("DRV_SET_PSM")就可以配置最低功耗模式为PSM+模式
sys.subscribe("DRV_SET_PSM", set_drv_psm)
@@ -0,0 +1,92 @@
--[[
@module main
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本demo演示的核心功能为:
通过若干个prj目录下的应用项目,演示常规模式,低功耗模式,PSM+模式的使用方法
更多说明参考本目录下的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进行远程升级,根据自己项目的需求,自定义格式即可
]]
PROJECT = "LOWPOWER"
VERSION = "001.999.000"
-- 在日志中打印项目名和项目版本号
log.info("main", PROJECT, VERSION)
------------------------------------ 加载应用项目主调度功能模块(每次从以下项目中选择一个来演示运行)-----------------------------------
-- 常规模式下的tcp长连接项目(每5分钟发送一次数据到tcp server)
-- require "prj_0_tcp_long"
-- PSM+模式3简单项目
-- require "prj_3"
-- 低功耗模式1简单项目
-- require "prj_1"
-- 常规模式0和低功耗模式1切换项目
-- require "prj_0_1"
-- 低功耗模式下的tcp长连接项目(每5分钟发送一次数据到tcp server)
-- require "prj_1_tcp_long"
-- PSM+模式下的tcp短连接项目(每次开机,发送一次数据到tcp server,无论成功还是失败,然后进入PSM+模式,1小时后唤醒)
require "prj_3_tcp_short"
-- 低功耗模式下的mqtt长连接项目(每5分钟发送一次数据到mqtt server)
-- require "prj_1_mqtt_long"
-- PSM+模式下的mqtt短连接项目(每次开机,读取一次温湿度数据,然后发送到mqtt server,无论成功还是失败,然后进入PSM+模式,1小时后唤醒)
-- require "prj_3_mqtt_short"
-- 低功耗模式+飞行模式下的上位机通过串口控制拍照以及照片回传项目(uart1 9600波特率接收上位机拍照指令,拍照后,通过115200波特率将照片回传给上位机)
-- require "prj_1_uart_camera"
------------------------------------ 加载应用项目主调度功能模块(每次从以上项目中选择一个来演示运行)-----------------------------------
-- 如果内核固件支持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)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行
@@ -0,0 +1,159 @@
--[[
@module prj_0_1
@summary 常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)切换,应用项目主调度功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)切换,应用项目主调度功能模块,核心业务逻辑为:
1、自动的在常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)之间切换,演示GPIO以及AGPIO输出电平的特性
2、显式的在常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)之间切换,演示GPIO以及AGPIO输出电平的特性
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在常规模式和低功耗模式示例代码中,并未对GPIO23进行额外配置,默认状态下为高电平,以此演示常规模式和低功耗模式下的实际功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,分为以下两种独立的场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约21秒后(包含20秒延时),成功进入低功耗状态;
初始化阶段(常规模式,持续20秒),平均电流51mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(因为有网络寻呼,所以是低功耗模式+常规模式自动切换,持续40秒),平均电流2.6mA左右(1.7mA到2.7mA左右都属于正常值,和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准,但是差异应该不是特别大才对)
第二次常规模式(持续20秒),平均电流31mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
第二次低功耗阶段(因为有网络寻呼,所以是低功耗模式+常规模式自动切换),平均电流2.2mA左右(1.7mA到2.3mA左右都属于正常值,和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准,但是差异应该不是特别大才对)
2、不插sim卡,上电开机之后,大约21秒后(包含20秒延时),成功进入低功耗状态;
初始化阶段(常规模式,持续20秒),平均电流28mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(因为有网络寻呼,所以是低功耗模式+常规模式自动切换,持续40秒),平均电流133uA左右(110uA到150uA左右都属于正常值)
第二次常规模式(持续20秒),平均电流29mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
第二次低功耗阶段(因为有网络寻呼,所以是低功耗模式+常规模式自动切换),平均电流35uA左右(30uA到60uA左右都属于正常值)
本文件和其他功能模块的通信接口有以下2个:
1、sys.publish("DRV_SET_LOWPOWER"):发布消息"DRV_SET_LOWPOWER",通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式
2、sys.publish("DRV_SET_NORMAL"):发布消息"DRV_SET_NORMAL",通知drv_normal驱动模块配置最低功耗模式为常规模式
]]
require "drv_lowpower"
require "drv_normal"
-- GPIO1为普通GPIO
-- 在常规模式下,可以正常工作
-- 在低功耗模式下掉电,无法正常工作
-- 此引脚对应Air780EXX系列每个模组的核心板上的丝印为22/GPIO1
local GPIO_ID = 1
-- GPIO24为AGPIO
-- 在常规模式下可以做为输出,输入或者终端,正常使用
-- 在低功耗模式下仅可以保持电平输出
-- 此引脚对应Air780EXX系列每个模组的核心板上的丝印为20/GPIO24
local AGPIO_ID = 24
-- 常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)切换任务
-- 通过演示一个普通GPIO和一个AGPIO的输出电平状态
-- 来简单理解常规模式(WORKMODE 0)和低功耗模式(WORKMODE 1)的两种功耗模式特性以及自动切换和显式切换的区别
local function normal_lowpower_switch_task()
log.info("normal_lowpower_switch_task enter")
local i
-- 此处循环20秒,每1秒翻转1次GPIO_ID和AGPIO_ID的输出电平
-- 因为没有主动设置过功耗模式,所以这20秒内一定是工作在常规模式,GPIO和AGPIO可以正常输出高低电平
for i=1,20 do
gpio.setup(GPIO_ID, i%2)
gpio.setup(AGPIO_ID, i%2)
sys.wait(1000)
end
-- 显式配置最低功耗模式为低功耗模式
-- 执行此行代码后,会通过异步消息"DRV_SET_LOWPOWER"通知drv_lowpower功能模块配置低功耗模式
-- 所以执行此行代码后,并不会马上进入低功耗模式
-- 而是等待sys.run()在分发处理到"DRV_SET_LOWPOWER"消息时,drv_lowpower功能模块才去配置低功耗模式
-- 即使运行到了drv_lowpower功能模块,也不一定马上进入低功耗模式,只有配置过低功耗模式,并且当前内核固件和脚本没有task处于运行状态,才能进入真正进入低功耗
sys.publish("DRV_SET_LOWPOWER")
-- 执行此代码时,处于常规模式
log.info("normal_lowpower_switch_task after publish DRV_SET_LOWPOWER")
-- 执行此代码时,处于常规模式
log.info("normal_lowpower_switch_task auto switch during gpio business")
-- 此处循环20秒,每1秒翻转1次GPIO_ID输出电平
-- 第一次循环:
-- 执行gpio.setup(GPIO_ID, i%2)时,因为此task处于运行状态,所以系统仍然处于常规模式,所以这个时刻可以正常输出高电平
-- 但是在执行sys.wait(1000)时,此task会处于阻塞状态,此时如果不考虑系统中其他运行的任务影响,系统就会立即自动进入到低功耗模式
-- 虽然刚才设置了GPIO_ID输出高电平,但是此时处于低功耗模式下,此GPIO_ID掉电,所以输出的高电平立刻消失
-- 如果使用示波器来抓波形的话,会看到一个时间非常短的高脉冲(可能是微秒级、毫秒级的时长),并不会像代码设计的一样持续1秒钟
-- 第二次循环:
-- 执行gpio.setup(GPIO_ID, i%2)时,因为此任务切换为运行状态,所以低功耗模式自动切换为常规模式,所以这个时刻可以正常输出低电平
-- 但是在执行sys.wait(1000)时,此task会处于阻塞状态,此时如果不考虑系统中其他运行的任务影响,系统就会立即自动进入到低功耗模式
-- 虽然刚才设置了GPIO_ID输出低电平,但是此时处于低功耗模式下,此GPIO_ID掉电,所以仍然是低电平,因为本来就是输出低电平,所以看不出来异常
-- 接下来的循环过程、功耗模式的自动切换逻辑、电平逻辑和第一次循环以及第二次循环的过程完全一致,系统不断的在低功耗模式和常规模式自动切换,呈现出一个低功耗模式持续时间长、常规模式持续时间短的特点
for i=1,20 do
gpio.setup(GPIO_ID, i%2)
sys.wait(1000)
end
-- 执行此代码时,处于常规模式(因为此task处于运行状态,会将系统自动切换为常规模式)
log.info("normal_lowpower_switch_task auto switch during agpio business")
-- 此处循环20秒,每1秒翻转1次AGPIO_ID输出电平
-- 和普通的GPIO相比,AGPIO的特点是,在低功耗模式下供电正常,可以保持电平输出
-- 虽然此处循环20次,系统也会在常规模式和低功耗模式之间自动切换,但是无论哪一种模式,此AGPIO_ID都能正常工作
-- 所以在此处,AGPIO_ID输出电平的逻辑和持续时长完全正确,1秒输出高电平,1秒输出低电平
for i=1,20 do
gpio.setup(AGPIO_ID, i%2)
sys.wait(1000)
end
-- 显式配置最低功耗模式为常规模式
-- 执行此代码时,处于常规模式(因为此task处于运行状态,会将系统自动切换为常规模式)
-- 执行此行代码后,会通过异步消息"DRV_SET_NORMAL"通知drv_normal功能模块配置常规模式
-- 等待sys.run()在分发处理到"DRV_SET_NORMAL"消息时,drv_normal功能模块才去配置常规模式
sys.publish("DRV_SET_NORMAL")
-- 执行此代码时,处于常规模式(因为此task处于运行状态,会将系统自动切换为常规模式)
log.info("normal_lowpower_switch_task auto switch during gpio business")
-- 此处循环20秒,每1秒翻转1次GPIO_ID输出电平
-- 第一次循环:
-- 执行gpio.setup(GPIO_ID, i%2)时,因为此task处于运行状态,所以系统仍然处于常规模式,所以这个时刻可以正常输出高电平
-- 在执行sys.wait(1000)时,此task会处于阻塞状态,但是此时系统并不会自动进入低功耗模式,因为刚才的"DRV_SET_NORMAL"消息还在sys.run()中等待处理
-- 所以说,虽然此时,本task处于阻塞状态,但是sys.run()中还在运行处理其他消息,具体到本demo,就是在drv_normal中处理"DRV_SET_NORMAL"消息,显式的配置最低功耗模式为常规模式
-- 经过显式配置之后,系统就会一直处于常规模式;所以此处的sys.wait(1000)期间,就会进入到显式常规模式中,就可以一直持续1秒钟输出高电平
-- 第二次循环:
-- 此时已经显式的处于常规模式,所以工作完全正常
-- 接下来的循环过程中都处于显式的常规模式中,所以工作完全正常
for i=1,20 do
gpio.setup(GPIO_ID, i%2)
sys.wait(1000)
end
-- 显式配置最低功耗模式为低功耗模式
-- 执行此行代码后,会通过异步消息"DRV_SET_LOWPOWER"通知drv_lowpower功能模块配置低功耗模式
-- 所以执行此行代码后,并不会马上进入低功耗模式
-- 而是等待sys.run()在分发处理到"DRV_SET_LOWPOWER"消息时,drv_lowpower功能模块才去配置低功耗模式
-- 即使运行到了drv_lowpower功能模块,也不一定马上进入低功耗模式,只有配置过低功耗模式,并且当前内核固件和脚本没有task处于运行状态,才能进入真正进入低功耗
sys.publish("DRV_SET_LOWPOWER")
-- 执行此代码时,处于常规模式
log.info("normal_lowpower_switch_task exit after publish DRV_SET_LOWPOWER")
end
sys.taskInit(normal_lowpower_switch_task)
@@ -0,0 +1,78 @@
--[[
@module prj_0_tcp_long
@summary 常规模式(WORKMODE 0)下的tcp client长连接应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为常规模式(WORKMODE 0)下的tcp长连接应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为常规模式(WORKMODE 0)
2、启动一个tcp client长连接,连接tcp server;连接断开后,自动重连
3、tcp client每隔一段时间发送数据到tcp server
4、tcp client接收到tcp server下发的数据后,在日志中打印出来
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在常规模式示例代码中,并未对GPIO23进行额外配置,默认状态下为高电平,以此演示常规模式下的实际功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.3V状态下,运行6分钟,测试功耗数据为31.7202mA左右
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_NORMAL"):发布消息"DRV_SET_NORMAL",通知drv_normal驱动模块配置最低功耗模式为常规模式
]]
require "drv_normal"
require "app_tcp_main"
-- 数据发送结果回调函数;
local function send_data_cbfunc(result)
sys.publish("SEND_DATA_RSP", result)
end
-- tcp client长连接任务函数;
local function tcp_long_task()
-- 发布消息“TCP_CLIENT_RUN_REQ”,通知tcp client socket主功能应用模块(例如app_tcp_main.lua);
-- 第二个参数用于设置连接的类型,“true”表示长连接,连接断开后会自动重连,“false”表示短连接,连接断开后不会自动重连;
-- tcp client主功能应用模块接收到“TCP_CLIENT_RUN_REQ”消息后,根据第二个参数判断开始运行tcp client长链接任务还是短连接任务;
sys.publish("TCP_CLIENT_RUN_REQ", true)
local count = 0 -- 发送数据的次数
local _, result -- 用于接收数据发送结果
-- 发布消息“SEND_DATA_REQ”,通知tcp client socket数据发送应用功能模块(例如app_tcp_sender.lua)将数据发到服务器;
while true do
-- 用于在发送的数据内容中体现发送的次数
count = count + 1
-- 发布消息“SEND_DATA_REQ”,通知tcp client socket数据发送应用功能模块(例如app_tcp_sender.lua)将数据发到服务器;
-- 发送的数据内容大致为”send from tcp_long_task: heart_1“、”send from tcp_long_task: heart_2“等;
-- 数据发送结果会通过回调函数send_data_cbfunc返回;
sys.publish("SEND_DATA_REQ", "tcp_long_task", "heart_"..count, {func = send_data_cbfunc})
-- 等待数据发送结果
_, result = sys.waitUntil("SEND_DATA_RSP")
log.info("tcp_long_task", "send data rsp", result)
-- 延时5分钟之后,再次循环
sys.wait(5*60*1000)
end
end
-- 发布消息“DRV_SET_NORMAL”,通知drv_normal驱动模块配置最低功耗模式为常规模式;
-- 此行代码配置与否没有任何影响,因为LuatOS内核固件默认就是工作在常规模式;
-- 此处配置,仅仅演示显式配置的方式;
sys.publish("DRV_SET_NORMAL")
-- 启动tcp client长连接任务
sys.taskInit(tcp_long_task)
@@ -0,0 +1,46 @@
--[[
@module prj_1
@summary 低功耗模式(WORKMODE 1)应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为低功耗模式(WORKMODE 1)应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为低功耗模式(WORKMODE 1)
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_LOWPOWER"):发布消息"DRV_SET_LOWPOWER",通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在低功耗模式示例代码中,并未对GPIO23进行配置,默认状态下为高电平,以此演示低功耗模式下的实际功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,分为以下三种独立的场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约7秒后,成功进入低功耗状态;
初始化阶段(常规模式),平均电流47mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(因为有网络寻呼,所以是低功耗模式+常规模式自动切换),平均电流1.2mA左右(900uA到1.5mA左右都属于正常值,和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准,但是差异应该不是特别大才对)
2、插sim卡,上电开机之后,立即进入飞行模式(打开drv_lowpower.lua中的mobile.flymode(0, true)代码),大约1.2秒后,成功进入低功耗状态;
初始化阶段(常规模式),平均电流20mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(低功耗模式),平均电流41uA左右(40uA到70uA左右都属于正常值)
3、不插sim卡,上电开机之后,大约0.91秒后,成功进入低功耗状态;
初始化阶段(常规模式),平均电流20mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(低功耗模式),平均电流44uA左右(40uA到70uA左右都属于正常值)
]]
require "drv_lowpower"
-- 发布消息“DRV_SET_LOWPOWER”,通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式;
-- drv_lowpower驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 1)设置最低功耗模式为低功耗模式(WORKMODE 1);
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_LOWPOWER")
@@ -0,0 +1,83 @@
--[[
@module prj_1_mqtt_long
@summary 低功耗模式(WORKMODE 1)下的mqtt client长连接应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为低功耗模式(WORKMODE 1)下的mqtt client长连接应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为低功耗模式(WORKMODE 1)
2、启动一个mqtt client长连接,连接mqtt broker;连接断开后,自动重连
3、mqtt client每隔一段时间发送数据到mqtt broker
4、mqtt client接收到mqtt broker下发的数据后,在日志中打印出来
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在低功耗模式示例代码中,并未对GPIO23进行配置,默认状态下为高电平,以此演示低功耗模式下的实际功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,在以下测试场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约7秒后,成功进入低功耗状态;
初始化阶段(常规模式),平均电流38mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(因为有网络寻呼和mqtt交互,所以是低功耗模式+常规模式自动切换),平均电流2.7mA左右(2.4mA到3.0mA左右都属于正常值,和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准,但是差异应该不是特别大才对)
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_LOWPOWER"):发布消息"DRV_SET_LOWPOWER",通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式
]]
require "drv_lowpower"
require "app_mqtt_main"
-- 数据发送结果回调函数;
local function send_data_cbfunc(result)
sys.publish("SEND_DATA_RSP", result)
end
-- mqtt client长连接任务函数;
local function mqtt_long_task()
-- 发布消息“MQTT_CLIENT_RUN_REQ”,通知mqtt client主功能应用模块(例如app_mqtt_main.lua);
-- 第二个参数用于设置连接的类型,“true”表示长连接,连接断开后会自动重连,“false”表示短连接,连接断开后不会自动重连;
-- mqtt client主功能应用模块接收到“MQTT_CLIENT_RUN_REQ”消息后,根据第二个参数判断开始运行mqtt client长链接任务还是短连接任务;
sys.publish("MQTT_CLIENT_RUN_REQ", true)
local count = 0 -- 发送数据的次数
local _, result -- 用于接收数据发送结果
-- 发布消息“SEND_DATA_REQ”,通知mqtt client数据发送应用功能模块(例如app_mqtt_sender.lua)将数据发到服务器;
while true do
-- 用于在发送的数据内容中体现发送的次数
count = count + 1
-- 发布消息“SEND_DATA_REQ”,通知mqtt client数据发送应用功能模块(例如app_mqtt_sender.lua)将数据发到服务器;
-- 发送的数据内容大致为”send from mqtt_long_task: heart_1“、”send from mqtt_long_task: heart_2“等;
-- 数据发送结果会通过回调函数send_data_cbfunc返回;
sys.publish("SEND_DATA_REQ", "mqtt_long_task", mobile.imei().."/up", "heart_"..count, 0, {func = send_data_cbfunc})
-- 等待数据发送结果
_, result = sys.waitUntil("SEND_DATA_RSP")
log.info("mqtt_long_task", "send data rsp", result)
-- 延时5分钟之后,再次循环
sys.wait(5*60*1000)
end
end
-- 发布消息“DRV_SET_LOWPOWER”,通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式;
-- drv_lowpower驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 1)设置最低功耗模式为低功耗模式(WORKMODE 1);
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_LOWPOWER")
-- 启动mqtt client长连接任务;
sys.taskInit(mqtt_long_task)
@@ -0,0 +1,84 @@
--[[
@module prj_1_tcp_long
@summary 低功耗模式(WORKMODE 1)下的tcp client长连接应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为低功耗模式(WORKMODE 1)下的tcp长连接应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为低功耗模式(WORKMODE 1)
2、启动一个tcp client长连接,连接tcp server;连接断开后,自动重连
3、tcp client每隔一段时间发送数据到tcp server
4、tcp client接收到tcp server下发的数据后,在日志中打印出来
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在低功耗模式示例代码中,并未对GPIO23进行配置,默认状态下为高电平,以此演示低功耗模式下的实际功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,在以下测试场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约9秒后,成功进入低功耗状态;
初始化阶段(常规模式),平均电流33mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
低功耗阶段(因为有网络寻呼和tcp交互,所以是低功耗模式+常规模式自动切换),平均电流2.3mA左右(2.1mA到2.7mA左右都属于正常值,和天线性能以及网络环境有关系,以自己的实际硬件+实际网络环境测试数据为准,但是差异应该不是特别大才对)
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_LOWPOWER"):发布消息"DRV_SET_LOWPOWER",通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式
]]
require "drv_lowpower"
require "app_tcp_main"
-- 数据发送结果回调函数;
local function send_data_cbfunc(result)
sys.publish("SEND_DATA_RSP", result)
end
-- tcp client长连接任务函数;
local function tcp_long_task()
-- 发布消息“TCP_CLIENT_RUN_REQ”,通知tcp client socket主功能应用模块(例如app_tcp_main.lua);
-- 第二个参数用于设置连接的类型,“true”表示长连接,连接断开后会自动重连,“false”表示短连接,连接断开后不会自动重连;
-- tcp client主功能应用模块接收到“TCP_CLIENT_RUN_REQ”消息后,根据第二个参数判断开始运行tcp client长链接任务还是短连接任务;
sys.publish("TCP_CLIENT_RUN_REQ", true)
local count = 0 -- 发送数据的次数
local _, result -- 用于接收数据发送结果
-- 发布消息“SEND_DATA_REQ”,通知tcp client socket数据发送应用功能模块(例如app_tcp_sender.lua)将数据发到服务器;
while true do
-- 用于在发送的数据内容中体现发送的次数
count = count + 1
-- 发布消息“SEND_DATA_REQ”,通知tcp client socket数据发送应用功能模块(例如app_tcp_sender.lua)将数据发到服务器;
-- 发送的数据内容大致为”send from tcp_long_task: heart_1“、”send from tcp_long_task: heart_2“等;
-- 数据发送结果会通过回调函数send_data_cbfunc返回;
sys.publish("SEND_DATA_REQ", "tcp_long_task", "heart_"..count, {func = send_data_cbfunc})
-- 等待数据发送结果
_, result = sys.waitUntil("SEND_DATA_RSP")
log.info("tcp_long_task", "send data rsp", result)
-- 延时5分钟之后,再次循环
sys.wait(5*60*1000)
end
end
-- 发布消息“DRV_SET_LOWPOWER”,通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式;
-- drv_lowpower驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 1)设置最低功耗模式为低功耗模式(WORKMODE 1);
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_LOWPOWER")
-- 启动tcp client长连接任务;
sys.taskInit(tcp_long_task)
@@ -0,0 +1,47 @@
--[[
@module prj_1_uart_camera
@summary 低功耗模式(WORKMODE 1)下的uart camera应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为低功耗模式(WORKMODE 1)下的uart camera应用项目主功能模块,核心业务逻辑为:
1、引用drv_lowpower驱动模块,用于配置最低功耗模式为低功耗模式(WORKMODE 1);
2、引用app_lpuart驱动模块,用于初始化uart,以及接收拍照指令和将拍照数据通过uart发送出去;
3、引用app_camera驱动模块,用于初始化camera,以及控制camera拍照;
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在低功耗模式示例代码中,并未对GPIO23进行配置,默认状态下为高电平,以此演示低功耗模式下的实际功耗表现;
使用Air780EXX系列每个模组的整机开发板,不插sim卡,烧录运行此demo,在vbat供电3.8V状态下,进行拍照+通过uart将图像数据发送出去,测试一分钟功耗数据为861.9937uA左右
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_LOWPOWER"):发布消息"DRV_SET_LOWPOWER",通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式
]]
require "drv_lowpower"
require "app_lpuart"
require "app_camera"
-- 硬件连接与操作说明:
-- 1、演示代码使用的是Air780EPM开发板进行测试,需要搭配一个gc032a的摄像头和两个串口板;
-- 2、测试时,使用两根usb转ttl串口线连接电脑和开发板,第一根线和开发板的uart1 tx相连(电脑上的串口工具配置为9600波特率),第二根线和开发板的uart1 rx相连(电脑上的串口工具配置为115200波特率);
-- 3、第一根线对应的电脑端串口工具下发A0001指令,就可以控制开发板拍照,拍照结束后,通过第二根线发给电脑端串口工具(每次接收到数据,可以单独保存为一个文件,修改文件名后缀为jpg,就能查看图片)
-- 设置SIM0进入飞行模式
-- 可以在此处配置,也可以在drv_lowpower.lua中设置(详情请查看drv_lowpower.lua中的代码注释说明)
mobile.flymode(0, true)
-- 发布消息“DRV_SET_LOWPOWER”,通知drv_lowpower驱动模块配置最低功耗模式为低功耗模式;
-- drv_lowpower驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 1)设置最低功耗模式为低功耗模式(WORKMODE 1);‘
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_LOWPOWER")
@@ -0,0 +1,42 @@
--[[
@module prj_3
@summary PSM+模式(WORKMODE 3)应用项目主调度功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为PSM+模式(WORKMODE 3)应用项目主调度功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为PSM+模式(WORKMODE 3
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_PSM"):发布消息"DRV_SET_PSM",通知drv_psm驱动模块配置最低功耗模式为PSM+模式
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在PSM+模式示例代码中,默认配置GPIO23为输入下拉的方式来演示PSM+模式的功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,分为以下两种独立的场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约1.2秒后,成功进入PSM+状态;
初始化阶段(常规模式),平均电流21mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
PSM+阶段(PSM+模式),平均电流3.9uA左右(2.8uA到10uA都属于正常值)
2、不插sim卡,上电开机之后,大约0.94秒后,成功进入PSM+状态;
初始化阶段(常规模式),平均电流21mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
PSM+阶段(PSM+模式),平均电流3.2uA左右(2.8uA到10uA都属于正常值)
]]
require "drv_psm"
-- 发布消息“DRV_SET_PSM”,通知drv_psm驱动模块配置最低功耗模式为PSM+模式;
-- drv_psm驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 3)设置最低功耗模式为PSM+模式;
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_PSM")
@@ -0,0 +1,108 @@
--[[
@module prj_3_mqtt_short
@summary PSM+模式下的mqtt client短连接应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为psm+模式下的mqtt短连接应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为psm+模式
2、启动一个mqtt client短连接,连接mqtt broker;连接断开后,不会自动重连
3、mqtt client发送一次数据到mqtt broker,无论成功还是失败,一段时间后主动断开连接,然后进入PSM+模式
4、mqtt client接收到mqtt broker下发的数据后,在日志中打印出来
5、进入PSM+模式休眠一个小时唤醒后,重新执行前面的操作
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在PSM+模式示例代码中,默认配置GPIO23为输入下拉的方式来演示PSM+模式的功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,在以下测试场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约2.6秒后,成功进入PSM+状态;
初始化阶段(常规模式),平均电流44.31mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
PSM+阶段(PSM+模式,关闭WiFi芯片,配置GPIO24为输入下拉),平均电流3.4uA左右(2.8uA到10uA都属于正常值)
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_PSM"):发布消息"DRV_SET_PSM",通知drv_psm驱动模块配置最低功耗模式为PSM+模式
2、sys.publish("READ_SHT30_REQ"):发布消息"READ_SHT30_REQ",通知app_sht30功能模块读取温湿度数据
]]
require "drv_psm"
require "app_sht30"
require "app_mqtt_main"
-- 数据发送结果回调函数;
local function send_data_cbfunc(result)
sys.publish("SEND_DATA_RSP", result)
end
-- mqtt client短连接任务函数;
local function mqtt_short_task()
-- 发布消息“READ_SHT30_REQ”,通知sht30_app应用功能模块(例如app_sht30.lua)读取温湿度数据;
sys.publish("READ_SHT30_REQ")
-- 温湿度数据通过“READ_SHT30_RSP”消息返回;此处等待读取结果,最多等待3秒钟;
-- 如果在3秒内没有读取到结果,则继续执行后面的代码
local no_timeout, result, temprature, humidity = sys.waitUntil("READ_SHT30_RSP", 3000)
log.info("mqtt_short_task", "read sht30 rsp", no_timeout, result, temprature, humidity)
-- 发布消息“MQTT_CLIENT_RUN_REQ”,通知mqtt client主功能应用模块(例如app_mqtt_main.lua);
-- 第二个参数用于设置连接的类型,“true”表示长连接,连接断开后会自动重连,“false”表示短连接,连接断开后不会自动重连;
-- mqtt client主功能应用模块接收到“MQTT_CLIENT_RUN_REQ”消息后,根据第二个参数判断开始运行mqtt client长链接任务还是短连接任务;
sys.publish("MQTT_CLIENT_RUN_REQ", false)
-- 根据读取的温湿度数据,构造payload
local payload
-- 如果成功读取到温湿度数据,则将数据格式化为json字符串
if temprature and humidity then
payload = json.encode({
temperature = string.format("%.2f", temprature),
humidity = string.format("%.2f", humidity)
})
-- 如果读取温湿度数据失败,则将payload设置为错误字符串
else
payload = "error!!!"
end
-- 发布消息“SEND_DATA_REQ”,通知mqtt client数据发送应用功能模块(例如app_mqtt_sender.lua)将数据发到服务器;
-- 发送的数据内容大致为”send from mqtt_short_task: {"humidity":"43.05","temperature":"13.92"}“等;
-- 数据发送结果会通过回调函数send_data_cbfunc返回;
sys.publish("SEND_DATA_REQ", "mqtt_short_task", mobile.imei().."/up", payload, 0, {func = send_data_cbfunc})
-- 等待数据发送结果,最长等待10秒钟
no_timeout, result = sys.waitUntil("SEND_DATA_RSP", 10000)
log.info("mqtt_short_task", "send data rsp", no_timeout, result)
-- 无论发送成功还是失败,主动断开mqtt client短连接
sys.publish("MQTT_CLIENT_CLOSE_REQ")
-- 等待断开结果,最长等待3秒钟
-- 为了更省电,此处也可以不等待结果,可以更快的进入PSM+模式;
-- 代价就是broker端无法及时检测到客户端已经断开,要等broker端超时之后,才会清空当前客户端在broker上的资源
no_timeout,result = sys.waitUntil("MQTT_CLIENT_CLOSE_RSP", 3000)
log.info("mqtt_short_task", "mqtt close rsp", no_timeout, result)
-- 配置深度休眠定时器1小时后唤醒(定时器时长有讲究,此处的时长不要小于80秒,而且为了省电,至少要几十分钟才可能有意义)
-- 可以在此处配置,也可以在drv_psm.lua中设置(详情请查看drv_psm.lua中的代码注释说明)
pm.dtimerStart(0, 60*60*1000)
-- 发布消息“DRV_SET_PSM”,通知drv_psm驱动模块配置最低功耗模式为PSM+模式;
-- drv_psm驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 3)设置最低功耗模式为PSM+模式;
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_PSM")
end
-- 启动mqtt client短连接任务
sys.taskInit(mqtt_short_task)
@@ -0,0 +1,82 @@
--[[
@module prj_3_tcp_short
@summary PSM+模式下的tcp client短连接应用项目主功能模块
@version 1.0
@date 2026.02.12
@author 马梦阳
@usage
本文件为psm+模式下的tcp短连接应用项目主功能模块,核心业务逻辑为:
1、初始化时配置最低功耗模式为psm+模式
2、启动一个tcp client短连接,连接tcp server;连接断开后,不会自动重连
3、tcp client发送一次数据到tcp server,无论成功还是失败,一段时间后主动断开连接,然后进入PSM+模式
4、tcp client接收到tcp server下发的数据后,在日志中打印出来
5、进入PSM+模式休眠一个小时唤醒后,重新执行前面的操作
Air780EGP/EGG模组内部包含有GNSS和GsensorAir780EGH模组内部只包含有GNSS,不包含Gsensor
GPIO23作为GNSS备电电源开关和Gsensor电源开关,默认状态下为高电平;
在低功耗模式和PSM+模式下,GNSS备电开启和Gsensor开启后,二者的功耗总和表现为30uA左右,客户应根据实际需求进行配置;
在PSM+模式示例代码中,默认配置GPIO23为输入下拉的方式来演示PSM+模式的功耗表现;
使用Air780EXX系列每个模组的核心板,烧录运行此demo,在vbat供电3.8v状态下,在以下测试场景来介绍一下功耗情况:
1、插sim卡,上电开机之后,大约2.6秒后,成功进入PSM+状态;
初始化阶段(常规模式),平均电流47.85mA;(此数据仅供参考,测试网络环境不同,持续时长以及平均电流都会不同,但是差异应该不是特别大才对)
PSM+阶段(PSM+模式,关闭WiFi芯片,配置GPIO24为输入下拉),平均电流2.8uA左右(2.8uA到10uA都属于正常值)
本文件和其他功能模块的通信接口只有1个:
1、sys.publish("DRV_SET_PSM"):发布消息"DRV_SET_PSM",通知drv_psm驱动模块配置最低功耗模式为PSM+模式
]]
require "drv_psm"
require "app_tcp_main"
-- 数据发送结果回调函数;
local function send_data_cbfunc(result)
sys.publish("SEND_DATA_RSP", result)
end
-- tcp client短连接任务函数;
local function tcp_short_task()
-- 发布消息“TCP_CLIENT_RUN_REQ”,通知tcp client socket主功能应用模块(例如app_tcp_main.lua);
-- 第二个参数用于设置连接的类型,“true”表示长连接,连接断开后会自动重连,“false”表示短连接,连接断开后不会自动重连;
-- tcp client主功能应用模块接收到“TCP_CLIENT_RUN_REQ”消息后,根据第二个参数判断开始运行tcp client长链接任务还是短连接任务;
sys.publish("TCP_CLIENT_RUN_REQ", false)
-- 发布消息“SEND_DATA_REQ”,通知tcp client socket数据发送应用功能模块(例如app_tcp_sender.lua)将数据发到服务器;
-- 发送的数据内容大致为”send from tcp_short_task: wakeup report“等;
-- 数据发送结果会通过回调函数send_data_cbfunc返回;
sys.publish("SEND_DATA_REQ", "tcp_short_task", "wakeup report", {func = send_data_cbfunc})
-- 等待数据发送结果,最长等待10秒钟;
local no_timeout, result = sys.waitUntil("SEND_DATA_RSP", 10000)
log.info("tcp_long_task", "send data rsp", no_timeout, result)
-- 无论发送成功还是失败,主动断开tcp client短连接;
sys.publish("TCP_CLIENT_CLOSE_REQ")
-- 等待断开结果,最长等待3秒钟;
-- 为了更省电,此处也可以不等待结果,可以更快的进入PSM+模式;
-- 代价就是server端无法及时检测到客户端已经断开,要等server端超时之后,才会清空当前客户端在server上的资源;
no_timeout, result = sys.waitUntil("TCP_CLIENT_CLOSE_RSP", 3000)
log.info("tcp_long_task", "tcp close rsp", no_timeout, result)
-- 配置深度休眠定时器1小时后唤醒(定时器时长有讲究,此处的时长不要小于80秒,而且为了省电,至少要几十分钟才可能有意义)
-- 可以在此处配置,也可以在drv_psm.lua中设置(详情请查看drv_psm.lua中的代码注释说明)
pm.dtimerStart(0, 60*60*1000)
-- 发布消息“DRV_SET_PSM”,通知drv_psm驱动模块配置最低功耗模式为PSM+模式;
-- drv_psm驱动模块内部已有中断唤醒引脚和功能引脚的配置说明,根据实际项目需求打开或关闭对应配置代码即可;
-- 在执行完中断唤醒引脚和功能引脚的配置之后,调用pm.power(pm.WORK_MODE, 3)设置最低功耗模式为PSM+模式;
-- 设置完之后并不会里面进入休眠,而是等所有业务逻辑处理完毕之后,才会进入休眠;
sys.publish("DRV_SET_PSM")
end
-- 启动tcp client短连接任务;
sys.taskInit(tcp_short_task)
@@ -0,0 +1,136 @@
## 演示功能概述
本demo演示的核心功能为:
Air780EXX系列模组在常规模式、低功耗模式1、PSM+模式3下的功耗表现,通过下列九个项目示例代码进行介绍:
1、prj_0_tcp_long:常规模式下的tcp长连接项目(每5分钟发送一次数据到tcp server
2、prj_3PSM+模式3简单项目
3、prj_1:低功耗模式1简单项目
4、prj_0_1:常规模式0和低功耗模式1切换项目
5、prj_1_tcp_long:低功耗模式下的tcp长连接项目(每5分钟发送一次数据到tcp server
6、prj_3_tcp_shortPSM+模式下的tcp短连接项目(每次开机,发送一次数据到tcp server,无论成功还是失败,然后进入PSM+模式,1小时后唤醒)
7、prj_1_mqtt_long:低功耗模式下的mqtt长连接项目(每5分钟发送一次数据到mqtt server
8、prj_3_mqtt_shortPSM+模式下的mqtt短连接项目(每次开机,读取一次温湿度数据,然后发送到mqtt server,无论成功还是失败,然后进入PSM+模式,1小时后唤醒)
9、prj_1_uart_camera:低功耗模式+飞行模式下的上位机通过串口控制拍照以及照片回传项目(uart1 9600波特率接收上位机拍照指令,拍照后,通过115200波特率将照片回传给上位机)
简单说明:
1、Air780EXX系列模组目前包括Air780EPM/EHM/EHN/EHU/EHV/EGH/EGG/EGP
2、Air780EGH/EGP/EGG模组内部包含有GNSS芯片,Air780EGP/EGG模组内部包含有Gsensor芯片,GPIO23作为GNSS芯片的供电使能引脚,一直保持高电平输出,此时会增加30uA左右的电流功耗,属于正常情况;
3、Air780EHV模组内部包含有Audio Codec芯片ES8311GPIO20作为Audio Codec芯片ES8311的供电使能引脚,外部不需要进行额外配置;
4、Air780EPM/EHM没有引出此引脚,所以无法配置CHG_DET(WAKEUP6)功能;
## 模组及核心板/开发板资料
[Air780EPM/EHM模组及核心板/开发板资料](https://docs.openluat.com/air780epm/product/shouce/)
[Air780EHV模组及核心板/开发板资料](https://docs.openluat.com/air780ehv/product/shouce/)
[Air780EGH/EGG/EGP模组及核心板/开发板资料](https://docs.openluat.com/air780egh/product/shouce/)
[Air780EHN/EHU模组及核心板/开发板资料](https://docs.openluat.com/air780ehnehu/product/shouce/)
## 演示硬件环境
1、Air780EXX系列核心板(可通过[上海合宙LuatOS官方企业店](https://luat.taobao.com/)采购)
2、Air780EXX系列开发板(可通过[上海合宙LuatOS官方企业店](https://luat.taobao.com/)采购,用于prj_1_uart_camera项目演示)
3、AirSHT30_1000温湿度传感器配件板(可通过[上海合宙LuatOS官方企业店](https://luat.taobao.com/)采购,用于prj_3_mqtt_short项目演示)
4、AirCAMERA _1040摄像头模组(可通过[上海合宙LuatOS官方企业店](https://luat.taobao.com/)采购,用于prj_1_uart_camera项目演示)
5、支持两个UART端口及以上的串口板
6、物联网卡(需要自行联系卡商)
7、Air9000P合宙功耗分析仪(可通过[上海合宙LuatOS官方企业店](https://luat.taobao.com/)采购,用于外部供电)
Air9000P与Air780EXX系列核心板接线说明:
- 将Air9000P的‘+’、‘-’极分别连接到核心板的VBAT、GND排针上,在测试低功耗模式1、PSM+模式3时需要使用外部供电才行;
- 将核心板USB旁边的拨码开关拨到OFF,断开USB供电;
- 电脑打开“功耗分析仪”软件(使用说明请看[Air9000P使用说明](https://hezhouyibiao.com/)),连接Air9000P
Air9000P与Air780EXX系列开发板接线说明:
- 将Air9000P的‘+’、‘-’极分别连接到开发板的4V、GND排针上,在测试低功耗模式1、PSM+模式3时需要使用外部供电才行;
- 将开发板USB旁边的拨码开关拨到“外部供电”,断开USB供电;
- 电脑打开“功耗分析仪”软件(使用说明请看[Air9000P使用说明](https://hezhouyibiao.com/)),连接Air9000P
AirSHT30_1000与Air780EXX系列核心板接线说明:
| Air780EXX系列核心板 | AirSHT30_1000温湿度传感器配件板 |
| ------------------- | ------------------------------- |
| VDD_EXT | 3.3V |
| GND | GND |
| 66/I2C1SDA | SDA |
| 67/I2C1SCL | SCL |
两个UART端口及以上的串口板与Air780EXX系列开发板接线说明:
1、使用两根usb转ttl串口线连接电脑和开发板,第一根线和开发板的uart1 tx相连(电脑上的串口工具配置为9600波特率),第二根线和开发板的uart1 rx相连(电脑上的串口工具配置为115200波特率);
2、第一根线对应的电脑端串口工具下发A0001指令,就可以控制开发板拍照,拍照结束后,通过第二根线发给电脑端串口工具(每次接收到数据,可以单独保存为一个文件,修改文件名后缀为jpg,就能查看图片)
## 演示软件环境
1、烧录工具:LuaTools下载调试工具(可鼠标右键点击[此处](https://docs.openluat.com/air780epm/common/Luatools/)并左键打开此链接进行下载);
2、内核固件:
- [Air780EPM/EHM最新版本内核固件](https://docs.openluat.com/air780epm/luatos/firmware/version/)
- [Air780EHV最新版本内核固件](https://docs.openluat.com/air780ehv/luatos/firmware/version/)
- [Air780EGH/EGG/EGP最新版本内核固件](https://docs.openluat.com/air780egh/luatos/firmware/version/#air780egg-luatos)
- [Air780EHN/EHU最新版本内核固件](https://docs.openluat.com/air780ehnehu/luatos/firmware/version/)
3、脚本文件:[lowpower_new](https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EPM/demo/lowpower_new)
4、lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件
准备好软件环境之后,接下来根据前面“模组及核心板/开发板资料”链接中各个模组核心板/开发板使用手册中的烧录说明,将本篇文章中演示使用的项目文件烧录到Air780EXX系列核心板/开发板中。
## 演示操作步骤
1、搭建好演示硬件环境;
- prj_3、prj_1、prj_0_1、prj_0_tcp_long、prj_1_tcp_long、prj_3_tcp_short、prj_1_mqtt_long这七个功能演示只需要使用Air780EXX系列核心板+物联网卡+Air9000P合宙功耗分析仪即可;
- prj_3_mqtt_short这一个功能演示时还需要在前面的基础上连接AirSHT30_1000温湿度传感器配件板;
- prj_1_uart_camera这一个功能演示时核心板无法演示,需要使用Air780EXX系列开发板,开发板上还需要接AirCAMERA _1040摄像头模组和两个UART端口及以上的串口板才行;
- 在进行搭建硬件环境时请参考前面的“演示硬件环境”;
2、在 main.lua 代码文件中根据需要演示的项目功能,打开对应的代码;
- prj_3、prj_1、prj_0_1这三个功能演示时只需要打开对应的代码即可;
- prj_0_tcp_long、prj_1_tcp_long、prj_3_tcp_short这两个功能演示时需要在app_tcp_main.lua代码文件中填写需要连接的TCP服务器地址和端口号;
- prj_1_mqtt_long、prj_3_mqtt_short这三个功能演示时需要在app_mqtt_main.lua代码文件中填写需要连接的MQTT服务器地址和端口号,并且prj_3_mqtt_short功能演示时需要连接AirSHT30_1000温湿度传感器配件板,接线说明见前面的“演示硬件环境”章节;
- prj_1_uart_camera这一个功能演示时需要使用开发板,开发板上需要接AirCAMERA _1040摄像头模组和两个UART端口及以上的串口板,接线说明见前面的“演示硬件环境”章节;
3、使用LuaTools工具烧录内核固件和修改后的demo脚本代码;
4、烧录成功后,自动开机运行,并使用Air9000P合宙功耗分析仪观察功耗表现;
- prj_3、prj_1、prj_0_1、prj_0_tcp_long、prj_1_tcp_long、prj_3_tcp_short、prj_1_mqtt_long、prj_3_mqtt_short这八个功能演示时是全自动运行的,用户无法进行额外操作(除非是需要修改功能配置项),只需观察功耗表现即可;
- prj_1_uart_camera这一个功能演示还需要通过PC端串口工具与模组进行串口通信,详细说明见前面的“演示硬件环境”章节;