#include<delay.h>#define KEY_SCAN P1
#define uchar unsigned char//char num/********************************/
/*函数名称:KEY_DOWN() */
/*函数功能:延时子函数 */
/*参数:无 */
/*返回:返回1或0*/
/*备注:1表示有键按下,0则无*/
/********************************/
bit KEY_DOWN()
{
KEY_SCAN=0x0f //先给键盘口赋个初值
if(KEY_SCAN!=0x0f) //判断是有按键按下,即KEY_SCAN不等于初值时有键按下
{
delayms(10)//消抖
if(KEY_SCAN!=0x0f) //再次判断是否真有键按下
return 1 //真有就返回1没有返回零
else
return 0
}
else
return 0
}/********************************/
/*函数名称:SCAN_GET() */
/*函数功能:键盘值函数 */
/*参数:无 */
/*返回:返回1或0*/
/*备注:无 */
/********************************/
uchar SCAN_GET()
{
char button
uchar key_code
button=KEY_SCAN
KEY_SCAN=0xf0
button=(button|KEY_SCAN)
while(KEY_SCAN!=0xf0)
delayms(10)
switch(button)
{
case 0xd7: key_code='1'break
case 0xdb: key_code='2'break
case 0xdd: key_code='3'break
case 0xb7: key_code='4'break
case 0xbb: key_code='5'break
case 0xbd: key_code='6'break
case 0x77: key_code='7'break
case 0x7b: key_code='8'break
case 0x7d: key_code='9'break
case 0xeb: key_code='0'break
case 0xee: key_code=0xeebreak
default : break
}
return key_code
}
//////////////////////////////////////////////////////////////
//此程序是上两个程序结合的
/********************************/
/*函数名称:Key_Get() */
/*函数功能:键盘扫描函数*/
/*参数:无 */
/*返回:无 */
/*备注:无 */
/********************************/
void Key_Get()
{
char button
KEY_SCAN=0x0f
if(KEY_SCAN!=0x0f)
{
delayms(5)
if(KEY_SCAN!=0x0f)
{
button=KEY_SCAN
KEY_SCAN=0xf0
button=(button|KEY_SCAN)
while(KEY_SCAN!=0xf0)
switch(button)
{
case 0xd7: num='1'P0=0x00break
case 0xdb: num='2'P0=0x0fbreak
case 0xdd: num='3'break
case 0xb7: num='4'break
case 0xbb: num='5'break
case 0xbd: num='6'break
case 0x77: num='7'break
case 0x7b: num='8'break
case 0x7d: num='9'break
case 0xeb: num='0'break
case 0xe7: num='a'break
case 0xed: num='b'break
case 0xee: num='c'break
case 0xde: num='d'break
case 0xbe: num='e'break
case 0x7e: num='f'break
default : break
}
}
}
}
4X4太浪费单片机IO了,我为你介绍5个IO控制25按键的电路,如下文:
本文以循序渐进的思路,引导大家思考如何用最少的IO驱动更多的按键,并依次给出5种方案原理图提供参考。在实际项目中我们经常会遇到有按键输入的需求,但有的时候为了节省资源成本,我们都会选择在不增加硬件的情况下使用最少的控制器IO驱动更多的按键,那么具体是怎么做的呢,下面我们就以用5个IO引脚为例,讲下怎么设计可以实现更多的按键?共有5种设计思路,下面依次介绍。
思路一首先通常想到的可能是下面这样的设计:
上图形式的按键就是我们通常说的行列式按键,它的驱动思路是这样的:
1. 对IO1、2、3配置为推挽输出,依次只让其中一个输出为0其他输出为1。
2. 对IO4、5进行读 *** 作,根据读出的结果判断哪个按键按下。
例如:配置IO1、2、3为011,读IO4、5,若IO4为0则SW14按下,若IO5为0则SW15按下;
依次的配置IO1、2、3为101,读IO4、5,若IO4为0则SW24按下,若IO5为0则SW25按下;
依次的配置IO1、2、3为110,读IO4、5,若IO4为0则SW34按下,若IO5为0则SW35按下;
思路二但是我们在不知道行列式按键之前我们肯定是依次将IO口接一个按键到GND或者到VCC,然后去读IO口去判断哪个按键按下,这也是最简单的方法,但是很浪费IO口,下面这种就结合了这种简单方法和行列式的思路,实现了又多增加3个按键,如下图:
这里我们的思路是先依次读IO1、2、3的电平来识别S1、2、3,哪个按键按下,其后的流程和思路一是一样的,这样就可以识别11个按键了。
思路三按照扫描的思想,某一时刻设置一个IO口为0,其他IO口读,如果有IO口读到0,则有对应按键按下。比如IO1为0,然后读到IO5也为0,那么K15就是按下的。对照这样的思路,我们可以有下面的设计:
这个电路按键识别思路是这样的:
1. 只配置IO1为0,其他IO读,若IO5读到0,则K15按下,若IO4读到0,则K14按下,依次识别K13,K12;
2. 只配置IO2为0,其他IO读,若IO5读到0,则K25按下,若IO4读到0,则K24按下,依次识别K23;
3. 只配置IO3为0,其他IO读,若IO5读到0,则K35按下,若IO4读到0,则K34按下;
4. 只配置IO4为0,其他IO读,若IO5读到0,则K45按下;
思路四对于思路3我们发现,如果只配置IO5为0,其他IO读,若IO1读到0,则K15按下,若IO2读到0,则K25按下,依次可识别K35和K45。这样就存在重复,那么有么有好的方法,解决这样的重复呢?我们发现,若配置IO1为0,K15按下,电流流向IO1的,若配置IO5为0,同样K15按下,电流是流向IO5的。这样我们就可以通过区分电流的流向来避免重复。于是就有了下图的设计:
这样就可以避免重复,IO5为0时,按K15,IO1是读不到0的。那么怎样设计,IO5为0时对应一个按键按下IO1为0呢?如是就有人想到下面的设计:
这个电路按键识别思路是这样的:
1. 只配置IO1为0,其他IO读,若IO5读到0,则K51按下,若IO4读到0,则K41按下,依次识别K31,K21;
2. 只配置IO2为0,其他IO读,若IO5读到0,则K52按下,若IO4读到0,则K42按下,依次识别K32,K21';
3. 只配置IO3为0,其他IO读,若IO5读到0,则K53按下,若IO4读到0,则K43按下,依次识别K32’,K31';
4. 只配置IO4为0,其他IO读,若IO5读到0,则K54按下,若IO4读到0,则K43’按下,依次识别K42’,K41';
5. 只配置IO5为0,其他IO读,若IO4读到0,则K54’按下,若IO3读到0,则K53’按下,依次识别K52’,K51'。
思路五很多人可能认为思路四已经识别20个按键了,但是真的就没有其他方法了吗?不要忘了,我们还没有将思路二你介绍的那种最简单的方法结合进去,于是又可以多5个按键,如下图:
这样我们可以先识别K01、K02、K03、K04、K05,若没有按键按下然后再和思路四的设计一样去识别其他按键。但这样存在一个问题,如果IO1配置为0,IO5读到0,那么怎么知道是K51按下还是K05按下呢,这里只需要在程序里做下判断,先判断下是不是K05按下,若不是就是K51,因为按键K01、K02、K03、K04、K05在5个IO口都为读取的情况下,就可以识别,不需要扫描识别处理,相当于这5个按键优先级高与其他按键。
总结综合上述,5个IO口最多可以识别25个按键,思路五程序上处理比较麻烦,若实际中只按思路四设计,也可识别20个按键,那么如果有N个IO口可识别多少按键呢?这里给出如下公式:
假设有N个IO口按照思路三可以识别N*(N-1)/2个;
按照思路四可识别N*(N-1)个;
按照思路5可以识别N*(N-1)+N个。
最后再说下,如果实际设计时,还是按思路四设计好,软件也没那么麻烦。如果是你的话你会选择哪种方法呢?你还有没有其他的设计方法呢?
//msp430F1494*4矩阵键盘P1口中断扫描
#include<msp430x14x.h>
#define
KEY_DIR
P1DIR
#define
KEY_OUT
P1OUT
#define
KEY_IN
P1IN
#define
KEY_IE
P1IE
#define
KEY_IES
P1IES
#define
KEY_IFG
P1IFG
/***************全局变量***************/
unsigned
char
Key_Val
//存放键值
void
CtrlKey(unsigned
char
sw)
//控制键盘开关//sw=0关
sw=1开
/*******************************************
函数名称:Init_Keypad
功
能:初始化扫描键盘的IO端口
参
数:无
返回值
:无
********************************************/
void
Init_Keypad(void)
{
KEY_DIR
=
0x0f
//P1.0~P1.3设置为输出状态,P1.4~P1.7输入
状态(上拉H)
KEY_OUT=0
KEY_IES
=0xf0
//P1.4~P1.7允许中断
KEY_IE
=0xf0
//P1.4~P1.7下降沿触发中断
KEY_IFG=0
//中断标志清0
Key_Val
=
0
}
/*******************************************
函数名称:Check_Key
功
能:扫描键盘的IO端口,获得键值
参
数:无
返回值
:无
********************************************/
//p14\5\6\7
接上拉电阻
/***************************************
key_Val
对应键值
列:[p14]
[p15]
[p16]
[p17]
↓
↓
↓
↓
行:
[p13]→
1
2
3
4
[p12]→
5
6
7
8
[p11]→
9
10
11
12
[p10]→
13
14
15
16
***************************************/
void
Check_Key(void)
{
unsigned
char
row
,col,tmp1,tmp2
unsigned
char
keymap[]
=
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}//设置键盘逻辑键值
与程序计算键值的映射
tmp1
=
0x08
for(row
=
0row
<
4row++)
//行扫描
{
KEY_OUT
=
0x0f
//P1.4~P1.7输出全1
KEY_OUT
-=
tmp1
//P1.4~p1.7输出四位中有一个为0
tmp1
>>=1
if((KEY_IN
&
0xf0)<0xf0)
//是否P1IN的P1.0~P1.3中有一位为0
{
tmp2
=
0x10
//
tmp2用于检测出哪一位为0
for(col
=
0col
<
4col++)
//
列检测
{
if((KEY_IN
&
tmp2)
==
0x00)
//
是否是该列,等于0为是
{
Key_Val
=
keymap[row*4
+
col]
//
获取键值
return
//
退出循环
}
tmp2
<<=
1
//
tmp2右移1位
}
}
}
}
/*******************************************
函数名称:delay
功
能:延时约15ms,完成消抖功能
参
数:无
返回值
:t=
tmp*5*clk
根据使用时钟调整tmp值
********************************************/
void
delay(void)
{
unsigned
int
tmp
for(tmp
=
12000tmp
>
0tmp--)
}
/*******************************************
函数名称:Key_Event
功
能:检测按键,并获取键值
参
数:无
返回值
:无
********************************************/
void
Key_Event(void)
{
unsigned
char
tmp
KEY_OUT
=0
//
设置P1OUT全为0,等待按键输入
tmp
=
KEY_IN
//
获取
p1IN
if((tmp
&
0xf0)
<
0xf0)
//如果有键按下
{
delay()
//消除抖动
Check_Key()
//
调用check_Key(),获取键值
}
}
/*********************************************************************
控制打开或者关闭键盘中断
SW=
0:关闭;
ELSE:打开
*********************************************************************/
void
CtrlKey(unsigned
char
sw)
{
if(sw==0)
KEY_IE
=0
//关闭端口中断
else
KEY_IE
=0xf0
//打开端口中断
}
/*端口1按键中断*/
#pragma
vector=PORT1_VECTOR
__interrupt
void
Port(void)
{
if((KEY_IFG&0xf0)!=0)
{
Key_Event()
if(Key_Val!=0)
//键值!=0有键按下
{
CtrlKey(0)
//关键盘中断
}
}
KEY_IFG=0KEY_OUT=0
//清中断标志
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)