单片机按键的解决方法.docx
- 文档编号:9117438
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:15
- 大小:88.97KB
单片机按键的解决方法.docx
《单片机按键的解决方法.docx》由会员分享,可在线阅读,更多相关《单片机按键的解决方法.docx(15页珍藏版)》请在冰豆网上搜索。
单片机按键的解决方法
单片机按键的解决解决方案
1、单片机上的按键控制一般采用两种控制方法:
中断和查询。
中断必须借助中断引脚,而查询按键可用任何IO端口。
按键较少时,一个按键占用一个端口,而按键较多时,多采用矩阵形式(如:
经常用4个端口作为输出,4个端口作为输入的4X4矩阵来获得16个按键);还可以用单片机的AD转换功能一个引脚接多个按键,根据电阻分压原理判断是哪个按键按下。
2、中断形式
STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI_n(8位,但是STM32中只使用4位,高4位有效),每4个通道的8位中断优先级控制字构成一个32位的优先级寄存器。
68个通道的优先级控制字至少构成17个32位的优先级寄存器.
4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。
按照这种分组,4bit一共可以分成5组
第0组:
所有4bit用于指定响应优先级;
第1组:
最高1位用于指定抢占式优先级,后面3位用于指定响应优先级;
第2组:
最高2位用于指定抢占式优先级,后面2位用于指定响应优先级;
第3组:
最高3位用于指定抢占式优先级,后面1位用于指定响应优先级;
第4组:
所有4位用于指定抢占式优先级。
所谓抢占式优先级和响应优先级,他们之间的关系是:
具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。
如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
每一个中断源都必须定义2个优先级。
有几点需要注意的是:
1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的围,将可能得到意想不到的结果;
2)抢占式优先级别相同的中断源之间没有嵌套关系;
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
#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;//得到位置码
for(i=0;i<16;i++)
{
if(c==tab[i])returni;//查表得到按键序号并返回
return-1;//无按键,则返回-1
}
}
Voidbeep(void)//蜂鸣器发出声音,模拟按键声音
{
Uchari;
For(i=0;i<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
#defineuintunsignedint
#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>0;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;//读回来了
temp&=0xf0;//因为我们只是读回来高4位
while(temp!
=0xf0){//下面的几个while循环判断可以用if好理解。
只看到第一行就行了。
//这几个while都是做判断用的
delay(5);//消除抖动的
temp=P3;
temp&=0xf0;
while(temp!
=0xf0){//确实不等于0xf0有按键按下
temp=P3;//我们这个时候只是把P3口的值赋给了temp
switch(temp){//检测P3口。
case 0xee:
num=1;
break;
case 0xde:
num=2;
break;
case 0xbe:
num=3;
break;
case0x7e:
num=4;
break;
}
while(temp!
=0xf0)//有按键按下可能是不等于的 循环在这里面 松手检测
{
temp=P3;
temp=temp&0xf0;//这个是松手检测 松手这里就等于了0xf0
}//下面就显示一下 退出整个一行的循环,不加松手检测会退不出去循环
//到这里是把第一行检测了。
}
}
//////以下下是其他几行检测的代码
P3=0xfd;//高4位是f等于写了1111也满足了先写1的要求
temp=P3;//读回来
temp&=0xf0;//因为我们只是读回来高4位
while(temp!
=0xf0){
delay(5);//消除抖动的
temp=P3;
temp&=0xf0;
while(temp!
=0xf0){//确实不等于0xf0有按键按下
temp=P3;//我们这个时候只是把P3口的值赋给了temp
switch(temp){//检测P3口。
case 0xed:
num=5;
break;
case 0xdd:
num=6;
break;
case 0xbd:
num=7;
break;
case0x7d:
num=8;
break;
}
while(temp!
=0xf0)//有按键按下可能是不等于的 循环在这里面 松手检测
{
temp=P3;temp=temp&0xf0;//这个是松手检测 松手这里就等于了0xf0
}//下面就显示一下 退出整个2行的循环。
不加松手检测会退不出去循环
//到这里是把第2行检测了。
}
}
P3=0xfb;//高4位是f等于写了1111也满足了先写1的要求
temp=P3;//读回来了
temp&=0xf0;//因为我们只是读回来高4位
while(temp!
=0xf0){
delay(5);//消除抖动的
temp=P3;
temp&=0xf0;
while(temp!
=0xf0){//确实不等于0xf0有按键按下
temp=P3;//我们这个时候只是把P3口的值赋给了temp
switch(temp){//检测P3口。
case 0xeb:
num=9;
break;
case 0xdb:
num=10;
break;
case 0xbb:
num=11;
break;
case0x7b:
num=12;
break;
}
while(temp!
=0xf0)//有按键按下可能是不等于的 循环在这里面 松手检测
{temp=P3;temp=temp&0xf0;//这个是松手检测松手这里就等于了0xf0
}//下面就显示一下 退出整个3行的循环。
不加松手检测会退不出去循环
//到这里是把第3行检测了。
}
}
P3=0xf7;//高4位是f等于写了1111也满足了先写1的要求
temp=P3;//读回来了
temp&=0xf0;//因为我们只是读回来高4位
while(temp!
=0xf0){
delay(5);//消除抖动的
temp=P3;
temp&=0xf0;
while(temp!
=0xf0){//确实不等于0xf0有按键按下
temp=P3;//我们这个时候只是把P3口的值赋给了temp
switch(temp)//检测P3口
{
case 0xe7:
num=13;
break;
case 0xd7:
num=14;
break;
case 0xb7:
num=15;
break;
case0x77:
num=16;
break;
}
while(temp!
=0xf0)//有按键按下可能是不等于的 循环在这里面 松手检测
{
temp=P3;
temp=temp&0xf0;//这个是松手检测 松手这里就等于了0xf0
}//下面就显示一下 退出整个4行循环。
不加松手检测会退不出去循
//到这里是把第4行检测了。
}
}
return num;//其实键盘扫描就需要一个值。
}
4、电阻分压控制按键
电阻分压控制按键方式原理:
利用电阻分压,使得不同按键处的电压值不同,通过检测按键处的电压值,判断是哪个按键按下了。
不同的按键可以看做是使用一个电位器旋钮采集一个ADC通道上的ADC值过程中电位器旋钮旋动过程中的不同位置。
注:
串联在电路中的电阻可以是相同阻值的电阻,也可以是不同电阻值的电阻。
一切视具体情况而定。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 按键 解决方法