单片机按键的解决方法Word格式.docx
《单片机按键的解决方法Word格式.docx》由会员分享,可在线阅读,更多相关《单片机按键的解决方法Word格式.docx(15页珍藏版)》请在冰豆网上搜索。
3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
GPIO外部中断:
STM32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间智能使用一个,如:
PA0,PB0,PC0,PD0,PE0,PF0这些为1组,如果我们使用PA0作为外部中断源,那么别的就不能使用了,在此情况下我们使用类似于PB1,PC2这种末端序号不同的外部中断源,每一组使用一个中断标志EXTIx.EXTI0~EXTI4这5个外部中断有着自己单独的中断响应函数。
EXTI5~EXTI9共用一个中断响应函数,EXTI10~EXTI15共使用一个中断响应函数。
对于中断的控制,STM32有一个专用的管理机构NVIC.中断的使能,挂起,优先级,活动等等都是由NVIC在管理的。
编写IO口外部中断步骤及其注意事项:
(1)设置中断优先级组;
(2)开启时钟(IO口时钟,复用时钟);
(3)设置中断线并对中断进行初始化配置(设置中断线,确定中断模式,中断触发沿设置,使用指定设置初始化外部中断);
(4)设置中断管理器NVIC各参数(包括:
使能产生外部中断外设的IO口所在的外部中断通道;
设置外部中断的优先级---抢占优先级,响应优先级;
使能外部中断通道;
使用设置好的各个中断管理器上的参数来初始化中断管理器)。
外部中断服务函数完成中断操作需要最终达到的目标。
3、矩阵形式
键盘矩阵原理:
a*b矩阵键盘由a条行线和b条列线组成,行线接端口P3(p3表任一端口)P3.0、P3.1、P3.2……p3.(a-1);
列线接p3.a,p3.(a+1)……P3.(b-1).按键位于每条行线和列线的交叉点上。
按键的识别可采用行扫描法和线反转法,这里采用简单的线反转法,只需三步。
第一步,执行程序使X0~X3均为低电平,此时读取各列线Y0~Y3的状态即可知道是否有键按下。
当无键按下时,各行线与各列线相互断开,各列线仍保持为高电平;
当有键按下时,则相应的行线与列线通过该按键相连,该列线就变为低电平,此时读取Y0Y1Y2Y3的状态,得到列码。
第二步,执行程序使Y0~Y3均为低电平,当有键按下时,X0~X3中有一条行线为低电平,其余行线为高电平,读取X0X1X2X3的状态,得到行码。
第三步,将第一步得到的列码和第二步得到的行码合并得到按键的位置码,即是Y3Y2Y1Y0X3X2X1X0(因为行线和列线各有一条电平,其余为高电平,所以位置码低四位和高四位分别只有一位低电平,其余为高电平)。
也就是说,当某个键按下时,该键两端所对应的行线和列线为低电平,其余行线和列线为高电平.比如,当0键按下时,行线X0和列线Y0为低电平,其余行列线为高电平,于是可以得到0键的位置码Y3Y2Y1Y0x3X2X1X0为11101110即是0xEE.
全部按键码为:
矩阵键盘在单片机上的简单应用-----显示数码管:
0~F(51单片机)
#include<
reg51.h>
#defineucharunsignedchar
#defineuintunsignedint
Sbitbuzzer=P1^0;
Ucharcode_dis[]=//0~9,A~F
{
0xC0,0XF9,0XA4,0xB0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0z88,0x83,
0xC6,0xA1,0x86,0x8E
};
Ucharcode_tab[]=//矩阵键盘按键位置码
0x77,0xb7,0xd7,0xe7,
0x7b,0xbb,0xdb,0xeb,
0x7d,0xbd,0xdd,0xed,
0x7e,0xbe,0xde,0xee
voiddelay(uintx)
//延时函数
uchari;
while(x--)
for(i=0;
i<
120;
i++);
}
ucharscan()//矩阵键盘扫描函数,得到按键号,采用线反转法
uchara,b,c,i;
P3=0XF0;
//P3口输出11110000
a=P3;
//读取列码
delay(10);
//防抖延时10ms
P3=0X0F;
//P3口输出00001111
b=P3;
//读取行码
c=a+b;
//得到位置码
16;
i++)
{
if(c==tab[i])returni;
//查表得到按键序号并返回
return-1;
//无按键,则返回-1
Voidbeep(void)//蜂鸣器发出声音,模拟按键声音
Uchari;
For(i=0;
100;
i++)
Buzzer=~buzzer;
Delay
(1);
Buzzer=0;
Voidmain(void)
ucharkey;
buzzer=0;
//关闭蜂鸣器
while
(1)
{key=scan();
//得到按键号
if(key!
=-1)//有按键则显示,并且蜂鸣器发出声音
{P0=dis[key];
beep();
delay(100);
}
扫描法:
矩阵键盘工作原理:
由于按键没有接地,4行
4列正好占用8个I/O
如果4行我们送P3.0到P3.3送入0111然后去读取4列的值,如果P3.0的按键按下那么P3.4---P3.7的值等于0111,假如是第2个键按下的话那么读回来的值是1011,如果第3个键按下去读回来的值是1101,如果第4个键按下去读回来的值是11
10
,如果没有键按下去读回来就是1111。
所以我们就根据读回来的值来判断按下去的是那个键。
当然这是对P3.0这一行,因为矩阵键盘是扫描的,所以下次把P3.0给1
P3.1给0对第2行,陆续的第3行第4行,0111101111011110
而每次都去从新扫描一遍列值列有4个值,以确定是那个键按下。
无论何时任何一个时间有一个按键被按下就跳出循环。
当然不可能有2个键刚好一起按下你的手没有这么好的力度,就算有2个键一起按键,程序也有先后检测的顺序,只能检测一个后面的检测不到。
P3=0XFE;
//第一行给0
temp;
定义个变量
temp=P3;
读回来
由于读需要先写1
因为P3=FE
已经把高4位给1了
所以能读了
temp&
oxf0
如果没有按键按下结果还是0xf0.如果有键按下结果就不是0xf0了。
num
然后我们再定义一个变量
让它赋值给这个按下去的按键值。
一次类推把第一行赋值0扫描一遍然后把第2行赋值0扫描一遍..............共扫描16遍。
只要有键按下就会得到一个值num就从1排到16.共16个按键4*4的矩阵键盘。
我再总结下思路:
首先低4位是行共4行
分别把每行给0低电平
就4次0111
、1011、1101、1110对吧
然后去检测高4位
4列啊
先不考虑极端情况,4列就4个按键只要按下一个P3口的高4位就会有一个值。
根据这个值就能判断是那个键了。
如:
P3=11111110
低四位是行先把第一行给0
有按键下的话temp=P3
11011110
然后temp&
0xf0
与运算下就判断下还等于oxf0吗?
如还等于就没有按下,如果不等于就肯定有按键按下。
定义个变量让它等于这个不是0XF0的值,做个标记。
依次类推。
然后用这个思路写个程序吧!
写的不太好看的不是很清楚只是做个参考吧,只要把思路理清楚就行了。
是这样我们分别按这16个按键让它分别显示是第几个比如按下第一个数码管就显示1第2个数码管就显示2,依次类推。
一直到F
(为了方便让所有的数码管显示同一个数0---F)
#include
#defineucharunsignedchar
sbitdula=P2^6;
sbitwela=P2^7;
sbitkey1=P3^4;
ucharcodetable[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0//加这个0就是什么都不显示
ucharnum,temp,num1;
voiddelay(uintz)
uintx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
ucharkeyscan();
//声明一下
//voiddisplay(ucharnum1);
//这里可以做个显示函数,但是我没做。
voidmain(){
num=17;
//让它显示0什么都不显示。
因为函数返回num值
dula=1;
P0=0;
dula=0;
wela=1;
P0=0xc0;
wela=0;
//以上P0口控制数码管的一上电什么都不显示
while
(1){
num1=keyscan();
//没按下返回17
dula=1;
P0=table[num1-1];
//17-1=16
dula=0;
//用ucharkeyscan()带返回值的函数代替整个矩阵键盘
当然显示就不要了dula
那3行我注释掉了
ucharkeyscan(){
P3=0xfe;
//高4位是f等于写了1111也满足了先写1的要求
temp=P3;
//读回来了
=0xf0;
//因为我们只是读回来高4位
while(temp!
=0xf0){//下面的几个while循环判断可以用if好理解。
只看到第一行就行了。
//这几个while都是做判断用的
delay(5);
//消除抖动的
temp=P3;
while(temp!
=0xf0){//确实不等于0xf0有按键按下
temp=P3;
//我们这个时候只是把P3口的值赋给了temp
switch(temp){//检测P3口。
case
0xee:
num=1;
break;
case
0xde:
num=2;
break;
0xbe:
num=3;
case0x7e:
num=4;
=0xf0)//有按键按下可能是不等于的
循环在这里面
松手检测
temp=temp&
0xf0;
//这个是松手检测
松手这里就等于了0xf0
}//下面就显示一下
退出整个一行的循环,不加松手检测会退不出去循环
//到这里是把第一行检测了。
//////以下下是其他几行检测的代码
P3=0xfd;
//读回来
=0xf0){
0xed:
num=5;
0xdd:
num=6;
0xbd:
num=7;
case0x7d:
num=8;
temp=temp&
退出整个2行的循环。
不加松手检测会退不出去循环
//到这里是把第2行检测了。
P3=0xfb;
temp=P3;
temp&
while(temp!
delay(5);
temp=P3;
while(temp!
0xeb:
num=9;
0xdb:
num=10;
0xbb:
num=11;
case0x7b:
num=12;
{temp=P3;
//这个是松手检测松手这里就等于了0xf0
}//下面就显示一下
退出整个3行的循环。
不加松手检测会退不出去循环
//到这里是把第3行检测了。
}
P3=0xf7;
switch(temp)//检测P3口
{
0xe7:
num=13;
0xd7:
num=14;
0xb7:
num=15;
case0x77:
num=16;
退出整个4行循环。
不加松手检测会退不出去循
//到这里是把第4行检测了。
return
num;
//其实键盘扫描就需要一个值。
4、电阻分压控制按键
电阻分压控制按键方式原理:
利用电阻分压,使得不同按键处的电压值不同,通过检测按键处的电压值,判断是哪个按键按下了。
不同的按键可以看做是使用一个电位器旋钮采集一个ADC通道上的ADC值过程中电位器旋钮旋动过程中的不同位置。
注:
串联在电路中的电阻可以是相同阻值的电阻,也可以是不同电阻值的电阻。
一切视具体情况而定。