六、独立按键和矩阵键盘

文章目录

  • 一、独立按键
    • 1、按键KEY1控制小灯D1
      • 1.1效果图
      • 1.2代码块
    • 2、按键KEY1、KEY2、KEY3、KEY4控制D1、D3、D5、D7
      • 2.1效果图
      • 2.2代码块
    • 思考与回答
  • 二、矩阵键盘
    • 1、第一行矩阵键盘点亮4个LED小灯
      • 1.1效果图
      • 1.2代码块
    • 2、4x4矩阵键盘检测8个LED小灯
      • 2.1效果图
      • 2.2代码块
    • 3、4x4矩阵键盘显示0-9 A-F
      • 3.1效果图
      • 3.2代码块

一、独立按键

1、按键KEY1控制小灯D1

1.1效果图

1.2代码块

#include<REGX51.H>sbit KEY1=P3^4;// 原理图按键1接P3.4,不是P2^4sbit LED1=P0^0;// LED连接P0.0,低电平点亮// 延时函数voiddelay_ms(unsignedintms){unsignedinti,j;for(i=0;i<ms;i++)for(j=0;j<123;j++);}voidmain(){P0=0xFF;// 初始所有LED熄灭(因低电平点亮)while(1){if(KEY1==0)// 按键按下(接地,低电平){delay_ms(10);// 消抖延时10msif(KEY1==0)// 再次确认按下{while(KEY1==0);// 等待按键松开,防止连发LED1=~LED1;// 翻转小灯亮灭状态}}}}

2、按键KEY1、KEY2、KEY3、KEY4控制D1、D3、D5、D7

KEY1控制D1小灯的开关
KEY2控制D3小灯的开关
KEY3控制D5小灯的开关
KEY4控制D7小灯的开关

2.1效果图

2.2代码块

#include<REGX51.H>// 按键定义sbit KEY1=P3^4;// 按键1sbit KEY2=P3^5;// 按键2sbit KEY3=P3^6;// 按键3sbit KEY4=P3^7;// 按键4// LED定义(低电平点亮)sbit LED1=P0^0;// D1小灯sbit LED2=P0^2;// D3小灯(P0.2对应D3)sbit LED3=P0^4;// D5小灯(P0.4对应D5)sbit LED4=P0^6;// D7小灯(P0.6对应D7)// 延时函数(11.0592MHz晶振,约1ms)voiddelay_ms(unsignedintms){unsignedinti,j;for(i=0;i<ms;i++)for(j=0;j<123;j++);}// 按键扫描函数(带消抖和等待释放)voidkey_scan(void){// 按键1控制D1if(KEY1==0){delay_ms(10);if(KEY1==0){while(!KEY1);// 等待按键释放LED1=~LED1;// 翻转状态}}// 按键2控制D3if(KEY2==0){delay_ms(10);if(KEY2==0){while(!KEY2);LED2=~LED2;}}// 按键3控制D5if(KEY3==0){delay_ms(10);if(KEY3==0){while(!KEY3);LED3=~LED3;}}// 按键4控制D7if(KEY4==0){delay_ms(10);if(KEY4==0){while(!KEY4);LED4=~LED4;}}}voidmain(){// 初始化:所有LED熄灭(低电平点亮,所以先给高电平)LED1=1;LED2=1;LED3=1;LED4=1;while(1){key_scan();// 持续扫描按键}}

思考与回答

问题:

  1. 程序中(P0 = 0xFF);的作用是什么?
  2. 为什么if(KEY1 == 0)后要加delay_ms(20)
  3. while(KEY1 == 0);有什么作用?
  4. 如果将LED1 = ~LED1;替换为LED1 = 0;,LED状态会如何变化?
  5. 程序中哪个部分实现了“单次按键触发”?请简要说明原理。

回答:

  1. 程序中(P0 = 0xFF);的作用是将P0口的8个引脚全部设置为高电平(1),可以确保所有LED处于熄灭状态,避免上电瞬间灯乱亮。
  2. if(KEY1 == 0)后要加delay_ms(20)是为了按键消抖,防止一次按下被误判为多次触发。
  3. while(KEY1 == 0);的作用是等待按键释放,也叫“松手检测”。
  4. 如果将LED1 = ~LED1;替换为LED1 = 0;,按键按一次LED会点亮,然后一直保持常亮,无法再关闭。LED1 = 0 是绝对赋值,无论之前状态是什么,都强制设为0(点亮)。
  5. 实现“单次按键触发”的核心是 “等待按键释放” 机制,程序如下:
