矩阵键盘

矩阵键盘

丹山起凤 2019-05-27 11:05:19  3785  收藏 8

分类专栏: 单片机

矩阵键盘的原理及应用 - MARS的博客 - CSDN博客 https://blog.csdn.net/qq_40642465/article/details/80334530

矩阵键盘原理图:

第一行的行控制线接到p17,第二行的行控制线接到p16,第三行的行控制线接到p15,第4行的行控制线接到p14
第一列的列控制线接到p13,第二列的列控制线接到p12,第三列的列控制线接到p11,第四列的列控制线接到p10
矩阵键盘的原理和独立按键类似,另外我们可以把矩阵键盘的任意一行或一列作为一个独立键盘使用,假如我们把第一行作为独立键盘,那么我们只需要让P17输出高电平,其余7个io口输出低电平即可,假如我们按下了s1,那么p13的电平就会被拉低,变为低电平,所以我们可以通过查找低4位里哪一位为低电平就可以知道哪个按键按下了。
下面来说说矩阵按键扫描原理(即当我们按下一个矩阵键盘的按键时,如何获取按键的位置)
方法有2种,一种是逐行扫描,一种是行列扫描.接下来就主要讲讲行列扫描.

1、行列扫描法


行列扫描的话,就是一开始让p1口高4位输出高电平,低4位输出低电平,若这4行按键里,有按键按下了,那么那一行按键对应的io的电平就会被拉低,我们就可以知道按键的行坐标.获取按键列坐标的方法也是类似的,就是一开始让p1口高4位输出低电平,低4位输出高电平,若这4列按键里,有按键按下了,那么那一列按键对应的io的电平就会被拉低,我们就可以知道按键的列坐标,获得了行坐标x,列坐标y后,4*(x-1)+y就是按键的编号.
接下来贴份应用的代码,目的就是赋予16个按键键值,分别对应的键值是从0~F。按下一个键,第一个数码管就显示对应的键值

  1. #include<reg52.h>
  2. sbit lsa=P2^2;
  3. sbit lsb=P2^3;
  4. sbit lsc=P2^4;
  5. #define duanxuan P0
  6. #define keyboard P1
  7. int zxm[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  8. int x,y;
  9. void delay(int i)
  10. {
  11.     while(i--);
  12. }
  13. void keyproc()
  14. {
  15.     int a=0;
  16.     P1=0x0f;//检测是哪一列有按键按下;
  17.     if(P1!=0x0f)
  18.     {
  19.         delay(1000);
  20.         if(P1!=0x0f)
  21.         {
  22.             P1=0x0f;
  23.             switch(P1)
  24.             {
  25.                 case(0x07):y=1;break;
  26.                 case(0x0b):y=2;break;
  27.                 case(0x0d):y=3;break;
  28.                 case(0x0e):y=4;break;
  29.             }
  30.         }
  31.         P1=0xf0;//检测是哪一行有按键按下
  32.         switch(P1)
  33.         {
  34.             case(0x70):x=1;break;
  35.             case(0xb0):x=2;break;
  36.             case(0xd0):x=3;break;
  37.             case(0xe0):x=4;break;
  38.         }
  39.         while(a<50&&P1!=0xf0)//当按键按下的时间超过了500ms或者按键松开了就退出while循环
  40.         {
  41.             delay(1000);
  42.             a++;
  43.         }
  44.         
  45.  
  46.     }
  47. }
  48. int main()
  49. {
  50.     lsa=0;
  51.     lsb=0;
  52.     lsc=0;//位选选中第一个数码管
  53.     P0=0x00;//第一个数码管先什么都不显示
  54.     while(1)
  55.     {
  56.         keyproc();
  57.         P0=zxm[(x-1)*4+y-1];//送入段选信息
  58.         
  59.         
  60.     }
  61.     return 0;
  62.     
  63. }

2、行扫描法

原文:https://blog.csdn.net/zxnsirius/article/details/51088946 

  1. 根据原理图 
    键盘扫描方法是:行线P10~P13为输出线,列线P14~P17为输入线。一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键按下,当列线有出现低电平时调用延时程序以此来去除按键抖动。延时完成后再判断是否有低电平,如果此时读入列线数据还是有低电平,则说明确实有键按下。最后一步确定键值。现在我们以第二行的S5键为例,若按下S5后我们应该怎么得到这个键值呢?当判断确实有键按下之后,行线轮流输出低电平,根据读入列线的数据可以确定键值。首先,单片机将P10输出为低电平,其它P11~P13输出高电平,此时读取列线的数据全为高电平,说明没有在第一行有键按下;其次,单片机将P11输出低电平,其它P10、P12、P13仍为高电平,此时再来读取列线数据,发现列线读到的数据有低电平,数值为1011(0x0B),如果我们的键盘布局已经确定,那么0x0B就代表S5的值了。转到S5键功能处理子程序就可以达到目的。

    /*  
        功能:矩阵键盘扫面,按键显示键值程序 
        作者:siriuszxn
                                      */
    #include "reg51.h"                                                                                                                
    #define KEYPORT = P1                                                                                                   

    unsigned char i;                                                                                                                                         
    unsigned char Keynum;                                                                                                        
    unsigned char Line;                                       //行                                                                 
    unsigned char Mask;                                                                                                         
    unsigned char Col;                                        //列                                                                      
    unsigned char ScanCode;                                                                                              

    unsigned char code psegs_table[] =                                                                                            {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};                                                                //共阳极数码管0-F                                                                                                                                            

    void delay_ms(unsigned int t)                      //ms延时程序                                                                      
    {                                                                                                                                       
        unsigned char i;                                                                                                                 
         unsigned int x;                                                                                                                  
         x=t;                                                                                                                              
         while(x--)                                                                                                                        
         {                                                                                                                                          
                 for(i=0;i<113;i++);                                                                                                              
         }                                                                                                                                           
    }                                                                                                                                        
    /* 键盘扫描程序 */                                                                                                                                        
    void keyscan()                                                                                                           
    {                                                                                                                                   
        while (1)              //循环扫描键盘       
        {                                                                                                                            
           P1 = 0xff;          //开始                                                         
            Line = 1;                                                                                         
            Mask = 0x01;                                                                                         

            for(i = 0; i < 4; i++)                                                                                   
            {                                                                                                                                                                                    
                P1 = ~Mask;                                                                                    

                ScanCode = P1 & 0xf0;                                                                                          

                if (ScanCode != 0xf0)                                                                                         
                {                                                                                                                                                                                    
                    delay_ms(5);                                                                               
                }                                                                                                                                                                                    

                ScanCode = P1 & 0xf0;                                                                                          

                switch(ScanCode)                                                
                {                                                                                                                                                                                    
                    case 0xe0:Col=1;break;                                                                                          
                    case 0xd0:Col=2;break;                                                                   
                    case 0xb0:Col=3;break;                                                                          
                    case 0x70:Col=4;break;                                                                  
                    default  :Col=0;break;                                                                                          
                }                                                                                                                                                                                    

                if (Col > 0)                                                                                                                                           
                {   
                    //根据行列计算键值                                                                                                                                                         
                    Keynum = (Line - 1) * 4 + Col;                                                                  
                    //通过P0口接数码管显示                                                                                                          
                    P0 = psegs_table[Keynum-1];                                                                                          

                    while(1)                                                                                           
                    {                                                                                
                        ScanCode = P1 & 0xf0;                                                                                
                        if(ScanCode == 0xf0)                                                               
                        {                                                                                                                                              
                            break;                                                    
                        }                                                                                                                       
                    }                                                                                
                    Mask <<= 1;                                                                                                      
                    Line++;                                                                                                 
                }                                                                                                                        
            }                                                                                                                                      
        }  
    }                                                                                                                                   

    void main()                                                                                         
    {                                                                                                                                     
        while(1)                                                                                                                      
        {                                                                                                                                 
            keyscan();                                                                                         
        }                                                                                                                                 
    }                           
    STM32 >> 矩阵键盘(代码风格优美,简明易懂)

  2. 原文:https://blog.csdn.net/weixin_40973138/article/details/86607562

key.h

  1. /**
  2.   ******************************************************************************
  3.   * @file    bsp_key.h
  4.   * @author  Waao
  5.   * @version V1.0.0
  6.   * @date    23-Jan-2019
  7.   * @brief   This file contains some board support package's definition for the KEY.
  8.   *            
  9.   ******************************************************************************
  10.   * @attention
  11.   *
  12.   * None
  13.     *
  14.   ******************************************************************************
  15.   */
  16. #ifndef __BSP_KEY_H_
  17. #define __BSP_KEY_H_
  18.  
  19. #include <stm32f4xx.h>
  20. #include <bsp_systick.h>
  21. #include <bsp_usart.h>
  22.  
  23. // Column1, Column2, Column3, Column4
  24. #define C1_PIN             GPIO_Pin_2
  25. #define C1_GPIO_PORT       GPIOE
  26. #define C1_GPIO_CLK        RCC_AHB1Periph_GPIOE
  27. #define C2_PIN             GPIO_Pin_3
  28. #define C2_GPIO_PORT       GPIOE
  29. #define C2_GPIO_CLK        RCC_AHB1Periph_GPIOE
  30. #define C3_PIN             GPIO_Pin_4
  31. #define C3_GPIO_PORT       GPIOE
  32. #define C3_GPIO_CLK        RCC_AHB1Periph_GPIOE
  33. #define C4_PIN             GPIO_Pin_5
  34. #define C4_GPIO_PORT       GPIOE
  35. #define C4_GPIO_CLK        RCC_AHB1Periph_GPIOE
  36.  
  37. // Row1, Row2, Row3, Row4
  38. #define R1_PIN             GPIO_Pin_12
  39. #define R1_GPIO_PORT       GPIOB
  40. #define R1_GPIO_CLK        RCC_AHB1Periph_GPIOB
  41. #define R2_PIN             GPIO_Pin_13
  42. #define R2_GPIO_PORT       GPIOB
  43. #define R2_GPIO_CLK        RCC_AHB1Periph_GPIOB
  44. #define R3_PIN             GPIO_Pin_14
  45. #define R3_GPIO_PORT       GPIOB
  46. #define R3_GPIO_CLK        RCC_AHB1Periph_GPIOB
  47. #define R4_PIN             GPIO_Pin_15
  48. #define R4_GPIO_PORT       GPIOB
  49. #define R4_GPIO_CLK        RCC_AHB1Periph_GPIOB
  50.  
  51. // detect and output
  52. #define DETECT_C1          GPIO_ReadInputDataBit(C1_GPIO_PORT, C1_PIN)
  53. #define DETECT_C2          GPIO_ReadInputDataBit(C2_GPIO_PORT, C2_PIN)
  54. #define DETECT_C3          GPIO_ReadInputDataBit(C3_GPIO_PORT, C3_PIN)
  55. #define DETECT_C4          GPIO_ReadInputDataBit(C4_GPIO_PORT, C4_PIN)
  56. #define DETECT_R1          GPIO_ReadInputDataBit(R1_GPIO_PORT, R1_PIN)
  57. #define DETECT_R2          GPIO_ReadInputDataBit(R2_GPIO_PORT, R2_PIN)
  58. #define DETECT_R3          GPIO_ReadInputDataBit(R3_GPIO_PORT, R3_PIN)
  59. #define DETECT_R4          GPIO_ReadInputDataBit(R4_GPIO_PORT, R4_PIN)
  60. // Keys
  61. #define S1                 0x77
  62. #define S2                 0xB7
  63. #define S3                 0xD7
  64. #define S4                 0xE7
  65. #define S5                 0x7B
  66. #define S6                 0xBB
  67. #define S7                 0xDB
  68. #define S8                 0xEB
  69. #define S9                 0x7D
  70. #define S10                0xBD
  71. #define S11                0xDD
  72. #define S12                0xED
  73. #define S13                0x7E
  74. #define S14                0xBE
  75. #define S15                0xDE
  76. #define S16                0xEE
  77.  
  78. void GPIO_RCC_Config(void);
  79. void ROCI_GPIO_Config(void);
  80. void RICO_GPIO_Config(void);
  81. void KEY_GPIO_ConfigAndDetect(void);
  82. #endif


有关输入输出管脚的选择可以多试验几组,有的管脚即使你配置成上拉输入,当你松开按键之后依然不会返回高电平,我在此就因为这个问题被卡了一阵子

关于我的矩阵键盘检测的原理简明阐述如下:

首先设置为行输出低电平,列上拉输入(即无外部干扰时保持高电平);
检测到按键按下,此时通过检测列的电平情况从而得知哪一列有按键被按下;
然后确定有按键被按下后,设置为列输出低电平,行上拉输入;
通过检测行的电平情况从而得知哪一行有按键被按下;
最后通过“不平行的两条直线相交于一点”原理,推知具体被按下的按键。
key.c

  1. /**
  2.   ******************************************************************************
  3.   * @file    bsp_key.c
  4.   * @author  Waao
  5.   * @version V1.0.0
  6.   * @date    23-Jan-2019
  7.   * @brief   This file contains some board support package's functions for the KEY.
  8.   *            
  9.   ******************************************************************************
  10.   * @attention
  11.   *
  12.   * None
  13.     *
  14.   ******************************************************************************
  15.   */
  16. #include <bsp_key.h>
  17.  
  18. /**
  19.   * @brief  Initialize the RCC of the 8 GPIO line.
  20.   * @param  None  
  21.   * @retval None
  22.   */
  23. void GPIO_RCC_Config(void)
  24. {
  25.     RCC_AHB1PeriphClockCmd(C1_GPIO_CLK, ENABLE);
  26.     RCC_AHB1PeriphClockCmd(C2_GPIO_CLK, ENABLE);
  27.     RCC_AHB1PeriphClockCmd(C3_GPIO_CLK, ENABLE);
  28.     RCC_AHB1PeriphClockCmd(C4_GPIO_CLK, ENABLE);
  29.     RCC_AHB1PeriphClockCmd(R1_GPIO_CLK, ENABLE);
  30.     RCC_AHB1PeriphClockCmd(R2_GPIO_CLK, ENABLE);
  31.     RCC_AHB1PeriphClockCmd(R3_GPIO_CLK, ENABLE);
  32.     RCC_AHB1PeriphClockCmd(R4_GPIO_CLK, ENABLE);
  33. }
  34.  
  35. /**
  36.   * @brief  Initialize the Row out Column in.
  37.   * @param  None  
  38.   * @retval None
  39.   */
  40. void ROCI_GPIO_Config(void)
  41. {
  42.     GPIO_InitTypeDef GPIO_Structure;
  43.     
  44.     //============ Column =============
  45.     GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
  46.     GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  47.     GPIO_Structure.GPIO_OType = GPIO_OType_PP;
  48.     GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
  49.     
  50.     GPIO_Structure.GPIO_Pin = C1_PIN;
  51.     GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
  52.     GPIO_Structure.GPIO_Pin = C2_PIN;
  53.     GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
  54.     GPIO_Structure.GPIO_Pin = C3_PIN;
  55.     GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
  56.     
  57.     GPIO_Structure.GPIO_Pin = C4_PIN;
  58.     GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
  59.     
  60.     //============== Row ===============
  61.     GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
  62.     GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  63.     GPIO_Structure.GPIO_OType = GPIO_OType_PP;
  64.     GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
  65.     
  66.     GPIO_Structure.GPIO_Pin = R1_PIN;
  67.     GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
  68.     GPIO_Structure.GPIO_Pin = R2_PIN;
  69.     GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
  70.     GPIO_Structure.GPIO_Pin = R3_PIN;
  71.     GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
  72.     
  73.     GPIO_Structure.GPIO_Pin = R4_PIN;
  74.     GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
  75.     
  76.     GPIO_ResetBits(R1_GPIO_PORT, R1_PIN);
  77.     GPIO_ResetBits(R2_GPIO_PORT, R2_PIN);
  78.     GPIO_ResetBits(R3_GPIO_PORT, R3_PIN);
  79.     GPIO_ResetBits(R4_GPIO_PORT, R4_PIN);
  80. }
  81.  
  82. /**
  83.   * @brief  Initialize the Row in Column out.
  84.   * @param  None  
  85.   * @retval None
  86.   */
  87. void RICO_GPIO_Config(void)
  88. {
  89.     GPIO_InitTypeDef GPIO_Structure;
  90.     
  91.     //============== Row ==================
  92.     GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
  93.     GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  94.     GPIO_Structure.GPIO_OType = GPIO_OType_PP;
  95.     GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
  96.     
  97.     GPIO_Structure.GPIO_Pin = R1_PIN;
  98.     GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
  99.     GPIO_Structure.GPIO_Pin = R2_PIN;
  100.     GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
  101.     
  102.     GPIO_Structure.GPIO_Pin = R3_PIN;
  103.     GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
  104.     
  105.     GPIO_Structure.GPIO_Pin = R4_PIN;
  106.     GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
  107.     
  108.     //============ Column ================
  109.     GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
  110.     GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  111.     GPIO_Structure.GPIO_OType = GPIO_OType_PP;
  112.     GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
  113.     
  114.     GPIO_Structure.GPIO_Pin = C1_PIN;
  115.     GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
  116.     GPIO_Structure.GPIO_Pin = C2_PIN;
  117.     GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
  118.     
  119.     GPIO_Structure.GPIO_Pin = C3_PIN;
  120.     GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
  121.     
  122.     GPIO_Structure.GPIO_Pin = C4_PIN;
  123.     GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
  124.     
  125.     GPIO_ResetBits(C1_GPIO_PORT, C1_PIN);
  126.     GPIO_ResetBits(C2_GPIO_PORT, C2_PIN);
  127.     GPIO_ResetBits(C3_GPIO_PORT, C3_PIN);
  128.     GPIO_ResetBits(C4_GPIO_PORT, C4_PIN);
  129. }
  130.  
  131. /**
  132.   * @brief  Configure the GPIO, and detect whether the key was pressed down
  133.   * @param  None  
  134.   * @retval None
  135.   */
  136. void KEY_GPIO_ConfigAndDetect(void)
  137. {
  138.     u8 TEMP_COMBINE = 0, TEMP_ROCI = 0, TEMP_RICO = 0;
  139.     
  140.     GPIO_RCC_Config();
  141.     printf("\nWhy so serious ?\tThe game just begin!");
  142.     while(1)
  143.     {
  144.         ROCI_GPIO_Config();
  145.         TEMP_ROCI = (u8)(((u8)DETECT_C1) << 3) |
  146.                                         (((u8)DETECT_C2) << 2) |
  147.                                         (((u8)DETECT_C3) << 1) |
  148.                                         (((u8)DETECT_C4) << 0);
  149.         if(TEMP_ROCI != 0x0f)
  150.         {
  151.             Delay(1000); // Eliminate the shaking. The parameter's unit is 10us
  152.             if(TEMP_ROCI != 0x0f) // Ensure one of the keys was pressed down indeed.
  153.             {
  154.                 RICO_GPIO_Config();
  155.                 TEMP_RICO = (u8)(((u8)DETECT_R1) << 3) |
  156.                                                 (((u8)DETECT_R2) << 2) |
  157.                                                 (((u8)DETECT_R3) << 1) |
  158.                                                 (((u8)DETECT_R4) << 0);
  159.                 TEMP_COMBINE = (u8)((TEMP_ROCI << 4) | TEMP_RICO); // Combine the two situation and we can know which key was pressed down.
  160.                 switch(TEMP_COMBINE)
  161.                 {
  162.                     case S1:
  163.                         printf("\nS1 was pressed down!");
  164.                         break;
  165.                     case S2:
  166.                         printf("\nS2 was pressed down!");
  167.                         break;
  168.                     case S3:
  169.                         printf("\nS3 was pressed down!");
  170.                         break;
  171.                     case S4:
  172.                         printf("\nS4 was pressed down!");
  173.                         break;
  174.                     case S5:
  175.                         printf("\nS5 was pressed down!");
  176.                         break;
  177.                     case S6:
  178.                         printf("\nS6 was pressed down!");
  179.                         break;
  180.                     case S7:
  181.                         printf("\nS7 was pressed down!");
  182.                         break;
  183.                     case S8:
  184.                         printf("\nS8 was pressed down!");
  185.                         break;
  186.                     case S9:
  187.                         printf("\nS9 was pressed down!");
  188.                         break;
  189.                     case S10:
  190.                         printf("\nS10 was pressed down!");
  191.                         break;
  192.                     case S11:
  193.                         printf("\nS11 was pressed down!");
  194.                         break;
  195.                     case S12:
  196.                         printf("\nS12 was pressed down!");
  197.                         break;
  198.                     case S13:
  199.                         printf("\nS13 was pressed down!");
  200.                         break;
  201.                     case S14:
  202.                         printf("\nS14 was pressed down!");
  203.                         break;
  204.                     case S15:
  205.                         printf("\nS15 was pressed down!");
  206.                         break;
  207.                     case S16:
  208.                         printf("\nS16 was pressed down!");
  209.                         break;
  210.                     default:
  211.                         break;
  212.                 }
  213.                 while(TEMP_RICO != 0x0F)
  214.                 {
  215.                     TEMP_RICO = (u8)(((u8)DETECT_R1)<<3) |
  216.                                                     (((u8)DETECT_R2)<<2) |
  217.                                                     (((u8)DETECT_R3)<<1) |
  218.                                                     (((u8)DETECT_R4)<<0);
  219.                 }
  220.             }
  221.         }
  222.     }
  223. }

  224.  
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_20312079

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值