.NET Core 2.1树莓派上FileSystemWatcher监听GPIO无响应问题
解决树莓派.NET Core中FileSystemWatcher监听GPIO电平变化失效的问题
我之前在树莓派上用.NET Core做GPIO相关项目时,碰到过几乎一模一样的问题!折腾了好一阵子才搞明白根源,下面给你分享下解决思路和方案:
问题根源
Linux内核对sysfs下的GPIO文件(比如/sys/class/gpio/gpio21/value)的更新逻辑,和普通文件不一样:
- 当你手动修改
direction这类文件时,是通过编辑器重写整个文件内容,这种操作会触发inotify(FileSystemWatcher依赖的底层机制)的修改事件; - 但物理按键触发GPIO电平变化时,内核是直接在内存中修改value文件的内容,并没有触发inotify需要的文件系统元数据变化(比如文件大小、修改时间),所以FileSystemWatcher完全感知不到。
可行解决方案
方案1:改用轮询机制(简单直接)
既然文件系统监听不靠谱,最稳妥的方式就是定期读取value文件,对比前后值来判断电平变化。示例代码如下:
private string _lastGpioValue; private readonly string _gpioValuePath = "/sys/class/gpio/gpio21/value"; public void StartGpioMonitoring() { // 初始化记录初始状态 _lastGpioValue = File.ReadAllText(_gpioValuePath).Trim(); // 每隔100ms检查一次(可根据需求调整间隔) var pollingTimer = new Timer(CheckGpioState, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } private void CheckGpioState(object state) { try { var currentValue = File.ReadAllText(_gpioValuePath).Trim(); if (currentValue != _lastGpioValue) { _lastGpioValue = currentValue; // 触发你的业务逻辑 Console.WriteLine($"GPIO21状态变化:{currentValue}"); OnGpioStateChanged(currentValue); // 自定义事件 } } catch (IOException ex) { // 处理文件读取异常(比如GPIO未导出) Console.WriteLine($"读取GPIO状态失败:{ex.Message}"); } }
方案2:使用官方GPIO专用库(推荐)
微软提供了专门针对嵌入式设备的System.Device.Gpio库,它直接和内核GPIO子系统交互,完全不需要依赖文件系统监听,可靠性高得多。注意.NET Core 2.1需要使用兼容的旧版本(比如1.0.x系列):
using System.Device.Gpio; public void SetupGpioWithLibrary() { using var gpioController = new GpioController(); // 打开GPIO21,设置为输入模式 gpioController.OpenPin(21, PinMode.Input); // 注册电平变化回调(监听上升沿和下降沿) gpioController.RegisterCallbackForPinValueChangedEvent( 21, PinEventTypes.Falling | PinEventTypes.Rising, (sender, args) => { var isHigh = args.ConvertPinValueToBoolean(); Console.WriteLine($"GPIO21状态变化:{(isHigh ? "高电平" : "低电平")}"); // 这里写你的事件处理逻辑 }); // 保持程序运行,防止进程退出 Console.WriteLine("监听GPIO21中,按回车退出..."); Console.ReadLine(); }
这个库还支持配置上拉/下拉电阻,对物理按键防抖也有更好的支持,比自己造轮子靠谱太多。
方案3:尝试调整FileSystemWatcher参数(不推荐)
如果一定要用FileSystemWatcher,可以试试添加NotifyFilters.Size和NotifyFilters.LastWrite,同时监听Changed和Modified事件,但我当时测试下来这个方法稳定性极差,偶尔能触发但大部分时候还是失效,不推荐用于生产场景。
总结
GPIO的sysfs文件属于内核虚拟文件,和普通磁盘文件的更新机制差异很大,FileSystemWatcher本来就不是为这种场景设计的。优先推荐使用System.Device.Gpio库,次选轮询方案,能彻底解决你的问题。
内容的提问来源于stack exchange,提问作者Lawrence Lee
相关产品推荐
相关产品推荐

