控制 IO 有多種方式。 這裡說最簡單的方式。 Linux 下 一切皆文件。 所以 GPIO 也會是一個文件。通過操作文件,可以控制它。 貼入代碼。 1 using NewLife; 2 using NewLife.Log; 3 using System; 4 using System.Collec ...
控制 IO 有多種方式。
這裡說最簡單的方式。
Linux 下 一切皆文件。 所以 GPIO 也會是一個文件。通過操作文件,可以控制它。
貼入代碼。
1 using NewLife; 2 using NewLife.Log; 3 using System; 4 using System.Collections.Generic; 5 using System.IO; 6 using System.Linq; 7 using System.Text; 8 using System.Threading; 9 using System.Threading.Tasks; 10 11 namespace Linux 12 { 13 /// <summary>GPIO 組</summary> 14 public enum PinGroup : int 15 { 16 PA = 0, 17 PB = 1, 18 PC = 2, 19 PD = 3, 20 PE = 4, 21 PG = 5, 22 PH = 6, 23 PI = 7, 24 PJ = 6, 25 } 26 27 /// <summary>引腳輸入輸出模式</summary> 28 public enum PinDir 29 { 30 In = 0, 31 Out = 1, 32 } 33 34 /// <summary>簡單實現 GPIO 的讀寫,不包含中斷處理</summary> 35 public class SimpleGpio : DisposeBase 36 { 37 /// <summary> 保證 結尾有/ 的路徑</summary> 38 private static String _GpioBasePath = @"/sys/class/gpio/"; 39 40 /// <summary>GPIO 的目錄</summary> 41 public static String GpioBasePath 42 { 43 get { return _GpioBasePath; } 44 set 45 { 46 if (value == null) return; 47 if (value == "") return; 48 49 _GpioBasePath = value; 50 51 if (!_GpioBasePath.EndsWith("/")) _GpioBasePath += "/"; 52 } 53 } 54 55 /// <summary>方向</summary> 56 public PinDir Dir; 57 58 /// <summary>狀態</summary> 59 public Boolean Opened { get; private set; } = false; 60 61 /// <summary>名稱</summary> 62 public String Name { get; set; } 63 64 65 /// <summary>引腳編號</summary> 66 private int _PinIdx = -1; 67 68 /// <summary>引腳路徑</summary> 69 private String pinPath; 70 71 72 #region 構造 73 74 public SimpleGpio() { } 75 76 /// <summary></summary> 77 /// <param name="gp">gpio 組</param> 78 /// <param name="gpidx">組內編號</param> 79 public SimpleGpio(PinGroup gp, int gpidx) 80 { 81 _PinIdx = (int)gp * 32 + gpidx; 82 83 Name = "gpio" + _PinIdx; 84 } 85 86 /// <summary></summary> 87 /// <param name="idx">全局gpio index</param> 88 public SimpleGpio(int idx) 89 { 90 _PinIdx = idx; 91 92 Name = "gpio" + _PinIdx; 93 } 94 95 /// <summary>析構</summary> 96 protected override void OnDispose(bool disposing) 97 { 98 base.OnDispose(disposing); 99 100 UnexportPin(); 101 } 102 103 #endregion 104 105 #region 基礎操作 106 107 /// <summary></summary> 108 /// <param name="idx">全局gpio index</param> 109 public void SetPin(int idx) 110 { 111 _PinIdx = idx; 112 113 Name = "gpio" + _PinIdx; 114 } 115 116 /// <summary> </summary> 117 /// <param name="gp">gpio 組</param> 118 /// <param name="gpidx">組內編號</param> 119 /// <param name="dir">輸入/輸出</param> 120 public void SetPin(PinGroup gp, int gpidx, PinDir dir = PinDir.In) 121 { 122 _PinIdx = (int)gp * 32 + gpidx; 123 Dir = dir; 124 125 Name = "gpio" + _PinIdx; 126 } 127 128 129 /// <summary>打開</summary> 130 /// <returns></returns> 131 public Boolean Open() 132 { 133 pinPath = GpioBasePath + Name + "/"; 134 XTrace.WriteLine("打開 " + pinPath); 135 136 if (!pinPath.AsDirectory().Exists) 137 { 138 try 139 { 140 if (!ExportPin()) return false; 141 } 142 catch 143 { 144 XTrace.WriteLine(pinPath + "導出引腳出錯,請 檢查參數 和 許可權"); 145 return false; 146 } 147 } 148 149 // 寫入配置 150 var dir = new FileInfo(pinPath + "direction"); 151 if (!dir.Exists) { XTrace.WriteLine("direction 文件呢?"); return false; } 152 153 var str = Dir == PinDir.Out ? "out\n" : "in\n"; 154 dir.WriteBytes(str.GetBytes()); 155 156 Opened = true; 157 return true; 158 } 159 160 /// <summary>關閉</summary> 161 public void Close() 162 { 163 UnexportPin(); 164 165 Opened = false; 166 } 167 168 /// <summary>寫引腳狀態</summary> 169 /// <param name="value"></param> 170 public void Write(bool value) 171 { 172 if (!Opened) return; 173 174 if (Dir == PinDir.In) return; 175 176 var fi = new FileInfo(pinPath + "value"); 177 if (!fi.Exists) { XTrace.WriteLine("value 文件呢?"); return; } 178 179 if (value) 180 fi.WriteBytes("1\n".GetBytes()); 181 else 182 fi.WriteBytes("0\n".GetBytes()); 183 } 184 185 /// <summary>讀取狀態</summary> 186 /// <returns></returns> 187 public bool Read() 188 { 189 if (!Opened) return false; 190 191 var fi = new FileInfo(pinPath + "value"); 192 if (!fi.Exists) { XTrace.WriteLine("value 文件呢?"); return false; } 193 194 var v = fi.ReadBytes(0, 1); 195 if (v == null) return false; 196 if (v.Length == 0) return false; 197 if (v[0] == '0') return false; 198 199 return true; 200 } 201 202 #endregion 203 204 #region 輔助 205 /// <summary>導出引腳</summary> 206 /// <returns></returns> 207 public bool ExportPin() 208 { 209 if (!GpioBasePath.AsDirectory().Exists) 210 { 211 XTrace.WriteLine("基礎目錄 {0} 不存在", GpioBasePath); 212 return false; 213 } 214 215 var export = new FileInfo(GpioBasePath + "export"); 216 if (!export.Exists) 217 { 218 XTrace.WriteLine("export 文件不存在,請確認gpio目錄是否正確"); 219 return false; 220 } 221 222 var param = _PinIdx + "\n"; 223 export.WriteBytes(param.GetBytes()); 224 Thread.Sleep(100); 225 226 if (!pinPath.AsDirectory().Exists) 227 { 228 XTrace.WriteLine("導出失敗,請確認 Pin 是否正確"); 229 return false; 230 } 231 232 // XTrace.WriteLine("導出 {0},成功", Name); 233 return true; 234 } 235 236 /// <summary>取消導出引腳</summary> 237 public void UnexportPin() 238 { 239 var unexport = new FileInfo(GpioBasePath + "unexport"); 240 if (!unexport.Exists) 241 { 242 XTrace.WriteLine("unexport 文件不存在,請確認gpio目錄是否正確"); 243 return; 244 } 245 246 var param = _PinIdx + "\n"; 247 unexport.WriteBytes(param.GetBytes()); 248 } 249 #endregion 250 } 251 }View Code
問題1: 導出失敗,請確認 Pin 是否正確
問題有可能是沒有許可權導出。
查看 /sys/class/gpio/export 文件所屬組
只允許 root 用戶進行導出 IO 口。
需要用 root 用戶運行導出函數 ExportPin() 。
解決辦法: 使用 root 許可權運行程式 sudo xxxxx.
或者 切換到 root 用戶再執行。 su
註意: 一旦導出,直到關機,引腳文件都會一直存在。 即 多次運行不必每次都導出。
問題2: 沒有控制GPIO 的許可權。
解決辦法: 將當前用戶添加到 IO 用戶組。或者切換到 IO 用戶。方法同問題1.