【物联网智能网关-05】扫描键盘编程设计

本文介绍在.NET MicroFramework环境下,如何利用STM32F207实现扫描键盘功能,包括扫描和中断两种方式,并展示了如何将扫描键盘应用于WPF应用程序中。

.NET Micro Framework模拟器提供了5个模拟按键(上、下、左、右和确认按键),所以一般.NET MF开发板也只需要提供5个按键就可以了,而这5个键,也是直接和CPU的pin脚相连,用GPIO的输入相关的函数就可以操作了,使用非常简单。

但是对一些特殊的应用,如一些.NET Micro Framework教育箱或一些工业实际用的系统,5个按键显然太少了点。但是如果需要十几个按键,如果直连芯片pin脚,显然占用的资源比较多了,也会导致其它的功能无法使用了,这时候最常用的就是扫描键盘了。


上述扫描键盘的原理图应该是最简单的一种了,复杂一点的,在行或列上,通过一个上拉电阻接VCC。这样,我们只需要8个pin脚,就可以获取16个按键的信息了。

一般实现的思路也比较简单:就是把行(或列)接芯片输出pin脚,把列(或行)接芯片输入pin脚,输出pin脚依次输出低(或高,需要看电路中接的上拉还是下拉电阻)电平,然后检查输入pin脚的电平变化。如果有变化,那么就说明,该列和该行的按键被按下了。

往往这个判断就放在while循环或线程里,不断的去运行。对一些单片而言,如果实现的功能单一,这样做也无可厚非,但是对一个系统平台来说,如果也这样做,显然对系统的资源占用还是比较厉害的。

所以最好的办法还是要采用中断的方式,平时的时候不去判断,靠中断触发,一旦中断触发了,然后再启动一轮判断,确定是哪一个按键被按下了。

1、扫描方式实现按键获取

public class ScanKeypad

{

public event NativeEventHandlerOnInterrupt;

OutputPort[]rows = null;

InputPort[]cols = null;

publicScanKeypad(Cpu.Pin[]Output_Pins, Cpu.Pin[]Input_Pins)

{

rows = newOutputPort[] { newOutputPort(Output_Pins[0], false), new OutputPort(Output_Pins[1], false), new OutputPort(Output_Pins[2], false), new OutputPort(Output_Pins[3], false) };

cols = newInputPort[] { newInputPort(Input_Pins[0], true, Port.ResistorMode.PullUp), newInputPort(Input_Pins[1], true, Port.ResistorMode.PullUp), newInputPort(Input_Pins[2], true, Port.ResistorMode.PullUp), newInputPort(Input_Pins[3], true, Port.ResistorMode.PullUp) };

ThreadthreadKeypad = new Thread(new ThreadStart(KeypadScan));

threadKeypad.Start();

}

voidKeypadScan()

{

intkey = -1, oldKey = -1;

while(true)

{

key = -1;

for(int i = 0; i < rows.Length; i++)

{

rows[i].Write(false);

for(int j = 0; j < cols.Length; j++)

{

if (!cols[j].Read())

{

key = i *rows.Length + j;

break;

}

}

rows[i].Write(true);

if(key > -1) break;

}

if(key > -1 && key != oldKey)

{

if(OnInterrupt != null) OnInterrupt((uint)key, 1, DateTime.Now);

oldKey = key;

}

elseif (oldKey > -1 && key == -1)

{

if(OnInterrupt != null) OnInterrupt((uint)oldKey, 0, DateTime.Now);

oldKey = -1;

}

Thread.Sleep(100);

}

}

}

2、中断方式实现按键获取

public class InterruptKeypad

{

public event NativeEventHandlerOnInterrupt;

OutputPort[]rows = null;

InterruptPort[]cols = null;

Cpu.Pin[] Pins = null;

uintkey = 0;

publicInterruptKeypad(Cpu.Pin[]Output_Pins, Cpu.Pin[]Input_Pins)

{

rows = newOutputPort[] { newOutputPort(Output_Pins[0], false), new OutputPort(Output_Pins[1], false), new OutputPort(Output_Pins[2], false), new OutputPort(Output_Pins[3], false) };

cols = newInterruptPort[Input_Pins.Length];

Pins = Input_Pins;

for(int i = 0; i < Input_Pins.Length; i++)

{

cols[i] = new InterruptPort(Input_Pins[i],true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);

cols[i].OnInterrupt += new NativeEventHandler(InterruptKeypad_OnInterrupt);

}

}

privateuint GetPinIndex(uintpin)

{

for(uint i = 0; i < Pins.Length; i++)

{

if(pin == (uint)Pins[i]) returni;

}

return0;

}

voidInterruptKeypad_OnInterrupt(uint data1, uint data2, DateTimetime)

{

if(data2 == 1)

{

for(int i = 0; i < cols.Length; i++)

{

cols[i].OnInterrupt -= new NativeEventHandler(InterruptKeypad_OnInterrupt);

}

//--

uintcol = GetPinIndex(data1);

for(int i = 0; i < rows.Length; i++)

{

rows[i].Write(true);

if(cols[col].Read())

{

key = (uint)(i * rows.Length + col);

Thread threadKeypad = new Thread(new ThreadStart(KeypadRun));

threadKeypad.Start();

break;

}

}

//--

for(int i = 0; i < rows.Length; i++)rows[i].Write(false);

for(int i = 0; i < cols.Length; i++)

{

cols[i].OnInterrupt += new NativeEventHandler(InterruptKeypad_OnInterrupt);

}

}

}

voidKeypadRun()

{

OnInterrupt(key, 1, DateTime.Now);

OnInterrupt(key, 0, DateTime.Now);

}

}

注意,中断方式中,触发事件必须放在线程里执行,否则会有问题(如果在Winform中使用,最好不用线程,而用winfrom提供的timer,否则就无法直接操作UI了,那就必须用委托方式了,和windows上的编程类似)。

