LED控制 | 我的日常分享

LED控制

51单片机-LED控制

一、点亮一个LED

实现原理:

image-20210320151527128

代码实现:

1
2
3
4
#include<reg52.h>
void main(){
P2 = 0xfe;//1111 1110 把P20置低电平
}

现象:

img

二、点亮多个LED

代码实现:

1
2
3
4
#include<reg52.h>
void main(){
P2 = 0xaa;//1010 1010
}

现象:

img

三、流水灯

3.1 案例1

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <reg52.h>

void main(){
while(1){
P2 = 0xfe;//1111 1110
P2 = 0xfd;//1111 1101
P2 = 0xfb;//1111 1011
P2 = 0xf7;//1111 0111
P2 = 0xef;//1110 1111
P2 = 0xdf;//1101 1111
P2 = 0xbf;//1011 1111
P2 = 0x7f;//0111 1111
}
}

现象:

img

分析:

为什么,所有灯都亮了,因为单片机的运行速度是非常快的,24MHz,每条语句没有进行延迟,也就是每个LED以24MHz的速度在闪烁,人眼分辨不出,但是每盏灯的亮度下降了。

为什么要加while循环,因为单片机在执行完main函数后,会再次从main函数开头执行,反反复复。

利用stc-isp生成延时函数:

image-20210320164933956

频率可以通过查看开发版上晶振上面的数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Delay500ms()		//@11.0592MHz
{
unsigned char i, j, k;

_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

为什么使用循环可以实现延时?在计算机组成原理中知道,cpu每执行一条语句是需要一定时间的。所以可以通过不停的执行空语句来实现延迟,但这种方法,降低了CPU的工作效率。

延时方法:软件延时和硬件延时。

  • 软件延时:空循环,通过for,while延时。
  • 硬件延时:通过定时器、nop();函数实现延时。

3.2 案例2

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <reg52.h>
void Delay500ms();

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();
}
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;

_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

现象:

5A21A654C27AB70A16D2C896A7BE9D51 00_00_00-00_00_30~1

注意:需要包含_nop_函数的头文件intrins.h,此函数作用为延迟一个指令周期。

四、独立按键控制LED的亮灭

4.1 独立按键

  • 轻触按键:相当于一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开

    image-20210320161025703

4.2 案例

image-20210320170051025

通过开发板原理图可以查看到,K1连接的是P31。

sfr与sbit的区别:在8位单片机C语言编程中,sfr用来定义特殊功能寄存器,一般占一个字节,8位;sbit用来定义特殊功能寄存器中可以位寻址的位,占1位。
在51单片机中,特殊功能寄存器只有16进制地址尾数为0或者8,其包含的各个位才可以位寻址。

代码:

1
2
3
4
5
6
7
8
9
10
#include <regx52.h>
void main(){
while(1){
if(P3_1 == 0){
P2_0 = 0;
}else{
P2_0 = 1;
}
}
}

现象

2D6A2772B38ABFB7F309BB7C496C2793 00_00_00-00_00_30

五、独立按键控制LED的状态

5.1 按键的抖动问题

对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动。虽然肉眼分辨不出,但是单片机可以识别到,从而对其造成影响。

image-20210320164218527

解决办法:

  • 硬件除抖:通过增加硬件实现
  • 软件除抖:通过代码实现,由上图知,抖动在5-10ms后会趋于稳定,我们可以延迟5-10ms再去检测按键的状态。

5.2 案例

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <regx52.h>
#include <intrins.h>
void Delay20ms();
void main(){
while(1){
if(P3_1 == 0){
Delay20ms();
while(P3_1 == 0){}
Delay20ms();
P2_0 = ~P2_0;
}
}
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;

i = 36;
j = 217;
do
{
while (--j);
} while (--i);
}

现象

6EFF41FD5983C35FE17A617E9B84A9C5 00_00_00-00_00_30

不加延迟有时候按下松开后,LED轻微的闪了几下后灭了。

六、独立按键控制LED显示二进制

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <regx52.h>
#include <intrins.h>
void Delay20ms();
void main(){
unsigned char LEDNum = 0;//0~255
while(1){
if(P3_1 == 0){
Delay20ms();
while(P3_1 == 0){}
Delay20ms();

LEDNum++;
P2 = ~LEDNum;//大于1111 1111(255)溢出变为0000 0000
}
}
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;

i = 36;
j = 217;
do
{
while (--j);
} while (--i);
}

现象:

7BC920E9A1A879A2FB68E05E7757400C 00_00_00-00_00_30

七、独立按键控制LED移位

1
2
3
4
5
6
7
8
9
10
/*
1111 1110 0000 0001
1111 1101 0000 0010
1111 1011 0000 0100
1111 0111 0000 1000
1110 1111 0001 0000
1101 1111 0010 0000
1011 1111 0100 0000
0111 1111 1000 0000
*/
  • 左移:低位补0
  • 右移:
    • 逻辑右移:高位补0
    • 算术右移:
      • 无符号数:高位补0
      • 有符号数:高位补符号位

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <regx52.h>
#include <intrins.h>
void Delay20ms();
void main(){
unsigned char LEDNum = 0;
unsigned char LEDNum1 = 7;
//定义LED初始状态
P2 = 0xfe;
while(1){
if(P3_1 == 0){
Delay20ms();
while(P3_1 == 0){}
Delay20ms();

LEDNum++;
P2 = ~(0x1<<LEDNum);
if(LEDNum >= 7){
LEDNum = -1;
}
}

if(P3_0 == 0){
Delay20ms();
while(P3_0 == 0){}
Delay20ms();

if(LEDNum!=0){
LEDNum--;
}else{
LEDNum = 8-1;
}
P2 = ~(0x1<<LEDNum);
if(LEDNum <= 0){
LEDNum = 8;
}
}
}
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;

i = 36;
j = 217;
do
{
while (--j);
} while (--i);
}

现象:

FF299E975D3D915111628BC24A69C205 00_00_00-00_00_30