51单片机学习记录——独立按键控制LED

目录

独立按键

今日任务一:独立按键控制LED的亮灭

今日任务二: 独立按键控制LED的状态

今日任务三:独立按键控制LED显示二进制

今日任务四:独立按键控制LED移位

今日所遇到的问题

总结


独立按键

        轻触按键,相当于是一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力谭东来实现接通和断开。独立按键模块开发原理图如下,注意P31和P30分别控制的是K1和K2!!

        今天的主要任务就是通过对独立按键进行编程,可以通过轻触按键以达到控制LED的功能。

今日任务一:独立按键控制LED的亮灭

        思路分析:此任务拟使用K1按钮来控制LED,所以我们就需要对P3_1寄存器进行赋值,当P3_1==0时,表示此按键被按下,LED亮,当P3_1!=0时,就表示按键没有被按下,LED灭,意思就是长按灯亮,不按灯灭。所以我们可以通过if语句来作判断,于此同时还需要加上一个while循环将其包裹,以至于可以重复判断,其代码如下所示: 

#include <REGX52.H>
void main()
{
	 while(1)
	 {
	  	if(P3_1==0)
		{
		    P2_0=0;
		}
		else
		{
			P2_0=1;
		}	
	 }
}

任务一还是比较容易实现的。

今日任务二: 独立按键控制LED的状态

        思路分析:有了任务一的基础,我想通过轻触一下来控制LED的状态应该很容易了吧,同样通过if语句就可以实现了,只是需要判断一下K1按键是否被按下即可以及是否松开就可以了,那如何判断按键是否松开了呢?可以通过一个空while语句来实现,如果检测到K1按键一直被按下,就将程序阻断,松开后才能进行下一步操作,由于是控制LED灯的亮灭,每次操作只需要将P_2取反就行,所以就有了以下的代码:

#include <REGX52.H>
void main()
{
	while(1)
	{
		if(P3_1==0)
		{
			while(P3_1==0);//阻断 判断按键有没有松开
			P2_0=~P2_0;
		}

	}
}

下载到板子上面之后,确实实现了我们需要的功能,但是这样真的完美吗?

        下面补充一点按键的抖动的知识:对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动,大概如下图所示:

其抖动时间很短,大概只要5-10ms,所以我们刚刚的我们看到实验现象是正常的,这是因为人眼分辨不出来。需要延时20ms来避开这个抖动期,这就需要我们上期的知识了,如有需要可以到移步我的上一篇博客。51单片机学习记录——LED模块入门学习-CSDN博客文章浏览阅读463次,点赞20次,收藏17次。做这个博客的目的是为了记录自己在学习51单片机的过程中所学到的知识点以及遇到的问题以便日后方便回顾。如果有同学一不小心看到这篇博客,希望也能够帮助到你。https://blog.csdn.net/m0_60645512/article/details/136445464?spm=1001.2014.3001.5502

        由此代码就变成如下所示了:

#include <REGX52.H>
#include <intrins.h>
void Delay(unsigned int xms)		//@11.0592MHz
{
	unsigned char i, j;
	while(xms)

	{
		  	_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}

}

void main()
{
	while(1)
	{
		if(P3_1==0)
		{
			Delay(20);
			while(P3_1==0);
			Delay(20);
			P2_0=~P2_0;
		}

	}
}

 这样就完美避开了机械抖动所带来的潜在问题。任务二完成。

今日任务三:独立按键控制LED显示二进制

        思路分析:此任务要求我们每一次按键之后都能够加一,以至于最终能够全部将将所有LED点亮,所以很容易想到P2++,但是这样做是不对的,得到的结果和期望的结果完全相反,所以需要引入一个全新的变量去代替P2++,这里我用无符号字符来定义了一个变量LEDNumber,用char来定义的好处是,其大小只有八位,超过八位之后溢出归0,P2的值就直接对LEDNumber的值取反就可以解决之前结果相反的问题了,其代码如下所示:

#include <REGX52.H>
#include <intrins.h>


 void Delay1ms(unsigned int xms)
{
	unsigned char i, j;
	while(xms)
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		xms--;	
	}
 
}
void main()
{
	 unsigned char LEDNumber=0;
	 while(1)
	 {
	 	if(P3_1==0)
		{
		  Delay1ms(20);
		  while(P3_1==0);
		  Delay1ms(20);
		  LEDNumber++;
		  P2=~LEDNumber;
		}
	 }
}

      任务三结束!  

今日任务四:独立按键控制LED移位

        思路分析:此任务要求我们使用两个按键,K1和K2,K1表示右移一位,K2表示左移一位,这就需要我们判断按下的按键是K1还是K2,同上用if语句判断。这里同样需要一个额外的变量LEDNumber,用作中间量来判断目前需要移位几次操作,最后再取反就可以了,最后记得对LEDNumber的值做一个判定,以达成循环移位的效果,还要记得先提前给P2赋值~(0x01),让初始状态D1是亮着的状态。代码如下:

