找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2015|回复: 6
打印 上一主题 下一主题
收起左侧

6条语句搞定16矩阵键盘扫描单片机C语言程序

  [复制链接]
跳转到指定楼层
楼主
ID:230500 发表于 2023-2-26 12:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我自己写了一段51单片机的代码分享给大家,有完整的注释,和解码过程图解,这个矩阵键盘扫描程序不同于网上那些逐行扫描; 思路新颖,语句简单,识别准确;
扫描子函数中包含变量定义,所有代码就10行;真正做解码的只用了6条语句
这段演示程序中没有任何延时阻塞函数;识别率挺高; 做项目最好加入中断定时扫描;如果单片机资源紧张,也可以在1-3 或者4-7;4条IO口上对地加4个104电容做硬件消抖;
程序在下面,里面还有一个LCD1602的显示函数, 用来演示按键扫描结果!


单片机源程序如下:
  1. #include <REGX51.H>
  2. #include "LCD1602.H"

  3. /*** 0-15键值 ***/        
  4. /*****************
  5. 0x77,0x7B,0x7D,0x7E
  6. 0xB7,0xBB,0xBD,0xBE
  7. 0xD7,0xDB,0xDD,0xDE
  8. 0xE7,0xEB,0xED,0xEE

  9. ******************/

  10. unsigned char Key_Scan();                //按键扫描函数声明

  11. /* 主函数从这里开始 */
  12. void main(void)
  13. {        
  14.         static unsigned char Key_Code = 0x00;                //定义一个静态变量
  15.         
  16.         LCD_Init();                //初始化LCD1602,用来显示键值

  17.         while(1)
  18.         {
  19.                 Key_Code = Key_Scan();
  20.                 switch (Key_Code)                //演示示例;用switch语句操作键码;比如我在1602液晶屏上显示数字1-16;也可以用数组来操作,自由发挥!
  21.                 {
  22.                         case 0x77: LCD_ShowNum(1,2,1,2); break;
  23.                         case 0x7B: LCD_ShowNum(1,2,2,2); break;
  24.                         case 0x7D: LCD_ShowNum(1,2,3,2); break;
  25.                         case 0x7E: LCD_ShowNum(1,2,4,2); break;
  26.                         case 0xB7: LCD_ShowNum(1,2,5,2); break;
  27.                         case 0xBB: LCD_ShowNum(1,2,6,2); break;
  28.                         case 0xBD: LCD_ShowNum(1,2,7,2); break;
  29.                         case 0xBE: LCD_ShowNum(1,2,8,2); break;
  30.                         case 0xD7: LCD_ShowNum(1,2,9,2); break;
  31.                         case 0xDB: LCD_ShowNum(1,2,10,2); break;
  32.                         case 0xDD: LCD_ShowNum(1,2,11,2); break;
  33.                         case 0xDE: LCD_ShowNum(1,2,12,2); break;
  34.                         case 0xE7: LCD_ShowNum(1,2,13,2); break;
  35.                         case 0xEB: LCD_ShowNum(1,2,14,2); break;
  36.                         case 0xED: LCD_ShowNum(1,2,15,2); break;
  37.                         case 0xEE: LCD_ShowNum(1,2,16,2); break;                        
  38.                         default: break;
  39.                 }
  40.         }
  41. }

  42. /* 带返回值的按键扫描函数*/
  43. unsigned char Key_Scan()
  44. {
  45.         unsigned char Key_Temp;                        //定义一个存放组合键码的变量
  46.         unsigned char Key_A,Key_B;        //        定义两个变量,Key_A 用于存放正向扫描的键码; Key_B 用于存放反向扫描的键码。
  47.         
  48.         P1 = 0xF0;                                                                        //把P1口的高4位(P1.4-P1.7)置高,低4位置低;(如果有按键按下 高4位肯定有一条线会被拉低)。
  49.         Key_Temp = P1;                                                        //把P1口的状态读回来,传递给Key_Temp。没有按键按下Key_Temp肯定是0XF0; 否则就是其它的数;
  50.         if(Key_Temp!= 0xF0)                                 // 进入if判断语句;如果Key_Temp不等于0XF0,说明有键按下了。
  51.         {
  52.                 Key_A = P1;        // 把P1口此时被按下的状态传递给Key_A保存
  53.                 P1 = 0x0F;        //开始反转扫描;把P1口的高4位置低,低4位(P1.0-P1.3)置高;(如果有按键按下 低4位肯定有一条线会被拉低)。
  54.                 Key_B = P1;        //把P1口此时被按下的状态传递给Key_A保存
  55.         }

  56.         Key_Temp = (Key_A | Key_B); //把正反两次扫描的结果相或, 就会得到按键按下的正确键码
  57.         return Key_Temp;  //把键码返回,给其他的函数调用
  58. }


  59. //下面是图解正反转扫描的程序工作原理

  60. /*
  61. 正向扫描,比如P1.7和P1.3连接的按键被按下 那么P1口的0XF0:1111 0000  就会变成0X70:0111 0000

  62.                                 P1.3        P1.2        P1.1        P1.0
  63.                                  0                 0                 0                 0
  64. P1.7        1        -+-                ---                ---                ---

  65. P1.6        1        ---                ---                ---                ---

  66. P1.5        1        ---                ---                ---                ---

  67. P1.4        1        ---                ---                ---                ---



  68. 反向扫描,比如P1.7和P1.3连接的按键被按下 那么P1口的0X0F:0000 1111  就会变成0X07:0000 0111

  69.                                 P1.3        P1.2        P1.1        P1.0
  70.                                  1                 1                 1                 1
  71. P1.7        0        -+-                ---                ---                ---

  72. P1.6        0        ---                ---                ---                ---

  73. P1.5        0        ---                ---                ---                ---

  74. P1.4        0        ---                ---                ---                ---


  75. 最后把 正反两次扫描的结果 0X70 与0X07相或 就会得到0X77的键码
  76. 只要得到正确的键码,就可以用这个键码做任何事情。比如我在液晶屏上显示数字1;表示数字1键被按下。
  77. */

  78. //下面这组键值根据不同的接线方式,会有不同的键值,需要提前自己算好;就类似数码管的段码一样;也可以做成一个数组。
  79. /*** 0-15键值 ***/        
  80. /*****************
  81. 0x77,0x7B,0x7D,0x7E
  82. 0xB7,0xBB,0xBD,0xBE
  83. 0xD7,0xDB,0xDD,0xDE
  84. 0xE7,0xEB,0xED,0xEE

  85. ******************/


