3.16 4×4键盘矩阵控制条形LED显示

当按键较多时会占用更多的控制器端口,为减少对端口的占用,本例使用4×4 键盘矩阵,这样大大减少了端口占用,但识别按键的代码比独立按键的代码要复杂一些。本例运行过程时所点亮的LED个数与按键键值相等,例如,按下K1时,第1只LED点亮,按下K2时前2只LED点亮,按下K10时第1~10只LED点亮。

本例电路及运行效果如图3-13所示。

图3-13 4×4键盘矩阵控制条形LED显示电路

程序设计调试与实训:

本例键盘矩阵行线连接P0.0~P0.3,列线连接P0.4~P0.7,扫描过程如下:

程序首先判断是否有键按下。为判断16个按键中是否有键按下,程序首先在4条行线上放置4个0,即在P1端口输出0xF0,如果有任一按键按下,则4条列线上必有一位为0。

如果已有键按下,则判断按键所在行、列位置,并返回按键序号。代码中行扫描码sCode初值为0xFE(11111110),通过将该值循环右移,可对P1.0~P1.3对应的4行逐行发送0,每次发送扫描码后即判断高4位的4个1中是否有0出现,如果出现0则说明按键在该行上,这时可将发送的低4位与读取的高4位取反,也就是P1取反,这样P1中将出现2个1,其余位均变为0,2个1分别处在低4位和高4位中,高低4位中1所处的位置各有4种可能,共有16种可能,对应16个不同按键,根据取反后的值查询键盘矩阵按键特征码表,即可得到按键序号。

另外,读者要注意在代码中用延时对按键进行消抖。

读者可将电路中的按键由纵向编号改为横向编号,重新修改代码,看能否得到正确的运行结果。

源程序代码:

        //-----------------------------------------------------------------
        //  名称: 4×4 键盘矩阵控制条形LED显示
        //-----------------------------------------------------------------
        //  说明: 运行本例时,按下的按键键值越大,点亮的LED越多,例如,按下K1时
        //       点亮第1只LED,按下K2时点亮第1,2只LED,按下K16时全部LED点亮。
        //-----------------------------------------------------------------
        #include <reg51.h>
        #include <intrins.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
        };
        //键盘矩阵按键特征码表
        uchar code KeyCodeTable[] =
        {       0x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,0x41,0x42,0x44,0x48,0x81,0x82,
    0x84,0x88};
        //-----------------------------------------------------------------
        // 延时
        //-----------------------------------------------------------------
        void Delay()
        {
          uchar i;
          for(i = 0; i < 200; i++);
        }
        //-----------------------------------------------------------------
        // 键盘矩阵扫描
        //-----------------------------------------------------------------
        uchar Keys_Scan()
        {
            uchar sCode,kCode,i,k;
            //低4位置0,放入四行
            P1 = 0xF0;
            //如果高4位出现0则有键按下
            if ((P1 & 0xF0) != 0xF0)
            {
              Delay();
              if ((P1 & 0xF0) != 0xF0)
              {
                //行扫描码初值
                sCode = 0xFE;
                //对4行分别进行扫描
                for (k = 0; k < 4; k++)
                {
            P1 = sCode;
            if (( P1 & 0xF0) != 0xF0)
            {
                kCode = ~P1;
                //查表得到按键序号并返回
                for( i = 0; i< 16; i++)
                  if (kCode == KeyCodeTable[i]) return i;
            }
            else sCode = _crol_(sCode,1);
                }
              }
            }
            return -1;
        }
        //-----------------------------------------------------------------
        // 主程序
        //-----------------------------------------------------------------
        void main()
        {
          //按键序号,-1表示无按键
          uchar KeyNo = -1;
          uchar i,P2_LED,P3_LED;
          while(1)
          {
            //扫描键盘获取按键序号KeyNo
            KeyNo = Keys_Scan();
            if (KeyNo != -1)
            {
                P2_LED = 0xFF;
                P3_LED = 0xFF;
                //键值越大,点亮的LED越多
                for (i = 0; i <= KeyNo; i++)
                {
                  if ( i < 8)
            P3_LED >>= 1;
                  else
                      P2_LED >>= 1;
                }
                //点亮条形LED
                P3 = P3_LED;
                P2 = P2_LED;
            }
          }
        }