单片机C语言程序设计实训100例
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.17 数码管显示4×4键盘矩阵按键

本例在识别键盘矩阵按键时,使用了不同的扫描程序代码,程序运行时数码管会显示相应按键的键值0~F。

本例电路如图3-14所示。

程序设计调试与实训:

读者要注意本例中P1端口低4位连接的是列线,高4位连接的是行线。

本例中键盘矩阵按键扫描思想与上一案例类似,但使用的代码有较大变化,而且没有再使用查表法得到按键序号,代码细节读者可以自行剖析。

图3-14 数码管显示4×4键盘矩阵按键电路

读者可在上一案例的键盘布局下重新修改本例扫描代码,实现按键识别功能。

另外,在本例及上一案例关于键盘矩阵单按键扫描的基础上,读者可修改代码,实现对多按键的判断(同时有2~3个按键按下)。在测试时,如果希望按键按下后不释放,然后再继续按第2个或第3个按键,这时不能用鼠标单击按键,而应单击按键旁边的上下箭头。

源程序代码:

        //-----------------------------------------------------------------
        //  名称: 数码管显示4×4 键盘矩阵按键序号
        //-----------------------------------------------------------------
        //  说明: 按下任意一按键时,数码管会显示它在键盘矩阵上的序号0~ F,
        //       扫描程序首先判断按键发生在哪一列,然后根据所发生的行附加
        //       不同的值,从而得到键盘按键序号。
        //-----------------------------------------------------------------
        #include <reg51.h>
        #define uchar unsigned char
        #define uint  unsigned int
        //0~9,A~F的数码管段码,最后一个是黑屏
        uchar code DSY_CODE[]=
        { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
          0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00
        };
        sbit  BEEP = P3^7;
        //上次按键和当前按键序号,该矩阵中序号范围为0~15,16表示无按键
        uchar Pre_KeyNo = 16, KeyNo = 16 ;
        //-----------------------------------------------------------------
        // 延时
        //-----------------------------------------------------------------
        void DelayMS(uint ms)
        {
            uchar t;
            while(ms--)  for(t = 0; t < 120; t++);
        }
        //-----------------------------------------------------------------
        // 键盘矩阵扫描
        //-----------------------------------------------------------------
        void Keys_Scan()
        {
            uchar Tmp;
            //高4位置1,放入4行
            P1 = 0x0F;
            DelayMS(1);
            //按键后00001111将变成0000XXXX,X中有1个为0,3个仍为1
            //下面的异或操作会把3个1变成0,唯一的0变成1
            Tmp = P1 ^ 0x0F;
            //判断按键发生于0~3列中的哪一列
            switch (Tmp)
            {
              case 1: KeyNo = 0; break;
              case 2: KeyNo = 1; break;
              case 4: KeyNo = 2; break;
              case 8: KeyNo = 3; break;
              default:   KeyNo = 16;  //无键按下
            }
            //低4位置0,放入4列
            P1 = 0xF0;
            DelayMS(1);
            //按键后11110000将变成XXXX0000,X中有1个为0,3个仍为1
            //下面的表达式会将高4位移到低4位,并将其中唯一的0变为1,其余为0
            Tmp = P1 >> 4 ^ 0x0F;
            //对0~3行分别附加起始值0,4,8,12
            switch (Tmp)
            {
              case 1: KeyNo += 0; break;
              case 2: KeyNo += 4; break;
              case 4: KeyNo += 8; break;
              case 8: KeyNo += 12;
            }
        }
        //-----------------------------------------------------------------
        // 蜂鸣器
        //-----------------------------------------------------------------
        void Beep()
        {
          uchar i;
          for (i = 0; i < 100; i++)
          {
            DelayMS(1);
            BEEP = ~BEEP;
          }
          BEEP = 1;
        }
        //-----------------------------------------------------------------
        // 主程序
        //-----------------------------------------------------------------
        void main()
        {
          P0 = 0x00;
          while(1)
          {
              P1 = 0xF0;
              if(P1 != 0xF0) Keys_Scan();    //扫描键盘获取按键序号KeyNo
              if (Pre_KeyNo != KeyNo)
              {
                P0 = ~DSY_CODE[KeyNo];       //显示(用~作共阴共阳转换)
                Beep();
                Pre_KeyNo = KeyNo;
              }
              DelayMS(100);
          }
        }