蓝桥杯单片机学习4——独立按键&矩阵按键

上期学习了数码管的静态显示,这次我们来学习独立按键&矩阵按键

独立按键

蓝桥杯单片机学习4——独立按键&矩阵按键_第1张图片

原理很简单,当作为独立按键使用时,跳线帽的23接在一起,此时按键如果按下,则按键连接的IO口电平会被拉低,通过捕获IO的电平变化,就可以判断按键是否按下。

按键消抖

什么是按键消抖?按键为什么会有抖动?
蓝桥杯单片机学习4——独立按键&矩阵按键_第2张图片

通常的按键所用开关为机械弹性开关。由于机械触电的弹性作用,按键在闭合及断开的瞬间均伴随有一连串的抖动。键抖动会引起一次按键被误读多次。为了确保CPU对键的一次闭合仅作一次处理,必须去除抖动。
如何消抖?
硬件消抖:硬件消抖的典型做法是:采用 R-S触发器 或RC积分电路。在没有MCU的情况下通常使用这种方法,但在嵌入式开发中,我们比较常用的时软件消抖。
软件消抖:软件消抖是当检测出键闭合后执行一个10ms~20ms的延时程序,再一次检测键的状态,如仍保持闭合状态,则确认真正有按键按下。

矩阵按键

蓝桥杯单片机学习4——独立按键&矩阵按键_第3张图片
作为矩阵按键使用时,跳线帽的12脚连接在一起。
矩阵按键的优点:可以通过比较少的IO实现对多个按键的控制,节省IO口。
缺点:在使用时需要对按键进行扫描。

扫描

对于独立按键,它的每一个IO都对应着一行或一列,通过读取按键按下时的行和列,就可以确定是哪一个按键按下。
扫描就是对按键的每一行(列)进行扫描,从而得到按键按下的行(列),从而确定是否有按键按下,以及按键按下的键码值。目前按键扫描的方法,主要分为行扫描和列扫描两种。
所谓行扫描就是,先把每一行和每一列的上的电平拉高,然后分别把每一行的电平依次拉低,去检测每一个列上的电平是否跟着被拉低,如果被拉低,说明按键按下,则可以去读到当前的行和列,计算出按下的键码值。
列扫描则和行扫描的逻辑相反,这里不做赘述。

代码实现

1.main.c

#include 
#include 
#include "Key.h"
#include "LS138.h"

//效果:当有按键按下时,会在数码管上显示当前按下按键的键码值
//当没有按键按下时,数码管会显示上一次按下的键码值
void main()
{
    unsigned int i =0;
    LS138_Init();
    Key_Init();     //初始化函数
    
	while(1)
	{
        
        if(Get_KeyBoard_Num())  //判断矩阵按键是否有按下
        {
            i = Get_KeyBoard_Num();     //如果按下则,改变当前变量的值,
        }
         SEG_Write_Num(i);              //通过数码管显示矩阵按键按下的键码值

	}
}

2.Key.h

#ifndef __KEY_H_
#define __KEY_H_
#include 
#include 

sbit Key7 = P3^0;
sbit Key6 = P3^1;
sbit Key5 = P3^2;
sbit Key4 = P3^3;

sbit Col1 = P4^4;
sbit Col2 = P4^2;
sbit Col3 = P3^5;
sbit Col4 = P3^4;

#define Row1  Key4
#define Row2  Key5
#define Row3  Key6
#define Row4  Key7

//延时函数,可以延时xms的时间
void Delayxms(unsigned int x);		//@11.0592MHz
//初始化函数
void Key_Init(void);

//按键扫描函数,由按键按下时返回值为1,否则为0
unsigned char Key_Scan(void);

//获取当前按键按下的数值,返回结果为4~7
//当没有按键按下是,返回值为0
//函数内部由两种实现方法,一直延时,一种不延时。可以按需要使用
unsigned int Get_Key_Num(void);

//获取当前矩阵按键中按下健的值
//返回值为4~19
//当没有按键按下时,返回值为0
unsigned int Get_KeyBoard_Num(void);

#endif  /*__KEY_H_*/

这里有一个Delayxms()延时函数,可以延时xms.这个不是static 修饰的,外部可调用

