03 GPIO
作者:拓毅恒
一、GPIO 概述
GPIO(General Purpose Input/Output)即通用输入/输出,是一种可以灵活配置的数字信号引脚,支持高电平(通常为 VCC)和低电平(通常为 GND)两种状态。
Air780EHV 提供了丰富的 GPIO 资源,支持多种工作模式,包括:
- 输出模式:控制 GPIO 输出高电平或低电平,用于驱动 LED、继电器等外部设备。
- 输入模式:读取 GPIO 外部输入的电平状态,用于检测按键、传感器等信号。
- 上拉/下拉模式:在输入模式下配置内部上拉或下拉电阻,提高信号稳定性。
- 中断模式:通过配置中断触发条件(上升沿、下降沿或双边沿),实现信号变化的实时响应。
GPIO 功能是嵌入式开发中最基础也是最常用的功能之一,掌握 GPIO 的各种工作模式和使用方法,对于实现各种控制逻辑和信号交互至关重要。
二、准备硬件环境
参考:Air780EHV 硬件环境清单,准备好硬件环境。
2.1 Air780EHV 核心板

三、准备软件环境
3.1 文章内容应用
在开始实践本示例之前,先筹备一下软件环境:
1. 烧录工具:Luatools 工具;
2. 内核固件:本demo开发测试时使用的固件为Air780EHV V2014 版本固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;
3. 脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHV/demo/gpio
4. LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。
准备好软件环境之后,接下来查看如何烧录项目文件到 780EHV 中,将本篇文章中演示使用的项目文件烧录到 Air780EHV 核心板中。
3.2 API 介绍
这里仅介绍本篇文档所使用的 API,详情请查看:API - gpio;API - pm
gpio.setup(pin, func, pull, irq)
配置 GPIO 引脚模式、功能和属性
gpio.get(pin)
读取 GPIO 引脚的当前电平状态
gpio.set(pin, level)
设置 GPIO 引脚的输出电平
gpio.debounce(pin, time)
配置 GPIO 引脚的防抖时间
gpio.count(pin)
读取 GPIO 引脚的中断触发次数(在计数模式下)
gpio.pulse(pin, pattern, count, delay)
通过 GPIO 引脚输出指定模式的脉冲序列
pm.power(device, enable)
控制系统电源和工作模式
四、GPIO 功能实现概述
本小节详细介绍 Air780EHV 核心板上 GPIO 各种功能模式的实现方法和核心代码逻辑。
4.1 GPIO 输出模式
GPIO 输出模式用于控制外部设备。
4.1.1 功能定义
配置 GPIO 引脚为输出模式,控制其输出高电平或低电平。
4.1.2 代码示例
local gpio_number = 26
gpio.setup(gpio_number, 1) -- 设置GPIO26为输出模式
local function controlgpio_task()
-- 开始演示GPIO输出功能
local count = 0
while true do
gpio.set(gpio_number, 1)
log.info("GPIO", "当前IO26电平设置为高",count)
sys.wait(1000)
gpio.set(gpio_number, 0)
log.info("GPIO", "当前IO26电平设置为低")
sys.wait(1000)
count = count + 1
end
end
-- 执行任务函数
sys.taskInit(controlgpio_task)
4.2 GPIO 输入模式
GPIO 输入模式用于读取外部信号,如按键状态、传感器输出等。
4.2.1 功能定义
配置一个 GPIO 引脚为输入模式,读取其电平状态,并将该状态反映到另一个作为输出的 GPIO 引脚上。
4.2.2 代码示例
-- 配置gpio24为输入模式
-- 配置GPIO26为输出模式
local inputpin = 24
local ledpin = 26
gpio.setup(inputpin, nil, gpio.PULLDOWN)
gpio.setup(ledpin, 1)
gpio.debounce(inputpin, 50)
--GPIO24检测到有高低电平输入后,会返回GPIO24当前获取到的电平为高还是低,高返回值为1,低返回值为0
--将这个返回值,传给GPIO26,为0 则GPIO26输出低电平,为1则输出高电平
local function controlgpio()
local level = 0
while true do
level = gpio.get(inputpin)
log.info("gpio","set netled level: ",level)
gpio.set(ledpin, level)
sys.wait(500)
end
end
sys.taskInit(controlgpio)
4.3 GPIO 上拉下拉模式
上拉下拉模式用于在输入状态下保持引脚的默认电平,防止信号不稳定。
4.3.1 功能定义
配置两个 GPIO 引脚,一个为上拉输入模式,一个为下拉输入模式,并定时读取它们的电平状态。
4.3.2 代码示例
-- 定义两个 GPIO 引脚
local gpio_pin1 = 2
local gpio_pin2 = 26
-- 按键防抖函数
gpio.debounce(gpio_pin1, 50)
gpio.debounce(gpio_pin2, 50)
-- 设置GPIO2引脚为上拉输入模式
gpio.setup(gpio_pin1, nil, gpio.PULLUP)
-- 设置GPIO26引脚为下拉输入模式
gpio.setup(gpio_pin2, nil, gpio.PULLDOWN)
local function gpiopulltask()
log.info("GPIO",gpio_pin1,"电平",gpio.get(gpio_pin1))
log.info("GPIO",gpio_pin2,"电平",gpio.get(gpio_pin2))
end
sys.timerLoopStart(gpiopulltask,1000)
4.4 GPIO 中断模式
中断模式允许 GPIO 在检测到特定信号变化时立即触发回调函数,无需持续轮询。
4.4.1 功能定义
配置 GPIO 引脚为中断模式,设置双边沿触发(上升沿和下降沿都触发),并在中断触发时执行回调函数当 GPIO24 的电平发生变化时,会触发中断并检测按键动作,在串口日志中打印短按(小于 3 秒)或长按(大于等于 3 秒)事件。
4.4.2 代码示例
-- 配置gpio24为中断模式,上升沿(gpio.RISING)和下降沿(gpio.FALLING)均触发(gpio.BOTH)
local gpio_pin = 24
-- gpio.debounce(gpio_pin, 100) -- 实际设计板子时,根据自己的需求可以更改防抖配置以及打开防抖
-- 按键状态变量
local long_press_threshold = 3000 -- 长按判断阈值,3秒
local current_state = 1 -- 跟踪当前按键状态,1为释放,0为按下
-- 定时器回调函数,处理长按事件
local function timer_callback(gpio_id)
log.info("按键检测", "长按事件", gpio_id)
end
-- 定义GPIO中断处理函数
local function gpio_irq_handler()
local pin_state = gpio.get(gpio_pin) -- 获取GPIO当前状态
-- 只有当状态发生变化时才处理
if pin_state ~= current_state then
current_state = pin_state -- 更新当前状态
if pin_state == 0 then
-- 按键按下
log.info("按键检测", "按键按下")
if not sys.timerIsActive(timer_callback, gpio_pin) then
-- 启动定时器,3秒后触发长按事件
sys.timerStart(timer_callback, long_press_threshold, gpio_pin)
end
elseif pin_state == 1 then
-- 按键释放
log.info("按键检测", "按键释放")
-- 如果定时器还在运行,说明是短按
if sys.timerIsActive(timer_callback, gpio_pin) then
sys.timerStop(timer_callback, gpio_pin)
log.info("按键检测", "短按事件")
end
end
end
end
-- 配置GPIO中断
gpio.setup(gpio_pin, gpio_irq_handler, gpio.PULLUP, gpio.BOTH)
4.5 GPIO 中断计数模式
中断计数模式专门用于统计外部信号的触发次数,适用于频率测量等应用场景。
4.5.1 功能定义
配置 GPIO 引脚为中断计数模式,定期统计中断触发次数。
4.5.2 代码示例
-- 配置gpio24为中断计数模式
-- 设置好后系统会自动记录中断触发次数。
local gpio_pin = 24
-- gpio.setup(gpio_pin, gpio.count, gpio.PULLUP, gpio.FALLING)
gpio.setup(gpio_pin, gpio.count)
-- 每隔1S统计一次中断触发的次数
local function countIrq()
while true do
sys.wait(1000)
-- 返回从上次调用该函数后到当前时刻的中断触发次数
log.info("irq cnt", gpio.count(gpio_pin)) -- 调用函数时会自动清空中断累计值
end
end
sys.taskInit(countIrq)
4.6 AGPIO 低功耗模式
AGPIO(Advanced GPIO)是一种特殊的 GPIO,可以在深度休眠模式下保持电平状态,适用于低功耗应用。
4.6.1 功能定义
比较普通 GPIO 和 AGPIO 在进入深度休眠模式前后的行为差异,展示 AGPIO 在低功耗模式下保持电平的特性。
4.6.2 代码示例
local gpio_number = 1 -- 普通GPIO GPIO号为1,休眠后掉电。
local Agpio_number = 26 -- AGPIO GPIO号为26,休眠后可保持电平。
gpio.setup(gpio_number, 1)
gpio.setup(Agpio_number, 1)
local function enterlowpower()
sys.wait(10000)
-- 关闭USB电源
pm.power(pm.USB, false)
-- 进入PSM+模式
pm.power(pm.WORK_MODE, 3)
end
sys.taskInit(enterlowpower)
4.7 GPIO 翻转测速模式
GPIO 翻转测速模式用于通过快速改变 GPIO 电平状态,生成特定模式的脉冲序列。
4.7.1 功能定义
配置 GPIO 引脚为输出模式,使用 gpio.pulse() 函数生成特定模式的电平变化序列,用于测试 GPIO 翻转速度或生成特定信号。
4.7.2 代码示例
-- 定义要使用的 GPIO 引脚
local test_gpio_number = 26
gpio.setup(test_gpio_number, 0, gpio.PULLUP)
local function gpiotoggletask()
sys.wait(100)
while true do
sys.wait(100)
-- 通过GPIO26脚输出输出8组电平变化
-- 0xA9就是输出的电平高低状态,即 10101001
gpio.pulse(test_gpio_number, 0xA9, 8, 0)
log.info("gpio----------->pulse")
end
end
sys.taskInit(gpiotoggletask)
五、功能演示
5.1 GPIO 输出模式演示
确保 main.lua 中保留 require "gpio_output_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

