获得更多单片机以及c相关的资料以及源代码例程,请私信回复 “单片机”一,键盘接口的设计需要解决的问题
  1. 需要判断是否有按键按下,如果有,那么进入下一个动作。
  2. 识别是哪一个按键被按下?并求出相应的键值。
  3. 根据键值找到相应的按键处理程序入口即可。

按键可以分为(独立按键,和矩阵键盘)

矩阵可以用做按键较多的案例。比如,计算器的编写

独立按键用来实现一些用到按键比较少的案例。

单片机行列式键盘的工作原理 单片机学习第四课(1)

矩阵键盘

单片机行列式键盘的工作原理 单片机学习第四课(2)

PCB板

二,键盘的工作原理

键盘中的一个按键开关的两端分别连接在行线和列线上,列线接地,行线通过电阻接到 5v上。当开关的机械触点断开,闭合,其行线的电压输出波形如下图(图二)

单片机行列式键盘的工作原理 单片机学习第四课(3)

单片机行列式键盘的工作原理 单片机学习第四课(4)

电压输出波形图

在第二张图中,我们可以看到,t1和t3分别为按键的闭合与断开过程中的抖动时间段,而且呈现一看连串的负脉冲,我们注意到这个抖动时间的长短与开关的机械特性有关,一般在我们按下按键后年,一般为5-10ms的样子。t2为一个稳定的闭合时间段。注意:在设计时,应该考虑到消抖(软件和硬件)

三,按键的识别高电平(低电平有效)

按键是否能够闭合,这与行线的输出电压有关系,其实就是反应在行线的输出电压的高电平还是低电平,单片机通过对行线电平的高低状态的检测,就可以确认按键是否按下与松开,为了确保单片机对一次按键发生的动作只确认一次按键有效,那么必须要消除抖动期的t1与t2的影响。

四,消除按键机械带来的抖动

我们一般都是采用两种方案:

  1. 软件消抖

主要的一个思想还是:当检测到有按键按下时,对该键对应的行线为低电平,且执行一段延时函数,大约为10ms的延时,确认该行线电平是否为低电平,如果仍为低电平,那么我们就确认确实有按键按下了。当按键被松开时,行线的低电平变为高电平,执行一短延时10ms的程序后,检测该行线为高电平,说明按键确实已经松开。

2.采用专用的键盘/显示器接口芯片。处理电路中的抖动。

五,键盘扫描瑜工作原理

单片机行列式键盘的工作原理 单片机学习第四课(5)

pcb原理图

具体原理说明:

单片机行列式键盘的工作原理 单片机学习第四课(6)

六,行列式键盘实战

1.简单的操作

①、通过仿真电路中的行列式键盘输入任意6个按键,要求识别按键后实现在6位数码管上显示按键编号;

②、数码管显示利用动态扫描方法;

③、在按键检测处理程序中增加软件消抖部分。

2.仿真电路图

如何建立工程与仿真

单片机行列式键盘的工作原理 单片机学习第四课(7)

单片机行列式键盘的工作原理 单片机学习第四课(8)

慧净开发板的键盘展示

3.源代码

#include<reg51.h> #include<intrish.h> #define uchar unsigned char #define schar signed char sbit DUAN=P2^6; sbit WEI=P2^7; sbit L1=P1^0; sbit L2=P1^1; sbit L3=P1^2; sbit L4=P1^3; uchar data password[6] ; uchar data led[6]={16,16,16,16,16,16}; uchar data ledwei[6]= {0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; uchar data displaytab[17]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; uchar n=0; void delay() { uchar x,y; for(x=2;x>0;x--) for(y=250;y>0;y--); } void delay10ms() { uchar x,y; for(x=20;x>0;x--) for(y=250;y>0;y--); } void display() { uchar i; for(i=0;i<6;i ) { P0=displaytab[led[i]]; DUAN=1; DUAN=0; P0=ledwei[i]; WEI=1; WEI=0; delay(); P0=0xff; WEI=1; WEI=0; } } void keyscan() { uchar temp,m; P1=0xef; for(m=0;m<=3;m ) { if(L1==0) { delay10ms(); if(L1==0) { password[n]= m*4 0; n ; while(!L1); delay10ms(); while(!L1) ; } } if(L2==0) { delay10ms(); if(L2==0) { password[n]=m*4 1; n ; while(!L2); delay10ms(); while(!L2); } } if(L3==0) {delay10ms(); if(L3==0) { password[n]=m*4 2; n ; while(!L3); delay10ms(); while(!L3); } } if(L4==0) {delay10ms(); if(L4==0) { password[n]=m*4 3; n ; while(!L4); delay10ms(); while(!L4) ; } } temp=P1; temp=temp|0x0f; temp=temp<<1; temp=temp|0x0f; P1=temp; } } void main() { uchar j; while(1) { display(); keyscan(); if(n==6) { n=0; for(j=0;j<=5;j ) { led[j]=password[j]; } } } }

