51单片机STC89C52RC——2.4 三个独立按键模拟控制LED流水灯方向Plus

目的

按下K1键LED流水向左移动

按下K2键LED流水向右移动

按下K3键LED流水停止(原位闪烁)

一,STC单片机模块

二,独立按键 

2.1 独立按键位置

2.2 独立按键电路图

 

这里要注意一个设计的bug

P3_1 引脚对应是K1

P3_0 引脚对应是K2

 要实现按一下点亮、再按一下熄灭,我们就需要分析按键上的电压变化。 

对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会立即断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动 。如上图。

具体在程序上我们就需要按照这个图做相应的处理。

		if(P3_1==0)			//如果K1按键按下
		{
			Delay(15);		//延时消抖
			while(P3_1==0);	//松手检测
			Delay(15);		//延时消抖			
			P2_0=~P2_0;		//LED1取反
		}

要实现左右移动分别控制, 我们定义变量左移就自减1右移就自加1.

        if(P3_1==0)				//如果K1按键按下
		{
			Delay_ms(15);		//延时消抖
			while(P3_1==0);		//松手检测 一直按着没松手
			Delay_ms(15);		//延时消抖				
			LED_Num--;			//变量减1
			if(LED_Num<0)		
			{
				LED_Num=7;		//当最左边一个灯亮后,下一个是最右边一个灯亮
			}
		}
		if(P3_0==0)				//如果K2按键按下
		{
			Delay_ms(15);		//延时消抖
			while(P3_0==0);		//松手检测 一直按着没松手
			Delay_ms(15);		//延时消抖		
			LED_Num++;			//变量加1
			if(LED_Num==8)
			{
				LED_Num=0;		//当最右边一个灯亮后,下一个是最左边一个灯亮
			}
		}

当在两头时我们要分别判定下,并重新从头开始。 

我们这里要记录方向的三种模式,向左、向右、暂停。以及暂停时LED所处的位置。

	unsigned int Dire=1;		//流水灯方向2-向左(K1), 1-向右(K2),0-暂停(K3),默认向右
	unsigned int PaseLED=0xff;	//按下暂停键保存当前P2的值

方向判定

        //方向判定
		if(Dire==0)				//暂停
		{
			if(P2==0xff){	
				P2=PaseLED;
			}
			else {
				P2=0xff;
			}
		}
		if(Dire==1)				//向右
		{
			if(P2==0xff){
				P2=PaseLED;
			} 
			P2=_crol_(P2,1);	//灯右移 
			PaseLED=P2;
		}
		if(Dire==2)				//向右
		{
			if(P2==0xff){
				P2=PaseLED;
			}
			P2=_cror_(P2,1);	//灯左移  
			PaseLED=P2;
		}

 我这里用到了 _cror_ 和 _crol_   移位运算的函数,所以需要引入 NTRINS.h

#include <INTRINS.h>

三,创建Keil项目

详细参考:51单片机STC89C52RC——创建Keil项目-CSDN博客

四,代码 

#include <REGX52.H>
#include <INTRINS.h>
/**
 * 函    数:延时函数 毫秒
 * 参    数:ms 延时多少毫秒
 * 返 回 值:无
 */
void Delay_ms(int ms)	//@12.000MHz
{
	unsigned char data i, j;
	while(ms--)
	{ 
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}
/**
 * 函    数:主函数
 * 参    数:无
 * 返 回 值:无
 */
void main()
{ 
	unsigned int Dire=1;		//流水灯方向2-向左(K1), 1-向右(K2),0-暂停(K3),默认向右
	unsigned int PaseLED=0xff;	//按下暂停键保存当前P2的值
	
	P2=0xFE;					//上电默认D1 亮
	while(1)
	{		
		Delay_ms(500);			//延时500毫秒		
		if(P3_1==0)				//K1被按下
		{
			Delay_ms(15);		//延时消抖
			while(P3_1==0);		//松手检测 一直按着没松手
			Delay_ms(15);		//延时消抖	
			Dire=2;				//0-向左
		}
		if(P3_0==0)				//K2被按下
		{
			Delay_ms(15);		//延时消抖
			while(P3_0==0);		//松手检测 一直按着没松手
			Delay_ms(15);		//延时消抖	
			Dire=1;				//1-向右
		}
		if(P3_2==0)				//K2被按下
		{
			Delay_ms(15);		//延时消抖
			while(P3_2==0);		//松手检测 一直按着没松手
			Delay_ms(15);		//延时消抖	
			Dire=0;				//暂停
		}
		
		//方向判定
		if(Dire==0)				//暂停
		{
			if(P2==0xff){	
				P2=PaseLED;
			}
			else {
				P2=0xff;
			}
		}
		if(Dire==1)				//向右
		{
			if(P2==0xff){
				P2=PaseLED;
			} 
			P2=_crol_(P2,1);	//灯右移 
			PaseLED=P2;
		}
		if(Dire==2)				//向右
		{
			if(P2==0xff){
				P2=PaseLED;
			}
			P2=_cror_(P2,1);	//灯左移  
			PaseLED=P2;
		}		 
	}
}

五,代码编译、下载到51单片机

代码编译请参考

51单片机STC89C52RC——代码编译-CSDN博客

代码下载请参考

《51单片机STC89C52RC——STCAI-ISP代码下载-CSDN博客

六,效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值