[原创] 基于Proteus的MSP430单片机仿真实例12-4X4矩阵键盘键值显示

tiankai001   2018-1-18 14:50 楼主
此内容由EEWORLD论坛网友tiankai001原创,如需转载或用于商业用途需征得作者同意并注明出处 一、任务要求
将4X4矩阵式键盘编号,如果其中一个按键闭合,则在LED数码管上显示相应的按键编号。
二、分析说明
4X4矩阵键盘只需要占用一个8位的I/O端口,硬件电路的设计较为简单,重点在于如何在程序中判断矩阵键盘的按键位置。
三、硬件电路
硬件电路如下图所示。
选取MSP430F247单片机的P4端口连接数码管,用以显示按键编号,P5端口8个引脚分别和矩阵式键盘的行线和列线连接,硬件电路如下图所示。
选取MSP430F247单片机的P4端口连接数码管,用以显示按键编号,P5端口8个引脚分别和矩阵式键盘的行线和列线连接,硬件电路如下图所示。
电路图中,列线P5.4~P5.7通过上拉电阻连接电源,处于输入状态;行线P5.0~P5.3为输出状态。键盘上没有按键闭合时,所有列线P5.4~P5.7的输入全部为高电平。当键盘上某个按键闭合时,则对应的行线和列线短接。
在检测是否有键闭合时,先使4条行线全部输出低电平,然后读取4条列线的状态,如果全部为高电平则表示没有任何按键闭合,如果有任一键闭合,由于列线上是上拉电阻,则行线上读到的将是一个非全“1”的值。
四、程序设计
确定矩阵式键盘上那个按键闭合通常采用行扫描法,又称为逐行(或列)扫描查询法,其软件主要基于扫描方式完成。
关于键盘扫描查询法的程序大致可以分为以下几个步骤:
1、检测当前是否有键闭合
首先看输入的列线,假设4条行线都输出低电平,4条列线上都是上拉电阻,在没有任何键闭合时,4条列线输入都为1,但当与某一条行线相连的4个键中的任何一个闭合时,这条列线将输入低电平,即当某条列线输入低电平时,必定是连接在这条裂线上的某个键闭合了。
2、去除按键抖动当检测到有按键闭合后,延长一段时间再做下一步的检测判断。
3、若有键闭合,检测出是哪一个键闭合
逐行扫描方式:在4条行线上分别输出0信号。第一次,在第一条行线上输出低电平,其它行线上输出高电平,第二次,在第二条行线上输出低电平,其它行线上输出高电平,,第三次,在第三条行线上输出低电平,其它行线上输出高电平,,第四次,在第四条行线上输出低电平,其它行线上输出高电平,当某一行线上输出低电平时,此时如果此行上有键被按下,那么相应键的列线上就会读到0,于是可以唯一的确定是那个那键被按下。
  1. //main.c
  2. #include "msp430f247.h"
  3. #include "stdlib.h"
  4. #include "string.h"
  5. /*****************************************软件延时,主频1M*******************/
  6. #define CPU_F1 ((double)1000000)
  7. #define delay_us1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000000.0))
  8. #define delay_ms1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000.0))
  9. /****************************************************************************/
  10. //共阳极数码管段码表
  11. unsigned char const Led_Tab1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
  12. 0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
  13. //共阴极数码管段码表
  14. unsigned char const Led_Tab2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
  15. 0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  16. static unsigned char key;
  17. unsigned char KeyScan(void);//
  18. unsigned char GetKeyValue(unsigned char keycode);//
  19. /************************************************
  20. 函数名称:主函数
  21. 函数功能:矩阵键盘编号显示
  22. 入口参数:无
  23. 出口参数:无
  24. 描述:
  25. 作者:老马识途单片机
  26. 日期:2018年1月7日
  27. ************************************************/
  28. main()
  29. {
  30. unsigned char key;
  31. WDTCTL = WDTPW + WDTHOLD;//关看门狗
  32. P4DIR=0xff;//端口初始化
  33. P4OUT=0x00;//端口初始化
  34. //行线P5.0~P5.3为输出状态。列线P5.4~P5.7为输入
  35. P5DIR=0x0f;//
  36. while(1)
  37. {
  38. key=GetKeyValue(KeyScan());//显示扫描
  39. if(key != 255)
  40. {
  41. P4OUT=Led_Tab2[key];
  42. }
  43. }
  44. }
  45. unsigned char KeyScan(void)
  46. {
  47. unsigned char ScCode,ReCode;
  48. P5OUT=0x00;
  49. if((P5IN & 0xf0) != 0xf0)//判断是否有键闭合
  50. {
  51. delay_ms1M(40);
  52. if((P5IN & 0xf0) != 0xf0)//延时后再次判断是否有按键闭合,
  53. {
  54. ScCode=0xfe;//逐行扫描初值,先扫描第一行
  55. while((ScCode&0x0f) != 0x0f)//行扫描完成
  56. {
  57. P5OUT=ScCode;//输出行扫描码
  58. if((P5IN & 0xf0) != 0xf0)//当前行有键闭合
  59. {
  60. ReCode=(P5IN & 0xf0) | 0x0f;//读取高4位列值,低4位置1
  61. key=(ScCode & ReCode);//行和列组合得到键盘编码
  62. return key;
  63. }
  64. else//所扫描行没有按键闭合,则扫描下一行
  65. {
  66. ScCode=(ScCode<<1)|0x01;//行扫描码左移一位
  67. }
  68. }
  69. }
  70. return 0xff;//无键按下
  71. }
  72. return 0xff;//无键按下
  73. }
  74. unsigned char GetKeyValue(unsigned char keycode)
  75. {
  76. unsigned char keyval;
  77. switch(keycode)
  78. {
  79. case 0x77:
  80. keyval=0;
  81. break;
  82. case 0x7b:
  83. keyval=1;
  84. break;
  85. case 0x7d:
  86. keyval=2;
  87. break;
  88. case 0x7e:
  89. keyval=3;
  90. break;
  91. case 0xb7:
  92. keyval=4;
  93. break;
  94. case 0xbb:
  95. keyval=5;
  96. break;
  97. case 0xbd:
  98. keyval=6;
  99. break;
  100. case 0xbe:
  101. keyval=7;
  102. break;
  103. case 0xd7:
  104. keyval=8;
  105. break;
  106. case 0xdb:
  107. keyval=9;
  108. break;
  109. case 0xdd:
  110. keyval=10;
  111. break;
  112. case 0xde:
  113. keyval=11;
  114. break;
  115. case 0xe7:
  116. keyval=12;
  117. break;
  118. case 0xeb:
  119. keyval=13;
  120. break;
  121. case 0xed:
  122. keyval=14;
  123. break;
  124. case 0xee:
  125. keyval=15;
  126. break;
  127. default:
  128. keyval=255;
  129. }
  130. return keyval;
  131. }
五、程序说明
主程序通过调用键盘扫描程序获取键值,并通过数码管显示出键盘编号。键盘扫描首先通过读取列线输入,如果不全是1,则延迟一定时间后再次判断列线是否全为1,如果依旧不全为1,则可以确定有稳定的按键动作,通过逐行扫描的方式得到按键的位置。
从程序上看还存在两个问题,一是按键扫描中延迟去抖需要一定的时间,浪费了单片机的运算资源;二是在扫描得到按键后如果按键闭合不动,主程序会得到多个相同的键值,即重复按键,这种情况可以通过判断按键弹起的动作来解决
六、仿真结果与分析
在proteus中画好电路图后,双击单片机,将可执行文件装载到单片机内,点击运行,观察数码管的显示情况。如下图所示。
本帖最后由 tiankai001 于 2019-1-7 08:19 编辑

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复