3.Key.c

#include "Key.h"

//延时函数,可以延时xms的时间
 void Delayxms(unsigned int x)		//@11.0592MHz
{
	unsigned char i,j,k;
    for(k=0;k<x;k++)
    {
        
        _nop_();
        _nop_();
        _nop_();
        i = 11;
        j = 190;
        do
        {
            while (--j);
        } while (--i);
    }
}
//初始化函数
void Key_Init(void)
{
    Key7 = Key6 = Key5 = Key4 =1;
    Col1 = Col2 = Col3 = Col4=1;
}

//按键扫描函数,由按键按下时返回值为1,否则为0
unsigned char Key_Scan(void)
{   
    static unsigned char Key_Count =0;
   if(Key7==0 | Key6==0 | Key5==0 | Key4==0 )
    {
        Key_Count++;
        Delayxms(1);
        if(Key_Count >= 100)
        {
            return 1;
            Key_Count=0;
        }
        
    }
    return 0;
}

//获取当前按键按下的数值,返回结果为4~7
//当没有按键按下是,返回值为0
//函数内部由两种实现方法,一直延时,一种不延时。可以按需要使用
unsigned int Get_Key_Num(void)
{
    #if 1       //这个是没有延时的,需要多次进入函数。
    static unsigned char  Key_Count = 0;
    if(Key7==0 | Key6==0 | Key5==0 | Key4==0 )
    {
        Key_Count++;
        Delayxms(1);
        if(Key_Count >= 100)
        {
            if(Key7 == 0)
            {
                return 7;
            }
             if(Key6 == 0)
            {
                return 6;
            }
             if(Key5 == 0)
            {
                return 5;
            }
             if(Key4 == 0)
            {
                return 4;
            }
            Key_Count=0;
        }
        
    }
    return 0;
    #if 0           //这个是有延时的,只需要进入函数一次,但是会导致系统Delay在函数内部
     if(Key7==0 | Key6==0 | Key5==0 | Key4==0 )
    {
        Delayxms(20);
        if(Key7 == 0)
        {
            while(!Key7)
            {
               
            }
             return 7;
        }
         if(Key6 == 0)
        {
            while(!Key6)
            {
               
            }
             return 6;
        }
         if(Key5 == 0)
        {
            while(!Key5)
            {
               
            }
             return 5;
        }
         if(Key4 == 0)
        {
            while(!Key4)
            {
               
            }
             return 4;
        }
    }
    else
    {
        return 0;
    }
    #endif 
}

//获取当前矩阵按键中按下健的值
//返回值为4~19
//当没有按键按下时,返回值为0
unsigned int Get_KeyBoard_Num(void)
{
    unsigned char i;
    for(i=0;i<4;i++)
    {
        P3 =0x03F;
        Col1 = Col2 = 1;
        P3 =~(0x08>>i);       //Rowi = 1;       //第一行为0
//        Delayxms(1);
        if(Col1==0 | Col2==0 | Col3==0 | Col4==0)   //扫描每一列是否有按键按下
        {
           Delayxms(20);
          if(~Col1)
          {
            return i+4;
          }
          if(~Col2)
          {
            return i+8;
          }
          if(~Col3)
          {
            return i+12;
          }
          if(~Col4)
          {
            return i+16;
          }
        }
    }
    return 0;
    
}

这里面获取独立按键的键码值的函数,我写了两种实现方式,
区别就是一个用到的软件消抖(使用了延时函数),另一个没有使用软件消抖,但是需要多次调用进入函数才可以使用,具体实现方法可以自己看代码的。需要使用哪一种方法,可以自行选择。
为什么这么写:在后面如果学习使用到了定时器的话,在函数内部进行延时,可能会影响其他对时间要求比较严格的模块。造成不必要的损失。

总结

独立按键&矩阵按键这一部分比较简单,原理也容易看懂,我这里只实现了基本的按键控制功能,大家也可以尝试着去实现,长按、短按、双击、等功能,我就不再去多写啦。好好努力吧!
蓝桥杯单片机学习4——独立按键&矩阵按键_第4张图片

你可能感兴趣的:(蓝桥杯单片机学习,蓝桥杯,单片机,学习,c语言,嵌入式硬件)