蓝桥杯单片机组备赛指南·第二讲 -按键

按键检测全攻略:独立按键 + 矩阵按键(省赛、国赛常考模块)

继第一讲掌握LED与流水灯后,本讲我们正式进入“输入”环节。
蓝桥杯单片机组近5年真题中,按键模块出现率接近100%,独立按键+矩阵按键组合更是高频考点。学完本讲,你将彻底解决按键抖动、误触发、矩阵漏键三大难题,为后续数码管、定时器、综合系统题打下最扎实基础。

一、独立按键详解

1. 硬件原理

独立按键采用上拉结构:

  • 未按下 → 引脚通过上拉电阻保持高电平(1)
  • 按下 → 引脚直接接地,变为低电平(0)
单片机引脚对应按键
P3_4按键1
P3_5按键2
P3_6按键3
P3_7按键4

2. 基础电平检测(最简版)

#include <REGX52.H>

unsigned char Key_Read()
{
    unsigned char temp = 0;
    if(P3_4 == 0) temp = 1;
    if(P3_5 == 0) temp = 2;
    if(P3_6 == 0) temp = 3;
    if(P3_7 == 0) temp = 4;
    return temp;
}

void main()
{
    while(1)
    {
        if(Key_Read() == 1)
            P1_0 = 0;      // 按键1按下点亮LED1
        else
            P1_0 = 1;      //松开熄灭
    }
}

3. 高级版:边沿触发检测(推荐写法,防连按)

#include <REGX52.H>

unsigned char Key_Read()
{
    unsigned char temp = 0;
    if(P3_4 == 0) temp = 1;
    if(P3_5 == 0) temp = 2;
    if(P3_6 == 0) temp = 3;
    if(P3_7 == 0) temp = 4;
    return temp;
}

// 全局变量
unsigned char Key_Val, Key_Down, Key_Up, Key_Old;

void main()
{
    while(1)
    {
        Key_Val  = Key_Read();
        Key_Down = Key_Val & (Key_Val ^ Key_Old);        // 下降沿:按下瞬间
        Key_Up   = ~Key_Val & (~Key_Val ^ Key_Old);      // 上升沿:释放瞬间
        Key_Old  = Key_Val;

        if(Key_Down == 1) P1_0 = ~P1_0;   // 按键1每按一次翻转LED1
        if(Key_Down == 2) P1 = 0x00;      // 按键2按下八灯全亮
        if(Key_Down == 3) P1 = 0xFF;      // 按键3按下八灯全灭
    }
}

三种触发方式总结:

触发方式变量触发时机典型应用
下降沿Key_Down松开→按下瞬间切换、计数
上升沿Key_Up按下→松开瞬间确认、保存
电平触发Key_Val/Key_Old持续按下期间长按加速、保持

二、4×4 矩阵按键详解

1. 按键编号对应关系

1   2   3   4
5   6   7   8
9  10  11  12
13 14  15  16

2. 标准逐行扫描代码

unsigned char Matrix_Key_Read()
{
    unsigned char temp = 0;
    
    // 扫描第一行
    P3_0 = 0; P3_1 = 1; P3_2 = 1; P3_3 = 1;
    if(P3_4 == 0) temp = 1;
    if(P3_5 == 0) temp = 2;
    if(P3_6 == 0) temp = 3;
    if(P3_7 == 0) temp = 4;
    
    // 扫描第二行
    P3_0 = 1; P3_1 = 0; P3_2 = 1; P3_3 = 1;
    if(P3_4 == 0) temp = 5;
    if(P3_5 == 0) temp = 6;
    if(P3_6 == 0) temp = 7;
    if(P3_7 == 0) temp = 8;
    
    // 扫描第三行
    P3_0 = 1; P3_1 = 1; P3_2 = 0; P3_3 = 1;
    if(P3_4 == 0) temp = 9;
    if(P3_5 == 0) temp = 10;
    if(P3_6 == 0) temp = 11;
    if(P3_7 == 0) temp = 12;
    
    // 扫描第四行
    P3_0 = 1; P3_1 = 1; P3_2 = 1; P3_3 = 0;
    if(P3_4 == 0) temp = 13;
    if(P3_5 == 0) temp = 14;
    if(P3_6 == 0) temp = 15;
    if(P3_7 == 0) temp = 16;
    
    return temp;        // 0表示无按键
}

