本章将介绍LED的点亮操作,以及如何用按键控制LED。
由于是速通,并不是傻瓜式教学,故具体的文件操作与烧录过程就不一一展示了,注重具体的代码实现与原理,具体过程请看下面给出的视频链接,看过一次操作即可。
前置知识为:C语言基础(这个很重要),以及数电的进制转换基础,以及:自备51单片机(博主的单片机为共阳连接)以及对应的软件,详细请看B站视频: [1-2] 开发工具介绍及软件安装_哔哩哔哩_bilibili
下面简单介绍一下数电的进制转换基础(二进制与十六进制的相互转换)
前置知识(数电进制转换与共阳连接及共阴连接)
进制转换
由于在计算机中都是采用二进制,而在代码中我们需要写入十六进制,故我们只需要二进制与十六进制相互转换的关系即可,其中二进制的四位从左到右依次对应十六进制的8 4 2 1,例如1101就是8+4+1=13。

共阳连接
共阳连接即对应着:
0------灯亮
1------灯灭
共阴连接
共阴连接即对应着:
0------灯灭
1------灯亮
一、点亮第一个LED灯
在本章中使用的51单片机中共有8个灯,对应着两组二进制,而51单片机中的P2端口则对应着八个灯,通过两组二进制来控制,但是实际上是用两个十六进制的数,
如下:该情况就对应着LED灯间隔亮暗
cpp
#include <REGX52.H>
void main()
{
P2=0xAA;//1010 1010
}
二、令LED灯闪烁
只需要让一个灯在01之间来回循环即可,但是在语句之间执行速度很快,所以需要delay延迟,在stc-isp中会有延迟时间函数可以自动生成,这里直接就拿来用就好。
cpp
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay500ms();
P2=0xFF;//1111 1111
Delay500ms();
}
}
三、使LED灯流水线式闪烁
这个本质是和上面一样的,通过输入给P2不同的进制,加上循环,从而达到不同的灯流水线式的闪烁,可以看下面代码的注释,0代表亮,1代表灭
cpp
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay500ms();
P2=0xFD;//1111 1101
Delay500ms();
P2=0xFB;//1111 1011
Delay500ms();
P2=0xF7;//1111 0111
Delay500ms();
P2=0xEF;//1110 1111
Delay500ms();
P2=0xDF;//1101 1111
Delay500ms();
P2=0xBF;//1011 1111
Delay500ms();
P2=0x7F;//0111 1111
Delay500ms();
}
}
我们不能一直依靠软件生成的延迟函数来固定延迟
可以尝试生成1毫秒的延迟代码,通过构造形参的方式,传入我们需要循环的次数,例如x次,那么就会循环x*1毫秒
cpp
#include <REGX52.H>
#include <stdio.h>
void Delay1ms(unsigned int x) //@12.000MHz
{
unsigned char i, j;
while(x)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
x -= 1;
}
}
void main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay1ms(100);
P2=0xFD;//1111 1101
Delay1ms(100);
P2=0xFB;//1111 1011
Delay1ms(100);
P2=0xF7;//1111 0111
Delay1ms(100);
P2=0xEF;//1110 1111
Delay1ms(100);
P2=0xDF;//1101 1111
Delay1ms(100);
P2=0xBF;//1011 1111
Delay1ms(100);
P2=0x7F;//0111 1111
Delay1ms(100);
}
}
四、使用独立按键控制LED灯
P3_1为第一个独立按键的按钮,按下则代表为0,松开则代表为1,此时我们只需要判断好按钮的状态,从而进入条件使灯亮暗即可。
控制LED灯亮灭
cpp
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1 == 0)//按下按键
{
P2_0 = 0;//亮
}
else
{
P2_0 = 1;//否则为暗
}
}
}
控制LED灯状态
按下按钮之后,让灯亮或者灯灭,我们需要利用按位取反的性质,单独对某个灯的状态按位取反,就能实现对某个灯的亮暗操作了,我们知道P2对应着八个灯,那么P2_0则对应着其中一个灯,我们就单独控制这个就好。
在物理世界中,按键按下时由于会有微小弹性,所以按下之后的短暂时间内会有回弹,此时如果不控制这段时间的话就会出现按下之后会有多次瞬间闪烁,那么我们就需要在按下之后消除掉这短暂的时间,也就是delay一下,再执行接下来的语句。当然,在松开之后同样需要消除一下短暂的时间
cpp
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
while(1)
{
if(P3_1 == 0)//当按下按钮
{
Delay(20);//消除短暂时间
while(P3_1 == 0);//如果一直按着还没松开则一直循环不动
Delay(20);//松开后,消除短暂时间
//此时完成一次按下松开的操作
P2_0 =~ P2_0;//灯亮或者灯灭
}
}
}
控制LED灯显示二进制
首先要知道,我们让P2每加一,那么就会从0000000->00000001,此时自身取反就成了11111110,那么就是第一颗灯亮了,我们就按照这个就能控制LED灯显示二进制即可,那么步骤就是检测到按下抬起按键一次。为了方便起见,我们就不直接控制P2,我们另设一个char变量来传给P2。
cpp
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
unsigned char LEDNum = 0;//传给P2的参数
while(1)
{
if(P3_1 == 0)
{
Delay(20);
while(P3_1 == 0);
Delay(20);
LEDNum++;
P2 =~ LEDNum;
}
}
}
控制LED灯移位
利用LEDNum的计数来操控变量00000001**(0x01)**左移或者右移的位数
左移:令LEDNum++,一旦≥8,则复位0,然后进行左移LEDNum位。
右移:令LEDNum--,一旦≤0,则复位7,然后进行右移LEDNum位。
当移动完成后,再按位取反赋值给P2即可完成操作。
由于char变量是无符号,所以在判断右移的情况有稍微不同,具体如下代码所示
cpp
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
unsigned char LEDNum;
void main()
{
P2 =~ 0x01;
while(1)
{
if(P3_1 == 0)
{
Delay(20);
while(P3_1 == 0);
Delay(20);
LEDNum++;
if(LEDNum >= 8)
{
LEDNum = 0;
}
P2 =~ (0x01<<LEDNum);
}
if(P3_0 == 0)
{
Delay(20);
while(P3_0 == 0);
Delay(20);
/*LEDNum--;
if(LEDNum < 0)
{
LEDNum = 7;
}*/
if(LEDNum <= 0)
{
LEDNum = 7;
}
else
{
LEDNum--;
}
P2 =~ (0x01 << LEDNum);
}
}
}