第七章 独立按键
1. 导入
在前几章中,我们学习了单片机的输出控制,包括LED、蜂鸣器和数码管。本章将引入输入设备 ------独立按键,实现人机交互的基本功能。
独立按键是最简单的输入装置,广泛应用于各种嵌入式系统中。通过本章学习,你将掌握:
- 按键的硬件连接与消抖原理;
- 如何检测按键按下与释放;
- 实现按键控制LED、数码管等输出设备;
- 编写可靠的按键检测函数;
- 为后续学习矩阵键盘、中断按键打下基础。
2. 硬件设计
2.1 按键工作原理
按键是一个机械开关,按下时导通,松开时断开。但在机械接触瞬间会产生抖动(Bounce),导致电平快速变化,可能被误判为多次按下。
2.2 硬件消抖
最简单的消抖方式是使用RC滤波电路,但教学中常用软件消抖,成本低、灵活性高。
2.3 按键连接方式
典型电路(共4个独立按键):
- 按键一端接地(GND);
- 另一端接单片机I/O口(如P3.0);
- I/O口内部或外部接上拉电阻(10kΩ),使未按下时为高电平。
51单片机P0、P1、P2口有弱上拉,P3口也有上拉能力,可直接使用。
引脚分配示例:
按键 | 连接引脚 | 功能 |
---|---|---|
K1 | P3.0 | 启动/停止 |
K2 | P3.1 | 加1 |
K3 | P3.2 | 减1 |
K4 | P3.3 | 模式切换 |
注意:P3.2和P3.3也可用于外部中断,后续可扩展。
3. 软件设计
3.1 按键检测原理
- 未按下:I/O口为高电平(上拉);
- 按下:I/O口被拉低,为低电平;
- 检测到低电平 → 可能按下 → 延时消抖 → 再次检测 → 确认按下。
3.2 简单按键检测函数
c
#include <reg52.h>
sbit KEY1 = P3^0;
sbit KEY2 = P3^1;
// 延时函数
void delay_ms(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 125; j++);
}
// 检测按键是否按下(返回1:按下,0:未按下)
unsigned char key_press(sbit key) {
if (key == 0) { // 电平为低,可能按下
delay_ms(10); // 软件消抖延时
if (key == 0) { // 仍为低,确认按下
while(key == 0); // 等待释放(防止重复触发)
return 1;
}
}
return 0;
}
说明:
while(key == 0)
用于等待按键释放,避免一次按下触发多次。
3.3 按键控制LED
实现:按下K1,LED状态翻转。
c
sbit LED = P1^0;
sbit KEY1 = P3^0;
void main() {
while(1) {
if (key_press(KEY1)) {
LED = ~LED; // 翻转LED状态
}
}
}
3.4 多按键检测
c
unsigned char key_scan() {
if (P3 == 0xFE) { // K1按下(P3.0=0,其余=1)
delay_ms(10);
if (P3 == 0xFE) {
while(P3 != 0xFF); // 等待释放
return 1;
}
}
else if (P3 == 0xFD) { // K2按下(P3.1=0)
delay_ms(10);
if (P3 == 0xFD) {
while(P3 != 0xFF);
return 2;
}
}
return 0;
}
优点:可同时检测多个按键状态;缺点:占用P3口全部引脚。
3.5 按键控制数码管数字增减
目标:K2加1,K3减1,数码管显示当前值。
c
#include <reg52.h>
sbit KEY_ADD = P3^1;
sbit KEY_SUB = P3^2;
unsigned char code seg_code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char num = 0;
void delay_ms(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 125; j++);
}
void display_digit(unsigned char n) {
P0 = seg_code[n];
P2 = 0x0E; // 选中第一位数码管
delay_ms(5);
}
void key_action() {
if (KEY_ADD == 0) {
delay_ms(10);
if (KEY_ADD == 0) {
num++;
if (num > 9) num = 0;
while(KEY_ADD == 0);
}
}
if (KEY_SUB == 0) {
delay_ms(10);
if (KEY_SUB == 0) {
num--;
if (num > 9) num = 9; // 防止溢出(无符号数)
while(KEY_SUB == 0);
}
}
}
void main() {
while(1) {
key_action();
display_digit(num);
}
}
说明:
num--
后若为-1,无符号数变为255,故用if(num > 9) num = 9;
拦截。
3.6 支持长按功能(扩展)
c
void key_long_press() {
static unsigned char count = 0;
if (KEY_ADD == 0) {
delay_ms(10);
if (KEY_ADD == 0) {
count++;
if (count >= 50) { // 长按500ms
num++; // 连续加
count = 40; // 控制加速度
}
}
} else {
count = 0;
}
}
可结合定时器实现更精准长按检测。
3.7 编译与下载
- Keil中创建工程;
- 确认按键与I/O连接正确;
- 编译生成HEX文件;
- 下载至单片机;
- 按下按键,观察LED或数码管是否响应。
若无响应:
- 检查按键是否接地;
- 确认上拉电阻存在;
- 测量按下时引脚是否为低电平。
##4. 小结
本章通过引入独立按键,实现了人机交互的基本功能,主要内容包括:
- 硬件连接:掌握按键的上拉接法与消抖电路设计;
- 软件检测:编写可靠的按键检测函数,支持单击、消抖、等待释放;
- 应用实例:实现按键控制LED翻转、数码管数字增减;
- 扩展功能:支持多按键识别与长按操作;
- 开发流程:完成输入-处理-输出的完整闭环。
4.1 常见问题与解决
问题 | 原因 | 解决方法 |
---|---|---|
按键无反应 | 未接上拉电阻、接地不良 | 检查电路,确保默认高电平 |
误触发多次 | 消抖不充分 | 增加延时或改进检测逻辑 |
按键卡死 | 未等待释放 | 加入while(key == 0) 等待松手 |
数码管闪烁 | 显示时间过长 | 缩短display_digit 延时至1~2ms |
4.2 下一步学习建议
- 学习外部中断,实现按键快速响应;
- 设计矩阵键盘,节省I/O资源;
- 结合定时器,实现非阻塞按键扫描;
- 应用于电子钟、密码锁等综合项目。
本章标志着你已掌握基本输入能力,下一章将进入定时器/计数器模块的深入学习,实现精准时间控制与中断响应。