5.2 GPIO设备
2026/7/21大约 7 分钟
title: "5.2 GPIO设备"
shortTitle: "GPIO设备"
description: "OneOS GPIO/PIN 设备驱动详解,包括引脚模式配置、电平读写、外部中断绑定与完整使用示例"
icon: "fa6-solid:bolt"
author: 学习阁
date: 2026-07-18
category: 设备驱动
tag:
- 驱动
- GPIO
- PIN
- 中断
order: 3
5.2 GPIO设备
📚 本节导读
学习时长: 约 40 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: C 语言基础、MCU GPIO 基础知识、5.1 设备驱动框架
🎯 学习目标
- 理解 OneOS 中 GPIO 抽象为 PIN 设备的设计理念
- 掌握引脚模式(输出/输入/上拉/下拉/开漏)的配置方法
- 掌握引脚电平的读写操作
- 掌握外部中断的绑定、使能与解绑
- 了解原始操作(raw)与设备框架操作的差异
一、概述
GPIO(General Purpose Input/Output)是 MCU 最基本的数字 IO 接口。OneOS 将 GPIO 抽象为 PIN 设备,提供统一的引脚模式设置、电平读写、中断绑定功能。PIN 设备驱动位于 drivers/pin/ 目录下,核心头文件为 pin.h。
PIN 设备框架的特点:
- 统一抽象:将不同 MCU 平台的 GPIO 统一封装为 PIN 设备
- 模式丰富:支持推挽输出、开漏输出、浮空输入、上拉输入、下拉输入等模式
- 中断支持:支持上升沿、下降沿、双边沿、高电平、低电平五种中断触发模式
- 双接口:提供标准设备框架接口和原始操作(raw)接口两种使用方式
二、核心数据结构
2.1 PIN 设备结构体 os_device_pin_t
typedef struct os_device_pin
{
struct os_device parent; /* 继承自 os_device_t */
const struct os_pin_ops *ops; /* PIN 操作函数表 */
int base; /* 引脚基地址 */
} os_device_pin_t;PIN 设备继承自 os_device_t,将通用设备结构体作为第一个成员,实现面向对象风格的继承。
2.2 PIN 操作函数表 struct os_pin_ops
struct os_pin_ops
{
void (*pin_mode)(struct os_device *device, os_base_t pin, os_base_t mode);
void (*pin_write)(struct os_device *device, os_base_t pin, os_base_t value);
int (*pin_read)(struct os_device *device, os_base_t pin);
os_err_t (*pin_attach_irq)(struct os_device *device,
int32_t pin,
uint32_t mode,
void (*hdr)(void *args),
void *args);
os_err_t (*pin_detach_irq)(struct os_device *device, int32_t pin);
os_err_t (*pin_irq_enable)(struct os_device *device, os_base_t pin, uint32_t enabled);
};| 函数指针 | 说明 |
|---|---|
pin_mode | 设置引脚工作模式 |
pin_write | 设置引脚输出电平 |
pin_read | 读取引脚输入电平 |
pin_attach_irq | 绑定引脚中断回调函数 |
pin_detach_irq | 解绑引脚中断 |
pin_irq_enable | 使能/禁用引脚中断 |
2.3 辅助结构体
struct os_device_pin_mode
{
uint16_t pin; /* 引脚编号 */
uint16_t mode; /* 引脚模式 */
};
struct os_device_pin_status
{
uint16_t pin; /* 引脚编号 */
uint16_t status; /* 引脚状态 */
};
struct os_pin_irq_hdr
{
int16_t pin; /* 引脚编号 */
uint16_t mode; /* 中断触发模式 */
void (*hdr)(void *args); /* 中断回调函数 */
void *args; /* 回调函数参数 */
};三、引脚模式详解
3.1 输出模式
#define PIN_MODE_OUTPUT 0x00 /* 推挽输出 */
#define PIN_MODE_OUTPUT_OD 0x04 /* 开漏输出 */| 模式 | 说明 | 典型应用 |
|---|---|---|
PIN_MODE_OUTPUT | 推挽输出,可主动输出高低电平 | LED 驱动、继电器控制 |
PIN_MODE_OUTPUT_OD | 开漏输出,只能输出低电平或高阻态,需外接上拉电阻 | I2C 总线、电平转换 |
3.2 输入模式
#define PIN_MODE_INPUT 0x01 /* 浮空输入 */
#define PIN_MODE_INPUT_PULLUP 0x02 /* 上拉输入 */
#define PIN_MODE_INPUT_PULLDOWN 0x03 /* 下拉输入 */| 模式 | 说明 | 典型应用 |
|---|---|---|
PIN_MODE_INPUT | 浮空输入,引脚悬空时电平不确定 | 外部信号已确定电平的场景 |
PIN_MODE_INPUT_PULLUP | 内部上拉输入,悬空时默认为高电平 | 按键检测(按下为低电平) |
PIN_MODE_INPUT_PULLDOWN | 内部下拉输入,悬空时默认为低电平 | 按键检测(按下为高电平) |
3.3 禁用模式
#define PIN_MODE_DISABLE 0x08 /* 禁用引脚 */3.4 电平定义
#define PIN_LOW 0x00 /* 低电平 */
#define PIN_HIGH 0x01 /* 高电平 */3.5 中断模式
#define PIN_IRQ_MODE_RISING 0x00 /* 上升沿触发 */
#define PIN_IRQ_MODE_FALLING 0x01 /* 下降沿触发 */
#define PIN_IRQ_MODE_RISING_FALLING 0x02 /* 双边沿触发 */
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03 /* 高电平触发 */
#define PIN_IRQ_MODE_LOW_LEVEL 0x04 /* 低电平触发 */| 中断模式 | 说明 |
|---|---|
PIN_IRQ_MODE_RISING | 引脚从低电平变为高电平时触发 |
PIN_IRQ_MODE_FALLING | 引脚从高电平变为低电平时触发 |
PIN_IRQ_MODE_RISING_FALLING | 任意电平变化时触发 |
PIN_IRQ_MODE_HIGH_LEVEL | 引脚为高电平时持续触发 |
PIN_IRQ_MODE_LOW_LEVEL | 引脚为低电平时持续触发 |
3.6 中断使能
#define PIN_IRQ_DISABLE 0x00 /* 禁用中断 */
#define PIN_IRQ_ENABLE 0x01 /* 使能中断 */四、核心 API 详解
4.1 PIN 设备注册
int os_device_pin_register(int pin_base, const struct os_pin_ops *ops, void *user_data);- 注册 PIN 设备,通常由 BSP 层在初始化时调用
pin_base:引脚基地址ops:PIN 操作函数表- 返回值:注册成功返回
OS_EOK
4.2 设置引脚模式
void os_pin_mode(os_base_t pin, os_base_t mode);- 设置指定引脚的工作模式
pin:引脚编号mode:模式值,如PIN_MODE_OUTPUT、PIN_MODE_INPUT_PULLUP等
4.3 写引脚电平
void os_pin_write(os_base_t pin, os_base_t value);- 设置指定引脚的输出电平
pin:引脚编号value:PIN_LOW或PIN_HIGH
4.4 读引脚电平
int os_pin_read(os_base_t pin);- 读取指定引脚的当前电平
- 返回值:
PIN_LOW或PIN_HIGH
4.5 绑定中断回调
os_err_t os_pin_attach_irq(int32_t pin, uint32_t mode, void (*hdr)(void *args), void *args);- 为指定引脚绑定外部中断回调函数
pin:引脚编号mode:中断触发模式,如PIN_IRQ_MODE_FALLINGhdr:中断回调函数指针args:传递给回调函数的参数- 返回值:
OS_EOK成功,其他值失败
4.6 解绑中断
os_err_t os_pin_detach_irq(int32_t pin);- 解除指定引脚的中断绑定
- 返回值:
OS_EOK成功
4.7 使能/禁用中断
os_err_t os_pin_irq_enable(os_base_t pin, uint32_t enabled);- 使能或禁用指定引脚的中断
enabled:PIN_IRQ_ENABLE或PIN_IRQ_DISABLE
4.8 原始操作(Raw 接口)
void raw_os_pin_mode(os_base_t pin, os_base_t mode);
void raw_os_pin_write(os_base_t pin, os_base_t value);
int raw_os_pin_read(os_base_t pin);- 绕过 PIN 设备框架,直接操作底层硬件
- 适用于系统启动早期、设备框架尚未就绪时使用
- 参数与标准接口完全一致
五、使用示例
示例 1:LED 闪烁
#include <pin.h>
#include <os_task.h>
#define LED_PIN 13 /* 假设 LED 连接在引脚 13 */
void led_blink_task(void *arg)
{
/* 设置引脚为推挽输出模式 */
os_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
while (1)
{
/* 点亮 LED */
os_pin_write(LED_PIN, PIN_HIGH);
os_task_msleep(500);
/* 熄灭 LED */
os_pin_write(LED_PIN, PIN_LOW);
os_task_msleep(500);
}
}示例 2:按键输入检测
#include <pin.h>
#include <os_task.h>
#define KEY_PIN 5 /* 假设按键连接在引脚 5 */
void key_scan_task(void *arg)
{
int key_state;
int last_state = PIN_HIGH; /* 上拉输入,默认高电平 */
/* 设置引脚为上拉输入模式 */
os_pin_mode(KEY_PIN, PIN_MODE_INPUT_PULLUP);
while (1)
{
key_state = os_pin_read(KEY_PIN);
/* 检测下降沿(按键按下) */
if (last_state == PIN_HIGH && key_state == PIN_LOW)
{
os_kprintf("Key pressed!\r\n");
}
/* 检测上升沿(按键释放) */
else if (last_state == PIN_LOW && key_state == PIN_HIGH)
{
os_kprintf("Key released!\r\n");
}
last_state = key_state;
os_task_msleep(20); /* 20ms 消抖 */
}
}示例 3:外部中断处理
#include <pin.h>
#include <os_task.h>
#define IRQ_PIN 6 /* 中断引脚 */
/* 中断回调函数 */
static void pin_irq_callback(void *args)
{
uint32_t *count = (uint32_t *)args;
(*count)++;
os_kprintf("Interrupt triggered! Count: %d\r\n", *count);
}
void exti_demo(void)
{
static uint32_t irq_count = 0;
/* 设置引脚为上拉输入模式 */
os_pin_mode(IRQ_PIN, PIN_MODE_INPUT_PULLUP);
/* 绑定中断回调:下降沿触发 */
os_pin_attach_irq(IRQ_PIN, PIN_IRQ_MODE_FALLING, pin_irq_callback, &irq_count);
/* 使能中断 */
os_pin_irq_enable(IRQ_PIN, PIN_IRQ_ENABLE);
os_kprintf("External interrupt demo started. Waiting for trigger...\r\n");
/* 主循环中可以做其他事情 */
while (1)
{
os_task_msleep(1000);
os_kprintf("Main loop running, irq_count: %d\r\n", irq_count);
}
}示例 4:系统启动早期使用 Raw 接口
#include <pin.h>
/* 在系统启动早期、设备框架未就绪时使用 */
void early_board_init(void)
{
/* 直接操作硬件引脚,绕过设备框架 */
raw_os_pin_mode(13, PIN_MODE_OUTPUT);
raw_os_pin_write(13, PIN_HIGH);
raw_os_pin_mode(5, PIN_MODE_INPUT_PULLUP);
}📝 本节小结
本节介绍了 OneOS 中 GPIO 设备(PIN 设备)的使用方法,包括:
- PIN 设备结构:
os_device_pin_t继承自os_device_t,通过os_pin_ops操作函数表实现六种标准操作 - 引脚模式:支持推挽输出、开漏输出、浮空输入、上拉输入、下拉输入、禁用六种模式
- 电平读写:
os_pin_write和os_pin_read提供简洁的引脚读写接口 - 中断机制:支持五种中断触发模式,通过
os_pin_attach_irq绑定回调,os_pin_irq_enable控制使能 - 双接口模式:标准框架接口和原始 raw 接口,分别适用于设备框架就绪后和启动早期
GPIO 是嵌入式系统中最常用的外设接口,掌握 PIN 设备的使用是进行外围电路控制的基础。