单片机C51 之(6)GPIO按键--基础应用

本文介绍了单片机中按键输入的基本使用,包括简单的按键控制LED亮灭,以及在按键操作中遇到的闪烁和误读问题。通过自锁和软件消抖方法,解决了按键长时间按下导致的闪烁以及按键抖动引起的误读,确保了单片机对按键操作的准确响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按键作为在单片机系统中,最简单的、常用的输入之一。

常用的机械弹性按键,也是比较便宜的,单片机最小系统里面使用的一般是这种,根据封装、尺寸分为很多型号。但基本机械原理都是类似的:按下时接通或断开电路,释放后状态即复原。
在这里插入图片描述
简单的使用
1、按下灯亮、松手灯灭:
在这里插入图片描述

#include <reg51.h>
sbit key = P2^0;  //按键硬件绑定P2口0引脚
void main()
{
	for( ; ; ) {	
		if(key == 0){  //由于51单片机GPIO默认状态是高电平,所以检测低电平变化
			P0 = 0x00;
		} else {
			P0 = 0xFF;
		}
	}
}

在这里插入图片描述
2、点击改变状态:按下亮、再按下灭

#include <reg51.h>
sbit key = P2^0;
void main()
{
	int i = 0;
	for( ; ; )	{	
		if(key == 0) 	{
			i++;
			if(i > 2) i = 0;
		}
		if(i == 1) {
			P0 = 0x00;  //第一次按下点亮
		} else {
			P0 = 0xff;  //第二次按下灭
		} 
	}
}

折腾一下就会发现这里有两个比较有趣的现象:
1).如果一直按着不放,就会发现LED存在闪烁的现象?
2).经常会出现明明我是第二次按下,为什么没有灭掉?

针对以上两个问题,我们来看一下原因和解决方案:
1.第一个问题,那是因为代码回一直循环的执行下去,不断的检测到key==0,就会一直改变i的值,进而改变P0口的输出状态。 解决这问题因为很简单,就是使用自锁,保证每次按键状态变化的时候,只有第一个生效,那就是后面的都不响应,但是使用自锁这样的程序设计,一定记得要解锁,不然把自己锁住了,以后再也进不去了。

#include <reg51.h>
sbit key = P2^0;
void main()
{
	int i = 0,j = 0;
	for( ; ; )	{	
		if(key == 0 && j == 0) 	{	//这里用j的变化来锁住程序响应
			j = 1;
			if(i == 1) i = 0;
			else i = 1;
		}
		
		if(i == 1) {
			P0 = 0x00;  //第一次按下点亮
		} else {
			P0 = 0xff;  //第二次按下灭
		} 
		
		if(key == 1 && j == 1)  j = 0; //按键放开后解锁
	}
}		

2.第二个问题:通常的按键所用开关为机械弹性开关。由于机械触电的弹性作用、人体按下的抖动,按键在闭合及断开的瞬间均伴随有一连串的抖动。这里的问题就是由于按键抖动会引起一次按键被误读多次,CPU的执行速度比人的反应速度,在整个按下和抬起的过程中,会读到很多次。
抖动时间是有按键的机械特性决定,稳定时间一般是由操作人员的按键动作控制的。
在这里插入图片描述

为了确保CPU对按键的一次闭合仅作一次处理,必须去除抖动。

消除抖动的方法有硬件和软件两种方法。
1、硬件方法常用RS触发器电路 – 过于复杂,不符合硬件电路尽可能简单的设计思想。
在这里插入图片描述

2、软件方法是当检测出键闭合后执行一个10ms~20ms的延时程序,再一次检测键的状态,如仍保持闭合状态,则确认真正有键按下 – 常用

#include <reg51.h>
sbit key = P2^0;

void DelayTime10ms(unsigned int DelayValue);

void main()
{
	int i = 0,j = 0;
	for( ; ; ) {	
	
		if(key == 0 && j == 0) {	//这里用j的变化来锁住程序响应
			DelayTime10ms(2);  //延时20ms在检测一次
			
			if(key == 0 && j == 0) {
				j = 1;
				if(i == 1) i = 0;
				else i = 1;
			}
		}
		
		if(i == 1) {
			P0 = 0x00;  //第一次按下点亮
		} else {
			P0 = 0xff;  //第二次按下灭
		} 
		if(key == 1 && j == 1)  j = 0; //按键放开后解锁
	}
}

void DelayTime10ms(unsigned int DelayValue)
{
	unsigned int a,b;
	for(a=0;a<DelayValue;a++)
		for(b=0;b<1828;b++);	
}

这样就可以实现正常的按下亮,在按下灭。
更多的使用技巧、方法,后续文章会详细讲述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值