【YFIOs】用C#开发硬件之GPIO操作

YF3300-ESP32S3 是 YF3300 系列中面向高性能边缘计算与无线物联网场景的衍生型号。设备搭载 ESP32-S3-N16R8 双核处理器,原生支持 Wi-Fi 与蓝牙通信。主板采用工业级宽压与全隔离设计,并内置高精度温湿度传感器,非常适合需要本地复杂逻辑运算、无有线网络环境以及机箱环境监测的 IoT 应用场景。

  • 深度适配 nanoFramework,完美支持使用 C# / VB.NET /进行二次开发,享受 .NET 生态的便利
  • 支持 ESP-IDF 与 MicroPython 等主流开发环境
  • 支持远程参数设置、固件 OTA 升级及在线调试
  • 多样化的设备对外接口及协议栈支持,可轻松对接各类 Modbus RTU 仪表、PLC 及智能传感器
核心参数
类别 说明
MCU ESP32-S3-N16R8 (双核 Xtensa LX7,主频 240MHz)
存储 片内 16MB Flash,8MB PSRAM
按钮 系统启动键 (Boot) ×1,硬件复位键 ×1
LED指示灯 电源指示灯 (红色) ×1,通信指示灯 (黄色) ×1,用户自定义灯 (绿色) ×1
调试接口 Type-C USB 接口(自带 ESD 静电保护)
无线通信 Wi-Fi + 蓝牙 BLE 5.0(支持外接高增益天线)
有线通信 1路 RS-485 接口
1路 RS-232 接口
I/O 接口 2路 光耦隔离开关量输入
1路 继电器输出 :提供常开(NO)、常闭(NC)、公共端(COM)
环境采集 内置 1 路 SHT30 温湿度传感器
电源接口 1路工业接线端子 (9-24V DC)
YF3300-ESP32S3 基于 ESP32-S3-N16R8 芯片,提供 48 个 GPIO 引脚。本页列出开发板已使用的引脚功能映射,供开发时快速查阅。

引脚总览表

GPIO 功能 类型 用途
GPIO0 BOOT 按钮 输入(上拉) 低电平触发
GPIO9 RS485 TX UART1 串口通信引脚
GPIO10 RS485 RX UART1 串口通信引脚
GPIO11 RS232 TX UART2 串口通信引脚
GPIO12 RS232 RX UART2 串口通信引脚
GPIO17 I2C SDA I2C SHT30 温湿度传感器数据线
GPIO18 I2C SCL I2C SHT30 温湿度传感器时钟线
GPIO21 开关量输入 I1 输入 光耦隔离,低电平触发
GPIO39 绿色 LED 输出(低有效) 配网状态指示
GPIO40 黄色 LED 输出(低有效) 网络状态指示
GPIO47 开关量输入 I2 输入 光耦隔离,低电平触发
GPIO48 继电器 Q1 输出(高有效) 常开/常闭/公共端

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 语句确保资源正确释放:

csharp 复制代码
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
csharp 复制代码
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
csharp 复制代码
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
csharp 复制代码
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}");
            }
        }
    }
}

YFESP32开发板详细开发文档 https://docs.yfios.net/docs/sdk/yfesp32s3-sdk

相关推荐
不会C语言的男孩9 小时前
C++ Primer Plus 第3章:处理数据
开发语言·c++
一天 24h9 小时前
Python自定义迭代器:从入门到精通
开发语言·python·迭代器模式·学习方法·新人首发
Starry-sky(jing)10 小时前
Hermes Agent 接入 Qwen3.7-Max 报 401?OpenCode Go 模型路由源码级排查与修复
开发语言·人工智能·chrome·golang
likerhood10 小时前
Java 集合框架入门:List、Set、Queue 与 Map
java·开发语言·list
郝学胜-神的一滴10 小时前
系统设计 013:高并发系统缓存:从原理到实践全解析
java·开发语言·python·缓存·系统架构·php·软件构建
学困昇10 小时前
Linux 信号机制详解:从 Ctrl+C 到 SIGCHLD,一文理解进程信号
linux·c语言·开发语言·人工智能·面试
rayyy910 小时前
卡牌抽取游戏
开发语言·python
阿里嘎多学长10 小时前
2026-05-28 GitHub 热点项目精选
开发语言·程序员·github·代码托管
C#程序员一枚10 小时前
程序如何打Dump文件
c#