跳转至

Air201-LuatOS-如何使用超低功耗

一、超低功耗模式概述

当 Air201 进入超低功耗模式后,CPU 会暂停工作,同时 RAM 掉电,即便是在尝试保留 RAM 数据的情形下也会如此。普通 GPIO 在与外设驱动相连时,同样会随掉电而失效。然而,AON_GPIO 能够保持其在进入休眠前的电平状态。此外,DTIMER 定时器具备唤醒设备的功能,而 wakeup 引脚同样可以作为唤醒设备的一种方式。一旦设备被唤醒,程序将会从头开始执行,休眠前所有的运行时数据都将丢失。

二、演示功能概述

Air201 进入超低功耗模式时会进入飞行模式、普通 GPIO 会掉电,定时唤醒(退出超低功耗模式),上报一个数据,然后再进入超低功耗模式。

三、准备硬件环境

3.1 Air201 模组

使用 Air201 开发套件,如下图所示:

淘宝购买链接:Air201 开发套件淘宝购买链接

此开发套件的详细使用说明参考:Air201 产品手册 中的 Air201 硬件手册Air201 的 LuatOS 快速入门

3.2 直流稳压电源

在需要直流稳压电源的场景(例如 adc 测量外部输入的模拟电压),使用合宙功耗分析仪 Air9000P,如下图所示:

淘宝购买链接:Air9000P 淘宝购买链接

3.3 SIM 卡

请准备一张可正常上网的 SIM 卡,该卡可以是物联网卡或您的个人手机卡。

特别提醒:请确保 SIM 卡未欠费且网络功能正常,以便顺利进行后续操作。

3.4 PC 电脑

WINDOWS 系统,其他暂无特别要求;

3.5 数据通信线

USB 数据线(其一端为 Type-C 接口,用于连接 Air201)。

四、准备软件环境

4.1 下载调试工具

使用说明参考:Luatools 下载和详细使用

4.2 功耗分析仪 PC 端软件

下载链接:功耗分析仪 PC 端软件

4.3 TCP/UDP测试网站

使用链接:TCP/UDP 测试网站

4.4 源码及固件

源码和固件已打包,如下所示:

注:缩包中 core 文件夹存放固件,code 文件夹存放 demo

五、Air201 软硬件资料

5.1 API 接口介绍

本教程使用 api 接口为:低功耗 api 接口socket-api 接口

5.2 Air201 烧录说明

将 Air201 通过 usb-boot 小板连接电脑,如下图所示:

注意:boot 小板和 Air201 连接时,要确保 RESET 按键,BOOT 按键,电源开关机键 三个按键在同一侧,否则无法进入 boot 下载模式。

如何判断有没有进入下载模式:可以通过 PC 端的设备管理器中虚拟出来的 USB 断开数量来判断,

正常开机模式:

下载模式:

六、代码示例介绍

6.1 Air201 超低功耗定时上报

6.1.1 代码介绍

1.关闭一些可能影响功耗,误唤醒的引脚。

gpio.close(22)
gpio.close(23)
gpio.close(24)
gpio.close(39) --wakeup 0
gpio.close(41) -- simcd脚

2.加入 vbus 插入检测函数,防止读取不了日志。

--打开VBUS唤醒函数会增加功耗,请根据实际需求选择是否使用
 local vbus_pin = 40 -- VBUS引脚
 local vbus_state = 0 -- 记录VBUS脚状态
-- -- 设置VBUS脚为中断唤醒脚,模拟USB插拔状态
-- -- 在此处加入了唤醒_低功耗模式切换函数,不然USB插上后只能供电,无法查看日志
 gpio.setup(vbus_pin, function()
     vbus_state = gpio.get(vbus_pin) -- 记录VBUS脚状态
     if vbus_state == 0 then -- USB拔出
         log.info("sleep") -- 进入睡眠模式
         pm.power(pm.USB, false) -- 关闭USB
     elseif vbus_state == 1 then -- USB插入
        log.info("wakeup") -- 退出睡眠模式
        pm.power(pm.USB, true) -- 开启USB
         log.info("USB插入") -- 打印日志
     end
 end, gpio.PULLUP, gpio.BOTH) -- 上拉模式(PULLUP), 双边缘触发(BOTH)