问题点1:由于我们采用的键盘并没有加上拉(或下拉)电阻电路,在最初做这个程序的时候,InputPort(Input_Pins[1], true,Port.ResistorMode.PullUp),最后一个参数,底层并没有实现内部上拉,下拉和悬空功能,所以设置是无效的。这就造成了,在按钮没有按下时,输入pin脚的状态是未知的,有时候是1,有时候是0,程序是无法正确运行的。

此外STM32F103和STM32F207的GPIO寄存器差别很大,内部实现上拉、下拉的设置也是不同的。分别实现后,发现内部上拉正常,设置下拉效果不明显,pin脚的状态还是未知的。所以我们实现的程序都设置为上拉。

问题点2:在实现中断方式的扫描键盘的代码的时候,发现PB6、PC0和PB1三个pin脚触发中断异常,但是在NativeSample层面又正常。目前没有发现这三个pin脚有何特别之处,此问题以后待查。所以如果采用中断方式,这三个pin脚不能使用。

以上两种方式都是在应用层面实现的,其实如果扫描键盘的pin脚固定,更好的方式可以在底层用C++实现,并且还可以把8个物理pin脚,虚拟出16个pin脚来,用法和物理的pin脚完全一样。

官方SimpleWPFApplication示例,是一个比较典型的WPF应用,但是需要5个按键才能操作,我们的紫藤207系统仅提供了一个物理按钮,所以是无法操作的。接上扫描键盘后,我们就有可能完整的演示这个示例了,不过由于我们使用的是扫描键盘,所以原程序无法使用,必须做如下修改才可以。

public sealed class GPIOButtonInputProvider

{

public readonly DispatcherDispatcher;

privateDispatcherOperationCallback callback;

privateInputProviderSite site;

privatePresentationSource source;

publicGPIOButtonInputProvider(PresentationSourcesource)

{

this.source= source;

site = InputManager.CurrentInputManager.RegisterInputProvider(this);

callback = newDispatcherOperationCallback(delegate(objectreport)

{

InputReportArgsargs = (InputReportArgs)report;

returnsite.ReportInput(args.Device, args.Report);

});

Dispatcher = Dispatcher.CurrentDispatcher;

Cpu.Pin[] Output_Pins = { (Cpu.Pin)GPIO_NAMES.PC8,(Cpu.Pin)GPIO_NAMES.PC9, (Cpu.Pin)GPIO_NAMES.PB7,(Cpu.Pin)GPIO_NAMES.PC2 };

Cpu.Pin[] Input_Pins = { (Cpu.Pin)GPIO_NAMES.PC3,(Cpu.Pin)GPIO_NAMES.PA0, (Cpu.Pin)GPIO_NAMES.PA5,(Cpu.Pin)GPIO_NAMES.PA6 };

InterruptKeypadkey = new InterruptKeypad(Output_Pins,Input_Pins);

key.OnInterrupt += new NativeEventHandler(key_OnInterrupt);

}

voidkey_OnInterrupt(uint data1, uint data2, DateTimetime)

{

RawButtonActionsaction = (data2 != 0) ? RawButtonActions.ButtonUp: RawButtonActions.ButtonDown;

RawButtonInputReportreport = new RawButtonInputReport(source,time, GetButton(data1), action);

Dispatcher.BeginInvoke(callback, new InputReportArgs(InputManager.CurrentInputManager.ButtonDevice,report));

}

ButtonGetButton(uint data)

{

switch(data)

{

case2:

returnButton.VK_UP;

case5:

returnButton.VK_LEFT;

case6:

returnButton.VK_SELECT;

case10:

returnButton.VK_DOWN;

case7:

returnButton.VK_RIGHT;

}

returnButton.None;

}

}

把GpioButtonInputProvider.cs里面的程序这样修改后,就可以使用了。

效果图如下:

实际运行视频链接如下:

http://v.youku.com/v_show/id_XNDI3ODU4OTg4.html

从视频可以看出,STM32F207平台运行WPF程序还是蛮流畅的。

-------------------------------------------------------------------------------

下载地址:http://www.sky-walker.com.cn/MFRelease/Sample/ScanKey_WPFTest.rar

MF简介:http://blog.youkuaiyun.com/yefanqiu/article/details/5711770

MF资料:http://www.sky-walker.com.cn/News.asp?Id=25



以工业能源、资源计量和监测为背景,设计了一种基于和的工业 物联网网关设备。实现了多种协议的工业计量仪表的数据采集、本地存储和远传。本文 利用工业级微控制器芯片,通过引脚复用,实现了七路数据采集端口。 采用芯片加以有效的信号隔离、电源隔离措施,实现了串行端口到总 线的自动双工转换。 在网络传输方面,本文充分利用微控制器的以太网介质接入层控制器,通过 接口连接芯片,实现了的双工以太网通信。 本文对网关设备设计的讨论主要分三方面,分别是硬件电路的设计实现、系统软 件的设计和应用层软件的设计。 网关设备的硬件部分主要包括微控制器、电源、日历、存储器、声卡、网卡、 接门、接门以及卡扩展槽等的原理分析和电路设计、板图的设计、制板及 硬件电路的调试。 系统软件方面采用作为引导加载程序,设了一个基于内核的嵌入式 操作系统并根据需要修改了部分驱动程序。操作系统采用制作了常用的系统工 具,并使用创建了根文件系统。 在系统的基础上,本文采用语言幵发了三种工业远传仪表规约的应用层 实现,利用和两种方式实现服务器的通信并根裾国家的相关标准实现 了数据采集和远传。 最后,本文针对网关设备的功能,进行了部分测试,并对功能的扩展和进步测试 做出了展望。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值