51单片机实现流水灯的三种方法
51单片机实现流水灯的三种方法
流水灯是单片机入门的经典实验之一,通过控制LED灯的亮灭顺序,可以实现各种有趣的灯光效果。本文将详细介绍如何使用51单片机实现流水灯的三种方法:库函数法、数组法和位运算符法。
原理
如果需要让LED灯点亮,那么就得给他一端高电平,一端低电平,而52单片机是弱上拉,强下拉,所以让单片机P2口负责低电平,另外给LED电源以防LED电压不足。
仿真图
在运行Proteus进行仿真时,需要注意将电阻阻值进行设置,建议为220,否则LED灯可能不会亮
实现方法
实现流水灯效果一共有三种方式:
- 库函数法
利用已经封装的库函数#include <intrins.h>
里面的左移函数_crol_
或者是右移函数_cror_
来实现流水灯效果
#include <reg52.h>
#include <intrins.h>//位移函数_crol_和_cror_的头文件
#define uint unsigned int //用该方法给unsigned int型数据类型取别名为uint
#define uchar unsigned char
/*
位移函数说明:
#include <intrins.h>为头文件,必须加上,否则报错
左移:
_crol_(x,y)为其中一个函数,x可以为变量,值应该为一个十六进制数,y为左移的位数
右移:
_cror_(x,y)为其中一个函数,x可以为变量,值应该为一个十六进制数,y为右移的位数
*/
//延时函数,参数z单位为毫秒,1000ms=1s
//该延时函数利用到了C语言的嵌套循环,空语句
void delay(uint z)
{
uint x,y;
for(x = z;x > 0;x--)
for(y = 114;y > 0;y--);
}
void main()
{
P2 = 0xfe; //P2为单片机控制LED的IO口
delay(1000);
while(1)
{
P2 = _crol_(P2, 1);//循环往左移一位,地位的补去高位
//_cror_ 循环往右移一位,高位的补去低位
delay(1000); //延时1s
}
}
效果如下图:
- 数组法
利用数组法把八位二进制数转换成两位十六进制数存放在一个数组里,利用循环来改变LED灯的状态,达到流水灯的效果
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code LED[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //字符型数组,存放十六进制数
// 延时函数:毫秒延时
void delay(uint z)
{
uint x,y;
for(x = 0; x < z; x++)
for(y = 0; y < 113; y++);
}
void main()
{
uchar i;
while(1)
{
for(i=0;i<8;i++)//将for循环与数组结合,不断改变LED灯状态达到流水灯效果
{
P2 = LED[i];
delay(1000);//延时1s
}
}
}
效果如下图:
- 位运算符法
位运算符法又分为暗灯流水和亮灯流水两种效果
暗灯流水
利用C语言里面的位运算符:按位左移符:<<
或者是按位右移符:>>
来实现
#include"reg52.h"
#define uint unsigned int
#define uchar unsigned char
//延时函数
void delay(uint t)
{
uint x,y;
for(x=t;x>0;x--)
{
for(y=110;y>0;y--);
}
}
void main()
{
uchar i;
while(1)
{
P2=0x01;
//给P2口赋初值必须放在死循环里,否则程序执行完for循环后会因为P2口
//未复位而而导致LED全部常量
delay(1000);
for(i=0;i<8;i++)
{
P2=P2<<1;
delay(1000);
}
}
}
效果如下图:
亮灯流水
这里以用到了C语言位运算符(<<)的一些特性:
假如设:unsigned char num=0xfe;
即: num(1111 1110)
当num左移一位:num<<1;
num(1111 1100)
num再次左移一位:num<<1;
num(1111 1000)
由于位移运算符只会补充低位的特性,所以我们可以结合取反(~)来进行操作,如下:
假如设:unsigned char num=0x01;
unsigned char k;
即: num(0000 0001)
取反为: num(1111 1110)
当k=1,num左移一位:num<<k;
num(0000 0010)
取反为: num(1111 1101)
当k=2,num再次左移两位:num<<k;
num(0000 1000)
取反为: num(1111 0111)
此时就可以实现流水灯的亮灯流水效果
#include <REGX52.H>
#define uint unsigned int
#define uchar unsigned char
//延时函数,参数为毫秒,1000ms=1s
void delay(uint x)
{
uint i,j;
for(i=0;i<x;i++)
for(j=110;j>0;j--);
}
void main()
{
while(1)
{
uint y; //循环变量y
for(y=0;y<8;y++)
{
P2=~(0x01<<y); //利用<<只会补充低位的特性,左移取反,实现亮灯流水
delay(200);
}
}
}
效果如下: