单片机控制LED灯实验:点亮、闪烁与流水灯效果
单片机控制LED灯实验:点亮、闪烁与流水灯效果
本文将介绍如何使用单片机控制LED灯的点亮、闪烁和流水灯效果。通过本教程,读者可以学习到单片机编程的基础知识,以及如何实现基本的LED控制功能。
原理图
本章所要实现的功能是:点亮D1 指示灯,即让P2.0 管脚输出一个低电平。完成后可再控制D1 指示灯闪烁,即间隔一段时间点亮和熄灭D1 指示灯。
仿真
点亮第一个LED
#include "reg52.h"
//sbit关键字用于定义特殊功能寄存器(SFR)中的位变量
sbit LED1 = P2 ^ 0;
void main(void) {
LED1 = 0;
}
仿真结果
实现LED闪烁
如果要实现LED 闪烁,只需循环让D1 指示灯先亮一会后熄灭。这里就有一个延时问题,如何来产生延时呢?我们知道单片机执行每条代码指令都是需要时间的,因此只需编写一个循环函数,让CPU 不干其它事,专门在那循环运行即可实现延时功能。依据人的肉眼余晖效应,延时时间不能太短,否则就无法观察到LED 闪烁。
#include "reg52.h"
#define uint unsigned int
sbit D1 = P2 ^ 0;
void delay_10us(uint ten_us);
void main() {
while (1) {
//点亮
D1 = 0;
delay_10us(50000);//如果需要精确延时,改用定时器
//熄灭
D1 = 1;
delay_10us(50000);
}
}
void delay_10us(uint ten_us) {
while (ten_us--);
}
LED闪烁
实现LED流水灯
如果要实现LED 流水灯,只需循环让D1-D8 指示灯逐个点亮。同样也需要延时。要实现循环点亮,可以使用最容易理解的方法:点亮D1 且把D2-D8 熄灭,延时一段时间后再点亮D2 且把D1、D3-D8 熄灭,延时一段时间后再点亮D3 且把D1-D2、D4-D8 熄灭,如此循环,这样就可以很简单的实现LED 流水灯实验,当然不推荐此种方法。
#include <reg51.h>
sfr x = 0xa0;//P2口在存储器中的地址是A0H, 通过sfr可定义8051内核单片机
//延时函数
void delay() {
unsigned char i, j;
for (i = 0; i < 250; i++)
for (j = 0; j < 250; j++)
;
}
void main() {
while (1) {
x = 0xfe;//1111 1110
delay();
x = 0xfd;//1111 1101
delay();
x = 0xfb;//1111 1011
delay();
x = 0xf7;//1111 0111
delay();
x = 0xef;//1110 1111
delay();
x = 0xdf;//1101 1111
delay();
x = 0xbf;//1011 1111
delay();
x = 0x7f;//0111 1111
delay();
}
}
LED流水1
C 语言相关的基础知识里面有移位以及循环语句操作,根据流水灯实现原理,即IO 口由低往高或者由高往低逐个输出低电平特点,那么我们可以将移位操作以及循环结合进来。
#include "reg52.h"
#define LED_PORT P2 //使用宏定义P2 端口
typedef unsigned char uchar;
typedef unsigned int uint;
void delay_10us(uint ten_us);
void main() {
uchar i = 0;
while (1) {
for (i = 0; i < 8; i++) {
LED_PORT = ~(0x01 << i); //将1 右移i 位,然后取反将结果赋值到LED_PORT
delay_10us(50000);
}
}
}
void delay_10us(uint ten_us){
while(ten_us--);
}
进入main 函数后首先定义一个变量i,然后进入while 循环,由于要实现8个LED 从D1->D8 循环点亮,因此可以使用for 循环语句循环8 次,每循环一次,点亮的小灯向右移动一个,而D1-D8 是连接到P2.0-P2.7 的,因此输出的低电平要左移一位,因此可以使用LED_PORT=~(0x01<<i);语句实现。0X01<<i 表示i增加1 次,0x01 中的1 就移动多少位,因为1(高电平)不会让LED 点亮,需要取反后变为低电平0 才能点亮,所以最后的结果需要取反后给LED_PORT 口,并且每次循环都要延时一段时间,这样才能分辨出来LED 在流水。
除了使用for 循环语句实现移位,KEIL C51 软件内还有对应的移位库函数,左移函数是_crol_(),右移函数是_cror_(),要使用这两个函数在我们的程序中必须包含intrins.h 头文件。这两个移位函数,其内部实现过程是看不到的,该移位函数实现的移位功能就相当于一个队列内循环移动,如果是左移,那么最高位就被移到最低位了,次高位变为最高位,依次类推。
#include "reg52.h"
#include "intrins.h"
#define LED_PORT P2
typedef unsigned char uchar;
typedef unsigned int uint;
void delay_10us(uint ten_us);
void main() {
uint i = 0;
LED_PORT = ~0x01;
delay_10us(50000);
while (1) {
//TODO
for (i = 0; i < 7; i++) {
//将LED左移一位
LED_PORT = _crol_(LED_PORT, 1);
delay_10us(50000);
}
for (i = 0; i < 7; i++) {
//将LED右移一位
LED_PORT = _cror_(LED_PORT, 1);
delay_10us(50000);
}
}
}
void delay_10us(uint ten_us) {
while (ten_us--);
}
流水灯2
进入main 函数后首先定义一个变量i,LED_PORT=~0x01,因为LED 是低电平点亮,所以0X01 取反后的结果是0XFE,对应二进制数为1111 1110,即最低位为0,因此最开始的D1 指示灯会点亮,然后进入while 循环,使用for 循环_crol_和_cror_移位函数实现LED 左右流水显示。
此处每个for 循环只有7 次,为什么不是8 次呢,这是因为在进入main 开始,就已经将LED_PORT 端口设置了一次状态,即让D1 点亮,并且我们是想让LED 从左至右依次点亮,然后继续又从右至左依次点亮,这样形成左右流水效果。