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系列模组,硬件定时器有如下要求:
硬件定时器id:0-5,六个硬件定时器
3和5固定被底层占用不可使用
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;
取值范围:0或1;
是否必选:必须传入此参数;
注意事项:当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;
取值范围:0或1;
是否必选:必须传入此参数;
注意事项:无
参数示例: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 不支持此功能。