m0单片机io口_51单片机独立按键和矩阵按键实现

独立按键实验

按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时, 开关断开。我们开发板上使用的按键及内部简易图如下图所示

m0单片机io口_51单片机独立按键和矩阵按键实现_第1张图片

管脚与管脚之间(注意是距离)距离长的是导通状态,短的是接通状态。 通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号 如下图所示:

m0单片机io口_51单片机独立按键和矩阵按键实现_第2张图片

如图所示,按键闭合式不会立刻稳定的接通,断开时也不会一下子断开,会伴随一些抖动。抖动的时间长短有按键特性决定,一般为5Ms到10ms.按键抖动会引起按键被误读多次。为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖

  • 消抖 消抖可分为硬件消抖和软件消抖。为了使电路更加简单,通常采用软件消抖。 一般来说一个简单的按键消抖就是先读取按键的状态, 如果得到按键按下之后, 延时 10ms, 再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。 其中延时 10ms 就是软件消抖处理。 消抖过程(软件) 1,先设置 IO 口为高电平(由于开发板 IO 都有上拉电阻,所以默认 IO 为高电平)。 2,读取 IO 口电平确认是否有按键按下。 3,如有 IO 电平为低电平后,延时几个毫秒。 4,再读取该 IO 电平,如果任然为低电平,说明对应按键按下。 5,执行相应按键的程序。
  • 键盘 键盘分为编码键盘和非编码键盘。键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值的称为编码键盘,如计算机键盘。而靠软件编程来识别的键盘称为非编码键盘,在单片机组成的各种系统中,用的较多的是非编码键盘。非编码键盘又分为独立键盘和行列式键盘(常说的矩阵键盘)。独立按键用的就是独立键盘。
  • 实现原理 原理图:

m0单片机io口_51单片机独立按键和矩阵按键实现_第3张图片

独立按键电路构成是由各个按键的一个管脚连接在一起接地,按键其他引脚分别接到单片机 IO 口。 单片机的 IO 口既可作为输出也可作为输入使用,当检测按键时用的是它的输入功能,独立按键的一端接地,另一端与单片机的某个 I/O 口相连,开始时先给该 IO 口赋一高电平,然后让单片机不断地检测该 I/O 口是否变为低电平,当按键闭合时,即相当于该 I/O 口通过按键与地相连,变成低电平,程序一旦检测到 I/O 口变为低电平则说明按键被按下,然后执行相应的指令。

m0单片机io口_51单片机独立按键和矩阵按键实现_第4张图片

由图可以看出,单片机的管脚(p1,p3,等管脚)都接有上拉电阻,上拉电阻接高电平。因此我们在消抖检测时,若按键以已经按下,则管脚接地,变为低电平,若管脚为低电平,则说明按键已经按下,执行LED灯点亮的步骤。

  • 代码实现
#include 
#include 
typedef unsigned char u8; //重定义全局字符型变量
typedef unsigned int u16; //重定义全局整型变量
sbit LED=P2^0 ;  //LED接P2口
sbit K1=P3^1; //按键k1接p3口,也可以是其他管脚

/*延时函数*/
void dealy(u16 i)
{
while(i--);
}

/*独立按键执行函数
*/
void KeyProcess()
{  
   if(K1==0){
     dealy(1000);
         //一个int型的所占的时间大约为10微妙,所以乘1000大约为10ms.
         if(K1==0){  //消抖后仍为低电平,则执行点亮进程
          LED=~LED;    //为了让LED产生明暗变化
         }
         while(!K1);  //判断按键是否松开,假如松开,则K1为真,加!为假,则循环结束跳出循环
   }
   
}

void main()
{ 
  LED=0;  //初始时灯位熄灭状态(LED原理),
  while(1)
  {
        KeyProcess();
  }      
}
 

矩阵按键实验

  • 前面我们讲到独立按键,接下来我们引入独立按键。为什么引入矩阵按键?
    独立键盘与单片机连接时,每一个按键都需要单片机的一个 I/O 口,若某单片机系统需较多按键,如果用独立按键便会占用过多的 I/O 口资源。单片机系统中 I/O 口资源往往比较宝贵,多个按键时为了减少 I/O 口引脚。
  • 4 * 4键盘的工作原理
    矩阵按键原理图

m0单片机io口_51单片机独立按键和矩阵按键实现_第5张图片

