news 2026/5/30 20:01:44

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【YFIOs】用C#开发硬件之GPIO操作

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

  • 深度适配 nanoFramework,完美支持使用 C# / VB.NET /进行二次开发,享受 .NET 生态的便利
  • 支持 ESP-IDF 与 MicroPython 等主流开发环境
  • 支持远程参数设置、固件 OTA 升级及在线调试
  • 多样化的设备对外接口及协议栈支持,可轻松对接各类 Modbus RTU 仪表、PLC 及智能传感器
核心参数
类别说明
MCUESP32-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功能类型用途
GPIO0BOOT 按钮输入(上拉)低电平触发
GPIO9RS485 TXUART1串口通信引脚
GPIO10RS485 RXUART1串口通信引脚
GPIO11RS232 TXUART2串口通信引脚
GPIO12RS232 RXUART2串口通信引脚
GPIO17I2C SDAI2CSHT30 温湿度传感器数据线
GPIO18I2C SCLI2CSHT30 温湿度传感器时钟线
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语句确保资源正确释放:

using(vargpio=newGpioController()){// 使用 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
usingSystem;usingSystem.Device.Gpio;usingSystem.Threading;namespaceGPIOTest.Drivers{publicclassLed:IDisposable{privatereadonlyGpioPin_pin;// GPIO引脚privatereadonlybool_activeLow;// 是否低电平点亮(true:低电平点亮,false:高电平点亮)privateTimer_blinkTimer;// 闪烁定时器privatebool_disposed;// 是否已释放资源privateint_onDurationMs=500;// 亮灯时间(毫秒)privateint_offDurationMs=500;// 熄灯时间(毫秒)publicintPinNumber=>_pin.PinNumber;// 获取LED引脚编号publicintOnDurationMs{get=>_onDurationMs;set=>_onDurationMs=value;}// 亮灯时间publicintOffDurationMs{get=>_offDurationMs;set=>_offDurationMs=value;}// 熄灯时间// 构造函数,初始化LED实例publicLed(GpioControllercontroller,intpinNumber,boolactiveLow=true){_activeLow=activeLow;_pin=controller.OpenPin(pinNumber,PinMode.Output);Off();}// 打开LED灯publicvoidOn(){_pin.Write(_activeLow?PinValue.Low:PinValue.High);}// 关闭LED灯publicvoidOff(){_pin.Write(_activeLow?PinValue.High:PinValue.Low);}// 切换LED灯状态publicvoidToggleLED(){_pin.Write(_pin.Read()==PinValue.High?PinValue.Low:PinValue.High);}// 闪烁LED灯(使用默认时间)publicvoidBlinkLED(){BlinkLED(_onDurationMs,_offDurationMs);}// 闪烁LED灯(指定亮/灭时间)publicvoidBlinkLED(intonMs,intoffMs){StopBlink();boolisOn=false;_blinkTimer=newTimer(_=>{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灯publicvoidStopBlink(){if(_blinkTimer!=null){_blinkTimer.Dispose();_blinkTimer=null;}}// 释放资源publicvoidDispose(){if(!_disposed){StopBlink();if(_pin!=null){_pin.Dispose();}_disposed=true;}}}}
Button.cs
usingSystem;usingSystem.Device.Gpio;usingSystem.Threading;namespaceGPIOTest.Drivers{// 按钮回调委托publicdelegatevoidButtonCallback(intpinNumber,boolisPressed);publicclassButton:IDisposable{privatereadonlyGpioPin_pin;// GPIO引脚privatereadonlybool_activeLow;// 是否低电平有效(true:按下低电平,false:释放高电平)privatebool_disposed;// 是否已释放资源privateTimer_initTimer;// 初始化延迟定时器privateButtonCallback_callback;// 按钮状态变化回调publicintPinNumber=>_pin.PinNumber;// 获取按钮引脚编号publicboolIsPressed=>_activeLow?_pin.Read()==PinValue.Low:_pin.Read()==PinValue.High;// 获取按钮当前状态// 构造函数,初始化按钮实例publicButton(GpioControllercontroller,intpinNumber,ButtonCallbackcallback,boolactiveLow=true,PinModepinMode=PinMode.InputPullUp){_activeLow=activeLow;_callback=callback;_pin=controller.OpenPin(pinNumber,pinMode);// 延迟订阅事件,等待引脚状态稳定_initTimer=newTimer(InitCallback,null,100,Timeout.Infinite);}// 延迟初始化回调privatevoidInitCallback(objectstate){if(_disposed)return;_pin.ValueChanged+=OnPinValueChanged;_initTimer.Dispose();_initTimer=null;}// GPIO引脚值变化事件处理privatevoidOnPinValueChanged(objectsender,PinValueChangedEventArgse){if(_disposed)return;// 低电平有效:Falling=按下,Rising=释放;高电平有效:相反boolisPressed=_activeLow?(e.ChangeType==PinEventTypes.Falling):(e.ChangeType==PinEventTypes.Rising);_callback?.Invoke(PinNumber,isPressed);}// 释放资源publicvoidDispose(){if(_disposed)return;_disposed=true;if(_initTimer!=null){_initTimer.Dispose();}_pin.ValueChanged-=OnPinValueChanged;_pin.Dispose();}}}
Program.cs
usingSystem;usingSystem.Device.Gpio;usingSystem.Diagnostics;usingSystem.Threading;usingGPIOTest.Drivers;namespaceGPIOTest{publicclassProgram{// 硬件引脚定义(参考YF3300_ESP32S3硬件配置)privateconstintYellowLEDPin=40;// 黄色LED - 网络状态指示privateconstintGreenLEDPin=39;// 绿色LED - 配网状态指示privateconstintButtonPin=0;// 按钮引脚publicstaticvoidMain(){Debug.WriteLine("=== LED双闪测试开始 ===");using(vargpio=newGpioController()){// 初始化黄色LED(快闪:亮500ms,熄灭1500ms)varyellowLed=newLed(gpio,YellowLEDPin,activeLow:true);Debug.WriteLine($"黄色LED (GPIO{YellowLEDPin}) - 快闪模式");yellowLed.BlinkLED(onMs:500,offMs:1500);// 初始化绿色LED(慢闪:亮200ms,灭200ms)vargreenLed=newLed(gpio,GreenLEDPin,activeLow:true);Debug.WriteLine($"绿色LED (GPIO{GreenLEDPin}) - 慢闪模式");greenLed.BlinkLED(onMs:200,offMs:200);// 初始化按钮,控制LED开关varbutton=newButton(gpio,ButtonPin,OnButtonChanged);Debug.WriteLine($"按钮 (GPIO{ButtonPin}) - 就绪");Thread.Sleep(Timeout.Infinite);}}// 按钮状态变化回调privatestaticvoidOnButtonChanged(intpinNumber,boolisPressed){if(isPressed){Debug.WriteLine($"按钮按下 - 引脚{pinNumber}");}else{Debug.WriteLine($"按钮释放 - 引脚{pinNumber}");}}}}

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/29 7:50:54

FreeRTOS Tickless模式实战:在STM32F103上实测功耗降低了多少?

FreeRTOS Tickless模式在STM32F103上的功耗优化实战1. 测试环境搭建与基准测量在嵌入式系统开发中,低功耗设计往往决定着产品的市场竞争力。我们选择STM32F103C8T6开发板作为测试平台,这款基于Cortex-M3内核的MCU在工业控制领域广泛应用,具有…

作者头像 李华
网站建设 2026/5/30 14:48:09

从零搭建自动化天文台:圆顶同步、PLC控制与远程观测实践

1. 项目概述:一个天文台的诞生几年前,我决定在后院搭建一个属于自己的天文台。这个念头源于无数次在寒风中调试设备、与突如其来的云层和光污染搏斗的挫败感。对于任何一个稍微深入一点的天文爱好者来说,一个固定的、受控的观测环境&#xff…

作者头像 李华
网站建设 2026/5/29 7:46:16

低预算先跑测试:投流公司常用小步快跑打法

一、先搞懂一个核心问题:低预算为什么还能跑得动很多投手有一个根深蒂固的观念:预算少就做不了测试。这个观念是错的。投流公司内部有一套通用的做法,叫“小步快跑”。它的逻辑很简单:用最低成本、最快速度跑通一个小实验&#xf…

作者头像 李华
网站建设 2026/5/29 7:44:03

微服务间的远程接口调用:OpenFeign 的使用

前言:OpenFeign 能做什么? OpenFeign 是一种声明式、模板化的 HTTP 客户端。在 Spring Cloud 中使用 OpenFeign ,可以做到使用 HTTP 请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法&a…

作者头像 李华
网站建设 2026/5/31 11:12:27

C166架构中sprintf浮点格式化异常的DPP寄存器问题解析

1. 问题现象与背景分析最近在C166开发环境中遇到一个奇怪的现象:使用sprintf函数格式化浮点数变量时,输出的字符串结果总是显示为零值。这个问题特别诡异,因为浮点变量的实际值明明在有效范围内,而且只有在使用自定义启动代码时才…

作者头像 李华