跳转至

gpio开发指南

本文档以 gpio_demo 为例,带你在 HiDiTing 开发板上快速跑通第一个 GPIO(通用输入输出)控制应用,并了解如何基于它构建自己的应用。


GPIO 驱动背景知识

GPIO 工作原理

GPIO(通用输入输出)是微控制器最基本的数字接口,可配置为输入或输出模式:

功能 说明 应用场景
输出模式 通过软件控制引脚输出高电平或低电平 控制 LED、蜂鸣器、继电器
输入模式 读取引脚上的电平状态(高或低) 读取按键、传感器信号、开关信号
设置方向 将引脚配置为输入模式或输出模式 动态切换引脚功能、复用引脚控制
电平反转 将当前输出电平取反 闪烁 LED、脉冲信号生成

设置方向说明:

  • 设置方向是 GPIO 操作的基础步骤,决定了引脚是用于输出控制还是输入读取。
  • 通过 uapi_gpio_set_dir(pin, direction) 接口配置:
    • GPIO_DIRECTION_OUTPUT:配置为输出模式
    • GPIO_DIRECTION_INPUT:配置为输入模式
  • 在输出和电平反转操作前,必须先将引脚方向设置为输出模式。

操作流程

本示例支持四种 GPIO 操作,每种操作都遵循标准的初始化流程:

通用初始化步骤(所有操作共享):

  1. PIN 初始化:调用 uapi_pin_init() 初始化 PIN 模块。
  2. GPIO 初始化:调用 uapi_gpio_init() 初始化 GPIO 模块。
  3. 设置 GPIO 模式:调用 uapi_pin_set_mode(pin, PIN_MODE_0) 将引脚配置为 GPIO 功能。

各操作特有流程:

操作 流程
GPIO 输出 设置方向为输出 → 设置输出电平 → 读取电平验证
GPIO 输入 使能输入 → 读取电平 → 关闭输入使能
设置方向 根据参数设置输出或输入方向
电平反转 设置方向为输出 → 设置初始电平 → 调用反转函数 → 读取电平验证

接口说明:本示例基于AT命令框架实现,通过串口发送AT指令控制GPIO,每个操作函数都封装了完整的初始化、配置、操作和验证流程。

电平值说明

宏定义 说明
GPIO_LEVEL_HIGH 1 高电平
GPIO_LEVEL_LOW 0 低电平

快速跑通 GPIO Demo

功能说明

GPIO Demo 通过 AT 命令方式提供交互式控制,支持以下命令:

AT 命令 功能 参数说明
AT+GPIOOUTPUT=pin,level GPIO 输出电平 pin: 引脚号(0-5), level:电平( 0-1)
AT+GPIOINPUT=pin GPIO 输入电平 pin: 引脚号(0-5)
AT+GPIOSETDIR=pin,dir 设置 GPIO 方向 pin: 引脚号(0-5), dir: 0(输入)/1(输出)
AT+GPIOTOGGLE=pin,level GPIO 电平反转 pin: 引脚号(0-5), level:电平( 0-1)

编译

完成一站式 CLI 环境配置后执行:

# 编译固件,编译生成的固件从 output/3322/fwpkg 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build

构建成功后,使用一站式 CLI 烧写固件并打开 UART2 串口监视器。以下为 Windows USB DFU 示例;将 COM3 替换为实际日志串口,其他平台和串口烧写参数参见一站式 CLI 开发环境使用指南

fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000

使用方式

  1. 烧录固件并启动设备
  2. 通过串口发送 AT 命令,格式如下:

    # GPIO 输出示例:设置 pin 0 输出高电平
    AT+GPIOOUTPUT=0,1
    
    # GPIO 输入示例:读取 pin 0 的电平
    AT+GPIOINPUT=0
    
    # 设置方向示例:将 pin 0 设置为输出
    AT+GPIOSETDIR=0,1
    
    # 电平反转示例:将 pin 0 从低电平反转为高电平
    AT+GPIOTOGGLE=0,0
    

通过串口发送 AT 命令,格式如下

预期结果

GPIO 输出(AT+GPIOOUTPUT)

GPIO 输出(AT+GPIOOUTPUT)

GPIO 输入(AT+GPIOINPUT)

GPIO 输入(AT+GPIOINPUT)

GPIO 设置方向(AT+GPIOSETDIR)