3.连接 tcp 服务器、设置深度定时器后进入休眠模式。

local function Task(ip, port)
    local txData
    if reason == 0 then
        txData = "normal wakeup"
    elseif reason == 1 then
        txData = "timer wakeup"
    elseif reason == 2 then
        txData = "pad wakeup"
    elseif reason == 3 then
        txData = "uart1 wakeup"
    end
    if slp_state > 0 then
        mobile.flymode(0,false) -- 退出飞行模式,进入psm+前进入飞行模式,唤醒后需要主动退出
    end

    local netc, needBreak
    local result, param, is_err
    netc = socket.create(nil, d1Name)
    socket.debug(netc, false)
    socket.config(netc) -- demo用TCP服务器,目前需要在用极致功耗模式时先断开服务器
    local retry = 0
    while retry < 3 do
        log.info(rtos.meminfo("sys"))
        result = libnet.waitLink(d1Name, 0, netc)
        result = libnet.connect(d1Name, 5000, netc, ip, port)
        if result then
            log.info("服务器连上了")
            result, param = libnet.tx(d1Name, 15000, netc, txData)
            if not result then
                log.info("服务器断开了", result, param)
                break
            else
                needBreak = true
            end
        else
            log.info("服务器连接失败")
        end
        libnet.close(d1Name, 5000, netc)
        retry = retry + 1
        if needBreak then
            break
        end
    end

    uart.setup(1, 9600)  --配置uart1,外部唤醒用
    pm.dtimerStart(3, period)  --启动深度休眠定时器,period的值是3分钟
    mobile.flymode(0,true)     --进入飞行模式
    pm.power(pm.USB, false)    -- 关闭USB,如果打开了USB唤醒函数可注释掉
    pm.power(pm.WORK_MODE,3)   --进入极致功耗模式
    log.info(rtos.meminfo("sys"))
    sys.wait(15000)   --demo演示唤醒时间是三分钟,如果15s后模块重启,则说明进入极致功耗模式失败,
    log.info("进入极致功耗模式失败,尝试重启")
    rtos.reboot()
end

6.1.2 运行结果展示

开机连接 tcp 服务器,然后进入超低功耗模式,设备内部设置了一个定时器,该定时器每隔三分钟会触发一次唤醒操作。当定时器触发时,设备会从超低功耗模式中唤醒,并重新建立与 TCP 服务器的连接(如果连接已经断开)。连接成功后,设备会发送一次预设的数据到 TCP 服务器。数据发送完成后,设备会再次进入超低功耗模式,等待下一次定时唤醒。因为设备的充电 IC 在会存在一个 20ua 的漏电流。由于这个硬件特性,那么 Air201 在超低功耗模式下实际的功耗(包括充电 IC 的漏电流)就是 25.07ua。

定时器每隔三分钟会触发一次唤醒操作,设备会从超低功耗模式中唤醒,并重新建立与 TCP 服务器的连接,并发送预设的数据

Air201 定时唤醒后,连接 tcp 平台发送数据时的功耗是 17.7898mA

7 个休眠发送周期为 21 分钟,平均功耗为 251.1095uA

6.2 添加 gesensor 功能,超低功耗模式下如果 gsenseor 中断产生,需要上报

6.2.1 代码介绍

1.gesensor 初始化