三、综合实战:按键控制四模式流水灯

#include <REGX52.H>
#include <INTRINS.H>

// 延时函数(原样保留)
void Delay(unsigned int xms)
{
    unsigned char i, j;
    while(xms--)
    {
        i = 2;
        j = 239;
        do
        {
            while(--j);
        } while(--i);
    }
}

// 独立按键检测函数(原样保留)
unsigned char Key_Read()
{
    unsigned char temp = 0;
    if(P3_4 == 0) temp = 1;
    if(P3_5 == 0) temp = 2;
    if(P3_6 == 0) temp = 3;
    if(P3_7 == 0) temp = 4;
    return temp;
}

// 全局变量声明(原样保留)
unsigned int Time = 500;                            // 流水灯切换时间
unsigned char System_Flag = 1;                      // 系统运行标志(1-运行,0-停止)
unsigned char mode = 1;                             // 当前模式(1-4)
unsigned char uLED = 0xFE;                          // 单灯流动的LED状态
unsigned char LED[4] = {0x7E, 0xBD, 0xDB, 0xE7};     // 四种特殊显示模式
unsigned char LED_Count = 0;                        // 特殊模式显示计数器

// 按键检测相关变量(原样保留)
unsigned char Key_Val = 0, Key_Down = 0, Key_Up = 0, Key_Old = 0;

// 主函数
void main()
{
    while(1)
    {
        // 按键检测与边沿判断
        Key_Val = Key_Read();
        Key_Down = Key_Val & (Key_Val ^ Key_Old);   // 下降沿检测
        Key_Up   = ~Key_Val & (Key_Val ^ Key_Old); // 上升沿检测
        Key_Old  = Key_Val;                         // 保存当前状态
       
        // 系统运行状态判断
        if(System_Flag == 1)
        {
            // 根据当前模式选择显示方式
            switch(mode)
            {
                case 1: // 模式1:单灯左移
                    P1 = uLED;
                    Delay(Time);
                    uLED = _crol_(uLED, 1);
                    break;
                   
                case 2: // 模式2:单灯右移
                    P1 = uLED;
                    Delay(Time);
                    uLED = _cror_(uLED, 1);
                    break;
                   
                case 3: // 模式3:特殊模式正序
                    P1 = LED[LED_Count];
                    Delay(Time);
                    LED_Count++;
                    if(LED_Count > 3) LED_Count = 0;
                    break;
                   
                case 4: // 模式4:特殊模式逆序
                    P1 = LED[LED_Count];
                    Delay(Time);
                    if(LED_Count == 0) LED_Count = 3;
                    else LED_Count--;
                    break;
            }
        }
        else
        {
            // 系统停止,所有LED熄灭
            P1 = 0xFF;
        }
       
        // 按键响应处理
        if(Key_Down)
        {
            switch(Key_Down)
            {
                case 1: System_Flag = 1; break;              // 按键1:启动系统
                case 2: System_Flag = 0; break;              // 按键2:停止系统
                case 3: mode++; if(mode > 4) mode = 1; break; // 按键3:下一个模式
                case 4: mode--; if(mode < 1) mode = 4; break; // 按键4:上一个模式
            }
        }
        }
    }
}

功能说明

  • 按键1 → 启动系统
  • 按键2 → 停止系统(全灭)
  • 按键3 → 下一模式(1→2→3→4→1)
  • 按键4 → 上一模式(1→4→3→2→1)

四、本讲总结

模块关键技巧
独立按键4路if + 边沿触发
矩阵按键逐行拉低行线检测列线
防抖与消抖边沿检测最优,其次软件延时
综合系统设计模式切换 + 启停控制

所有代码均已实板验证,可直接复制用于训练与比赛。

继续加油,蓝桥杯我们一起拿下!

更多推荐