if(KEY1==0)// 检测按键按下{delay_ms(10);// 消抖延时if(KEY1==0)// 确认真正按下{while(!KEY1);// 等待按键释放 ← 关键!LED1=~LED1;// 释放后才执行动作}}

二、矩阵键盘

1、第一行矩阵键盘点亮4个LED小灯

点击开关S0,D1灯亮
点击开关S1,D2灯亮
点击开关S2,D3灯亮
点击开关S3,D4灯亮

1.1效果图

1.2代码块

#include<reg52.h>// 引入51单片机寄存器定义头文件#defineucharunsignedchar// 宏定义:uchar = unsigned char(8位无符号)// 将P0口的第0~7位分别定义为8个LED灯(低电平点亮)sbit led1=P0^0;sbit led2=P0^1;sbit led3=P0^2;sbit led4=P0^3;// 延时函数,x控制延时时间voiddelay(uchar x){uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}// 主函数入口voidmain(){// 初始化:所有LED熄灭(高电平)led1=1;led2=1;led3=1;led4=1;while(1)// 无限循环运行{// **********扫描第一行按键*********************P2=0xfe;// 选中第一行(1111 1110,P2.0=0)if(P2!=0xfe)// 判断是否有按键按下{delay(50);// 消抖处理if(P2!=0xfe)// 再次确认按键状态{switch(P2)// 根据P2值判断按键{case0xee:led1=0;break;// 1110 1110 → S0按下 → D1亮case0xde:led2=0;break;// 1101 1110 → S1按下 → D2亮case0xbe:led3=0;break;// 1011 1110 → S2按下 → D3亮case0x7e:led4=0;break;// 0111 1110 → S3按下 → D4亮}}}}}

2、4x4矩阵键盘检测8个LED小灯

2.1效果图

2.2代码块

#include<reg52.h>// 引入51单片机寄存器定义头文件#defineucharunsignedchar// 宏定义:uchar = unsigned char(8位无符号)// 将P0口的第0~7位分别定义为8个LED灯(低电平点亮)sbit D1=P0^0;// S0控制亮,S8控制灭sbit D2=P0^1;// S1控制亮,S9控制灭sbit D3=P0^2;// S2控制亮,S10控制灭sbit D4=P0^3;// S3控制亮,S11控制灭sbit D5=P0^4;// S4控制亮,S12控制灭sbit D6=P0^5;// S5控制亮,S13控制灭sbit D7=P0^6;// S6控制亮,S14控制灭sbit D8=P0^7;// S7控制亮,S15控制灭// 延时函数,x控制延时时间voiddelay(uchar x){uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}// 关闭所有LEDvoidAllLedOff(){D1=1;D2=1;D3=1;D4=1;D5=1;D6=1;D7=1;D8=1;}// 主函数入口voidmain(){// 初始化所有LED熄灭AllLedOff();while(1)// 无限循环运行{// **********扫描第一行按键(S0, S1, S2, S3)点亮LED*********************P2=0xfe;// 选中第一行(1111 1110,P2.0=0)if(P2!=0xfe)// 判断是否有按键按下{delay(50);// 消抖处理if(P2!=0xfe)// 再次确认按键状态{switch(P2)// 根据P2值判断按键{case0xEE:D1=0;break;// S0按下 → D1亮case0xDE:D2=0;break;// S1按下 → D2亮case0xBE:D3=0;break;// S2按下 → D3亮case0x7E:D4=0;break;// S3按下 → D4亮}while(P2!=0xfe);// 等待按键释放}}// **********扫描第二行按键(S4, S5, S6, S7)点亮LED*********************P2=0xfd;// 选中第二行(1111 1101,P2.1=0)if(P2!=0xfd)// 判断是否有按键按下{delay(50);// 消抖处理if(P2!=0xfd)// 再次确认按键状态{switch(P2)// 根据P2值判断按键{case0xED:D5=0;break;// S4按下 → D5亮case0xDD:D6=0;break;// S5按下 → D6亮case0xBD:D7=0;break;// S6按下 → D7亮case0x7D:D8=0;break;// S7按下 → D8亮}while(P2!=0xfd);// 等待按键释放}}// **********扫描第三行按键(S8, S9, S10, S11)熄灭LED*********************P2=0xfb;// 选中第三行(1111 1011,P2.2=0)if(P2!=0xfb)// 判断是否有按键按下{delay(50);// 消抖处理if(P2!=0xfb)// 再次确认按键状态{switch(P2)// 根据P2值判断按键{case0xEB:D1=1;break;// S8按下 → D1灭case0xDB:D2=1;break;// S9按下 → D2灭case0xBB:D3=1;break;// S10按下 → D3灭case0x7B:D4=1;break;// S11按下 → D4灭}while(P2!=0xfb);// 等待按键释放}}// **********扫描第四行按键(S12, S13, S14, S15)熄灭LED*********************P2=0xf7;// 选中第四行(1111 0111,P2.3=0)if(P2!=0xf7)// 判断是否有按键按下{delay(50);// 消抖处理if(P2!=0xf7)// 再次确认按键状态{switch(P2)// 根据P2值判断按键{case0xE7:D5=1;break;// S12按下 → D5灭case0xD7:D6=1;break;// S13按下 → D6灭case0xB7:D7=1;break;// S14按下 → D7灭case0x77:D8=1;break;// S15按下 → D8灭}while(P2!=0xf7);// 等待按键释放}}}}

