我在学习单片机时,刚入门编写程序的课程就是控制流水灯,流水灯之所以被我们广泛的学习是因为流水灯的实例在我们日常生活中随处可见,便于引起我们学习者的兴趣。比如流水彩灯、彩色灯条、圣诞树彩灯、渐亮渐灭呼吸灯、水滴流水灯等等。毫不夸张的说如果我们初学单片机编程的小伙伴,能够熟练的控制这些流水灯的发光样式,那么你的单片机技术就已经入门了,也就是说你已经学会了80%的单片机技术。为了帮助刚学单片机的小伙伴们进一步掌握流水灯的控制方法,下面给出三个实例供大家参考。
实例一:左右循环移动流水灯
#include
#define uchar unsigned char
#define uint unsigned int
#define LED P2 //8个LED接口
uchar code led_mod_1[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //LED从左到右点亮
uchar code led_mod_2[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //LED从右到左点亮
void delay_ms(uint n) //延时函数,单位时间为1ms左右
{
uint i;
uchar j;
for(i=0;i
for(j=0;j<110;j++);
}
void led_display(uchar *led_mod) //向LED接口输出8种状态
{
uchar i;
for(i=0;i<8;i++)
{
LED = *(led_mod+i); //指针指向地址
delay_ms(700);
}
}
void main( )//主函数
{
while(1)
{
led_display(led_mod_1); //将led_mod_1数组的每个数据输到LED接口上
led_display(led_mod_2); //将led_mod_2数组的每个数据输到LED接口上
}
}
实例二:多花样流水灯程序的编写
#include
#define uchar unsigned char
#define uint unsigned int
#define LED P2 //8个LED接口
#define KEY P1 //按键接口
sbit INDICATOR = P3^3; //指示灯接口
uchar code led_mod_1[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //LED从左到右点亮
uchar code led_mod_2[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //LED从右到左点亮
uchar code led_mod_3[8] = {0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00}; //从左到右依次点亮
uchar code led_mod_4[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; //从右到左依次点亮
uchar code led_mod_5[4] = {0xe7,0xc3,0x81,0x00}; //中间两个向傍边点亮
bit led_mod_select; //LED流水灯模式切换标志,0:手动切换:1:自动切换
uchar time = 50; //计时时间,计时time*10ms
uchar mod_count = 0; //模式计数
uchar output_count = 0; //状态输到LED接口计数
void delay_ms(uint n) //延时函数,单位时间为1ms左右
{
uint i;
uchar j;
for(i=0;i
for(j=0;j<110;j++);
}
void led_output(uchar *led_out,uchar num,uchar *num_count,uchar *led_mod) //向LED接口输出8种状态
{
LED = *(led_out+*num_count);
(*num_count)++;
if(*num_count>=num)
{
*num_count = 0;
if(led_mod_select) //自动切换模式
{
(*led_mod)++; //切换到下一个模式
}
}
}
uchar key_scan() //按键扫描
{
uchar key_val;
KEY = 0xff;
if((KEY&0x07)!=0x07)
{
KEY = 0xff;
delay_ms(10); //按键消抖
if((KEY&0x07)!=0x07)
{
key_val = KEY;
key_val = key_val&0x07; //按键只接低3位I/O口,需要屏蔽高5位I/O口
while((KEY&0x07)!=0x07) //按键是否释放
KEY = 0xff;
return key_val;
//返回按键值
}
}
return 0; //无按键按下
}
void key_function() //按键功能(三个按键功能)
{
uchar val;
val = key_scan();
switch(val)
{
case 0x06:
if(led_mod_select==0)
{
mod_count --;
output_count = 0;
}
break;
case 0x05:
if(led_mod_select==0)
{
mod_count ++;
output_count = 0;
}
break;
case 0x03:
led_mod_select = ~led_mod_select; //选择手动/自动模式
INDICATOR = led_mod_select;
output_count = 0;
mod_count = 0;
break;
default:break;
}
}
void main_init() //初始化
{
led_mod_select = 1; //LED流水灯自动切换
TMOD = 0x01; //初始化定时器寄存器
TH0 = (0xffff-10000)/256; //10ms的计时值初值
TL0 = (0xffff-10000)%256;
IE = 0x82;
TR0 = 1; //进定时器中断
}
void main() //主函数
{
main_init();
while(1)
{
key_function();
}
}
void led_display() interrupt 1
{
static uchar time_count = 0; //时间计数,单位时间为10ms
TH0 = (0xffff-10000)/256; //重装10ms的计时值
TL0 = (0xffff-10000)%256;
time_count++;
if(time_count>=time)
{
time_count = 0;
switch(mod_count)
{
case 0: led_output(led_mod_1,8,&output_count,&mod_count); break;
case 1: led_output(led_mod_2,8,&output_count,&mod_count); break;
case 2: led_output(led_mod_3,8,&output_count,&mod_count); break;
case 3: led_output(led_mod_4,8,&output_count,&mod_count); break;
case 4: led_output(led_mod_5,4,&output_count,&mod_count); break;
default: mod_count = 0; break;
}
}
实例三:按键可控流水灯的控制
#include
#define uchar unsigned char
#define uint unsigned int
#define LED P0 //8个LED接口
#define KEY P1 //按键接口
sbit INDICATOR = P3^3; //指示灯接口
uchar code led_mod_1[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //LED从左到右点亮
uchar code led_mod_2[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //LED从右到左点亮
uchar code led_mod_3[8] = {0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00}; //从左到右依次点亮
uchar code led_mod_4[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; //从右到左依次点亮
uchar code led_mod_5[4] = {0xe7,0xc3,0x81,0x00}; //中间两个向傍边点亮
//uchar code led_mod_6[8] = {}; //产生堆积的效果
bit led_mod_select; //LED流水灯模式切换标志,0:手动切换:1:自动切换
uchar time = 50; //计时时间,计时time*10ms
uchar mod_count = 0; //模式计数
uchar output_count = 0; //状态输到LED接口计数
bit stop; //停止/运行标志,0:运行;1:停止
bit suspend; //暂停/继续标志,0:继续;1:暂停
void delay_ms(uint n) //延时函数,单位时间为1ms左右
{
uint i;
uchar j;
for(i=0;i
for(j=0;j<110;j++);
}
void led_output(uchar *led_out,uchar num,uchar *num_count,uchar *led_mod) //向LED接口输出8种状态
{
LED = *(led_out+*num_count);
(*num_count)++;
if(*num_count>=num)
{
*num_count = 0;
if(led_mod_select) //自动切换模式
{
(*led_mod)++; //切换到下一个模式
}
}
}
uchar key_scan( )//按键扫描
{
uchar key_val;
KEY = 0xff;
if(KEY!=0xff)
{
KEY = 0xff;
delay_ms(10); //按键消抖
if(KEY!=0xff)
{
key_val = KEY;
key_val = key_val&0x07; //按键只接低3位I/O口,需要屏蔽高5位I/O口
while(KEY!=0xff) //按键是否释放
KEY = 0xff;
return key_val;//返回按键值
}
}
return 0; //无按键按下
}
void key_function() //按键功能
{
uchar val;
val = key_scan();
switch(val)
{
case 0xfe: //上一个模式
if((0==stop)&&(0==suspend)) //处于运行和继续的状态
{
if(led_mod_select==0)
{
mod_count --;
output_count = 0;
}
}
break;
case 0xfd: //下一个模式
if((0==stop)&&(0==suspend))
{
if(led_mod_select==0)
{
mod_count ++;
output_count = 0;
}
}
break;
case 0xfb: //模式切换
if((0==stop)&&(0==suspend))
{
led_mod_select = ~led_mod_select;
INDICATOR = led_mod_select;
output_count = 0;
mod_count = 0;
}
break;
case 0xf7: //时间加
if((0==stop)&&(0==suspend))
{
time = time+10;
if(time>=100)
{
time = 100;
}
}
break;
case 0xef: //时间减
if((0==stop)&&(0==suspend))
{
if(time<10)
{
time = 10;
}
time = time-10;
}
break;
case 0xdf: //暂停/继续
if(0==stop)
{
suspend = ~suspend;
if(suspend)
{
TR0 = 0;
}
else
{
TR0 = 1;
}
}
break;
case 0xbf: //停止/开始
stop = ~stop;
if(stop)
{
TR0 = 0; //定时器停止计数
LED = 0xff; //初始化变量
led_mod_select = 1;
suspend = 0;
INDICATOR = led_mod_select;
led_mod_select = 1; //LED流水灯自动切换
time = 50; //计时时间,计时time*10ms
mod_count = 0; //模式计数从0开始
output_count = 0; //数组的第一个状态
}
else
{
TR0 = 1; //定时器开始计数
}
break;
case 0x7f:
break;
default:break;
}
}
void main_init() //主函数初始化
{
led_mod_select = 1; //LED流水灯自动切换
TMOD = 0x01; //初始化定时器寄存器
TH0 = (0xffff-10000)/256; //10ms的计时值初值
TL0 = (0xffff-10000)%256;
IE = 0x82;
TR0 = 1;
}
void main() //主函数
{
main_init();
while(1)
{
key_function();
}
}
void led_display() interrupt 1
{
static uchar time_count = 0; //时间计数,单位时间为10ms
TH0 = (0xffff-10000)/256; //重装10ms的计时值
TL0 = (0xffff-10000)%256;
time_count++;
if(time_count>=time)
{
time_count = 0;
switch(mod_count)
{
case 0: led_output(led_mod_1,8,&output_count,&mod_count); break;
case 1: led_output(led_mod_2,8,&output_count,&mod_count); break;
case 2: led_output(led_mod_3,8,&output_count,&mod_count); break;
case 3: led_output(led_mod_4,8,&output_count,&mod_count); break;
case 4: led_output(led_mod_5,4,&output_count,&mod_count); break;
default: mod_count = 0; break;
}
}
}
以上仅举例了三种流水灯的编写方法,希望能对刚学单片机的小伙伴们有所帮助。我们学习单片机技术就是要通过实践才能对电路知识有更深的理解,对电路参数的计算才能有新的认识。在程序的编写上提高了我们程序块之间的连接能力。在软件方面熟悉了编程软件Keilc51、单片机仿真软件P roteus的使用,提高了我们软件的编写,调试能力。
喜欢的话欢迎转载、有问题可以留言互动!