4.运行程序后,随意按下键盘上的六个键,数码管上会显示相应的数值。附上计算器的源代码(大家可以试试)

①原理图

单片机行列式键盘的工作原理 单片机学习第四课(9)

②代码(注释乱码,其他正常)

main程序

#include <reg52.h> #include "key.h" #include "smg.h" #include "timer.h" int main(void) { u8 ret = 0; Show_Number(0); while(1) { Smg_Dymainc( ); Jz_Key_Scan( ); } }

按键 key.c

#include "key.h" u8 code KeyCode[16] = { 0x31, 0x32, 0x33, 0x26, 0x34, 0x35, 0x36, 0x25, 0x37, 0x38, 0x39, 0x28, 0x30, 0x1B, 0x0D, 0x27}; void Key_Delay(u16 n) { u16 x, y; for(x = 0; x < n; x ) { for(y = 0; y < 110; y ); } } u8 buf[5][3]; u8 Key_Scan(void) { static u8 key_sta = 0; static char i = 0; if((KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0) && (key_sta == 0)) { Key_Delay(10); if((KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0) && (key_sta == 0)) { if(KEY1 == 0) { key_sta = 1; TR0 = !TR0; }else if(KEY2 == 0) { key_sta = 1; buf[i][0] = msec; buf[i][1] = sec; buf[i][2] = min; i ;//1 2 if(i >= 5) i = 0; }else if(KEY3 == 0) { key_sta = 1; i--; if(i < 0) i = 0; msec = buf[i][0]; sec = buf[i][1]; min = buf[i][2]; }else if(KEY4 == 0) { key_sta = 1; msec = 0; sec = 0; min = 0; } } } else if(KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1)//û°´¼ü°´Ï { key_sta = 0; } return 0; } u8 Jz_Key_Scan(void) { u8 temp = 0xff; static u8 flag = 0; P1 = 0x0f; if((P1 != 0x0f) && (flag == 0)) { Key_Delay(10); if((P1 != 0x0f) && (flag == 0)) { flag = 1; switch(P1) { case 0x07: temp = 0; break; case 0x0b: temp = 1; break; case 0x0d: temp = 2; break; case 0x0e: temp = 3; break; } P1 = 0xf0; switch(P1) { case 0x70: temp = 0; break; case 0xb0: temp = 4; break; case 0xd0: temp = 8; break; case 0xe0: temp = 12; break; } Data_Control(KeyCode[temp]); } }else if(P1 == 0x0f) { flag = 0; } return temp; }

数码管显示

