跳转至

ioqueue - io 序列操作

作者:孟伟

一、概述

ioqueue 模块提供了 IO 序列操作的功能,可以通过硬件定时器精确控制 GPIO 的操作时序。

注意事项:

对于 Air700EXX 系列、Air780EXX 系列、Air8000 系列模组,硬件定时器有如下要求:

硬件定时器 id:0-5,六个硬件定时器,

定时器精度:20 微秒,为硬件支持的最小时间单位。

3 和 5 固定被底层占用不可使用

pwm 功能依赖硬件定时器,ioqueue 不可与 pwm 功能同时使用

pwm0 对应 0

pwm4 对应 4

以此类推

注意:Air6101/Air8101 不支持此功能

1.1 使用场景

ioqueue 主要是输出一些特殊的电平序列,捕获自定义协议。

如果有以下需要就可以使用该库:

  • 精确控制多个 GPIO 的开关时序
  • 循环执行固定的 GPIO 操作序列
  • 捕获 GPIO 边沿变化的精确时间戳
  • 模拟非标准通信协议

1.1.1 输入捕获场景(以 DHT11 数据读取为例)

单总线协议要求严格的时序控制、主机需要先发送特定启动信号、传感器响应时间精确到微秒级、数据通过脉冲宽度编码

使用流程:

下面演示使用硬件定时器精确控制 DHT11 通信时序,通过捕获下降沿时间戳解码温湿度数据,实现微秒级精确通信:

dht11 通讯协议介绍:

数据分为小数部分和整数部分,一次完整的数据传输为 40bit,高位先出

数据格式:8bit 湿度整数数据 +8bit 湿度小数数据 +8bit 温度整数数据 +8bit 温度小数数据 +8bit 校验

8bit 校验 = 8bit 湿度整数数据 +8bit 湿度小数数据 +8bit 温度整数数据 +8bit 温度小数数据

校验可以判断数据是否正确发送

DHT11 工作时序:

  • 主机发送起始信号以后,DHT11 发送响应信号,然后发送 40bit 的数据,高位在前

总时序图如下:

  • 起始信号:总线空闲状态由 DHT11 内置上拉电阻拉高,主机拉低总线至少 18ms释放总线 20-40us
  • DHT11 响应:存在的 DHT11 会及时响应主机,同时拉低总线 80us 后,释放总线 80us,然后拉低总线,表示开始传送数据

  • 发送数据:当总线是低电平是表示开始发送数据,同时存在 50us 低电平时隙,之后拉高总线,高电平的持续时间表示发送 0 或者 1,当高电平持续时间为 26us-28us 表示发送 0,高电平持续时间为 70us 时,表示发送 1
  • 数据发送完毕,由上拉电阻拉高,置回空闲高电平状态

-- 测试单总线DHT11
-- 第一步:确保硬件定时器空闲
ioqueue.stop(hw_timer_id)

-- 第二步:初始化io队列
ioqueue.init(hw_timer_id, 100, 1)


-- 第三步:初始状态设置
ioqueue.setgpio(hw_timer_id, capture_pin, true, gpio.PULLUP)
-- 参数详解:
-- 10000: 延时10ms(10000微秒)
-- 0: 时间微调值
-- false: 单次延时(非连续模式)
-- 作用:初始空闲状态时长为10ms,给传感器足够的准备时间
ioqueue.setdelay(hw_timer_id, 10000, 0, false)


-- 第四步:配置DHT11传感器的启动信号,主机主动拉低总线开始通信
ioqueue.setgpio(hw_timer_id, capture_pin, false, 0, 0)

-- 18000: 延时18ms,这是DHT11协议要求的启动信号最小时间
ioqueue.setdelay(hw_timer_id, 18000, 0, false)