local function init()
    i2c.close(i2cId)
    i2c.setup(i2cId, i2c.SLOW)
    i2c.send(i2cId, da267Addr, {0x00, 0x24}, 1)
    sys.wait(20)
    i2c.send(i2cId, da267Addr, {0x0F, 0x00}, 1)
    i2c.send(i2cId, da267Addr, {0x11, 0x34}, 1)
    i2c.send(i2cId, da267Addr, {0x10, 0x07}, 1)

    sys.wait(50)

    -- int set1
    i2c.send(i2cId, da267Addr, {0x16, 0x87}, 1)

    -- init active interrupt
    i2c.send(i2cId, da267Addr, {0x38, 0x03}, 1)
    i2c.send(i2cId, da267Addr, {0x39, 0x05}, 1)
    i2c.send(i2cId, da267Addr, {0x3A, 0x05}, 1)
    i2c.send(i2cId, da267Addr, {0x3B, 0x05}, 1)
    i2c.send(i2cId, da267Addr, {0x19, 0x04}, 1)

    -- enable active
    i2c.send(i2cId, da267Addr, {0x11, 0x30}, 1)

    -- init step counter
    i2c.send(i2cId, da267Addr, {0x33, 0x80}, 1)
end

sys.taskInit(function()
    mcu.altfun(mcu.I2C, i2cId, 23, 2, 0)
    mcu.altfun(mcu.I2C, i2cId, 24, 2, 0)
    while true do
        init()
        while true do
            local result = sys.waitUntil("RESTORE_GSENSOR", 60 * 1000)
            if result then
                break
            end
            i2c.send(i2cId, da267Addr, 0x01, 1)
            local data = i2c.recv(i2cId, da267Addr, 1)
            if not data or data == "" or string.byte(data) ~= 0x13 then
                break
            end
        end
    end
end)

2.gesensor 触发中断回调

local function ind()
    log.info("int", gpio.get(intPin))
    if gpio.get(intPin) == 1 then
        log.info("da267", "interrupt")
        i2c.send(i2cId, da267Addr, 0x02, 1)
        local data = i2c.recv(i2cId, da267Addr, 6)
        if data and #data == 6 then
            local xl, xm, yl, ym, zl, zm = string.byte(data, 1, 1), string.byte(data, 2, 2), string.byte(data, 3, 3), string.byte(data, 4, 4), string.byte(data, 5, 5), string.byte(data, 6, 6)
             x, y, z = (xm << 8 | xl ) >> 4, (ym << 8 | yl) >> 4, (zm << 8 | zl ) >> 4
            log.info("da267", "x:", x, "y:", y, "z:", z)
            sys.publish("GSENSOR", x, y, z)
        else
            sys.publish("RESTORE_GSENSOR")
        end
        i2c.send(i2cId, da267Addr, 0x0D, 1)
        local data = i2c.recv(i2cId, da267Addr, 2)
        if data and #data == 2 then
            local xl, xm = string.byte(data, 1, 1), string.byte(data, 2, 2)
            local step = ((xl << 8) + xm) // 2
            log.info("da267", "step:", step)
            sys.publish("STEP_COUNTER", step)
        else
            sys.publish("RESTORE_GSENSOR")
        end
    end
end

6.2.2 运行结果展示

开机初始化 gesensor,连接 tcp 服务器,进入超低功耗模式;当 gesensor 触发时唤醒 Air201 并上传三轴参数到 tcp 服务器。

发送数据时的电流

七、总结

本章介绍了 Air201 的超低功耗模式定时三分钟上传,和一个 gsenser 拓展示例;在超低功耗模式下: 电流为 5.07ua 左右(注意 需要减去 ic 的漏电流),上传数据时的电流为 17ma;拓展示例:超低功耗模式下 电流为 236ua,触发 gesensor 唤醒 Air201,并上报三轴参数 上传数据时电流为 32.5ma;后续更多低功耗模式下玩法等你来探索。

常见问题

1.超低功耗模式下是否可以联网

超低功耗模式下会进入飞行模式,无法联网

2.无法进入超低功耗模式,功耗降不下来

检查是否关闭 usb 功能;其他不用的 agpio 可以关闭掉