51单片机开发板实验:流水灯
- 物联网-嵌入式工程师
- 2天前
- 52热度
- 0评论

一、实验目标
设计并实现一个循环逻辑,使LED灯按照一定的顺序(如从左到右或从右到左)依次点亮。可以通过调整延时函数来改变流水灯的速度。
在程序中实现延时功能,控制LED灯点亮的持续时间以及相邻LED灯之间的切换时间。

二、LED电路
在单片机开发板上有 8 个 LED 连接单片机 P2 IO 口上,具体电路如下图所示:

从电路图可以看出,LED 控制管脚直接连接到 51 单片机的IO 上。LED 采用共阳接法,即所有 LED 阳极管脚接电源 VCC,阴极管脚通过一个470 欧的限流电阻接到 P2 口上。
三、软件设计
要实现LED流水灯效果,只需循环控制D1至D8指示灯逐个点亮即可。同样地,本实验也需要延时来实现循环点亮。
一种简单但效率较低的方法是:首先点亮D1并熄灭D2至D8,延时后点亮D2并熄灭D1、D3至D8,接着再延时后点亮D3并熄灭D1至D2和D4至D8,如此循环。不过,这种方法并不推荐。
鉴于我们之前已学习C语言的基础知识,包括移位和循环语句操作,我们可以根据LED流水灯的实现原理——即IO口由低至高或由高至低逐个输出低电平——来优化实现方法。结合移位操作和循环,可以更有效地实现LED流水灯效果。
四、编写程序
启动Keil软件后,创建一个新项目,选择单片机型号STC89C52RC。在项目中添加C语言源文件main.c。
在main.c文件内输入下面的源代码:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define led P2
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
void main()
{
u8 i;
led=~0x01;
delay(50000); //大约延时450ms
while(1)
{
for(i=0;i<8;i++)
{
P2=~(0x01<<i); //将1右移i位,然后将结果赋值到P2口
delay(50000); //大约延时450ms
}
}
}
代码解读
reg52.h是一个头文件,它定义了8051(或类似型号如AT89C52)的所有寄存器名称和数据类型。
u16和u8,分别表示无符号的16位整数和8位整数(即通常所说的uint16_t和uint8_t,但使用了更简洁的别名)。
宏定义led表示8051微控制器的P2端口。通过这个宏,可以更方便地引用P2端口,而不需要每次都写P2。但在此代码中,直接使用P2可能会更清晰一些。
delay()是一个简单的延时函数,它通过循环递减一个16位整数来实现延时。但请注意,这种延时方法非常不准确,因为它依赖于微控制器的时钟频率和编译器优化。这里delay(50000)大约延时了450ms,但这只是一个粗略的估计。
在main()函数内。led=~0x01; 这行代码将P2端口的第0位(P2.0)设置为高电平,其他位设置为低电平。但由于前面定义了led为P2,所以这里直接写P2=~0x01;可能更清晰。
然后,有一个短暂的延时(大约450ms)。
在while(1)无限循环中,程序遍历P2端口的8个引脚,每次将一个引脚设置为高电平,其他为低电平,并延时约450ms。这样,你会看到LED从P2.0到P2.7依次亮起,形成一个流水灯效果。
五、实验现象
使用 USB 线将开发板和电脑连接成功后(电脑能识别开发板上 CH340 驱动串
口),把编写好的程序编译后将编译产生的.hex 文件烧入到芯片内,可以看到开发板上 LED 模块的 D1~D8指示灯依次亮起。
六、知识小结
在8051微控制器的编程中,P2 通常是一个代表端口2的寄存器。这个寄存器有8位,每一位都对应一个物理引脚,可以用来控制连接到这些引脚的外部设备(比如LED灯)。
~ 是一个按位取反操作符,在C语言中用于对一个整数的每一位进行取反操作。具体来说,如果某个位是1,则取反后变为0;如果某个位是0,则取反后变为1。
0x01 是一个十六进制数,其二进制表示为 0000 0001。当我们将这个数与 P2 寄存器中的值进行按位取反操作时,实际上是在说:“我想保持 P2 寄存器中除了最低位(即P2.0)以外的所有位不变,仅取反P2.0的值”。
P2=~(0x01<<i); 该语句设置8051微控制器P2端口上特定LED(由i的值决定)为低电平,而其他LED为高电平的语句。
具体到 P2=~(0x01<<i); 这行代码:
当i为0时,0x01 << 0 保持不变,即 0000 0001。取反后得到 1111 1110,这意味着P2.0被设置为低电平(因为对应的位是0),而其他位(P2.1到P2.7)被设置为高电平(因为对应的位是1)。
当i为1时,0x01 << 1 变为 0000 0010。取反后得到 1111 1101,P2.1被设置为低电平,其他位为高电平。
以此类推,直到i为7时,0x01 << 7 变为 1000 0000。取反后得到 0111 1111,P2.7被设置为低电平,其他位为高电平。
通过这种方式,你可以通过改变i的值来依次点亮P2端口上的每一个LED。在代码中,这通常用于实现LED流水效果。