矩阵键盘原理

一 .介绍

端口PC分配给矩阵键盘,行线连接PC4至PC7,列线连接PC0至PC3。 还有一些 节省GPIO的方法,比如采用“并入串出”类芯片进行电路调整,把键盘行列情况变成串行数字脉冲信号,再由GPI0取回串行数据经过移位后得到并行数据,或者采用专用的键盘扩展芯片扩

展按键资源.

二. 线反转式键盘扫描(也有其他办法)

1.配置PC高4位为推挽输出,低4位为上拉输入,让4条行线全部输出低电平且4条列线由于上拉作用都保持高电平。

2.假设这时候没有按键按下,那么读取PC端口的值肯定应该是(0x0F) B,若读回的值与预想值不相等,那么可以肯定是有按键被按下了。

3.当按键按下时4条列线上就不再是高电平了(应该有1个位变为低电平),若端口值为(0x0E) H则第0列按下,若为(0x0D) H则第1列按下,若为(0x0B) H则第2列按下,若为(0x07) H则第3列按下,这样一来我们就先得到 了按键按下时的列值。

三.代码案例

下面的代码是我查的不具备可行性,但是有思想其实可以看看的,也有一些小错误(可以忽略)


#include "main.h" 
#include "Keypad.h"

/**
  * @brief  KeyPad Init  port Group of ports   
  * @param  pin Group of pins   
*/ 
KeyPad_Init(GPIO_TypeDef* Port,unsigned long int Pin)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    uint16_t i;
    
    RCC_AHB1PeriphClockCmd(RCC_GPIOE, ENABLE);//使能GPIOE时钟
    
    GPIO_InitStruct.GPIO GPIO_Mode_IN;   //设置为输入端口
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//设置为推挽
    GPIO_GPIO_Speed = GPIO_Speed_100MHz;  //设置100M时钟
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;  //拉
    
    /*初始化第一排*/
    for(i = 4; i < 8; i++)
        GPIO_InitStruct.GPIO_Pin = Pin;
        GPIO_Init(Port, &GPIO_InitStruct);
        Pin = Pin <<1;
    }
    
     /*CC_AHB1PeriphClockCmd(RCC_AHB1Per,  0;*/
    for(i = 4; i < 8; i++){
        GPIO_InitStruct.GPIO_Pin = Pin;
        GPIO_Init(Port, &GPIO_InitStruct);
        Pin = Pin << 1
}

/**
  * @brief  Get KeyPad Num    
  * @param  none
  * @retval key num   
  */
uint8_t Get_KeyPad_Num(void)
{
    uint8_t i;
    uint8_t KeyVal=0;    
    GPIOE->ODR&=~0xf << 4;  //PE4-PE7 输出低
    GPIOD->ODR|=0xf << 4;   //PD4-PD7 输出高
    while(1)
    {
        for(int i=4;i<8; i++ )
        {
            if(GPIO_ReadInputDataBit(GPIOD,GPIO_4<<i)==RESET)
            {
                while(ReadInputDataBit(GPIOD,GPIO_Pin_4<<i)ET);
                    KeyVal=(4<<4)|i;
            }
            if (GPIO_ReadInputGPIOE,GPIO_Pin_4<<i)==RESET)  //键盘低
            {
                while(GPIO_ReadInputDataBit(GP,GPIO_Pin_4<<i)==RESET);
                KeyVal=i;
            }
            if(KeyVal!=0) return KeyVal;  //有按键按下时返回按键值
        }
    }
}


1. 首先定义键值:

   ```c
   const Key_Type Key_Value[ROW][COL] = { { '1', '2', '3', 'A' }, 
                                          { '4', '5', '6', 'B' }, 
                                          { '7', '8', '9', }, 
                                          { '*', '0', '#', 'D' } };
   ```

2. 用查询表的思想来实现扫描,同时用4个数组变量来接收列值,两个状态变量(一个列状态,一个行状态):

   ```c
   u8 key_num = 0;   //按键数量变量
   u8 key_row = 0;   //存放该按键的行号
   u8 key_status = 0;//按键的状态
   u8 key_data[COL];  //存放按键的查询表
   ```