GPIO 设置方向(AT+GPIOSETDIR)

GPIO 电平反转(AT+GPIOTOGGLE)

GPIO 电平反转(AT+GPIOTOGGLE)


文件结构与代码走读

文件职责

文件 作用
samples/native_samples/gpio/CMakeLists.txt 定义 gpio_sample 组件及驱动依赖。
samples/native_samples/gpio/gpio.h 定义串口测试参数结构和命令表。
samples/native_samples/gpio/gpio.c 实现输入、输出、方向设置、电平翻转和资源释放。
samples/native_samples/gpio/README.md 给出完整命令和预期结果。

关键参数与常量

名称 作用 开发注意事项
pin 指定 GPIO 编号。 使用前核对原理图、复用关系和目标电压域。
PIN_MODE_0 当前 Sample 使用的 GPIO 复用模式。 不同引脚的 GPIO 复用模式可能不同,应以 pinctrl 配置为准。
GPIO_DIRECTION_INPUT / GPIO_DIRECTION_OUTPUT 设置输入或输出方向。 方向必须在读写电平前配置。
GPIO_LEVEL_LOW / GPIO_LEVEL_HIGH 表示低、高电平。 不要用未经范围检查的业务参数直接转换为电平枚举。
PIN_IE_ENABLE 打开输入使能。 输入场景结束后按产品资源策略关闭输入使能。

gpio_args_tgpio_intput_args_tgpio_setdir_args_t 是 AT 适配层参数,不是 GPIO 驱动要求的业务数据结构。

核心业务流程

  1. 调用 uapi_pin_init()uapi_gpio_init(),再用 uapi_pin_set_mode() 将目标引脚切换到 GPIO 功能。
  2. 输出场景先设置 GPIO_DIRECTION_OUTPUT,再写入并回读电平;输入场景先打开输入使能,再读取电平。
  3. 翻转场景先设置已知输出电平,再调用 uapi_gpio_toggle() 并回读确认结果。
  4. 每一步检查返回值;失败和正常退出都按实际所有权释放 pin 和 GPIO 资源。

AT 命令表只负责参数校验和调用转发。自定义应用不复制四套 AT 处理函数,直接在任务、服务或 UI 事件中复用上述初始化、操作和释放顺序;可构建的 app_run 示例见下一节。

基于 GPIO Demo 开发自己的应用

上面的demo是使用AT指令触发运行,HiDiTing还支持app_run方式触发应用在系统启动时自动运行,以下示例将以app_run的方式开发一个开发者自己的应用

  • app_run(func) 是HiDiTing中应用层注册应用函数的宏,基于 GCC 编译器属性和自定义段区(section)自动注册来实现集中调用应用函数,系统启动时会自动遍历所有用 app_run 注册过的函数并执行,无需在 系统 main 函数里逐个调用函数。

代码清单

新建一个 GPIO 控制应用(以 my_gpio_demo 为例)通常只需要以下改动:

  • 新建 my_gpio_demo.c 源文件
  • 新建 my_gpio_demo.h 头文件
  • 新建 CMakeLists.txt 源文件
  • my_gpio_demo.c 中实现GPIO操作函数
  • my_gpio_demo.h 中定义宏常量和函数声明
  • CMakeLists.txt 源文件编译规则

my_gpio_demo文件结构:

/samples/native_samples/my_gpio_demo/
├── my_gpio_demo.c
├── my_gpio_demo.h
└── CMakeLists.txt

CMakeLists.txt 修改示例

# 在新建的 CMakeLists.txt 中添加应用的源文件
set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/my_gpio_demo.c
)

set(PUBLIC_HEADER
    ${CMAKE_CURRENT_SOURCE_DIR}
)

set(PRIVATE_HEADER

)

set(PUBLIC_DEFINES
    MY_GPIO_DEMO_ENABLE
)

build_component()

关键代码片段

my_gpio_demo.c —— GPIO 控制实现

#include "my_gpio_demo.h"
#include "pinctrl.h"
#include "pinctrl_porting.h"
#include "errcode.h"
#include "hal_gpio.h"
#include "debug_print.h"
#include "driver/gpio.h"
#include "driver/pinctrl.h"
#include "app_init.h"
#include "soc_osal.h"

