矩阵键盘原理

这篇具有很好参考价值的文章主要介绍了矩阵键盘原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一 .介绍

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

展按键资源.

矩阵键盘原理,期末复习,江苏海洋大学,ARM,计算机外设,单片机,嵌入式硬件,arm开发,stm32,Powered by 金山文档

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

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列按下,这样一来我们就先得到 了按键按下时的列值。

矩阵键盘原理,期末复习,江苏海洋大学,ARM,计算机外设,单片机,嵌入式硬件,arm开发,stm32,Powered by 金山文档

三.代码案例

下面的代码是我查的不具备可行性,但是有思想其实可以看看的,也有一些小错误(可以忽略)文章来源地址https://www.toymoban.com/news/detail-541501.html


#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;  //如果没有按键按下返回零
}

到了这里,关于矩阵键盘原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2021山东大学众智期末复习笔记

    目录 社交网络 同质性 正负关系 小世界 搜索引擎 博弈论 市场 权力 从众 新事物的扩散 信息不对称 流⾏病和线粒体夏娃 强连通图:有向图G中,任意两点可以相互到达。 有向图的强连通分量:有向图中的极大强连通子图。 三元闭包:如果两个互不相识的人有了一个共同的朋

    2023年04月08日
    浏览(43)
  • 数据结构(期末复习篇) 清华大学出版社

    1.1.1 数据结构的定义 数据:描述客观事物的数和字符的集合 数据元素: 数据的基本单位 数据对象: 性质相同的数据元素的集合,是数据的一个子集 数据结构: 数据元素以及数据元素之间的关系,可以看作互相之间有着特定关系的集合 1.1.2 逻辑结构 1.逻辑结构的表示 一 

    2024年01月20日
    浏览(40)
  • 四川大学软件学院|系统级编程期末复习

    选择题 50 分(原题率 80%):http://tieba.baidu.com/p/1250021454?share=9105fr=sharewiseunique=967707B1DAECEF4A785B61D29AF36950st=1639102957client_type=1client_version=12.10.1sfc=copyshare_from=post 程序执行的六个过程 E d i t   →   P r e   P r o c e s s   →   C o m p i l e   →   L i n k   →   L o a d   →   E x e c u t e

    2024年02月01日
    浏览(36)
  • Java EE 期末复习提纲【太原理工大学】

    目录 一、题型 二、考点 1. MyBatis 2. Spring 3. Spring MVC 1. 选择题 20 个,每个 1 分,共 20 分。 2. 填空题 20 个,每个 1 分,共 20 分。 3. 判断题 10 个,每个 1 分,共 10 分。 4. 程序修改题 2 个,每个 5 分,共 10 分。 5. 程序阅读题 2 个,每个 12 分,共 24 分。 6. 编程题,1个,16 分

    2024年02月03日
    浏览(29)
  • 燕山大学机器学习期末复习知识点罗列

    本文根据燕山大学软件工程专业机器学习课程期末复习纲要编写,文本内容来源为上课所使用的PPT,由于时间紧迫这个版本是比较全的知识点,只包含的速记突击版本后续会上传。 机器学习是人工智能的一个分支。我们使用计算机设计一个系统,使它能够根据提供的训

    2024年02月11日
    浏览(42)
  • 【网络安全】大学信息安全技术 期末考试复习题

    一、单选题(一) 1、在以下人为的恶意攻击行为中,属于主动攻击的是( )A A.数据篡改及破坏 B.数据窃听 C.数据流分析 D.非法访问 2、数据完整性指的是( )C A.保护网络中各系统之间交换的数据,防止因数据被截获而造成泄密 B.提供连接实体身份的鉴别 C.防止非

    2024年02月11日
    浏览(44)
  • 《大学英语4》期末考试复习(一)听力原文+答案速记

    目录 Unit 1 Long conversation Passage 1 Unit 2 Long conversation Passage 1 Unit 3 Long conversation Passage 1 Unit 4 Long conversation Passage 1 Unit 5 Long conversation Passage 1 Unit 6 Long conversation Passage 1 Unit 7 Long conversation Passage 1 Unit 8 口诀如下: Long conversation M: I love working out! W: Ugh! You’re sweating all over the floor

    2024年02月10日
    浏览(46)
  • 【图论】重庆大学图论与应用课程期末复习资料(私人复习资料)

    填空 顶点集和边集都有限的图,称为有限图 只有一个顶点的图,称为平凡图 边集为空的图,称为空图 顶点数为n的图,称为n阶图 连接两个相同顶点的边的条数称为边的重数;重数大于1的边,称为重边 端点重合为一点的边,称为环 既无环又无重边的图,称为简单图 每两个

    2024年02月05日
    浏览(30)
  • 大学生Python期末复习冲刺(有这一篇足够)

    还愁要自己总结知识点?有这一篇就足够 👌🏻   干货满满不看后悔 👍👍👍 📝个人主页→数据挖掘博主ZTLJQ的主页 ​ 个人推荐python学习系列: ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 数据类型和变量 👑1、数字类型(int) 1.浮点

    2024年02月03日
    浏览(37)
  • 西安石油大学 C++期末考试 重点知识点+题目复习(下)

    析构函数的调用顺序与对象的创建和销毁顺序相反。 对于单个对象,当对象的生命周期结束时(例如离开作用域),会调用其析构函数。因此,析构函数会在对象销毁之前被调用。 对于类的成员对象,它们的析构函数的调用顺序与它们在类中的声明顺序相反。即,在类的析

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包