GPIO基础
概述
GPIO(通用输入输出)是嵌入式开发中最基础也是最重要的外设之一。YF3300-ESP32S3 开发板提供了丰富的 GPIO 资源,本章节将介绍如何使用 nanoFramework 进行 GPIO 编程,包括 LED 控制和按钮输入。
所需 NuGet 包
在 nanoFramework 项目中使用 GPIO 需要引用以下包:
| 包名 | 说明 |
|---|---|
nanoFramework.CoreLibrary | 基础类库(通常自动包含) |
nanoFramework.System.Device.Gpio | 核心 GPIO 操作库 |
nanoFramework.Runtime.Events | 事件运行时支持(下载 GPIO 核心库时自动包含) |
核心概念
GpioController
GpioController 是 nanoFramework 中 GPIO 操作的核心类,负责管理所有 GPIO 引脚的初始化、读写和释放。推荐使用 using 语句确保资源正确释放:
using (var gpio = new GpioController())
{
// 使用 GPIO 控制器进行引脚操作
}
PinMode(引脚模式)
nanoFramework 的 System.Device.Gpio 模块支持 8 种 GPIO 模式,分为输入模式和输出模式两大类:
输入模式(3种)
| 模式 | 说明 | 适用场景 |
|---|---|---|
PinMode.Input | 浮空输入(高阻态) | 外部已接上拉/下拉电阻的输入场景 |
PinMode.InputPullUp | 内部上拉输入 | 按钮、开关,未按下时为高电平 |
PinMode.InputPullDown | 内部下拉输入 | 按钮、开关,未按下时为低电平 |
输出模式(5种)
| 模式 | 说明 | 适用场景 |
|---|---|---|
PinMode.Output | 推挽输出 | LED、继电器等需要较强驱动能力的场景 |
PinMode.OutputOpenDrain | 开漏输出 | I2C 总线、漏极开路通信协议 |
PinMode.OutputOpenDrainPullUp | 开漏+内部上拉 | 需要上拉电阻的开漏总线 |
PinMode.OutputOpenSource | 开极输出(推挽互补) | 需要低侧驱动的场景 |
PinMode.OutputOpenSourcePullDown | 开极+内部下拉 | 需要下拉电阻的推挽总线 |
关于模拟输入(ADC):nanoFramework 并未省略 ADC 功能,而是将其独立为
System.Device.Adc模块。System.Device.Gpio专门处理数字信号(开关量),而模拟信号读取需要使用System.Device.Adc模块。
PinValue(引脚值)
| 值 | 说明 | 电压范围(典型) |
|---|---|---|
PinValue.High | 高电平 | 接近 VCC(3.3V) |
PinValue.Low | 低电平 | 接近 GND(0V) |
PinEventTypes(中断事件类型)
用于检测引脚电平变化的中断事件:
| 事件类型 | 说明 |
|---|---|
PinEventTypes.None | 无事件 |
PinEventTypes.Rising | 上升沿(低→高) |
PinEventTypes.Falling | 下降沿(高→低) |
注意:.NET nanoFramework 官方定义的 PinEventTypes 枚举中没有提供“双边沿触发 (Both)”选项。但双边沿触发可通过
Rising | PinEventTypes.Falling位运算实现。
综合示例:LED 与按钮控制
硬件连接说明
LED
YF3300-ESP32S3 开发板板载 2 个 LED,均采用低电平点亮方式:
| LED 名称 | 颜色 | GPIO 引脚 | 功能说明 |
|---|---|---|---|
| 通信指示灯 | 黄色 | GPIO40 | 网络状态指示(CommLED) |
| 用户指示灯 | 绿色 | GPIO39 | 用户自定义(UserLED) |
按钮
YF3300-ESP32S3 开发板板载 1 个 BOOT 按钮,采用上拉输入方式:
| 按钮名称 | GPIO 引脚 | 连接方式 | 功能说明 |
|---|---|---|---|
| BOOT 按钮 | GPIO0 | 上拉输入 | 系统启动/配网触发 |
注意:未按下时引脚为高电平,按下时为低电平。
代码示例
Led.cs
using System;
using System.Device.Gpio;
using System.Threading;
namespace GPIOTest.Drivers
{
public class Led: IDisposable
{
private readonly GpioPin _pin; // GPIO引脚
private readonly bool _activeLow; // 是否低电平点亮(true:低电平点亮,false:高电平点亮)
private Timer _blinkTimer; // 闪烁定时器
private bool _disposed; // 是否已释放资源
private int _onDurationMs = 500; // 亮灯时间(毫秒)
private int _offDurationMs = 500; // 熄灯时间(毫秒)
public int PinNumber => _pin.PinNumber; // 获取LED引脚编号
public int OnDurationMs { get => _onDurationMs; set => _onDurationMs = value; } // 亮灯时间
public int OffDurationMs { get => _offDurationMs; set => _offDurationMs = value; } // 熄灯时间
// 构造函数,初始化LED实例
public Led(GpioController controller,int pinNumber,bool activeLow = true)
{
_activeLow = activeLow;
_pin = controller.OpenPin(pinNumber, PinMode.Output);
Off();
}
// 打开LED灯
public void On()
{
_pin.Write(_activeLow ? PinValue.Low : PinValue.High);
}
// 关闭LED灯
public void Off()
{
_pin.Write(_activeLow ? PinValue.High : PinValue.Low);
}
// 切换LED灯状态
public void ToggleLED()
{
_pin.Write(_pin.Read() == PinValue.High ? PinValue.Low : PinValue.High);
}
// 闪烁LED灯(使用默认时间)
public void BlinkLED()
{
BlinkLED(_onDurationMs, _offDurationMs);
}
// 闪烁LED灯(指定亮/灭时间)
public void BlinkLED(int onMs, int offMs)
{
StopBlink();
bool isOn = false;
_blinkTimer = new Timer(_ =>
{
if (isOn)
{
Off();
if (_blinkTimer != null) _blinkTimer.Change(offMs, Timeout.Infinite);
}
else
{
On();
if (_blinkTimer != null) _blinkTimer.Change(onMs, Timeout.Infinite);
}
isOn = !isOn;
}, null, 0, Timeout.Infinite); // 立即开始闪烁
}
// 停止闪烁LED灯
public void StopBlink()
{
if (_blinkTimer != null)
{
_blinkTimer.Dispose();
_blinkTimer = null;
}
}
// 释放资源
public void Dispose()
{
if (!_disposed)
{
StopBlink();
if(_pin != null)
{
_pin.Dispose();
}
_disposed = true;
}
}
}
}
Button.cs
using System;
using System.Device.Gpio;
using System.Threading;
namespace GPIOTest.Drivers
{
// 按钮回调委托
public delegate void ButtonCallback(int pinNumber, bool isPressed);
public class Button : IDisposable
{
private readonly GpioPin _pin; // GPIO引脚
private readonly bool _activeLow; // 是否低电平有效(true:按下低电平,false:释放高电平)
private bool _disposed; // 是否已释放资源
private Timer _initTimer; // 初始化延迟定时器
private ButtonCallback _callback; // 按钮状态变化回调
public int PinNumber => _pin.PinNumber; // 获取按钮引脚编号
public bool IsPressed => _activeLow ? _pin.Read() == PinValue.Low
: _pin.Read() == PinValue.High; // 获取按钮当前状态
// 构造函数,初始化按钮实例
public Button(GpioController controller, int pinNumber, ButtonCallback callback, bool activeLow = true, PinMode pinMode = PinMode.InputPullUp)
{
_activeLow = activeLow;
_callback = callback;
_pin = controller.OpenPin(pinNumber, pinMode);
// 延迟订阅事件,等待引脚状态稳定
_initTimer = new Timer(InitCallback, null, 100, Timeout.Infinite);
}
// 延迟初始化回调
private void InitCallback(object state)
{
if (_disposed) return;
_pin.ValueChanged += OnPinValueChanged;
_initTimer.Dispose();
_initTimer = null;
}
// GPIO引脚值变化事件处理
private void OnPinValueChanged(object sender, PinValueChangedEventArgs e)
{
if (_disposed) return;
// 低电平有效:Falling=按下,Rising=释放;高电平有效:相反
bool isPressed = _activeLow ? (e.ChangeType == PinEventTypes.Falling)
: (e.ChangeType == PinEventTypes.Rising);
_callback?.Invoke(PinNumber, isPressed);
}
// 释放资源
public void Dispose()
{
if (_disposed) return;
_disposed = true;
if (_initTimer != null)
{
_initTimer.Dispose();
}
_pin.ValueChanged -= OnPinValueChanged;
_pin.Dispose();
}
}
}
Program.cs
using System;
using System.Device.Gpio;
using System.Diagnostics;
using System.Threading;
using GPIOTest.Drivers;
namespace GPIOTest
{
public class Program
{
// 硬件引脚定义(参考YF3300_ESP32S3硬件配置)
private const int YellowLEDPin = 40; // 黄色LED - 网络状态指示
private const int GreenLEDPin = 39; // 绿色LED - 配网状态指示
private const int ButtonPin = 0; // 按钮引脚
public static void Main()
{
Debug.WriteLine("=== LED双闪测试开始 ===");
using (var gpio = new GpioController())
{
// 初始化黄色LED(快闪:亮500ms,熄灭1500ms)
var yellowLed = new Led(gpio, YellowLEDPin, activeLow: true);
Debug.WriteLine($"黄色LED (GPIO{YellowLEDPin}) - 快闪模式");
yellowLed.BlinkLED(onMs: 500, offMs: 1500);
// 初始化绿色LED(慢闪:亮200ms,灭200ms)
var greenLed = new Led(gpio, GreenLEDPin, activeLow: true);
Debug.WriteLine($"绿色LED (GPIO{GreenLEDPin}) - 慢闪模式");
greenLed.BlinkLED(onMs: 200, offMs: 200);
// 初始化按钮,控制LED开关
var button = new Button(gpio, ButtonPin, OnButtonChanged);
Debug.WriteLine($"按钮 (GPIO{ButtonPin}) - 就绪");
Thread.Sleep(Timeout.Infinite);
}
}
// 按钮状态变化回调
private static void OnButtonChanged(int pinNumber, bool isPressed)
{
if (isPressed)
{
Debug.WriteLine($"按钮按下 - 引脚{pinNumber}");
}
else
{
Debug.WriteLine($"按钮释放 - 引脚{pinNumber}");
}
}
}
}