烧录完毕后,日志中会打印 IO26 电平高低变化的信息

实际测量也能看到电流每秒变化一次。

5.2 GPIO 输入模式演示
确保 main.lua 中保留 require "gpio_input_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

每 500 ms 读取一次 GPIO24 电平,打印并将采集到的电平设置到 GPIO26。

5.3 GPIO 上拉下拉模式演示
确保 main.lua 中保留 require "gpio_pull_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

在悬空状态下,上拉模式的 GPIO2 通常会读取到高电平(1),下拉模式的 GPIO26 通常会读取到低电平(0)
当日志输出显示 GPIO2 电平为 1,GPIO26 电平为 0 时,表示上拉下拉配置生效

当用杜邦线将 GPIO2 连接到 GND 时,其电平应变为 0


当用杜邦线将 GPIO26 连接到 VCC 时,其电平应变为 1


5.4 GPIO 中断模式演示
确保 main.lua 中保留 require "gpio_irq_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

用杜邦线触碰 GND 模拟按键按下,当 GPIO24 引脚上的电平发生变化时,中断处理函数会被触发,根据触碰时长,日志中会打印 "短按事件" 和 "长按事件"的信息。


5.5 GPIO 中断计数模式演示
确保 main.lua 中保留 require "gpio_irqcount_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