3. 扫描过程:

   ```c
   void Scan_Key(void)
   {
       u8 key_time = 0;  //判断按下按键时间
   
       //列输出,放低对应行
       GPIO_ResetBits(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);
       GPIO_SetBits(GPIOG, GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);
   
       //获取矩阵键盘状态,存放到key_data[4]中
       for(u8 i=0; i<4; i++)
       {
           key_data[i]=((~GPIOE->IDR)>>2 | (0xf0));    //引脚PE2-PE5/PG1-PG4读取状态
           GPIO_ResetBits(GPIOG, GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);
           GPIO_SetBits(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);
           delay_us(2);
       }
       //检查4行4列查询表中的键值根据查询表附加状态
       for(u8 i=0; i<ROW; i++)
       {
           for(u8 j=0; j<COL; j++)
           {
               if(key_data[j] & (0x01<<i))
               {
                   if(!key_status)    //如果没有按键按下,判断按键状态
                   {
                       key_status = 1;    //记录按键状态
                       key_num = Key_Value[i][j]; //记录按键值
                       key_row = i;  //记录按下的按键所属行数
                       key_time = 0;    //按下按键时间
                   }
                   else if(i == key_row)    //检查是否是按下的同一按键
                   {
                       key_time++;        //如果是按键时间加1
                       if(key_time > 20)    //如果按键时间大于20,按键时间清0_time = 0;
                           Key_Handler(key_num); //按键处理函数
                       }
                       break;
                   }
               }
           }
           if(!key_data[j] | (0x01<<i))
           {
               key_status = 0;    //没有按键按下,记录按键状态为没有按键按下
           }
       }
   }
   ```

4. 消抖函数:

   ```c
   void Key_Handler(u8 Key_Value)
   {
       static unsigned char key_buf=0;    //用来进行消抖的缓存区
       if( Key_Value != key_buf )        //如果两次输入按键不一样,把新输入的值存入缓存区
       {
           key_buf=Key_Value;
           if(Key_Value != 0XFF)        //如果按键不是 非法数值,执行逻               
               switch(Key_Value)
               {
                   //执行用户定义的操作
               }
           }
       }
   }
   ```
uint8_t key_scan(void)
{
    uint8_t keys,keyVal=0xFF;
    uint8_t keyrow,keycol;
    GPIO_InitTypeDef gpio;

    gpio.GPIO_Mode =  GPIO_Mode_OUT;
/*************** COL ******************/
    gpio.GP_12IO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;//推挽输出键列
    GPIO_Init(GPIOD, &gpio);
    GPIO_SetBits(GPIOD,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //把列线高电平
/*************** ROW ******************/
    gpio.GPIO_Mode =  GPIO_Mode_IN;
    gpio.GPIO_Pin  =  GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;//浮空输入IOE, &gpio);

/****************start Key scan******************/
    for(keyrow=0;keyrow<4;keyrow++){
        switch (keyrow){
            case 0:GPIO_ResetBits(GPIOD, GPIO_Pin_12); break; //拉低行线
            case 1:GPIO_ResetBits(GPIOD, GPIO_Pin_13); break;
            case 2:GPIO_ResetBits(GPIOD, GPIO_Pin_14); break;
            case 3:GPIO_ResetBits(GPIOD, GPIO_Pin_15);ResetBits(GPIOD, GPIO_Pin_12); break;
        }

   /***************** colum Scan *********************/
        for(keycol=0;keycol<4;keycol++){
            switch (keycol){
                case 0:keys=GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_0); break; //获取列口
                case 1:keys=GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_1); break;
                case 2:keys=GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2); break;
                case 3:keys=GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3); break;
                default:keys=GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_0); break;
            }

        if(!keys) keyVal = keyrow*4+keycol ;
        }
        GPIO_Set12|GPIO_Pin//拉高 } **************** 这里错的  少了
return keys
}
void Matrix_ssKey_Pin_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; 
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}    
int Matrix_Key_Scan(void)
{
    u8 temp = 0;
    int key_val = -1;
    
    GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11);            //拉低行线
    delay_us(10);
 
    temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;    
    
    //没有按键按下时扫描
    if (temp == 0xf0) 
    {
            delay_ms(50); 
            GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11);            //拉低行线
            delay_us(10);
            temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;    
        
            if (temp != 0xf0) //按键按下时,对键值进行赋值
            {
                //第一行
                GPIO_Write(GPIOB,0);
                delay_ms(5);
                GPIO_Write(GPIOB,(uint16_t)(0xFE << 8)); 
                
                if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                {
                        delay_ms(20);//消抖
 
                        if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                        {
                                temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFE);        //对列进行扫描
                                switch(temp)
                                {
                                        case 0xEE:  key_val = 1;   break;
                                        case 0xDE:  key_val = 2;   break;
                                        case 0xBE:  key_val = 3;   break;
                                        case 0x7E:  key_val = 4;   break;
                                        default:    key_val = -1;   break;
                                }
                        }
                }
                
                //第二行
                GPIO_Write(GPIOB,0);
                delay_ms(5);
                GPIO_Write(GPIOB,(uint16_t)(0xFD << 8));
                
                if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0)!= 0XF0)
                {
                        delay_ms(20);
 
                        if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                        {
                                temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFD);
                                switch(temp)
                                {
                                        case 0xED:  key_val = 5;   break;
                                        case 0xDD:  key_val = 6;   break;
                                        case 0xBD:  key_val = 7;   break;
                                        case 0x7D:  key_val = 8;   break;
                                        default:    key_val = -1;   break;
                                }
                        }
                }
                
                //第三行
                GPIO_Write(GPIOB,0);
                delay_ms(5);
                GPIO_Write(GPIOB,(uint16_t)(0xFB << 8));
                
                if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                {
                        delay_ms(20);
 
                        if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                        {
                                temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFB);
                                switch(temp)
                                {
                                        case 0xEB:  key_val = 9;   break;
                                        case 0xDB:  key_val = 10;   break;
                                        case 0xBB:  key_val = 11;   break;
                                        case 0x7B:  key_val = 12;   break;
                                        default:    key_val = -1;   break;
                                }
                        }
                }
                
                //第四行
                GPIO_Write(GPIOB,0);
                delay_ms(5);
                GPIO_Write(GPIOB,(uint16_t)(0xF7 << 8));
                
                if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) !=0XF0)
                {
                        delay_ms(20);
 
                        if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
                        {
                                temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XF7);
                                switch(temp)
                                {
                                        case 0xE7:  key_val = 13;   break;
                                        case 0xD7:  key_val = 14;   break;
                                        case 0xB7:  key_val = 15;   break;
                                        case 0x77:  key_val = 16;   break;
                                        default:    key_val = -1;   break;
                                }
                        }
                    }
                }
            }
    
    return key_val;
 
}