#include <REGX52.H>
#include <intrins.h>


 void Delay1ms(unsigned int xms)
{
	unsigned char i, j;
	while(xms)
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		xms--;	
	}
 
}
void main()
{
	unsigned char LEDNumber =0;
	P2=~(0x01);
	while(1)
	{
		if(P3_1==0)
	   {
			Delay1ms(20);
			while(P3_1==0);
			Delay1ms(20);
			if(LEDNumber==0)
			{
				LEDNumber=7;
			}
			else
			{
			  	LEDNumber--;
			}
			P2=~(0x01<<LEDNumber);
	   }
	   if(P3_0==0)
	   {
			Delay1ms(20);
			while(P3_0==0);
			Delay1ms(20);
			LEDNumber++;
			if(LEDNumber>=8)
			{
				LEDNumber=0;
			}
			P2=~(0x01<<LEDNumber);
	   }
	}
   
}

任务四到此结束!

今日所遇到的问题

1.在移位的时候我想的太单纯,直接使用了左移运算符和右移运算符,导致到后面多按几次按键后,发现灯全灭,无法达到循环移位的效果,这是因为在移位的过程中,低位或高位被0补齐,唯一的1可能被赋值为0,无法再变回1,取反后就无法点亮LED。

2.在写第一个任务的时候我大学用else无法达到预期效果,按键后松开,LED不灭,后来我改成了else if(P3_1!=0)就正常了,后面我再改回去else的时候又能够正常得到预期效果了,我想这可能是软件的问题吧。

总结

        今天的独立按键的学习是基于昨天的LED模块的知识之上,所以感觉还是比较简单的,等今天上了课之后,做点按键和LED的小联动,搞点有趣的东西。都看到这里来了,如果觉得我写的文章还不错,就请点个赞吧!

后续

        上完课回来之后,我总结运用了一下这两天学习的知识,将四个独立按键都与LED模块绑定了,K1负责流水灯的演示,K2负责两个灯泡点亮由中间向两边点亮,K3负责自动演示二进制进位,K4负责退出当前状态。由于学习的内容还是比较少,比较简单,所以实现的东西好像也不是很有趣哈哈哈哈。初始状态为D1灯常量,然后退出当前状态之后,我设置的所有灯泡长亮,更容易看出来退出是成功了的。但是也有不足就是感觉代码好冗杂,而且也没法从一个状态直接转向于另一个状态(本来想用goto语句但是太破坏代码完整性了),必须先退出当前状态再进入另一个状态(其实我觉得这样也挺安全的哈哈哈哈),代码的重复度蛮高的,也不知道该怎么去优化,先慢慢学吧。

代码如下:

#include <REGX52.H>
#include <intrins.h>

 void Delay1ms(unsigned int xms)
{
	unsigned char i, j;
	while(xms)
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
		xms--;	
	}
 
}

int fun_break()//用于判断是否按下K4
{
	if(P3_3==0)
	{
		Delay1ms(20);
		while(P3_3==0);
		Delay1ms(20);
		return 1;
	}
	else
	{
		return 0;
	}
}

void main()//第一个键实现流水灯设计//第二个键实现从中间到两边 第三个按键自动进行二进制加法;
{
	unsigned char LEDNumber=1;
	P2 = 0xFE;
	while (1)
	{
		if (P3_1 == 0)//流水灯
		{
			Delay1ms(20);
			while (P3_1 == 0);
			Delay1ms(20);
			while (1)
			{
				if (fun_break())
				{
					break;
				}
				P2 = 0xFE;//1111 1110
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xFD;//1111 1101
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xFB;//1111 1011
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xF7;//1111 0111
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xEF;//1110 1111
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xDF;//1101 1111
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0xBF;//1011 1111
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
				P2 = 0x7F;//0111 1111
				Delay1ms(100);
				if (fun_break())
				{
					break;
				}
			}
			P2 = 0x00;
			
		}
		if (P3_0 == 0)//中间到两边
		{
			Delay1ms(20);
			while (P3_0 == 0);
			Delay1ms(20);
			while (1)
			{
				if (fun_break())
				{
					break;
				}
				P2 = 0xE7;//1110 0111
				Delay1ms(200);
				if (fun_break())
				{
					break;
				}
				P2 = 0xDB;//1101 1011
				Delay1ms(200);
				if (fun_break())
				{
					break;
				}
				P2 = 0xBD;//1011 1101
				Delay1ms(200);
				if (fun_break())
				{
					break;
				}
				P2 = 0x7E;//0111 1110
				Delay1ms(200);
			}
			P2 = 0x00;
		}
		if(P3_2==0)//自动二进制加法
		{
			LEDNumber=0;
			Delay1ms(20);
			while (P3_2 == 0);
			Delay1ms(20);
			P2 = 0xFE;
			while(1)
			{
				LEDNumber++;
				P2=~(LEDNumber);
				Delay1ms(200);
				if (fun_break())
				{
					break;
				}	
			}
		   P2 = 0x00;
		}
	
	}
}

演示视频:

51单片机独立按键模块与LED模块结合练习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值