单片机学习小组
直播中

李刚

7年用户 1317经验值
私信 关注

怎样通过矩阵键盘去控制8个数码管同时显示一个字符呢

矩阵键盘算法有何功能呢?

怎样通过矩阵键盘去控制8个数码管同时显示一个字符呢?

回帖(1)

徐远瑶

2022-2-23 09:31:24
基于蓝桥杯的单片机模块练习——矩阵键盘算法


功能概述


通过矩阵键盘控制8个数码管同时显示一个字符。

C代码


#include "stc15f2k60s2.h"
//行
***it R1 = P3^0;
***it R2 = P3^1;
***it R3 = P3^2;
***it R4 = P3^3;
//列
***it C1 = P4^4;
***it C2 = P4^2;
***it C3 = P3^5;
***it C4 = P3^4;

unsigned char code SMG_duanma[] = {0xc0,0xf9,0xa4,0xb0,
                                   0x99,0x92,0x82,0xf8,
                                   0x80,0x90,0x88,0x83,
                                   0xc6,0xa1,0x86,0x8e,
                                   0xbf,0x7f};
void ScanKey();
void DisplayAll(unsigned char num);
void SystemInit();
void SelectHC573(unsigned channel);
void Timer0_Init();      
void KeyAction(unsigned char KeyCode);
                                                                                                                                         
void main()
{
        SystemInit();
        Timer0_Init();      
        while(1)
        {
                ScanKey();
        }
      
}

void SelectHC573(unsigned channel)
{
        switch(channel)
        {
                case 0 : P2 = (P2 & 0X1F) | 0X00;break;
                case 4 : P2 = (P2 & 0X1F) | 0X80;break;
                case 5 : P2 = (P2 & 0X1F) | 0XA0;break;
                case 6 : P2 = (P2 & 0X1F) | 0XC0;break;
                case 7 : P2 = (P2 & 0X1F) | 0XE0;break;
        }
}

void SystemInit()
{
        SelectHC573(5);
        P0 = 0x00;
        SelectHC573(0);
        P0 = 0xff;
      
}

void DisplayAll(unsigned char num)
{
      
        SelectHC573(6);
        P0 = 0xff;
        SelectHC573(7);
        P0 = SMG_duanma[num];
      
}
unsigned char KeyStat[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};//经消抖之后的键值
//矩阵按键编号的映射表,按照键盘标号映射.比如S7就映射0x07
unsigned char code KeyCodeMap[4][4] = {{0x07,0x11,0x15,0x19},
                                       {0x06,0x10,0x14,0x18},
                                                                                                                                                               {0x05,0x09,0x13,0x17},
                                                                                                                                                         {0x04,0x08,0x12,0x16}
};
void KeyAction(unsigned char KeyCode)//对照着映射表完成相应按键的动作
{
        switch(KeyCode)
        {
                case 0x04 : DisplayAll(4);break;
                case 0x05 : DisplayAll(5);break;
                case 0x06 : DisplayAll(6);break;
                case 0x07 : DisplayAll(7);break;
                case 0x08 : DisplayAll(8);break;
                case 0x09 : DisplayAll(9);break;
                case 0x10 : DisplayAll(10);break;
                case 0x11 : DisplayAll(11);break;
                case 0x12 : DisplayAll(12);break;
                case 0x13 : DisplayAll(13);break;
                case 0x14 : DisplayAll(14);break;
                case 0x15 : DisplayAll(15);break;
                case 0x16 : DisplayAll(16);break;
                case 0x17 : DisplayAll(17);break;
                case 0x18 : DisplayAll(17);break;
                case 0x19 : DisplayAll(17);break;
        }
}
void ScanKey()
{
        unsigned char i,j;
        static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};储存上一次的键值
                for(i = 0; i<4; i++)
                {
                        for(j = 0; j<4;j++)
                        {
                                if(backup[j] != KeyStat[j])
                                {
                                        if(backup[j] == 0)//松手检测,松开按键后动作
                                        {
                                                KeyAction(KeyCodeMap[j]);
                                        }
                                        backup[j] = KeyStat[j];
                                }
                        }
                }
}
void Timer0_Init()
{
        TMOD = 0X00;
        TH0 = (65536 - 1000) / 256;
        TL0 = (65536 - 1000) % 256;
        EA = 1;
        ET0 = 1;
        TR0 = 1;
}

void Timer0_Service() interrupt 1
{
    unsigned char i;
    static unsigned char keyout = 0;  //矩阵按键扫描输出索引
    static unsigned char Keybuf[4][4] = {  //矩阵按键扫描缓冲区
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF}
    };
   
    //将一行的4个按键值移入缓冲区
    Keybuf[keyout][0] = (Keybuf[keyout][0] << 1) | C1;
    Keybuf[keyout][1] = (Keybuf[keyout][1] << 1) | C2;
    Keybuf[keyout][2] = (Keybuf[keyout][2] << 1) | C3;
    Keybuf[keyout][3] = (Keybuf[keyout][3] << 1) | C4;
    //消抖后更新按键状态
    for (i=0; i<4; i++)  //每行4个按键,所以循环4次
    {
        if ((Keybuf[keyout] & 0x0F) == 0x00)
        {   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
            KeyStat[keyout] = 0;
        }
        else if (( Keybuf[keyout] & 0x0F) == 0x0F)
        {   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
            KeyStat[keyout] = 1;
        }
    }
    //执行下一次的扫描输出
    keyout++;                //输出索引递增
    keyout = keyout & 0x03;  //索引值加到4即归零
    switch (keyout)          //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
        case 1: R1 = 1; R2 = 0; break;
        case 2: R2 = 1; R3 = 0; break;
        case 3: R3 = 1; R4 = 0; break;
        
    }
}

相关知识点

keyout = keyout & 0x03; //加到4即归零
keyout = keyout & 0x01; //加到2即归零
keyout = keyout & 0x07; //加到8即归零
keyout = keyout & 0x0f; //加到16即归零

拓展功能

长、短按键的算法

void KeyScan()
{
        unsigned char i,j;
        static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
        for(i=0; i<4; i++)
        {
                for(j=0; j<4; j++)
                {
                        if(backup[j] != KeySta[j])
                        {
                                lkey_flag = 0;
                        count_key = 0;
                                while(KeySta[j]==0);
                                if(backup[j] == 1)
                                {
                                        if(lkey_flag)
                                        KeyAction(KeyCodemap[j]);//长按键
                                        else
                                        KeyAction(255 - KeyCodemap[j]);//短按键
                                }
                                backup[j] = KeySta[j];
                        }
                }
        }
}
//****************在中断里的计时判断**********
//count_key每1ms自加一
if(count_key == 1000)
        {
                lkey_flag = 1;
                count_key = 0;
        }
//*******************************************

哪位大佬有没有更高级的长短按键判断的算法,告诉兄弟一下。抱拳了!!!

  switch (keyout)          //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
        case 1: R1 = 1; R2 = 0; break;
        case 2: R2 = 1; R3 = 0; break;
        case 3: R3 = 1; R4 = 0; break;
        
    }

这部分代码在用到串口通讯时需要修改,不能再对R1和R2进行操作。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分