#define GPIO_TEST_PIN    1   // 测试使用的引脚号
#define TASK_PRIO        26
#define TASK_STACK_SIZE  0x1000

static void *my_gpio_task(const char *arg)
{
    unused(arg);
    printf("my_gpio_demo start\n");

    // 初始化
    uapi_pin_init();
    uapi_gpio_init();
    uapi_pin_set_mode(GPIO_TEST_PIN, PIN_MODE_0);

    // 设置为输出模式
    uapi_gpio_set_dir(GPIO_TEST_PIN, GPIO_DIRECTION_OUTPUT);

    // 输出高电平
    uapi_gpio_set_val(GPIO_TEST_PIN, GPIO_LEVEL_HIGH);
    printf("gpio set high\n");

    // 读取并验证
    gpio_level_t level = uapi_gpio_get_val(GPIO_TEST_PIN);
    printf("read level: %d\n", level);

    // 翻转电平
    uapi_gpio_toggle(GPIO_TEST_PIN);
    level = uapi_gpio_get_val(GPIO_TEST_PIN);
    printf("after toggle, read level: %d\n", level);

    printf("my_gpio_demo done\n");
    return NULL;
}

static void my_gpio_entry(void)
{
    osal_task *task_handle = NULL;
    osal_kthread_lock();
    task_handle = osal_kthread_create((osal_kthread_handler)my_gpio_task, 0, "MyGpioTask", TASK_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, TASK_PRIO);
    }
    osal_kthread_unlock();
}

app_run(my_gpio_entry);

测试验证

完成一站式 CLI 环境配置后执行:

# 编译固件,编译生成的固件从 output/3322/fwpkg 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build
1. 烧录固件并启动设备 2. 通过串口观察输出日志:

通过串口观察输出日志

说明

  • 因为app_run是在系统启动时运行应用,所以应用的运行日志会被夹在开机启动日志中。

  • 为使该gpio应用参与编译,还需在上层CMakeLists.txt文件中以宏MY_GPIO_DEMO_ENABLE为条件添加该my_gpio_demo文件。

  • MY_GPIO_DEMO_ENABLE默认关闭。如需启用新建GPIO示例功能,需要在config.py中的diting-community配置项下将其打开。

app_run运行配置

app_run应用默认是关闭的,如需启用此应用,需用户手动在acore.prelds文件中添加 KEEP (*(SORT(.zinitcall.app_run*.init))) 具体参考示意图如下:

apprun运行配置

acore.prelds


注意事项

引脚配置注意事项:

  • GPIO 引脚号范围为 0-5,具体引脚对应的物理引脚请参考芯片手册。
  • 使用前必须依次调用 uapi_pin_init()uapi_gpio_init() 完成初始化。
  • 必须调用 uapi_pin_set_mode(pin, PIN_MODE_0) 将引脚配置为 GPIO 模式。

输入模式注意事项:

  • 读取输入电平前,必须调用 uapi_pin_set_ie(pin, PIN_IE_ENABLE) 使能输入功能。
  • 读取完成后,建议调用 uapi_pin_set_ie(pin, PIN_IE_DISABLE) 关闭输入使能。

电平反转注意事项:

  • 反转操作前必须将引脚设置为输出模式。
  • 反转后的电平应与初始电平不同,否则操作失败。

AT 命令注意事项:

  • 命令名称为大写字母,如 GPIOOUTPUT
  • 参数使用逗号分隔,如 AT+GPIOOUTPUT=0,1
  • 参数范围:pin 为 0-5,level 为 0/1。

常见错误

错误现象 原因 解决方法
undefined reference to 'uapi_gpio_init' 未链接 GPIO 驱动库 检查 CMakeLists.txt 中是否正确添加了头文件路径
undefined reference to 'uapi_at_cmd_table_register' 未链接 AT 命令库 检查 CMakeLists.txt 中是否正确添加了 AT 相关头文件路径
编译报 at_ret_t 未定义 未包含 at.h 头文件 添加 #include "at.h"
串口无输出 AT 命令未注册 确认调用了 at_diting_gpio_example_cmd_register()
引脚无响应 引脚未正确初始化 确认依次调用了 uapi_pin_init()uapi_gpio_init()uapi_pin_set_mode()
输入读取异常 输入使能未开启 确认调用了 uapi_pin_set_ie(pin, PIN_IE_ENABLE)