-- 第五步:配置捕获参数,为接收传感器数据做准备,此命令仅配置参数,实际捕获需配合后续的capture()命令执行
-- 参数详解:
-- gpio.PULLUP: 设置引脚为上拉输入模式(释放总线控制权)
-- gpio.FALLING: 只捕获下降沿,捕获到后会记录io编号,电平高低,以及时间
-- 100000 * tick_us: 单个capture()命令的最大等待时间100ms,超时后继续执行后续命令,每个capture()都是独立的100ms等待窗口
ioqueue.set_cap(hw_timer_id, capture_pin, gpio.PULLUP, gpio.FALLING, 100000 * tick_us)
--[[关于一个捕获周期含义:
set_cap不等于开始捕获,只是配置参数捕获参数
其中set_cap配置的最大等待时间是防止因传感器故障导致程序永久卡住
开始:当执行 ioqueue.capture() 命令时开始一个捕获周期
结束:满足以下任一条件时结束:
    检测到下降沿 → 立即记录时间戳并结束本次捕获周期,然后执行下一条命令
    达到100ms超时 → 直接结束,不记录数据,然后执行下一条命令
    调用cap_done() → 强制结束命令队列
以上面代码为例:
在100ms内,一次下降沿也没有检测到,则直接结束,执行队列中的下一条命令
在100ms内,检测到一次下降沿,立即记录时间戳并结束,然后执行队列中的下一条命令;
]]

-- 第六步:预分配捕获缓冲区 ,对io操作队列增加42次捕获IO状态命令
for i = 1, 42, 1 do
   ioqueue.capture(hw_timer_id)
end

-- 停止捕获,不再监听该引脚的边沿变化
ioqueue.cap_done(hw_timer_id, capture_pin)

-- 恢复数据线为上拉输入状态,释放总线
ioqueue.setgpio(hw_timer_id, capture_pin, true, gpio.PULLUP)


-- 第七步:执行整个命令序列
-- 开始按顺序执行前面设置的所有命令
ioqueue.start(hw_timer_id)

-- 等待执行完成,系统会在完成时发布这个事件
-- 这是异步操作,不会阻塞其他任务
sys.waitUntil("IO_QUEUE_DONE_"..hw_timer_id)

-- 停止硬件定时器
ioqueue.stop(hw_timer_id)


-- 第八步:读取捕获的数据
cnt1, cnt2 = ioqueue.get(hw_timer_id, buff1, buff2)
-- 参数详解:
-- buff1: 存储输入数据的缓冲区
-- buff2: 存储捕获数据的缓冲区
-- cnt1: 读取io数据的数量,此返回值对应ioqueue.input()接口所配置的对读取gpio命令数量,此代码中是nil
-- cnt2: 捕获数据的数量(应该是42)

if cnt2 ~= 42 then
   log.info('test fail')
   goto TEST_OUT
end
-- 如果捕获数据不是42个,说明通信失败

-- 第九步:解析数据
-- 从捕获缓冲区读取第二个下降沿的时间戳
-- 数据结构:每个捕获点占6字节
-- 字节0: GPIO ID编号
-- 字节1: 电平状态(0=下降沿,1=上升沿)
-- 字节2-5: 32位时间戳(4字节)
-- 所以第二个捕获点在偏移量6处,时间戳在6+2处
lastTick = buff2:query(6 + 2, 4, false)


j = 0
bit = 8
buff1[0] = 0

for i = 2, 41, 1 do  -- 遍历40个数据位(跳过第1个下降沿的DHT11响应信号)
    -- 验证数据完整性
    if buff2[i * 6 + 0] ~= capture_pin or buff2[i * 6 + 1] ~= 0 then
         log.error("capture", i, buff2[i * 6 + 0], buff2[i * 6 + 1])
    end

    -- 计算时间间隔
    -- 当前位的时间戳
    nowTick = buff2:query(i * 6 + 2, 4, false)
    -- 左移1位,为新的数据位腾出空间
    buff1[j] = buff1[j] << 1

    -- DHT11数据编码原理:
    -- 每个数据位都以50us低电平开始
    -- 然后高电平持续时间不同:
    --   26-28us → 数据0
    --   70us    → 数据1
    -- bit1Tick 是100us阈值,总时间 > 100us → 判断为位1,≤ 100us → 判断为位0
    if (nowTick - lastTick) > bit1Tick then
         buff1[j] = buff1[j] + 1  -- 设置最低位为1
     end

     bit = bit - 1
     if bit == 0 then  -- 完成1字节(8位)
         j = j + 1     -- 移动到下一字节
         bit = 8       -- 重置位计数器
     end
     lastTick = nowTick  -- 更新参考时间戳
end

-- 第十步:数据校验
buff1[5] = buff1[0] + buff1[1] + buff1[2] + buff1[3]
-- DHT11协议:第5字节是前4字节的校验和
if buff1[4] ~= buff1[5] then
      log.info('check fail', buff1[4], buff1[5])
else
       log.info("湿度", buff1[0] .. '.' .. buff1[1], "温度", buff1[2] .. '.' ..  buff1[3])
       -- buff1[0]: 湿度整数部分
       -- buff1[1]: 湿度小数部分
       -- buff1[2]: 温度整数部分
       -- buff1[3]: 温度小数部分
       -- buff1[4]: 校验和
end

::TEST_OUT::
-- 释放硬件定时器资源,可以重新分配使用
ioqueue.release(hw_timer_id)

具体波形如下:

1.1.2 输出精确脉冲场景

需要不同的脉冲宽度、软件循环无法满足精度要求、需要连续输出大量脉冲

使用流程:

下面演示利用硬件定时器生成固定频率或可变宽度的精确脉冲序列,支持连续和单次延时模式,实现微秒级脉冲控制:

固定间隔脉冲

-- 第一步:初始化
-- 100个命令,循环1次(生成100个脉冲)
ioqueue.init(hw_timer_id, 100, 1)

-- 设置GPIO为输出模式,初始输出高电平
ioqueue.setgpio(hw_timer_id, out_pin, false, 0, 1)


-- 第二步:配置连续延时模式
ioqueue.setdelay(hw_timer_id, 20, tick_us - 3, true)


-- 第三步:生成脉冲序列
-- 每个循环生成1个完整周期:低电平20us + 高电平20us = 40us周期
for i = 0, 40, 1 do
    ioqueue.output(hw_timer_id, out_pin, 0)  -- 输出低电平
    ioqueue.delay(hw_timer_id)               -- 延时20us
    ioqueue.output(hw_timer_id, out_pin, 1)  -- 输出高电平
    ioqueue.delay(hw_timer_id)               -- 延时20us
end



-- 第四步:执行
ioqueue.start(hw_timer_id)
-- 等待执行完成,系统会在完成时发布这个事件
sys.waitUntil("IO_QUEUE_DONE_"..hw_timer_id)
-- 停止硬件定时器
ioqueue.stop(hw_timer_id)
-- 释放硬件定时器资源,可以重新分配使用
ioqueue.release(hw_timer_id)

可变宽度脉冲序列

log.info('output 2 start')
--测试高精度可变间隔定时输出
ioqueue.init(hw_timer_id, 100, 10)
--设置成输出口,电平1
ioqueue.setgpio(hw_timer_id, out_pin, false, 0, 1)
--单次延迟20us,如果不准,对time_tick微调
ioqueue.setdelay(hw_timer_id, 20, tick_us - 3)
--低电平
ioqueue.output(hw_timer_id, out_pin, 0)
--单次延迟30us
ioqueue.setdelay(hw_timer_id, 30, tick_us - 3)
--高电平
ioqueue.output(hw_timer_id, out_pin, 1)
--单次延迟40us
ioqueue.setdelay(hw_timer_id, 40, tick_us - 3)
--低电平
ioqueue.output(hw_timer_id, out_pin, 0)
--单次延迟50us
ioqueue.setdelay(hw_timer_id, 50, tick_us - 3)
--高电平
ioqueue.output(hw_timer_id, out_pin, 1)
--单次延迟60us
ioqueue.setdelay(hw_timer_id, 60, tick_us - 3)
--低电平
ioqueue.output(hw_timer_id, out_pin, 0)
--单次延迟70us
ioqueue.setdelay(hw_timer_id, 70, tick_us - 3)
--高电平
ioqueue.output(hw_timer_id, out_pin, 1)
ioqueue.start(hw_timer_id)
sys.waitUntil("IO_QUEUE_DONE_" .. hw_timer_id)
log.info('output 2 done')
ioqueue.stop(hw_timer_id)
ioqueue.release(hw_timer_id)
sys.wait(500)

二、核心示例

示例可参考 1.1.1 章节具体使用分析。

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

ioqueue 模块没有常量。

四、函数详解

ioqueue.init(hwtimer_id, cmd_cnt, repeat_cnt)

功能

初始化一个 io 操作队列。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:对于Air700EXX系列Air780EXX系列Air8000系列模组,硬件定时器有如下要求:
         硬件定时器id0-5,六个硬件定时器
         35固定被底层占用不可使用
         pwm功能依赖硬件定时器ioqueue不可与pwm功能同时使用
         pwm0对应0
         pwm4对应4
         以此类推
         Air6101/Air8101不支持此功能
是否必选:必须传入此参数;
注意事项:与pwm共用,同一个通道号不能同时为pwm和ioqueue
参数示例:0

cmd_cnt

参数含义:一个完整周期需要的命令数;可以比实际的多
数据类型:number
取值范围:1~65535
是否必选:必须传入此参数;
注意事项:命令是:
          ioqueue.setdelay添加的延时命令
          ioqueue.setgpio设置的gpio命令
          ioqueue.input的读取gpio命令
          ioqueue.output配置输出GPIO命令
          ioqueue.set_cap捕获gpio命令
参数示例:100

repeat_cnt

参数含义:重复次数;
数据类型:number
取值范围:默认是1,如果写0则表示无限次数循环;
是否必选:必须传入此参数;
注意事项:无
参数示例:1

返回值

无返回值。

示例

ioqueue.init(0, 10, 5) _--以timer0为时钟源初始化一个io操作队列,有10个有效命令,循环5次_

ioqueue.setdelay(hwtimer_id, time_us, time_tick, continue)

功能

对 io 操作队列增加延时命令。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

time_us

参数含义:延时时间(微秒);
数据类型:number
取值范围:0~65535
是否必选:必须传入此参数;
注意事项:无
参数示例:1000

time_tick

参数含义:延时微调时间;单位是tick,可通过mcu.hz()接口获取每秒的tick数量,然后可计算出1tick的时间
         例如:local hz = mcu.hz()
              --1tick时间通常比较小,可将秒化为微秒然后计算
              local tick_time = 1000000/hz
数据类型:number
取值范围:0~255tick
是否必选:必须传入此参数;
注意事项:总的延时时间是time_us * 1us_tick + time_tick
参数示例:100

continue

参数含义:是否连续延时;
数据类型:boolean
取值范围:true/false;默认false
是否必选:可选传入此参数;
注意事项:如果是连续延时,定时器在时间到后不会停止而是重新计时;
         连续延时表现:定时器周期性地重复计时,每次ioqueue.delay()调用都使用相同的延时值,
         调用ioqueue.stop()停止,或者命令队列执行完毕
         可以通过下面例子看出:
             如果次参数为false,则是直接将命令插入命令队列,
             如果此参数是true,则还需调用_ioqueue.delay()才会将命令插入命令队列_
参数示例:false

返回值

无返回值。

示例

_-- 单次延时模式 (continue = false)
ioqueue.setdelay(0, 1000, 0, false)  -- 延时1ms,仅生效一次
__ioqueue.delay(0)  -- 错误:前面没有连续延时配置,此调用无效_

_-- 连续延时模式 (continue = true)
ioqueue.setdelay(0, 1000, 0, true)   -- 配置1ms连续延时模板
ioqueue.delay(0)  -- 执行1ms延时
ioqueue.delay(0)  -- 再次执行1ms延时
__ioqueue.delay(0)  -- 继续执行1ms延时_

ioqueue.delay(hwtimer_id)

功能

对 io 操作队列增加一次重复延时,在前面必须有 setdelay 并且是连续延时。

注意事项

必须在前面的 ioqueue.setdelay 设置 continue=true

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

无返回值。

示例

_--延时9us+15个tick,在之后遇到delay命令时,会延时9us+15个tick_
ioqueue.setdelay(0, 9, 15, true)
--必须ioqueue.setdelay第四个参数设置为true,才可以使用ioqueue.delay,并且延时时长与ioqueue.setdelay所设置的一样
ioqueue.delay(0)

ioqueue.setgpio(hwtimer_id, pin, is_input, pull_mode, init_level)

功能

对 io 操作队列增加设置 gpio 命令。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:无
参数示例:1

is_input

参数含义:是否是输入模式;true为输出模式false为输出模式
数据类型:boolean
取值范围:true/false
是否必选:必须传入此参数;
注意事项:无
参数示例:true

pull_mode

参数含义:上下拉模式;
数据类型:number
取值范围:0, gpio.PULLUP, gpio.PULLDOWN;其中0是无上下拉
是否必选:必须传入此参数;
注意事项:当参数is_input为true时pull_mode这个参数才有意义
参数示例:gpio.PULLUP

init_level

参数含义:初始输出电平;
数据类型:number
取值范围:01
是否必选:必须传入此参数;
注意事项:当is_input为false时有效
参数示例:0

返回值

无返回值。

示例

ioqueue.setgpio(0, 17, true, gpio.PULLUP, 0) _--GPIO17设置成上拉输入_
ioqueue.setgpio(0, 17, false, 0, 1) _--GPIO17设置成默认上下拉输出高电平_

ioqueue.input(hwtimer_id, pin)

功能

对 io 操作队列增加读取 gpio 命令。

应用场景:在精确时序点读取 GPIO 电平状态

使用时必须先调用 ioqueue.setgpio 设置输入模式,然后通过 ioqueue.get()读取输入数据

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:该引脚必须已设置为输入模式;
参数示例:1

返回值

无返回值。读取的数据需要通过 ioqueue.get 获取。

示例

_    -- 创建缓冲区:input_buff 用于存储输入数据
    -- 数据格式: 每组数据包含 1字节(pin号) + 1字节(电平)
    local input_buff = zbuff.create(200) -- 缓冲区大小根据需要调整
    local capture_buff = zbuff.create(200) -- 本例未使用捕获功能,但ioqueue.get需要此参数

    -- 初始化io队列
    ioqueue.init(hw_timer_id, 50, 1)

    -- 第一步:将GPIO设置为输入模式,并配置上拉电阻
    ioqueue.setgpio(hw_timer_id, input_pin, true, gpio.PULLUP, 0)

    -- 第二步:添加一个延时,例如10毫秒
    ioqueue.setdelay(hw_timer_id, 10000, 0, false)

    -- 第三步:在此时序点添加一个GPIO输入读取命令
    ioqueue.input(hw_timer_id, input_pin)

    -- 可以继续添加更多操作,例如再次延时并读取
    ioqueue.setdelay(hw_timer_id, 5000, 0, false) -- 延时5ms
    ioqueue.input(hw_timer_id, input_pin) -- 再次读取

    -- 启动io操作队列
    ioqueue.start(hw_timer_id)

    -- 等待队列执行完成(异步操作)
    sys.waitUntil("IO_QUEUE_DONE_" .. hw_timer_id)

    -- 停止硬件定时器并获取结果
    ioqueue.stop(hw_timer_id)

    -- 从队列中获取输入和捕获的数据
    local input_cnt, capture_cnt = ioqueue.get(hw_timer_id, input_buff, capture_buff)

    -- 打印读取到的输入数据组数
    log.info("ioqueue", "输入数据组数:", input_cnt)

    -- 解析input_buff中的数据
    -- 数据格式: 每2个字节为一组 [pin号, 电平值]
    for i = 0, input_cnt - 1 do
        local offset = i * 2
        local pin_read = input_buff[offset]
        local level = input_buff[offset + 1]
        log.info("ioqueue", string.format("第%d次读取 - 引脚: %d, 电平: %d", i+1, pin_read, level))
    end

    -- 释放硬件定时器资源
__    ioqueue.release(hw_timer_id)_

ioqueue.output(hwtimer_id, pin, level)

功能

对 io 操作队列增加输出 GPIO 命令。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:该引脚必须已设置为输出模式;
参数示例:0

level

参数含义:输出电平;
数据类型:number
取值范围:01
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

无返回值。

示例

_-- 对GPIO17输出低电平_
ioqueue.output(0, 17, 0)

ioqueue.set_cap(hwtimer_id, pin, pull_mode, irq_mode, max_tick)

功能

对 io 操作队列增加设置捕获某个 IO 命令。

捕获的配置命令

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:无
参数示例:1

pull_mode

参数含义:上下拉模式;
数据类型:number
取值范围:0, gpio.PULLUP, gpio.PULLDOWN;其中0是无上下拉
是否必选:必须传入此参数;
注意事项:无
参数示例:gpio.PULLUP

irq_mode

参数含义:中断模式;
数据类型:number
取值范围:gpio.BOTH, gpio.RISING, gpio.FALLING
是否必选:必须传入此参数;
注意事项:gpio.BOTH参数仅Air780EXXX系列支持Air8000系列支持
参数示例:gpio.RISING

max_tick

参数含义:定时器最大计时时间,单位是tick,可通过mcu.hz()接口获取每秒的tick数量,然后可计算出1tick的时间
         例如:local hz = mcu.hz()
              --1tick时间通常比较小,可将秒化为微秒然后计算
              local tick_time = 1000000/hz
         作用:
         1.防止硬件定时器无限期等待;
         2.控制捕获过程的时间边界
         详细使用方法以及含义参考示例中的注释
数据类型:number
取值范围:最小0x10000, 最大值为0x7fffffff;默认:0x7fffffff
是否必选:可选传入此参数;
注意事项:无
参数示例:1000

返回值

无返回值。

示例

_-- 捕获指令_
--当执行到 ioqueue.capture() 命令时开始等待
--硬件立即开始监听GPIO 17的下降沿信号

--成功捕获:
-- 当GPIO 17从高电平→低电平时
-- 立即记录:引脚号 + 电平状态 + 精确时间戳
-- 立即停止本次捕获的定时器
-- 然后继续执行队列中的下一个命令
--当前捕获成功后就会自动停止本次的定时器计时,然后执行下一个命令

--超时停止:
-- 如果48000000 tick 内没有检测到任何下降沿
-- 自动停止等待,继续后续命令

--手动停止:
-- 通过调用ioqueue.cap_done结束捕获命令
ioqueue.set_cap(0, 17, gpio.PULLUP, gpio.FALLING, 48000000)

ioqueue.capture(hwtimer_id)

功能

对 io 操作队列增加捕获一次 IO 状态命令。

捕获的执行命令,必须先经过 ioqueue.set_cap 配置后才能使用 ioqueue.capture 来捕获,一个 set_cap 配置可以被多个 capture 命令复用

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:需要先使用ioqueue.set_cap设置捕获参数
参数示例:0

返回值

无返回值。捕获的数据需要通过 ioqueue.get 获取。

示例

ioqueue.capture(0)

ioqueue.cap_done(hwtimer_id, pin)

功能

对 io 操作队列结束捕获某个 IO 命令。

使用场景:

1.捕获任务完成时 :主动结束,告诉系统数据读取完成,停止 gpio 捕获

2.切换捕获目标时:比如从捕获 gpio1 切换到捕获 gpio2,需要先结束捕获 gpio1。

3.错误处理或者提前退出时调用。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:无
参数示例:1

返回值

无返回值。

示例

_-- 结束捕获_
ioqueue.cap_done(0, 17)

ioqueue.get(hwtimer_id, input_buff, capture_buff)

功能

获取 io 操作队列中输入和捕获的数据。

注意事项

input,set_cap,capture 这三个配置接口配置的功能,缓存到的输入数据和捕获数据,都是通过 get 接口来读取出来

input_buff ← 存储 ioqueue.input() 的即时电平采样结果

capture_buff ← 存储 ioqueue.capture() 的边沿事件 + 时间戳

input_cnt = 成功的 ioqueue.input() 操作数量

capture_cnt = 成功的 ioqueue.icapture() 操作数量(可能因超时而小于计划数)

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

input_buff

参数含义:存放IO输入数据的buff;由ioqueue.input接口设置读取电平命令所得来的
数据类型:zbuff
取值范围:按照1byte pin + 1byte level 形式存放数据;
是否必选:必须传入此参数;
注意事项:无
参数示例:buff1

capture_buff

参数含义:存放IO捕获数据的buff;由ioqueue.capture接口配置的捕获命令所得来的
数据类型:zbuff
取值范围:按照1byte pin + 1byte level + 4byte tick形式存放数据
是否必选:必须传入此参数;
注意事项:无
参数示例:buff2

返回值

local input_cnt, capture_cnt = ioqueue.get(hwtimer_id, input_buff, capture_buff)

input_cnt

含义说明:返回成功读取的IO输入数据组数
数据类型:number
取值范围:≥0

capture_cnt

含义说明:返回成功读取的IO捕获数据组数
数据类型:number
取值范围:≥0

示例

local input_cnt, capture_cnt = ioqueue.get(0, input_buff, capture_buff)

ioqueue.start(hwtimer_id)

功能

启动 io 操作队列。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

无返回值。

示例

ioqueue.start(0)

ioqueue.stop(hwtimer_id)

功能

停止 io 操作队列,可以通过 start 从头开始。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

local loop_cnt, cmd_cnt = ioqueue.stop(hwtimer_id)

loop_cnt

含义说明:返回已经循环的次数;
数据类型:number
取值范围:如果是0,表示一次循环都没有完成;

cmd_cnt

含义说明:返回当前循环中已执行的命令数量
数据类型:number
取值范围:0 ~ 队列总命令数
注意事项:如果是0,表示当前循环刚开始或刚结束;如果是M,当前循环执行到第M个命令时被停止

示例

local loops, cmds = ioqueue.stop(0)
log.info("IO Queue", "已循环次数:", loops, "已执行命令数:", cmds)

ioqueue.release(hwtimer_id)

功能

释放 io 操作队列的资源,下次使用必须重新 init。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

无返回值。

示例

ioqueue.release(0)

ioqueue.clear(hwtimer_id)

功能

清空 io 操作队列。

此接口重置了命令队列但保留了硬件定时器资源,可以直接添加新的命令。前提是你确信之前队列的状态完全被清空,且新的命令序列与之前的结构兼容。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

无返回值。

示例

ioqueue.clear(0)

ioqueue.done(hwtimer_id)

功能

检测 io 操作队列是否已经执行完成。

参数

hwtimer_id

参数含义:硬件定时器id
数据类型:number
取值范围:与初始化时使用的定时器id一致
是否必选:必须传入此参数;
注意事项:无
参数示例:0

返回值

local is_done = ioqueue.done(hwtimer_id)

is_done

含义说明:队列是否执行完成;
数据类型:boolean
取值范围:true/false

示例

local result = ioqueue.done(0)
if result then
    log.info("IO Queue", "执行完成")
else
    log.info("IO Queue", "执行中")
end

ioqueue.exti(pin, pull_mode, irq_mode, onoff)

功能

启动/停止一个带系统 tick 返回的外部中断。

ioqueue.exti 是一个独立的外部中断接口,与 ioqueue 队列系统完全分离,提供简单的 GPIO 边沿事件捕获功能。

使用场景:简单的按键检测、传感器状态监控、旋转编码器计数

参数

pin

参数含义:GPIO ID编号
数据类型:number
取值范围:根据具体硬件平台确定;
是否必选:必须传入此参数;
注意事项:无
参数示例:1

pull_mode

参数含义:上下拉模式;
数据类型:number
取值范围:0, gpio.PULLUP, gpio.PULLDOWN;其中0是无上下拉
是否必选:可选传入此参数;
注意事项:无
参数示例:gpio.PULLUP

irq_mode

参数含义:中断模式;
数据类型:number
取值范围:gpio.BOTH, gpio.RISING, gpio.FALLING
是否必选:可选传入此参数;
注意事项:gpio.BOTH参数仅Air780EXXX系列支持Air8000系列支持
参数示例:gpio.RISING

onoff

参数含义:开关状态;
数据类型:boolean
取值范围:true/false,默认false
是否必选:可选传入此参数;
注意事项:无
参数示例:true

返回值

无返回值。

示例

_-- 对GPIO17进行外部中断捕获_
ioqueue.exti(17, gpio.PULLUP, gpio.BOTH, true)

local _, level, tick_str = sys.waitUntil("IO_QUEUE_EXTI_17")
log.info( "按键事件发生","时间戳:", tick_str ,"电平:",level)

-- 临时禁用中断(如正在处理关键任务时)
ioqueue.exti(17, gpio.PULLUP, gpio.FALLING, false)

-- 重新启用
ioqueue.exti(17, gpio.PULLUP, gpio.FALLING, true)

_-- 关闭GPIO17的外部中断_
ioqueue.exti(17)

五、产品支持说明

仅支持 Air700EXX 系列、Air780EXX 系列、Air8000 系列模组,Air6101/Air8101 不支持此功能。