一.独立按键基本知识

在单片机上,独立按键是这个:
在这里插入图片描述
电路原理图是:
在这里插入图片描述
注意:K1接P3_1口,K2接P3_0口,顺序上是反过来的,不要搞错了。

由原理图不难得知,由于独立按键右端接地,所以

当连接独立按键的P3对应端口为低电平时,表示导通了。

比如,判断独立按键K1是否导通的代码就是P3_1==0。

由此,我们也可以理解“独立按键”的含义了:

所谓独立,即这个电键并不是直接与电路相连而去控制电路的,而是通过我们对这个独立电键的操作所返回的信息来达成一定的判断条件,在判断条件之下控制电路的。比如我们按下K1,原电路并不会有什么改变,我们所做的只是将K1导通了而已。但是K1导通所带来的信息就是P3_1==0,在这条信息之下,我们就可以让程序去执行相应的操作了。


二.通过独立按键实现一些操作(控制LED亮灭、移位,显示二进制)

其中,需要用到C语言二进制中的“位”运算操作,这我将在后面的模块三种讲述。

(1)首先,我们先来看一下独立按键控制LED亮灭的程序:

#include<regx52.h>      

void main(void)
{
		while(1)
		{
				if (P3_1==0)
				{
					  P2_0=0;    //press the key and turn on the LED
				}
				else
				{
					  P2_0=1;
				}
		}
}

只要明白独立按键的原理,这个程序就很好理解了。

(2)消除按键抖动:
在这里插入图片描述
所以,要精确地控制按键,我要我们用Delay去延迟几毫秒(不然按一下可能会动两下)。
经过我的测试,使用下面这个函数Delay(10000)可以粗略地消除这个问题。

void Delay(int x)
{
		while(x!=0)
		{
				x--;
		}
}

当然,有非常精确的延时函数:
在这里插入图片描述

(3)独立按键控制LED移位:

#include<regx52.h>

void Delay(int x)
{
		while(x!=0)
		{
				x--;
		}
}

void main()
{
		char LEDnum=0;    //initialize at 0000 0000 
	
	    P2=~0x01;  //initial condiction:0000 0001 ->actually:1000 0000
		while(1)
		{
				
				if(P3_0==0)   //move right
				{
						Delay(10000);
					    while(P3_0==0);
						Delay(10000);
						
						LEDnum++;
						if(LEDnum>=8)
						{
								LEDnum=0;
						}
						P2=~(0x01<<LEDnum);   //0000 0001 -> 0000 0010 -> actually:0100 0000
				}
				
				if(P3_1==0)   //move left
				{
						Delay(10000);
					    while(P3_1==0);
						Delay(10000);
						
						LEDnum--;    
						if(LEDnum<0)
						{
								LEDnum=7;
						}
						P2=~(0x01<<LEDnum);   
				}
		}
}

这个程序拆解开来讲解:
①按下电键,松手后才执行操作:
if(P3_0 == 0) 是判断是否按下,while(P3_0 ==0); 是维持按下状态,松手后跳出循环,执行后续操作。前后两个Delay(10000)是分别消除“按下”和“松开”时的按键抖动。

if(P3_0==0)   
		{
			Delay(10000);
			while(P3_0==0);
			Delay(10000);
			/*………………………………*/
		}

②LEDnum参数记录现在需要亮的LED位置。

③位操作控制LED亮灭:先移位,再取反。(从只有一个LED灭,取反成只有一个LED亮)

P2=~(0x01<<LEDnum);   //0000 0001 -> 0000 0010 -> 1111 1101 ->actually:1011 1111 (last:0111 1111)

可能有些疑惑,为什么向左移位LEDnum是- -,向右移位LEDnum是++呢?因为我手上的这个单片机,每个灯对应接口正好是与二进制从左向右读是反过来的。初始赋予的状态是0000 0001,是最左边的LED处于点亮状态。LEDnum++带来的结果是二进制中的0(即点亮位置)向左移动一格,现实中则为向右。
在这里插入图片描述

④边界考虑:左移到小于0,跳转到7。右移到大于7,跳转到0。

(4)独立按键控制LED实现二进制进位模拟:

#include<regx52.h>

void Delay(int x)
{
		while(x!=0)
		{
				x--;
		}
}

void main()
{		
		char temp=0;
		while(1)
		{
				if(P3_1==0)
				{
						Delay(1000);
						while(P3_1==0);
						Delay(1000);
					
						temp++;
						P2=~temp;
				}
		}
}

核心在于temp++表示二进制的加法,刚好可以通过LED亮灭模拟。
(初状态0000 0000->0000 0001->0000 0010->0000 0011->…………)


三.知识储备:C语言二进制位运算

在这里插入图片描述
(1)<<按位左移:
所有位向左移动x个位置。最高位移除,最低位补0
比如0011 1110<<2 得到1111 1000;1111 0000<<1 得到1111 0000。
(2)>>按位右移:
所有位向右移动x个位置。最低位移除,最高位补0
比如0011 1110>>2 得到0000 1111;1111 0000>>1 得到0111 1000。
(3)&按位与:
对两个二进制数每一位进行“与”的逻辑判断,如果“与”成立则为1,“与”失败则为0。通俗的将,把0当成非,1当成是,进行每一位的逻辑判断,对应生成新的二进制数。0 & 0 -> 0 、1 & 1 ->1 、1 & 0 -> 0
比如0001 1000 & 0010 1010 得到 0000 1000。
(4)|按位或:
基本同“按位与”,就是讲每一次的与判断换成或判断。0 | 0 -> 0 、1 | 1 -> 1、1 | 0 -> 1。
比如0001 1000 | 0010 1010 得到 0011 1010。
(5)^按位亦或:
数字一样则为0,不一样则为1。0 ^ 0 -> 0、1 ^ 1 ->0、1 ^ 0 -> 1。
比如0001 1000 ^ 0010 1010得到 0011 0010。
(6)~按位取反:
每一位上的0变1,变0。 ~0 -> 1、 ~1 -> 0。
比如~0001 1000 得到 1110 0111。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