GPIO24 每 1 秒读取并打印一次中断触发次数


5.6 AGPIO 低功耗模式演示
确保 main.lua 中保留 require "agpio_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

初始阶段,两个 GPIO 引脚都输出高电平


当系统进入深度休眠模式后,普通 GPIO(GPIO2)的电平会丢失(变为不确定状态)

而 AGPIO(GPIO26)会保持高电平

5.7 GPIO 翻转测速模式演示
确保 main.lua 中保留 require "gpio_toggle_task" 语句,注释其他功能模块

使用 Luatools 将代码烧录到 Air780EHV 核心板

日志中会定期打印 "gpio----------->pulse" 信息

每组包含 8 个电平变化,随后有短暂的停顿,翻转一次所需时间大概 50ns

六、总结
本文档详细展示了 Air780EHV GPIO 各种功能模式的实现方法和使用场景。通过这些示例,我们可以看到:
- GPIO 输出模式:通过简单的电平控制,可以方便地驱动外部设备,实现基本的控制功能。
- GPIO 输入模式:用于读取外部信号,结合消抖功能可以稳定地检测按键等输入。
- GPIO 上拉下拉模式:通过内部电阻配置,提高输入信号的稳定性,防止悬空状态下的信号干扰。
- GPIO 中断模式:无需持续轮询,在信号变化时立即响应,提高系统效率和实时性。
- GPIO 中断计数模式:专门用于信号统计,适用于频率测量、脉冲计数等应用。
- AGPIO 低功耗模式:在深度休眠状态下保持电平,适用于低功耗场景中的特定输出需求。
- GPIO 翻转测速模式:通过生成特定模式的脉冲序列,可用于测试 GPIO 性能或产生控制信号。
掌握这些 GPIO 功能模式,将为 Air780EHV 的各种应用开发提供坚实的基础。用户可以根据实际需求,选择合适的 GPIO 模式,实现丰富的控制逻辑和信号交互功能。
七、常见问题
7.1 GPIO 引脚编号问题
问题:如何确定 Air780EHV 核心板上的物理引脚对应的 GPIO 编号?
解决方案:参考 Air780EHV 硬件手册或核心板原理图,查找物理引脚与 GPIO 编号的对应关系。通常,开发板上会标注主要 GPIO 的编号。
7.2 GPIO 输出无反应
问题:配置 GPIO 为输出模式后,输出电平无变化或设备无反应。
解决方案:
- 检查 GPIO 编号是否正确
- 确认 GPIO 未被其他功能占用
- 检查外部电路连接是否正确
- 对于驱动 LED 等设备,确保有限流电阻保护
7.3 IO 复用简介
由于固件特性的存在,LuatOS 的 io 复用默认是固定的,详细用法可以查看 GPIO 复用。