开发板上将 16 个按
键排成 4 行 4 列,第一行将每个按键的一端连接在一起构成行线,第一列将每
个按键的另一端连接在一起构成列线,这样便一共有 4 行 4 列共 8 根线,我们将
这 8 根线连接到单片机的 8 个 I/O 口上,通过程序扫描键盘就可检测 16 个
键。

  • 矩阵按键的消抖
    1.检查按键是否按下

m0单片机io口_51单片机独立按键和矩阵按键实现_第6张图片


由原理图可知,独立按键和矩阵按键是有所不同的。独立按键的各个按键一端接引脚,一端并联在一起接地。所以检测按键是否按下只需要看单片机的管脚是否为低电平即可。而矩阵按键,他们的两端分别并联在一起,
每一行(共4行)并联在一起接高位管脚上(7~4),每一列(共4列)并联在一起接到低位管脚上(3~0)。
所以检测方法有所不同。
一般情况下有两种方法。
方法一:
逐行扫描:我们可以通过高四位轮流输出低电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。逐行扫描的时间是非常快的,肉眼难以观察。
举个例子,假设此时p7管脚为低电平,那么第一行按键的一段都为低电平,另一端分别连接低4位的管脚,只有当某一个开关按下,低4位的管脚与其中一个低电平的管脚连接变为低电平,所以只要查看低4位那个管脚为低电平就可以确定那个按键以按下。其他三行同理,每一行依次不断进行。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。相当于第一次确定列,第二次确定行,行列交叉形成点,这个点就是我们要找的已经闭合的按键。

  • 静态数码管显示按键

m0单片机io口_51单片机独立按键和矩阵按键实现_第7张图片


如图,每一个按键可用一个键值来代替,让对应的键值号来作为静态数码管的段选,从而实现按下按键显示数字的效果。

  • 代码实现
    采用第二种行列扫描的检测方法
#include                          //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;         //对数据类型进行声明定义
typedef unsigned char u8;

#define GPIO_DIG P0        //宏定义p0口(静态显示数码管对应的管脚)
#define GPIO_KEY P1       //矩阵按键对应管脚


u8 KeyValue;    //用来存放读取到的键值


u8 code smgduan[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
                                        0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//显示0~F的值

/*延时·函数*/
void delay(u16 i)
{
        while(i--);     
}

/*检测按键是否按下,消抖,读取键值*/
void KeyDown(void)
{
        char a=0;
        GPIO_KEY=0x0f;    
        //0x0f转化为为二进制为0000 1111,即矩阵按键的八个管脚,高位为低电平(0),低位为高电平(1)
        if(GPIO_KEY!=0x0f)//读取按键是否按下
        {
                delay(1000);//延时10ms进行消抖
                if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
                {       
                        /*对列进行测试(高位低电平,低位高电平)*/
                        GPIO_KEY=0X0F;
                        switch(GPIO_KEY)
                        {
                                case(0X07): KeyValue=0;break; //对应管脚高低电平0000 0111,第0列
                                case(0X0b): KeyValue=1;break; //对应管脚高低电平0000 1011,第1列
                                case(0X0d): KeyValue=2;break; //对应管脚高低电平0000 1101,第2列
                                case(0X0e): KeyValue=3;break;//对应管脚高低电平0000 1110,第3列
                        }
                        /*对行进行测试(低位高电平,高位低电平)*/
                        GPIO_KEY=0XF0;
                        switch(GPIO_KEY)
                        {        /*上一行对应的列号加上相应有规律的字号就等于按键号,可由原理图查看*/
                                case(0X70): KeyValue=KeyValue;break; //对应管脚高低电平0111 0000,第0行
                                case(0Xb0): KeyValue=KeyValue+4;break; //对应管脚高低电平1011 0000,第1行
                                case(0Xd0): KeyValue=KeyValue+8;break;//对应管脚高低电平1101 0000,第2行
                                case(0Xe0): KeyValue=KeyValue+12;break;     //对应管脚高低电平1110 0000,第0行
                        }
                        
                }
        }
        while((a<50)&&(GPIO_KEY!=0xf0))
    //检测按键松手检测(只有当按键松开时矩阵连接的管脚高位和低位才会互换继续检测行。否则进行循环延迟)
        {
                delay(100);
                a++;
        }
}

/*主函数*/
void main()
{	

	while(1)
	{	
		KeyDown();		   //按键判断函数
		GPIO_DIG=~smgduan[KeyValue];	  //
	}		
}

你可能感兴趣的:(m0单片机io口,单片机按键防抖程序,矩阵键盘与六位数码管)