int main(void)
{
    int key_val = 0;
    Sys_Delay_Init();
    Matrix_ssKey_Pin_Init();
    Usart1_Pin_Init(115200);
    printf("初始化成功\r\n");
    
    while(1)
    {
        key_val = Matrix_Key_Scan();
 
        if (key_val > 0 && key_val < 17)
            printf("This is S%d key\r\n",key_val);
 
    }
}
    #define keyboard P1  //四条行线三条列线所连接的IO口
    unsigned char Check_Keyboard()
    {
    unsigned char row_scan_code=0x01; //行扫描码
    unsigned char col_scan_code=0xEF;//列扫描码
    unsigned char keycode;  //按键键值
    unsigned char i,x,j;
    //可以做一个消抖处理
    for(i=0;i<3;i++)//逐列扫描,将列线逐列拉低
    {
        keycode=i+1;
        keyboard=col_scan_code;
        x=keyboard; //读取行线状态
        for(j=0;j<4;j++)//逐行扫描
        {
            if(!(x&row_scan_code))//说明对应行的按键按下,使行线被拉低
            {
                keycode+=3*j;
                //如果按键还未释放,则仍有行线被拉至低电平
                while((keyboard&0x0f)!=0x0f);//等待按键释放
                P1=0x0F;     //恢复原状态,为下次按键做准备
                return keycode;     //已检测到按键键码,返回
            }
            else
                row_scan_code=_crol_(row_scan_code,1);
        }
        col_scan_code=_crol_(col_scan_code,1);//左移一位,将下一列线拉低
        row_scan_code=0x01;//重置行扫描码,为下一行扫描作准备
    }
    keycode=0;//没有按键按下,键值记为0
    return keycode;
    }
//@brief:判断4*4矩阵键盘是否有键可靠按下,高4位口接行线,低四位口接列线
//@retval:当有键可靠按下时返回1-16的键值,否则返回0
#define keyboard P1
unsigned char Check_Keydown()
{
    unsigned char KeyValue=0;
    keyboard=0x0f;
    if(keyboard!=0x0f)//如果按键按下
    {
        delay_ms(10);//延时10ms消抖
        if(keyboard!=0x0f)//按键确实按下
        {    
            //判断按键所在列,以所在列的第一行的按键键值赋给KeyValue
            keyboard=0X0F;
            switch(keyboard)
            {
                case(0X07):    KeyValue=1;break; //第一列按下
                case(0X0b):    KeyValue=2;break; //第二列按下
                case(0X0d): KeyValue=3;break; //第三列按下
                case(0X0e):    KeyValue=4;break; //第四列按下
            }
            //判断按键所在行
            keyboard=0XF0;
            switch(keyboard)
            {
                case(0X70):    KeyValue=KeyValue;break;  //第一行按下
                case(0Xb0):    KeyValue=KeyValue+4;break;  //第二行按下
                case(0Xd0): KeyValue=KeyValue+8;break;  //第三行按下
                case(0Xe0):    KeyValue=KeyValue+12;break;  //第四行按下
            }
            while(keyboard!=0xf0); //按键松手后退出
                return KeyValue;
        }
        else  //否则认为是信号干扰导致
        {
            return 0;  //认为没有按键按下
        }
    }
    return 0;  //如果没有按键按下返回零
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值