跳转至

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

常量含义:VBUSUSB唤醒脚,不支持输出;
数据类型: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 核心库。