温馨提示: 为了获得更好的阅读效果,建议移步到微信PC客户端阅读。
通过前面的两课,相信大家已经掌握如何用单片机点亮一盏LED。 本节一灯大师要和大家探讨流水灯的实现,一起玩转流水灯。
设单片机的P0.3~P0.0外接了4只发光二极管(LED),如图1所示。二极管的负极连接到单片机,正极通过一个限流电阻连接到VCC。
当单片机输出低电平,发光二极管正向导通,LED点亮;当单片机输出高电平,LED熄灭。
图1 流水灯电路(以4只LED为例)
下面以图1为例,实现4只流水灯效果。我们将使用2种不同的方法。至于哪种方法更好,希望大家能有自己的判断。
让我们先按照流水灯状态,写出P0.3~P0.0的输出值,注意高位写在左边,低位写在右边。
表1 流水灯状态与单片机控制I/O的关系
由表1可知,P0口低4位顺序输出1110、1100、1000和0000就可以实现流水灯,此为方法1。
图1只使用了P0的低4位,编程时一般以P0为整体操作,要避免对单个I/O操作,指令越少越好,一是代码好维护,二是代码阅读性好。
高四位输出全1(即F),而不是0,这是为什么呢? 请大家先思考。
方法1源码:
#include
//函数声明
void delayMS(unsigned int x); //ms延时函数声明
void main()
{
while(1)
{
P0 = 0xFF; delayMS(1000); //初始化所有灯全熄灭
P0 = 0xFE; delayMS(1000); //D1亮
P0 = 0xFC; delayMS(1000); //D1、D2亮
P0 = 0xF8; delayMS(1000); //D1、D2、D3亮
P0 = 0xF0; delayMS(1000); //D1、D2、D3、D4亮
}
}
/****************************
函数:delayMS@12MHz
功能:ms级延时函数
参数: x:unsigned int, 延时时间,单位:ms
返回值:无
****************************/
void delayMS(unsigned int x) //delayMS函数实现
{
unsigned int i,j;
for(i=0;i
for(j=0;j
}
//高四位输出全1(即F),而不是0,这是因为单片机默认输出高电平,此处输出高电平,一般不会影响外部电路(假设此引脚外接了其它电路)。
编译下载验证,方法1代码可以实现由左向右的流水灯效果。
假设,要求流水灯由右向左,速度为500ms,如何修改源代码?由于代码较少,修改还算比较顺利,对吧,但是稍不注意,可能会改错。
当流水的灯有16只、32只或更多,方法1的局限性暴露无遗.......费人力,费时间,费工夫。
怎么应对多变的流水需求(速度,方向,花样等)?稍安勿躁。 让我们回看表1,标出各个流水状态下单片机输出低电平的情况(点亮LED)。
我的天呢(借用小岳岳的台词),下一个状态刚好是上一个状态左移一位。我们发现了规律,达到了科学的目的之一(科学的目的:发现并掌握规律)。于是乎,一个主意顺势而生,
使用移位操作实现流水灯——此为方法二。
为了便于调用和代码维护,我们将流水灯操作用一个函数封装起来,void ledFlow(unsigned int speed), 支持流水速度可编程。
//方法2源码
#include
//函数声明
void delayMS(unsigned int x); //ms延时函数声明
void ledFlow(unsigned int speed); //流水灯函数定义
void main()
{
while(1)
{
ledFlow(1000);
ledFlow(500);
}
}
/****************************
函数:delayMS@12MHz
功能:ms级延时函数
参数: x:unsigned int, 延时时间,单位:ms
返回值:无
****************************/
void delayMS(unsigned int x) //delayMS函数实现
{
unsigned int i,j;
for(i=0;i
for(j=0;j
}
/****************************
函数:ledFlow
功能:流水灯函数,LED数量4
参数: speed:unsigned char, 流水灯速度,单位:ms
返回值:无
****************************/
void ledFlow(unsigned int speed)
{
unsigned char i;
P0 = 0xFF; //初始化全灭
delayMS(speed);
for(i=0;i
{
P0 = P0
delayMS(speed);
}
}
方法2验证:
其实,流水可以玩很多花样,如参数化设置流水方向,设置流水运行次数,例如:
void ledFlow(unsigned int speed, bit dir, unsigned char times);
实现起来比简单。方向由移位方向决定,流水运行次数用循环实现即可。代码略。
写到此,一灯大师要退场了。走之前,一灯跟大家分享一个单片机初学者编写的心形流水灯文章,链接见http://forum.eepw.com.cn/thread/251409/1/#6
过程全有,独无代码,总觉得缺了点什么。于是有了下面的内容,纯属自娱。
为什么登山,因为山在那里——新西兰登山运动家埃德蒙德·希拉里。
为什么玩单片机,因为单片机在那里。
图2 心形流水灯电路图(32只LED,分别接P0~P3)
表2接口对应表
源代码:
#include
//函数声明
void delayMS(unsigned int x); //ms延时函数声明
void heartBeat(unsigned int speed,unsigned char n); //心闪烁函数声明
void heartSpark(unsigned int speed,unsigned char n); //心形流水灯函数声明
//主程序
void main()
{
while(1)
{
heartBeat(750,18); //心闪烁18次,频率:1分钟80次左右
heartSpark(500,3); //心形流水灯18次
heartBeat(600,100);//心闪烁100次,频率:1分钟100次左右
}
}
/****************************
函数:delayMS@12MHz
功能:ms级延时函数
参数: x:unsigned int, 延时时间,单位:ms
返回值:无
****************************/
void delayMS(unsigned int x) //delayMS函数实现
{
unsigned int i,j;
for(i=0;i
for(j=0;j
}
/****************************
/****************************
函数:heartBeat
功能:心闪烁函数,闪烁速度可设置
参数: speed:unsigned char, 闪烁速度,越小闪烁越快,单位:ms;n:执行次数,不做检查
返回值:无
****************************/
void heartBeat(unsigned int speed,unsigned char n)
{
while(n--) //先判断再执行--
{
//取反,灯状态翻转
P0=~P0;
P1=~P1;
P2=~P2;
P3=~P3;
delayMS(speed); //延时越短,闪烁越快
}
}
/****************************
函数:heartSpark
功能:心形流水灯函数,有底部分左右同时向上流水,流水速度可设置
参数: speed:unsigned char, 流水灯速度,越小速度越快,单位:ms;n:执行次数,不做检查
返回值:无
****************************/
void heartSpark(unsigned int speed,unsigned char n)
{
unsigned char nCount = 16; //16次,完成一次流水灯动作
unsigned char i;
unsigned int leftHeart; //P0-P1作为一组,由2字节的无符号整型变量移位实现流水灯,P0为低字节,P1为高字节
unsigned int rightHeart; //P2-P3作为一组,由2字节的无符号整型变量移位实现流水灯,P2为低字节,P2为高字节
while(n--)
{
leftHeart=0xFFFF; //心灯熄灭
rightHeart=0xFFFF; //心灯熄灭
delayMS(speed); //延时1s
for(i=0;i
{
leftHeart = leftHeart
rightHeart = rightHeart>>1;
P0 = leftHeart&0x00FF; //取leftHeart低八位,控制P0口外接的led7-led0
P1 = (leftHeart&0xFF00)>>8; //取leftHeart高八位,控制P1口外接的led15-led8
P2 = rightHeart&0x00FF; //取rightHeart低八位,控制P2口外接的led23-led16
P3 = (rightHeart&0xFF00)>>8; //取rightHeart高八位,控制P0口外接的led31-led24
delayMS(speed);
}
}
}
仿真结果:
文末附上一段视频,“战胜自己,克服自己”。
领取专属 10元无门槛券
私享最新 技术干货