【物联网智能网关-05】扫描键盘编程设计
2019独角兽企业重金招聘Python工程师标准>>>
.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脚不能使用。
注:该问题已修正,需要更新固件(版本V1.6.10以上),另外示例需要参考最新的扫描键盘示例。
以上两种方式都是在应用层面实现的,其实如果扫描键盘的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.csdn.net/yefanqiu/article/details/5711770
MF资料:http://www.sky-walker.com.cn/News.asp?Id=25
转载于:https://my.oschina.net/u/1777222/blog/270569
【物联网智能网关-05】扫描键盘编程设计相关推荐
- 物联网智能网关应用系统的一般设计方法
随着互联网的日益普及.信息共享程度的要求不断提高,各种家电设备.仪器仪表以及工业生产中的数据采集与控制设别在逐步走向网络化,以便利用庞大的网络资源,实现分布式远程监控.信息交换与共享.物联网的发展更是 ...
- 【物联网智能网关-08】TinyGUI和WPF汉字显示技术比较
TinyGUI是我在2010上半年的时候,基于.NET Micro Framework系统开发的一个轻量级图形库,虽然TinyGUI运行需要的资源少,运行快,但是不支持汉字显示(如需显示汉字还是必须借 ...
- 西门子SIMATIC IOT2050与钡铼技术BL102工业物联网智能网关的区别
工业物联网智能网关是工业物联网技术不断发展的必然产物,是融合IT与OT的纽带.不管是工业控制领域的国际大品牌玩家,还是国内的小精专企业,都根据市场需求推出了自己的产品.这些工业物联网智能网关广泛应用于 ...
- 【物联网智能网关-02】获取摄像头数据+显示
在上一篇文章<通过AD采集获取温湿度>我们介绍了物联网智能网关的AD端口的使用情况,AD接口是.NET Micro Framework标准库函数之一,只要底层BSP支持就可以直接使用.但是 ...
- 工业4.0时代,您需要的是高性价工业物联网智能网关(超高性价比),PLC远程监控,PLC远程维护,系统数据采集,一个都不能少。
www.maiside.cn www.maiside.top 如何实现智能制造? 第一步能够完成生产过程的自动化,第二步将生产过程中的数据实时上送到MES.ERP.EAM.大数据分析系统.设备远程运维 ...
- BHIOT-833物联网智能网关
物联网网关可以实现感知网络与通信网络,以及不同类型感知网络之间的协议转换.既可以实现广域互联.也可以实现局域互联. 简单的来说,有了网关,所谓的 M2M 不再是狭义上机器与机器的对话,而是设备.系统. ...
- 【物联网智能网关-01】通过AD采集获取温湿度
无论是机房管理系统,还是面向农村温室大棚的管理系统,温湿度采集模块是必不可少的.常见的温湿度模块从通信接口上来说,一般有三种,第一种是单总线方式(我以前写了两篇博文来介绍这方面的内容<DHT11 ...
- 工业物联网 | 智能网关实现换热站远程监控方案
换热站是连接供热工业与用户的一个重要环节,目前,设备运行的安全性.可靠性直接影响了供热的质量.目前大多数的换热点电站大多都采用人员轮换的值守模式:一方面容易出现事故发现时难以被发现,另一方面,工作人员 ...
- 【物联网智能网关-14】Html5:Canvas+WebSocket实现远程实时通信(下)
在上篇博文<Html5:Canvas+WebSocket实现远程实时通信(上)>中已经介绍了当前实现动态网页的一些基本技术,也说明了在.NET micro framework平台下实现We ...
最新文章
- php中mvc控制器作用,理解PHP中的MVC编程之控制器
- 大道至简第一章观后感(伪代码)
- MS SQL Server查询优化方法
- linux内核参数优化 for 高并发服务器
- TreeSet的定制排序
- Function Programming - 柯里化(curry)
- Promise学习笔记
- css3 media queries
- is和==,encode和decode
- b站弹幕姬python_自用 Bilibili 弹幕姬 for macOS
- SecureCRTSecureFX_HH_x86_7.0.0.326_PortableSoft.rar下载安装百度云
- [人工智能-深度学习-58]:生成对抗网络GAN - 概述与常见应用
- Unity3D 第一人称视角摄像机旋转控制
- sqlmap tamper mysql_sqlmap之常用tamper脚本
- BDS/Galileo融合精密单点定位性能评估
- AUTOCAD——图层线型
- html中数字效果,使用css实现电子数字效果
- 计算机相关双人相声,双人相声剧本简短
- 【一起入门MachineLearning】中科院机器学习第3课-朴素贝叶斯分类器
- js 个性标签图片生成