4x4矩陣鍵盤掃描
Windows 10 IoT Core 是微軟針對物聯網市場的一個重要產品,與以往的Windows版本不同,是為物聯網設備專門設計的,硬件也不僅僅限於x86架構,同時可以在ARM架構上運行。
上一章我們講了 Win10 IoT 如何對本地 IoT 設備內嵌 SQLite 數據庫進行 CURD 操作 ,這章我們來學習如何使用 GPIO Pin 掃描4x4矩陣鍵盤按鍵狀態。如果對安裝部署過程還不熟悉可以參考前幾篇文章,Raspberry安裝 IoT系統及搭建開發環境(http://www.cnblogs.com/cloudtech/p/5562120.html),創建 IoT應用及三種部署方法(http://www.cnblogs.com/cloudtech/p/5637983.html)。
准備工作:
刷好Win 10 IoT Core系統的 Raspberry Pi 2
部署Visual Studio 2015開發環境的PC
4x4矩陣鍵盤
GPIO擴展板
IDC排線
杜邦線
面包板

實驗目標: 在4x4矩陣鍵盤上按下按鍵后,在程序界面上顯示對應的按鍵字符。
1.安裝元器件
首先將 GPIO擴展板 安裝到面包板上,再通過 IDC排線 與 Raspberry Pi 2 的 GPIO 接口連接。

4x4矩陣鍵盤電路圖

行線R0-3分別與Pin5、Pin6、Pin13、Pin19 引腳連接。
列線C0-3分別與Pin12、Pin16、Pin20、Pin21 引腳連接。

2.編寫代碼
打開 VS 2015 點擊 New Project 在Visual C# -> Windows -> Universal 中找到 Blank App (Universal Windows) 項目模板,選中模板輸入項目名稱后點擊OK按鈕創建項目。

項目創建完成后,在Reference Manager Extensions中 勾選Windows IoT Extensions for the UWP 添加 IoT擴展。

程序啟動后獲取默認GPIO控制器,對引腳進行初始化。
行線R0-3設置為輸入端,20ms延時消抖,檢測到高電平認為有按鍵按下,對列線逐一掃描確認。
列線C0-3設置為輸出端高電平。
鍵碼映射表如下

行線R0-3對應鍵碼低4位。
列線C0-3對應鍵碼高4位。
這里為了簡便把MainPage.cs作為ViewModel,來實現INotifyPropertyChanged接口完成一個簡易的MVVM框架。
代碼如下:
namespace CloudTechIot6
{
//http://www.cnblogs.com/cloudtech
//cloudtechesx@gmail.com
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
#region Fileds
//GPIO控制器
//Gpio Controller
private GpioController _gpioController;
//引腳集合
//Pin Collection
private GpioPin[] _pins;
//鍵碼表
//KeyCode Table
private Dictionary<byte, char> _keyMaps;
private bool _initCompleted;
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Properties
private string _msg;
//鍵碼
//Key Code
public string Msg
{
get
{
return _msg;
}
set
{
_msg = value;
OnPropertyChanged(this, new PropertyChangedEventArgs("Msg"));
}
}
public string FreshTime
{
get
{
return _freshTime;
}
set
{
_freshTime = value;
OnPropertyChanged(this, new PropertyChangedEventArgs("FreshTime"));
}
}
private string _freshTime;
#endregion
#region Constructor
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
_initCompleted = false;
_keyMaps = new Dictionary<byte, char>();
InitKeyMaps();
//獲取默認GPIO控制器
//Get Default Gpio Controller
_gpioController = GpioController.GetDefault();
if (null == _gpioController)
{
throw new Exception("GpioController init failed");
}
//初始化 GPIO Pin
//Init GPIO 引腳
_pins = new GpioPin[] { _gpioController.OpenPin(5), _gpioController.OpenPin(6), _gpioController.OpenPin(13), _gpioController.OpenPin(19), _gpioController.OpenPin(12), _gpioController.OpenPin(16), _gpioController.OpenPin(20), _gpioController.OpenPin(21) };
for (int i = 0; i < 8; i++)
{
//設置為輸入並監聽引腳電平變化
//set input mode and listen pin level change
if (i < 4)
{
_pins[i].SetDriveMode(GpioPinDriveMode.Input);
_pins[i].DebounceTimeout = TimeSpan.FromMilliseconds(20);
_pins[i].ValueChanged += (GpioPin sender, GpioPinValueChangedEventArgs args) =>
{
lock (this)
//高電平
//high level
if (_initCompleted && GpioPinEdge.RisingEdge == args.Edge)
//掃描列線
//scan column pin
for (int j = 4; j < 8; j++)
{
_pins[j].Write(GpioPinValue.Low);
if (GpioPinValue.Low == sender.Read())
{
//獲取生成鍵碼並輸出到界面
//generate keycode and print on UI
Msg = _keyMaps[(byte)((1 << ToIndex(sender)) | (1 << j))].ToString();
FreshTime = DateTime.Now.ToString("HH:mm:ss");
_pins[j].Write(GpioPinValue.High);
break;
}
_pins[j].Write(GpioPinValue.High);
}
};
}
//設置為輸出高電平
//set output high level
else
{
_pins[i].SetDriveMode(GpioPinDriveMode.Output);
_pins[i].Write(GpioPinValue.High);
}
}
Msg = "Push Button";
//初始化完成
//initialize completed
_initCompleted = true;
}
#endregion
#region Methods
//MVVM依賴屬性通知事件
private async void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { PropertyChanged?.Invoke(sender, e); });
}
//初始化鍵碼表
//initialize keycode
private void InitKeyMaps()
{
_keyMaps.Add(0x88, '1');
_keyMaps.Add(0x84, '2');
_keyMaps.Add(0x82, '3');
_keyMaps.Add(0x81, 'A');
_keyMaps.Add(0x48, '4');
_keyMaps.Add(0x44, '5');
_keyMaps.Add(0x42, '6');
_keyMaps.Add(0x41, 'B');
_keyMaps.Add(0x28, '7');
_keyMaps.Add(0x24, '8');
_keyMaps.Add(0x22, '9');
_keyMaps.Add(0x21, 'C');
_keyMaps.Add(0x18, '*');
_keyMaps.Add(0x14, '0');
_keyMaps.Add(0x12, '#');
_keyMaps.Add(0x11, 'D');
}
//獲取行線索引
//get row pin index
private int ToIndex(GpioPin pin)
{
int result = -1;
for (int i = 0; i < _pins.Length; i++)
{
if (pin.Equals(_pins[i]))
{
result = i;
break;
}
}
if (0 > result)
{
throw new Exception("Unknow Pin Index");
}
else
{
return result;
}
}
#endregion
}
}
3.調試代碼
為Raspberry連接電源及網線,連接HDMI顯示器。接通電源待系統啟動完成后顯示器上會顯示當前IoT設備的IP地址。
在 Visual Studio 2015 的工具欄中選擇 Remote Machine 進行調試,IP地址輸入設備對應地址。點擊運行后會自動部署到設備上。
![]()
這里要注意平台要選擇ARM。
程序啟動后按下4x4矩陣鍵盤上的按鍵后,程序界面上顯示對應的按鍵字符,與預期結果一致。


到這里C#操作 Win10 IoT設備的4x4矩陣鍵盤過程就完成了,如果對代碼有優化的建議,歡迎留言或發郵件給我(cloudtechesx@gmail.com)。也可以掃描下面的二維碼加我的微信號查看以前的文章。
完整項目源碼 GitHub https://github.com/CloudTechx/CloudTechIot 的 CloudTechIot6 目錄下。
Win10 IoT C#開發 1 - Raspberry安裝IoT系統及搭建開發環境 http://www.cnblogs.com/cloudtech/p/5562120.html
Win10 IoT C#開發 2 - 創建基於XAML的UI程序 及 應用的三種部署方法 http://www.cnblogs.com/cloudtech/p/5637983.html
Win10 IoT C#開發 3 - GPIO Pin 控制發光二極管 http://www.cnblogs.com/cloudtech/p/5617902.html
Win10 IoT C#開發 4 - UART 串口通信 http://www.cnblogs.com/cloudtech/p/5518306.html
Win10 IoT C#開發 5 - 操作 IoT 設備內嵌 SQLite 數據庫 CURD http://www.cnblogs.com/cloudtech/p/5657123.html


