EXTI是边沿触发的。
当你按下键时,肯定会出现抖动,那抖动一次就是一个边沿,自然会一次次的触发中断了。我以前也试验过,很不好使。
用systick扫描是一个办法,我用这个实现了线反转法扫描4X4的键盘矩阵。设置10ms中断一次,每次进中断首先检查有没有按键,如果没有就pass,如果有就先计个数再退出,重复三次操作确定都有按键(也就完成了消抖),然后翻转线路状态扫描一次确定行列位置,这样就确定键值了。
很简单的啊,不太清楚你的电路图,我把主要程序写一下:
#includereg52.h
unsigned char flag=0;//设置flag作为标志位,初值为0,一旦产生中断,将其置1
void main()
{
EA=1;//开总中断
EX0=1;//开外部中断0 ,假设是由P3.2产生的中断
IT0=1;//设置产生中断的方式,这是表示下降沿触发
P0=0X0F;//假设矩阵键盘接P0口,给所有列线低电平,所有行线高电平
while(1)
{
if(flag==1) //这个是表示,如果中断不产生,下面的程序不会运行,只有中断了,才会键盘扫描
{
按键扫描程序,这个我就不写了,写法有很多啦
}
数码管显示程序,这个我也不写了,不晓得你是什么电路图
}
}
void scan() interrupt 0
{
flag=1;//表示,一旦中断产生了,将flag置1
}
希望对你有用,呵呵
嗯,想法很不错..
我试着帮你解释下第一个吧..
这应该是选用的线扫法(好像这么说的吧).
比如说,键盘口为,P1
在一开始输出,01111111B,再判断P1口值是否变化..
若没变化再换成,10111111B,再判断P1口值是否变化..
这样依次到,11101111B,
在有变化时就可以得到把描码了..就像是你那个表中所示.的数值就经过这四次都可以得出其中一种....
#includereg51.h
#define uchar unsigned char
#define KeyPad P0
code uchar key_tab[17]=
{0xed,0x7e,0x7d,0x7b,
0xbe,0xbd,0xbb,0xde,
0xdd,0xdb,0x77,0xb7,
0xee,0xd7,0xeb,0xe7,0XFF};
code uchar key_show[]=
{1,2,3,0x0a,
4,5,6,0x0b,
7,8,9,0x0e,
0x0c,0,0x0d,0x0f,0xff};
uchar Keyscan()
{
uchar i=0x01,j,k;
KeyPad=~i;
j=~i;
for (k=0;k4;k++)
{
if(KeyPad==j)
{
i*=2;
KeyPad=~i;
j=~i;
}
else
k=KeyPad;//取出扫描码.
}
i=0;
if(k!=4)
{
while(key_tab[i++]!=0xff)
{
if(k==key_tab[i])
k=i;
else
k=16;
}
}
return key_show[k];
}
以上是整个扫描键盘子程序..
程序编译通过,不知道实际怎么样..
其中未用中断..
不过,方法是一样的...
明白思想才是最重要的..
祝你好运!
^_^
//msp430F149
4*4矩阵键盘P1口中断扫描
#includemsp430x14x.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
=
0;row
4;row++)
//行扫描
{
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
=
0;col
4;col++)
//
列检测
{
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
=
12000;tmp
0;tmp--);
}
/*******************************************
函数名称: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_IFG0xf0)!=0)
{
Key_Event();
if(Key_Val!=0)
//键值!=0有键按下
{
CtrlKey(0);
//关键盘中断
}
}
KEY_IFG=0;KEY_OUT=0;
//清中断标志
}
GPIO_Write(GPIOB,(GPIOB-ODR 0xfff0 | 0xf))
这个地方是说!你先把GPIOB口的输出寄存器低四位清零,让后在把他与0xf相与在把低四位置高。
GPIOB是32位寄存器所以,0xfff0正好是32位,那个0xf是0x0f的意思!
寄存器配置一定要看手册来配,不然谁会
STM32的GPIO多很多,所有的GPIO口都可用作外部中断,但同组的只能选择一个,如GPIOA的第1脚与其他都是1脚(如GPIOC的第一脚)的归为一组,所以SYSCFG-EXTICR[0] = ~(0x0f (0 * 4));这句是来配置外部中断0的中断线选择GPIOA的,即GPIOA的第0脚;
EXTICR[0]是选择外部中断0到3的,其他以此类推。
例如你的按键为PC5,则你选择外部中断5,
SYSCFG-EXTICR[1] = ~(0x0f (1 * 4));
配置成上升沿触发EXTI-RTSR |= 1 5;
或者配置成下降沿触发EXTI-FTSR |= 1 5;
或者两者都行,这需要看你的外部电路,按下由低电平转高则选上升沿
最后开放对应中断线的请求EXTI-IMR |= 1 5;
后面那几行根据你的要求写中断分组,中断优先级,最后写你的中断函数
本文标签:4x4矩阵按键stm32中断