gpio - GPIO 操作
作者:拓毅恒
一、概述
GPIO(General Purpose Input/Output)即通用输入输出接口,是嵌入式系统中最常用的接口类型之一。它可以用于连接各种外部设备,如 LED、按键、传感器等,并通过软件控制这些设备的状态和行为。
LuatOS 提供了功能丰富的 GPIO 核心库,支持输入、输出、中断、电平捕获、脉冲输出等多种功能,满足各种应用场景的需求。
二、核心示例
1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的相关示例:demo/gpio。
local gpio_number = 27
LED = gpio.setup(gpio_number, 1) -- 设置GPIO27为输出模式
function led_test()
-- 开始呼吸灯
local count = 0
while 1 do
-- 呼吸灯程序
LED(1)
log.info("GPIO", "LED OPEN")
sys.wait(500)--点亮时间 500ms
LED(0)
log.info("GPIO", "LED CLOSE")
sys.wait(500)--熄灭时间 500ms
count = count + 1
end
end
sys.taskInit(led_test)
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;
如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;
3.1 GPIO电平常量
gpio.LOW
常量含义:低电平;
数据类型:number;
常量取值: 0;
示例代码:gpio.set(17, gpio.LOW);
适用产品型号:全支持;
gpio.HIGH
常量含义:高电平;
数据类型:number;
常量取值: 1;
示例代码:gpio.set(17, gpio.HIGH);
适用产品型号:全支持;
3.2 上下拉常量
gpio.PULLUP
常量含义:上拉;
数据类型:number;
常量取值: 1;
示例代码:gpio.setup(17, nil, gpio.PULLUP);
适用产品型号:全支持;
gpio.PULLDOWN
常量含义:下拉;
数据类型:number;
常量取值: 2;
示例代码:gpio.setup(17, nil, gpio.PULLDOWN);
适用产品型号:全支持;
3.3 中断触发方式常量
gpio.RISING
常量含义:上升沿触发;
数据类型:number;
常量取值: 0;
示例代码:gpio.setup(27, irqFunc, gpio.PULLUP, gpio.RISING);
适用产品型号:全支持;
gpio.FALLING
常量含义:下降沿触发;
数据类型:number;
常量取值: 1;
示例代码:gpio.setup(27, irqFunc, gpio.PULLUP, gpio.FALLING);
适用产品型号:全支持;
gpio.BOTH
常量含义:双向触发;
数据类型:number;
常量取值: 2;
示例代码:gpio.setup(27, irqFunc, gpio.PULLUP, gpio.BOTH);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
3.4 唤醒脚常量
gpio.WAKEUP0
常量含义:休眠唤醒脚0,不支持输出;
数据类型:number;
常量取值: 39;
示例代码:gpio.setup(gpio.WAKEUP0, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP1
常量含义:VBUS,USB唤醒脚,不支持输出;
数据类型:number;
常量取值: 40;
示例代码:gpio.setup(gpio.WAKEUP1, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP2
常量含义:USIM热插拔脚,不支持输出;
数据类型:number;
常量取值: 41;
示例代码:gpio.setup(gpio.WAKEUP2, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP3
常量含义:休眠唤醒脚3,与GPIO20是同一个引脚;
数据类型:number;
常量取值: 42;
示例代码:gpio.setup(gpio.WAKEUP3, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP4
常量含义:休眠唤醒脚4,与GPIO21是同一个引脚;
数据类型:number;
常量取值: 43;
示例代码:gpio.setup(gpio.WAKEUP4, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP5
常量含义:休眠唤醒脚5,与GPIO22是同一个引脚;
数据类型:number;
常量取值: 44;
示例代码:gpio.setup(gpio.WAKEUP5, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.WAKEUP6
常量含义:休眠唤醒脚6,不支持输出;
数据类型:number;
常量取值: 45;
示例代码:gpio.setup(gpio.WAKEUP6, nil);
适用产品型号:仅Air8000系列支持;
3.5 特殊功能引脚常量
gpio.AUDIOPA_EN
常量含义:音频PA使能脚,仅Air780EHV特有的引脚;
数据类型:number;
常量取值: 22;
示例代码:gpio.setup(gpio.AUDIOPA_EN, 0);
适用产品型号:仅Air780EHV支持;
gpio.PWR_KEY
常量含义:开机键,模组工作电压范围 3.3V-4.35V,内部上拉至 VBAT;
如果 PWRKEY 接地,此功能无法使用,芯片上电即开机;
PWRKEY 不接地时:
开机前:只能做输入,检测到 PWRKEY下降沿,模组启动上电流程;
开机后:
1. 作为中断输入使用,是否执行关机或者其它动作,由软件决定;
2. 软件可以检测上升沿和下降沿,也可以检测高电平和低电平;
3. 模组内部已上拉至VBAT,因此,不支持上下拉操作;
数据类型:number;
常量取值: 46;
示例代码:gpio.setup(gpio.PWR_KEY, nil);
适用产品型号:仅Air780EXXX系列支持,Air8000系列支持;
gpio.CHG_DET
常量含义:命名为CHG_DET,但实际功能同PWRKEY一样;
开机前用于开机,开机后用于中断输入检测,内部固定上拉至一个不对外开放的LDO_1.8V;
CHRG DET 开机前,下降沿触发模组开机;
CHRG DET 内部上拉,不可外接高电平,只能外接高阻、强下拉或弱下拉;
USB Vbus 可通过 MOS 管反向连接到 CHRG DET,实现插入 USB 线触发开机;
不实现插入 USB 线开机时:
开机前:只能做输入,检测到 CHG_DET下降沿,模组启动上电流程;
开机后:
1.开机后和PWRKEY一样的功能和特性;
2.开机后仅支持双向触发中断,不支持输出;
3.模组内部固定上拉至LDO_1.8V,因此,不支持上下拉操作;
数据类型:number;
常量取值: 45;
示例代码:gpio.setup(gpio.CHG_DET, nil);
适用产品型号:Air780Exx系列(780EPM/EHM除外)/Air8000系列支持;
四、函数详解
gpio.setup(pin, mode, pull, irq)
功能
设置 GPIO 引脚的功能,包括输入/输出模式、上下拉配置、中断触发方式等。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:17 表示设置 GPIO17;
mode
参数含义:输入输出模式;
数据类型:number或者nil或者function;
取值范围:数字0/1代表输出模式,0 输出低电平,1 输出高电平;
nil代表输入模式;
function代表中断模式;
gpio.count代表中断计数功能,中断时不回调(详情看下方gpio.count);
是否必选:必须传入此参数;
注意事项:不同模式下,GPIO 的操作方式不同,不能初始化输入模式,实际上使用输出模式;
参数示例:0 表示设置为输出模式,初始电平为低;
pull
参数含义:内部上拉下拉模式;
数据类型:number;
取值范围:gpio.PULLUP(上拉)、gpio.PULLDOWN(下拉)、0(开漏模式);
是否必选:可选传入此参数;如果没有传入此参数或者传入了 nil 类型,则遵循硬件默认配置;
注意事项:需要根据实际硬件选用合适的上下拉模式;
参数示例:gpio.PULLUP 表示启用内部上拉;
irq
参数含义:中断触发模式;
数据类型:number;
取值范围:gpio.RISING(上升沿)、gpio.FALLING(下降沿)、gpio.BOTH(双向触发);
是否必选:可选传入此参数;如果没有传入此参数或者传入了 nil 类型,则使用默认值 gpio.BOTH;
注意事项:仅在中断模式下有效,gpio.BOTH,并不是所有产品都支持,需参考常量详解中gpio.BOTH的说明;
参数示例:gpio.RISING 表示设置为上升沿触发;
返回值
local pin_func = gpio.setup(pin, mode, pull, irq)
pin_func
含义说明:输出模式返回设置电平的函数,输入模式和中断模式返回获取电平的函数;
数据类型:function;
取值范围:无特别限制;
注意事项:可以直接调用返回的函数来设置或获取电平;
返回示例:返回一个函数,调用该函数可以设置或获取 GPIO 的电平;
示例
-- 设置gpio17为输入
gpio.setup(17, nil)
-- 设置gpio17为输出,且初始化电平为低,使用硬件默认上下拉配置
gpio.setup(17, 0)
-- 设置gpio17为输出,且初始化电平为高
gpio.setup(17, 1)
-- 设置gpio27为中断,默认双向触发
function gpio_func(val, io_num)
log.info("io", io_num, val) -- 提醒,val并不代表触发方向,仅代表中断后某个时间点的电平,io_num是IO序号
end
gpio.setup(27, gpio_func, gpio.PULLUP)
-- 设置gpio27为中断,仅上升沿触发
gpio.setup(27, function(val)
print("IRQ_27", val) -- 提醒,val并不代表触发方向,仅代表中断后某个时间点的电平
end, gpio.PULLUP, gpio.RISING)
-- 设置gpio7为中断计数,获取 GPIO 的中断数量,并清空累计值。
gpio.setup(7, gpio.count)
-- 注意事项:
-- 当管脚为输入模式或中断,才能通过gpio.get()获取到电平
-- 当管脚为输出模式,才能通过gpio.set()设置电平
-- 当管脚为输出模式,通过gpio.get()总会得到0
-- 中断回调的val参数不代表触发方向, 仅代表中断后某个时间点的电平
-- 双向触发EC618不支持,BK7258不支持,BK7236不支持,EC718M支持
-- 默认设置下,中断是没有防抖时间的,可以通过gpio.set_debounce(pin, 50)来设置防抖时间
gpio.caplevel(pin, level, func)
功能
(仅输入模式可用)捕获 GPIO 引脚电平持续的时长,单位为微秒(us)。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:26 表示捕获 GPIO26 的电平;
level
参数含义:需要捕获的电平;
数据类型:number;
取值范围:gpio.HIGH(高电平)、gpio.LOW(低电平)、1(高电平)、0(低电平);
是否必选:必须传入此参数;
注意事项:捕获设定的 level 持续时间;
参数示例:1 表示捕获高电平的持续时间;
func
参数含义:完成捕获后的回调函数;
数据类型:function;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:回调函数仅在成功捕获一次完整的电平持续时间后执行一次,而不是每次检测到电平变化就执行;
回调函数仅一个参数,参数为捕获到的时间长度(number 型数值,单位 us);
参数示例:捕获到的时间:
function(us_int)
log.info("us_int:", us_int)
end;
返回值
local get_level = gpio.caplevel(pin, level, func)
get_level
含义说明:返回获取电平的函数;
数据类型:function;
取值范围:无特别限制;
注意事项:调用该函数可以获取当前 GPIO 的电平;
返回示例:返回一个函数,调用该函数可以获取 GPIO 的当前电平;
示例
gpio.setup(26, nil, gpio.PULLUP)
-- 回调函数会在每次成功捕获一段完整的高电平持续时间后执行一次
-- us_int参数为捕获到的高电平持续时间,单位为微秒
function gpio_test(us_int)
log.info("GPIO测试", "高电平持续时间:", us_int, "微秒")
end
gpio.caplevel(26, 1, gpio_test)
gpio.set(pin, value)
功能
(仅输出模式可用)设置 GPIO 引脚的输出电平,使用前需先用 gpio.setup 进行过一次初始化。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:17 表示设置 GPIO17 的电平;
value
参数含义:输出电平值;
数据类型:number;
取值范围:gpio.HIGH(高电平)、gpio.LOW(低电平)、1(高电平)、0(低电平);
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:1 表示设置为输出高电平;
返回值
无返回值。
示例
-- 注意!!! 仅输出状态下,这个函数才有效
-- 一定要先gpio.setup,起码执行过一次gpio.setup,才能使用本函数,但不需要每次都gpio.setup
-- 设置gpio17输出低电平
gpio.set(17, 0)
-- 设置gpio17输出高电平
gpio.set(17, gpio.HIGH)
gpio.get(pin)
功能
(仅输入模式和中断模式可用)获取 GPIO 引脚的当前电平,使用前需先用 gpio.setup 进行过一次初始化。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:17 表示获取 GPIO17 的电平;
返回值
local value = gpio.get(pin)
value
含义说明:输入电平值;
数据类型:number;
取值范围:gpio.HIGH(高电平,对应数值1)、gpio.LOW(低电平,对应数值0);
注意事项:仅输入模式或者中断模式状态下,这个函数才有效;
返回示例:1 表示当前输入电平为高电平;
示例
-- 注意!!! 仅输入模式或者中断模式状态下,这个函数才有效
-- 一定要先gpio.setup,起码执行过一次gpio.setup,才能使用本函数,但不需要每次都gpio.setup
-- 获取gpio17的当前输入电平
local value = gpio.get(17)
log.info("gpio", "GPIO17:", value)
gpio.close(pin)
功能
关闭 GPIO 引脚功能,恢复高阻输入态,并关掉中断。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:17 表示关闭 GPIO17;
返回值
无返回值,总是执行成功。
示例
-- 关闭gpio17
gpio.close(17)
gpio.toggle(pin)
功能
变换 GPIO 脚的输出电平,仅输出模式可用。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:16 表示切换 GPIO16 的电平;
返回值
无返回值。
示例
-- 注意!!! 仅输出状态下,这个函数才有效
-- 每500ms变换一次输出电平
gpio.setup(16, 0)
function gpio_test()
gpio.toggle(16)
end
sys.timerLoopStart(gpio_test, 500)
gpio.pulse(pin, level, len, delay)
功能
函数用于在同一个 GPIO 上输出一组脉冲。
注意事项 :
- 这是一个阻塞操作,不可以一次性输出太多脉冲,否则可能导致系统死机;
- 该函数仅适用于 GPIO 输出模式;
- len 参数的单位是 bit,高位在前。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:1 表示使用 GPIO1 输出脉冲;
level
参数含义:脉冲数据;
数据类型:number:表示以十六进制或十进制形式的数值,例如 0xA9 表示输出一个字节的数据
string:可以传入二进制字符串形式的脉冲数据;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:0xA9 表示输出一个字节的数据;
len
参数含义:脉冲长度;
数据类型:number;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:单位是 bit,高位在前;
参数示例:8 表示输出 8 位的脉冲;
delay
参数含义:高低电平延迟时间,0表示不延迟;
数据类型:number;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:用的软件 while 来 delay,这里的 delay 值是 while 循环次数,具体 delay 时间必须实际调试才知道,适用于时序要求不是特别严格的场景;
参数示例:当调用 gpio.pulse(1, 0xA9, 8, 10) 时:
0xA9的二进制是10101001
函数会依次输出高电平(1)、低电平(0)、高电平(1)、低电平(0)、高电平(1)、低电平(0)、低电平(0)、高电平(1)
每个电平变化后都会执行10次空循环作为延迟;
返回值
无返回值。
示例
-- 注意,len的单位是bit,高位在前,高低电平时间均是由delay决定。
-- 本API是阻塞操作,一次性最多输出5条脉冲!!! 否则有可能会死机!!!
-- 通过GPIO1脚输出输出8个电平变化,while循环次数是0,即不进行任何延迟
gpio.pulse(1, 0xA9, 8, 0)
-- 通过GPIO2输出16位数据0xAA55,每一位之间延迟5次循环
gpio.pulse(2, 0xAA55, 16, 5)
gpio.debounce(pin, ms, mode)
功能
设置 GPIO 的防抖参数,根据硬件 ticks(时钟滴答)来进行精确的时间计算,确保防抖时间的准确性。该函数是对 GPIO 输入信号进行预处理,可以与任何需要稳定输入信号的场景配合使用。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:7 表示设置 GPIO7 的防抖;
ms
参数含义:防抖时长;
数据类型:number;
取值范围:0~65555 ms,设置为 0 则关闭防抖;
是否必选:必须传入此参数;
注意事项:单位为毫秒;
参数示例:100 表示设置 100ms 的防抖时间;
mode
参数含义:防抖模式;
数据类型:number;
取值范围:0(冷却模式)、1(延时模式);
是否必选:可选传入此参数;如果没有传入此参数或者传入了 nil 类型,则使用默认值 0;
注意事项:0:触发中断后,马上上报一次,然后冷却ms个毫秒(具体时长看参数二)后,重新接受中断;
1:触发中断后,延迟ms个毫秒(具体时长看参数二),期间没有新中断且电平没有变化,上报一次;
参数示例:1 表示使用延时模式;
返回值
无返回值。
示例
-- 消抖模式,当前支持2种
-- 0 触发中断后,马上上报一次,然后冷却ms个毫秒后,重新接受中断
-- 1 触发中断后,延迟ms个毫秒,期间没有新中断且电平没有变化,上报一次
-- 开启防抖,模式0-冷却,中断后马上上报,但100ms内只上报一次
gpio.debounce(7, 100) -- 对应GPIO7
-- 开启防抖,模式1-延时,中断后等待100ms,期间若保持该电平了,时间到之后上报一次
-- 对应的,如果输入的是一个 50hz的方波,那么不会触发任何上报
gpio.debounce(7, 100, 1)
-- 关闭防抖,时间设置为0就关闭
gpio.debounce(7, 0)
gpio.count(pin)
功能
(仅中断计数模式可用)获取 GPIO 的中断数量,并清空累计值。
参数
pin
参数含义:GPIO 编号,必须是数值;
数据类型:number;
取值范围:产品支持的 GPIO,可以查询具体产品的硬件手册;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:10 表示获取 GPIO10 的中断计数;
返回值
local count = gpio.count(pin)
count
含义说明:从中断计数开始或上次获取计数后到当前的中断次数;
数据类型:number;
取值范围:无特别限制;
注意事项:中断计数最大值为uint32_t,即4294967295。调用此函数后会清空累计值;
返回示例:5 表示捕获到 5 次中断;
示例
log.info("irq cnt", gpio.count(10))
五、产品支持说明
支持 LuatOS 开发的所有产品都支持 gpio 核心库。