3、4x4矩阵键盘显示0-9 A-F

要求:
第一排按键显示:0 1 2 3
第二排按键显示:4 5 6 7
第三排按键显示:8 9 A b
第四排按键显示:C d E F

3.1效果图

3.2代码块

#include<reg52.h>// 52单片机头文件#defineucharunsignedchar#defineuintunsignedintsbit dula=P1^6;// 段选锁存(控制数码管显示内容)sbit wela=P3^4;// 位选锁存(控制哪一位亮)uchar num=0;// 当前显示的数值uchar temp;// 保存按键扫描值// 段码表(共阴极数码管)uchar code table[]={0x3F,// 00x06,// 10x5B,// 20x4F,// 30x66,// 40x6D,// 50x7D,// 60x07,// 70x7F,// 80x6F,// 90x77,// A0x7C,// b0x39,// C0x5E,// d0x79,// E0x71// F};// 延时函数(用于消抖)voiddelay(uchar x){uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}// 数码管显示函数voiddisplay(uchar x){P0=table[x];// 输出段码dula=1;// 锁存段选dula=0;P0=0xc0;// 1100 0000 -> 选中第1位数码管wela=1;// 锁存位选wela=0;}// 4x4键盘扫描函数ucharkeyscan(){uchar key_value;// ===== 扫描第1行 =====P2=0xfe;// 1111 1110if(P2!=0xfe){delay(50);if(P2!=0xfe){temp=P2;switch(temp){case0xee:key_value=0;break;// 第1行第1列 -> 0case0xde:key_value=1;break;// 第1行第2列 -> 1case0xbe:key_value=2;break;// 第1行第3列 -> 2case0x7e:key_value=3;break;// 第1行第4列 -> 3}while(P2!=0xfe);// 等待松手returnkey_value;}}// ===== 扫描第2行 =====P2=0xfd;// 1111 1101if(P2!=0xfd){delay(50);if(P2!=0xfd){temp=P2;switch(temp){case0xed:key_value=4;break;// 第2行第1列 -> 4case0xdd:key_value=5;break;// 第2行第2列 -> 5case0xbd:key_value=6;break;// 第2行第3列 -> 6case0x7d:key_value=7;break;// 第2行第4列 -> 7}while(P2!=0xfd);returnkey_value;}}// ===== 扫描第3行 =====P2=0xfb;// 1111 1011if(P2!=0xfb){delay(50);if(P2!=0xfb){temp=P2;switch(temp){case0xeb:key_value=8;break;// 第3行第1列 -> 8case0xdb:key_value=9;break;// 第3行第2列 -> 9case0xbb:key_value=10;break;// 第3行第3列 -> Acase0x7b:key_value=11;break;// 第3行第4列 -> b}while(P2!=0xfb);returnkey_value;}}// ===== 扫描第4行 =====P2=0xf7;// 1111 0111if(P2!=0xf7){delay(50);if(P2!=0xf7){temp=P2;switch(temp){case0xe7:key_value=12;break;// 第4行第1列 -> Ccase0xd7:key_value=13;break;// 第4行第2列 -> dcase0xb7:key_value=14;break;// 第4行第3列 -> Ecase0x77:key_value=15;break;// 第4行第4列 -> F}while(P2!=0xf7);returnkey_value;}}return16;// 无按键按下返回16}// 主程序voidmain(){uchar key;while(1){key=keyscan();// 扫描键盘if(key<16)// 有效按键(0-15){num=key;// 更新显示值}display(num);// 显示结果delay(5);// 短暂延时,避免显示闪烁}}