复制代码
Keil代码下载:
6条语句搞定4X4矩阵按键.rar (35.42 KB, 下载次数: 45)

评分

参与人数 2黑币 +92 收起 理由
ldc2000 + 12 很给力!
admin + 80 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏7 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:366877 发表于 2023-2-26 15:48 | 只看该作者
简单问题复杂化了,本来处理就是几句话的事。
回复

使用道具 举报

板凳
ID:526108 发表于 2023-2-26 18:31 | 只看该作者
跟我写的非常接近了,但还能简化,对于高速单片机这代码行不通,给两点建议:实时性和性能问题
回复

使用道具 举报

地板
ID:807591 发表于 2023-2-27 08:58 | 只看该作者
全键无冲没解决
回复

使用道具 举报

5#
ID:409878 发表于 2023-2-27 13:45 | 只看该作者
个人看楼主的程序很好。楼上有好的想法和写法的,可以分享下。
回复

使用道具 举报

6#
ID:971308 发表于 2023-2-28 21:44 | 只看该作者
思路不错
回复

使用道具 举报

7#
ID:213173 发表于 2023-3-9 10:01 | 只看该作者
还能再省一句
  1. #include <REGX51.H>
  2. #include "LCD1602.H"

  3. /*** 0-15键值 ***/       
  4. /*****************
  5. 0x77,0x7B,0x7D,0x7E
  6. 0xB7,0xBB,0xBD,0xBE
  7. 0xD7,0xDB,0xDD,0xDE
  8. 0xE7,0xEB,0xED,0xEE

  9. ******************/

  10. unsigned char Key_Scan();                //按键扫描函数声明

  11. /* 主函数从这里开始 */
  12. void main(void)
  13. {       
  14. //        static unsigned char Key_Code = 0x00;                //定义一个静态变量
  15.        
  16.         LCD_Init();                //初始化LCD1602,用来显示键值

  17.         while(1)
  18.         {
  19. //                Key_Code = Key_Scan();
  20.                 switch (Key_Scan())                //演示示例;用switch语句操作键码;比如我在1602液晶屏上显示数字1-16;也可以用数组来操作,自由发挥!
  21.                 {
  22.                         case 0x77: LCD_ShowNum(1,2,1,2); break;
  23.                         case 0x7B: LCD_ShowNum(1,2,2,2); break;
  24.                         case 0x7D: LCD_ShowNum(1,2,3,2); break;
  25.                         case 0x7E: LCD_ShowNum(1,2,4,2); break;
  26.                         case 0xB7: LCD_ShowNum(1,2,5,2); break;
  27.                         case 0xBB: LCD_ShowNum(1,2,6,2); break;
  28.                         case 0xBD: LCD_ShowNum(1,2,7,2); break;
  29.                         case 0xBE: LCD_ShowNum(1,2,8,2); break;
  30.                         case 0xD7: LCD_ShowNum(1,2,9,2); break;
  31.                         case 0xDB: LCD_ShowNum(1,2,10,2); break;
  32.                         case 0xDD: LCD_ShowNum(1,2,11,2); break;
  33.                         case 0xDE: LCD_ShowNum(1,2,12,2); break;
  34.                         case 0xE7: LCD_ShowNum(1,2,13,2); break;
  35.                         case 0xEB: LCD_ShowNum(1,2,14,2); break;
  36.                         case 0xED: LCD_ShowNum(1,2,15,2); break;
  37.                         case 0xEE: LCD_ShowNum(1,2,16,2); break;                       
  38.                         default: break;
  39.                 }
  40.         }
  41. }

  42. /* 带返回值的按键扫描函数*/
  43. unsigned char Key_Scan()
  44. {
  45.         unsigned char Key_Temp;                //定义一个存放组合键码的变量
  46. //        unsigned char Key_A,Key_B;        //        定义两个变量,Key_A 用于存放正向扫描的键码; Key_B 用于存放反向扫描的键码。
  47.         P1 = 0xf0;                                        //把P1口的高4位(P1.4-P1.7)置高,低4位置低;(如果有按键按下 高4位肯定有一条线会被拉低)。
  48.         if(P1!= 0xf0)                 // 进入if判断语句;如果Key_Temp不等于0XF0,说明有键按下了。
  49.         {
  50.                 Key_Temp = P1;        // 把P1口此时被按下的高4位状态保存
  51.                 P1 = 0x0f;        //开始反转扫描;把P1口的高4位置低,低4位(P1.0-P1.3)置高;(如果有按键按下 低4位肯定有一条线会被拉低)。
  52.                 Key_Temp |= P1&0x0f;        //把P1口此时被按下的低4位状态与高4位状态合并
  53.         }
  54.         return Key_Temp;  //把键码返回,给其他的函数调用
  55. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表