https://blog.csdn.net/qq_38351824/article/details/89135034
    分类
    编码键盘:闭合键的识别有专门的硬件编码器来实现,以此产生编码号和键值;
    非编码键盘:靠软件编程来识别的键盘,在单片机里用的较多,分为独立键盘和矩阵式键盘
    按下:接通电平
    按下和松开时会存在抖动现象,默认按下很多次,因此要消抖。
    image.png
    消抖原理:延时函数,把抖动时间(大约5ms)消除掉

    独立按键控制led,四个按键控制亮灭**

    1. #include "reg51.h"
    2. typedef unsigned char u8;
    3. typedef unsigned char u16;
    4. sbit led=P2^0; //led,P1口
    5. sbit k1=P3^1; //按键的口
    6. sbit k2=P3^0; //按键的口
    7. sbit k3=P3^2; //按键的口
    8. sbit k4=P3^3; //按键的口
    9. void delay(u16 i)
    10. {
    11. while (i--);
    12. }
    13. void keypros()
    14. {
    15. if(k1==0) //判断是否低电平
    16. {
    17. delay(1000);//延时10ms消抖处理,利用延时把抖动的信号屏蔽掉
    18. if(k1==0) //稳定闭合阶段的低电平,判断是否按下
    19. {
    20. led=~led; //状态反转
    21. }
    22. while(!k1); //松开的判断,松开电位为1,非运算跳出循环,往下进行
    23. }
    24. else if(k2==0)
    25. {
    26. delay(1000);
    27. if(k2==0)
    28. {
    29. led=~led;
    30. }
    31. while(!k2);
    32. }
    33. else if(k3==0)
    34. {
    35. delay(1000);
    36. if(k3==0)
    37. {
    38. led=~led;
    39. }
    40. while(!k3);
    41. }
    42. else if(k4==0)
    43. {
    44. delay(1000);
    45. if(k4==0)
    46. {
    47. led=~led;
    48. }
    49. while(!k4);
    50. }
    51. }
    52. void main()
    53. {
    54. led=1;
    55. while(1)
    56. {
    57. keypros();
    58. }
    59. }

    矩阵按键原理
    由来:排成四行的独立按键,横向公用一条线,纵向公用另一条线。独立键盘与单片机连接时,每一个按键都需要单片机的一个I/O口,若某单片机系统需较多按键,如果用独立按键便会占用过多的I/O口资源。单片机系统中I/O口资源往往比较宝贵,当用到多个按键时,为了节省I/O口线,我们引入矩阵键盘。
    image.pngimage.png
    检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。这就是矩阵键盘检测的原理和方法。

    1. #include "reg52.h"
    2. #include "intrins.h"
    3. typedef unsigned char u8;
    4. typedef unsigned char u16;
    5. sbit LSA=P2^2;
    6. sbit LSB=P2^3;
    7. sbit LSC=P2^4;
    8. #define GPIO_KEY P1
    9. #define GPIO_DIG P0 //定义按键端口
    10. u8 KeyValue,a;
    11. u8 code smgduan[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 , 0x6d ,0x7d , 0x07 , 0x7f , 0x6f , 0x77 , 0x7c ,
    12. 0x39 , 0x5e , 0x79 , 0x71 , 0x00};
    13. void delay(u16 i)
    14. {
    15. while(i--);
    16. }
    17. void KeyDown() //扫描程序,行列扫描
    18. {
    19. GPIO_KEY=0x0f; //初始化为低电平
    20. if(GPIO_KEY!=0x0f)
    21. {
    22. delay(1000); //延时消抖
    23. if(GPIO_KEY!=0x0f)
    24. {
    25. GPIO_KEY=0x0f;
    26. switch(GPIO_KEY) //高四位0,低四位1扫描,测试列
    27. {
    28. case 0x07: KeyValue=0; break; //0000 0111转16进制,表示第一个列按下
    29. case 0x0b: KeyValue=1; break; //数码管显示1
    30. case 0x0d: KeyValue=2; break;
    31. case 0x0e: KeyValue=3; break;
    32. }
    33. GPIO_KEY=0xf0;
    34. switch(GPIO_KEY) //低四位0,高四位1扫描,测试行,电平反过来
    35. {
    36. case 0x70: KeyValue=KeyValue; break; //0111 0000转16进制,表示第一个行按下,电平是反的
    37. case 0xb0: KeyValue=KeyValue+4; break; //数码管显示5,此时keyvalue是行的返回值
    38. case 0xd0: KeyValue=KeyValue+8; break;
    39. case 0xe0: KeyValue=KeyValue+12; break;
    40. }
    41. while((a<50)&&(GPIO_KEY!=0xf0)) //检测是否按下
    42. {
    43. delay(1000);
    44. a++; //a到50退出循环,防止一直按着消抖占用cpu
    45. }
    46. }
    47. }
    48. }
    49. void main()
    50. {
    51. LSA=0;
    52. LSB=0;
    53. LSC=0; //数码管位选
    54. while(1) //一直检测按键
    55. {
    56. KeyDown();//判断按键按下后
    57. GPIO_DIG=smgduan[KeyValue]; //调用按键数码显示函数
    58. }
    59. }

    **