#include "smg.h" u8 leddata[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71, 0x40, 0x00 }; u8 buff[8] = {0}; void Smg_Delay(u16 n) { u16 x, y; for(x = 0; x < n; x ) { for(y = 0; y < 110; y ); } } void Smg_Static(u8 number) { P0 = leddata[number]; } void Smg_Dymainc(void) { u8 i; for(i = 0; i < 8; i ) { P0 = 0x00; switch(i) { case 0: LA = 0; LB = 0; LC = 0; break; case 1: LA = 1; LB = 0; LC = 0; break; case 2: LA = 0; LB = 1; LC = 0; break; case 3: LA = 1; LB = 1; LC = 0; break; case 4: LA = 0; LB = 0; LC = 1; break; case 5: LA = 1; LB = 0; LC = 1; break; case 6: LA = 0; LB = 1; LC = 1; break; case 7: LA = 1; LB = 1; LC = 1; break; } Smg_Static(buff[i]); Smg_Delay(1); } } void Show_Number(u16 dis)//12 { u8 bf[8] = {0}; char i = 0; for(i = 0; i < 8; i ) { bf[i] = dis % 10;//bf[0] = 2 bf[1] = 1 bf[2] -- bf[7] = 0 dis = dis / 10; } for(i = 7; i >= 1; i--)//b[2] - bf[7] { if(bf[i] == 0) { buff[i] = 17; }else { break;//1 } } for(; i >= 0; i--) { buff[i] = bf[i]; } } void Data_Control(u8 dat)//12 5 { static u16 temp = 0; static u16 result = 0; static bit add_flag = 0; //¼Ó·¨±ê־λ static bit sub_flag = 0; //¼õ·¨±ê־λ static bit mul_flag = 0; //³Ë·¨±ê־λ static bit div_flag = 0; //³ý·¨±ê־λ if(dat >= 0x30 && dat <= 0x39)//°´¼ü°´ÏµÄÊÇÊý×Ö { temp = temp * 10 dat - '0'; //12 Show_Number(temp);//ÏÔʾÊý×Ö } else if(dat == 0x26) // ºÅ { result = temp; temp = 0; add_flag = 1; Show_Number(result);//ÏÔʾÊý×Ö } else if(dat == 0x25) // -ºÅ { if(result == 0 && temp != 0) { result = temp; }else { result -= temp; } sub_flag = 1; temp = 0; Show_Number(result);//ÏÔʾÊý×Ö } else if(dat == 0x28) // *ºÅ { if(result == 0 && temp != 0) { result = temp; }else if(result != 0 && temp == 0) { result = result; } else { result *= temp; } mul_flag = 1; temp = 0; Show_Number(result);//ÏÔʾÊý×Ö } else if(dat == 0x27) // /ºÅ { if(result == 0 && temp != 0) { result = temp; }else if(result != 0 && temp == 0) { result = result; } else { result /= temp; } div_flag = 1; temp = 0; Show_Number(result);//ÏÔʾÊý×Ö } else if(dat == 0x0D) // =ºÅ { if(add_flag == 1)//ÇóºÍ { add_flag = 0; result = temp; }else if(sub_flag == 1)//Çó²î { sub_flag = 0; result -= temp; } else if(mul_flag == 1)//Çó»ý { mul_flag = 0; result *= temp; } else if(div_flag == 1)//ÇóÉÌ { div_flag = 0; result /= temp; } temp = 0; Show_Number(result);//ÏÔʾÊý×Ö } else if(dat == 0x1b) // ÇåÁã { result = 0; temp = 0; Show_Number(result);//ÏÔʾÊý×Ö } }

timer.c

#include "timer.h" //º¯Êý¹¦ÄÜ£º¶¨Ê±Æ÷³õʼ»¯ //º¯ÊýÐβΣºÎÞ //·µ»ØÖµ£ºÎÞ void Timer_Init(void) { TMOD &= 0xf0; // XXXX XXXX // 1111 0000 // XXXX 0000 TMOD |= 0x01; // XXXX 0000 // 0000 0001 // XXXX 0001 TH0 = (65536 - 1000) / 256; TL0 = (65536 - 1000) % 256; ET0 = 1; EA = 1; } u8 msec; u8 min; u8 sec; void Timer_interrupt(void) interrupt 1 //1ms { static u16 cnt = 0; TH0 = (65536 - 1000) / 256; TL0 = (65536 - 1000) % 256; cnt ; if(cnt >= 10) { cnt = 0; msec ; if(msec >= 100) { msec = 0; sec ; if(sec >= 60) { sec = 0; min ; if(min >= 60) min = 0; } } }

,