单片机初学者轻松入门之(六):单片机制作花样流水灯
小娄学51单片机 2018-03-21 10:47:46
流水灯可以有一个花样,也可以有多个花样,所以可称为花样流水灯。
1、RROTEUS仿真电路图如下(共阳极接法、P2口八路流水灯)
2、写出程序并创建*.hex文件(按不同花样分解依次设计程序)。
花样1:自左至右依次流水,每次只亮一个灯。程序如下:
先来补充三个知识点。
(1)“宏”定义
#define是一个宏定义命令,它常用来指定常数、字符串或者宏函数的代用标识符。其指令格式如下。
#define 代名词 常数(字符串或者宏函数)
例如:
#define outputs P0 //定义使用outputs代替P0。
定义后,当程序中用P0口输出时,如P0=0xFF就可以用outputs=0xFF代替。
程序中 #define uchar unsigned char定义使用uchar代替unsigned char,#define uint unsigned int定义使用uint代替unsigned int。
(2)移位(〉〉和〈〈)和循环移位函数(_crol_ _cror_)
A、标准C语言中的移位操作符"<<"左移一次,超过8位的就被舍去了,最低位补0;">>"右移一次,超过8位的就被舍去了,最高位补0。
应用举例:
一,问:计算表达式14 << 2的值。
答:表达式14 << 2的值为56,因为14(即二进制的00001110)向左移两位等于56(即二进制的00111000)。
二,问: 计算表达式8 >> 2的值。
答:表达式8 >> 2的值为2,因为8(即二进制的00001000)向右移两位等于2(即二进制的00000010)。
具体还需要自己多调试调试。
B、循环移位函数(_crol_, _cror_)
在51头文件reg51.h中没有循环移位函数的定义,而在intrins.h中有说明,所以需要调用intrins.h头文件。
_crol_( m1 , m2 )循环左移位函数
_cror_( m1 , m2 )循环右移位函数
其中m1为需要移位的变量,m2为需要移动的位数。移出去的码循环移动的另一端。
例如程序中i=0xfe(1111 1110); i=_crol_(i,1)意思为将变量i循环左移一位,i=0xfd(1111 1101);
循环移位函数在执行效率上,肯定比标准C的移位效率高,因为不用管移出的超过8位的位。
(3)延时子程序delay(uint t)
子函数是一种具有相对独立功能的程序,其结构与主程序相似。函数格式如下:
返回数据类型 函数名(传入数据类型)
函数可将要处理的数据传入该函数,也可将函数处理完成的数据返回到调用它的程序中。如将一个字符型数据(char)传入函数,处理完成后返回一个整型数据(int),假定其函数名为“SUB_name”,则函数可以这样定义:int SUB_name(char x)
如果不需要传入函数,则可在小括号内用"void"代替,函数可以这样定义:int SUB_name(void)
如果不要返回数据,则可以在函数名左侧用"void"代替,函数可以这样定义:void SUB_name(char x)。
如本设计中的1ms延时子函数:
void delay(uint t) //无返回值的带有传入数据的子函数
{
uchar j;
while(t--)
for(j=0;j<120;j++); //根据上一节的知识介绍,此循环为 //11.0592MHz 51单片机的1ms延时
}
因此,如果想要一个500ms的延时,可以直接调用此函数delay(500),使用起来非常方便,而且理论延时时间很接近实际时间。
此外,需要掌握几个时间转换公式。
1ms=1000us, 1s=1000ms, 1s=106us
现将程序附于下:
#include<reg51.h> //调用51单片机头文件,include调用
#include<intrins.h> //调用头文件,intrins.h中含有循环移位函数
#define uchar unsigned char //宏定义使用uchar代替unsigned char
#define uint unsigned int //宏定义使用uint代替unsigned int
void delay(uint t) //1ms延时子函数
{
uchar j;
while(t--)
for(j=0;j<120;j++);
}
void main()
{
uchar i;
i=0xfe; //设定左边第一个灯亮的初始码
while(1) //死循环
{
P2=i; //将代码编入外接八路流水灯的P2口
delay(500); //延时500ms,如果是delay(1000)则延时1s
i=_crol_(i,1); //将代码循环左移一位数
}
}
花样2:自右至左依次流水,每次只亮一个灯。程序如下:
只改动了主程序中我注释的两处,在此不再详述。
花样3:自右至左依次流水,每次亮两个灯。程序如下:
花样4:自左至右依次流水,每次亮两个灯。程序如何改动呢?
花样5:每次只亮一个灯,流水时间隔一个灯再亮?
花样6:八路灯同时闪烁?
... ...
各种花样太多了,就不一一罗列了。
最后将你需要的花样组合到一个程序之中,就可以实现你想要的效果。
用单片机控制的LED流水灯设计(电路、程序全部给出)
1.引言
当今时代是一个新技术层出不穷的时代,在电子领域尤其是自动化智能控制领域,传统的分立元件或数字逻辑电路构成的控制系统,正以前所未见的速度被单片机智能控制系统所取代。单片机具有体积小、功能强、成本低、应用面广等优点,可以说,智能控制与自动控制的核心就是单片机。目前,一个学习与应用单片机的高潮正在工厂、学校及企事业单位大规模地兴起。学习单片机的最有效方法就是理论与实践并重,本文笔者用AT89C51单片机自制了一款简易的流水灯,重点介绍了其软件编程方法,以期给单片机初学者以启发,更快地成为单片机领域的优秀人才。
2.硬件组成
按照单片机系统扩展与系统配置状况,单片机应用系统可分为最小系统、最小功耗系统及典型系统等。AT89C51单片机是美国ATMEL公司生产的低电压、高性能CMOS 8位单片机,具有丰富的内部资源:4kB闪存、128BRAM、32根I/O口线、2个16位定时/计数器、5个向量两级中断结构、2个全双工的串行口,具有4.25~5.50V的电压工作范围和0~24MHz工作频率,使用AT89C51单片机时无须外扩存储器。因此,本流水灯实际上就是一个带有八个发光二极管的单片机最小应用系统,即为由发光二极管、晶振、复位、电源等电路和必要的软件组成的单个单片机。其具体硬件组成如图1所示。
图1 流水灯硬件原理图
从原理图中可以看出,如果要让接在P1.0口的LED1亮起来,那么只要把P1.0口的电平变为低电平就可以了;相反, 如果要接在P1.0口的LED1熄灭,就要把P1.0口的电平变为高电平;同理,接在P1.1~P1.7口的其他7个LED的点亮和熄灭的方法同LED1。因此,要实现流水灯功能,我们只要将发光二极管LED1~LED8依次点亮、熄灭,8只LED灯便会一亮一暗的做流水灯了。在此我们还应注意一点,由于人眼的视觉暂留效应以及单片机执行每条指令的时间很短,我们在控制二极管亮灭的时候应该延时一段时间,否则我们就看不到“流水”效果了。
3.软件编程
单片机的应用系统由硬件和软件组成,上述硬件原理图搭建完成上电之后,我们还不能看到流水灯循环点亮的现象,我们还需要告诉单片机怎么来进行工作,即编写程序控制单片机管脚电平的高低变化,来实现发光二极管的一亮一灭。软件编程是单片机应用系统中的一个重要的组成部分,是单片机学习的重点和难点。下面我们以最简单的流水灯控制功能即实现8个LED灯的循环点亮,来介绍实现流水灯控制的几种软件编程方法。
3.1位控法
这是一种比较笨但又最易理解的方法,采用顺序程序结构,用位指令控制P1口的每一个位输出高低电平,从而来控制相应LED灯的亮灭。程序如下:
ORG 0000H ;单片机上电后从0000H地址执行
AJMP START ;跳转到主程序存放地址处
ORG 0030H ;设置主程序开始地址
START:MOV SP,#60H ;设置堆栈起始地址为60H
CLR P1.0 ;P1.0输出低电平,使LED1点亮
ACALL DELAY ;调用延时子程序
SETB P1.0 ;P1.0输出高电平,使LED1熄灭
CLR P1.1 ;P1.1输出低电平,使LED2点亮
ACALL DELAY ;调用延时子程序
SETB P1.1 ;P1.1输出高电平,使LED2熄灭
CLR P1.2 ;P1.2输出低电平,使LED3点亮
ACALL DELAY ;调用延时子程序
SETB P1.2 ;P1.2输出高电平,使LED3熄灭
CLR P1.3 ;P1.3输出低电平,使LED4点亮
ACALL DELAY ;调用延时子程序
SETB P1.3 ;P1.3输出高电平,使LED4熄灭
CLR P1.4 ;P1.4输出低电平,使LED5点亮
ACALL DELAY ;调用延时子程序
SETB P1.4 ;P1.4输出高电平,使LED5熄灭
CLR P1.5 ;P1.5输出低电平,使LED6点亮
ACALL DELAY ;调用延时子程序
SETB P1.5 ;P1.5输出高电平,使LED6熄灭
CLR P1.6 ;P1.6输出低电平,使LED7点亮
ACALL DELAY ;调用延时子程序
SETB P1.6 ;P1.6输出高电平,使LED7熄灭
CLR P1.7 ;P1.7输出低电平,使LED8点亮
ACALL DELAY ;调用延时子程序
SETB P1.7 ;P1.7输出高电平,使LED8熄灭
ACALL DELAY ;调用延时子程序
AJMP START ;8个LED流了一遍后返回到标号START处再循环
DELAY: ;延时子程序
MOV R0,#255 ;延时一段时间
D1: MOV R1,#255
DJNZ R1,$
DJNZ R0,D1
RET ;子程序返回
END ;程序结束
3.2循环移位法
在上个程序中我们是逐个控制P1端口的每个位来实现的,因此程序显得有点复杂,下面我们利用循环移位指令,采用循环程序结构进行编程。我们在程序一开始就给P1口送一个数,这个数本身就让P1.0先低,其他位为高,然后延时一段时间,再让这个数据向高位移动,然后再输出至P1口,这样就实现“流水”效果啦。由于8051系列单片机的指令中只有对累加器ACC中数据左移或右移的指令,因此实际编程中我们应把需移动的数据先放到ACC中,让其移动,然后将ACC移动后的数据再转送到P1口,这样同样可以实现“流水”效果。具体编程如下所示,程序结构确实简单了很多。
ORG 0000H ;单片机上电后从0000H地址执行
AJMP START ;跳转到主程序存放地址处
ORG 0030H ;设置主程序开始地址
START:MOV SP,#60H ;设置堆栈起始地址为60H
MOV A,#0FEH ;ACC中先装入LED1亮的数据(二进制的11111110)
MOV P1,A ;将ACC的数据送P1口
MOV R0,#7 ;将数据再移动7次就完成一个8位流水过程
LOOP: RL A ;将ACC中的数据左移一位
MOV P1,A ;把ACC移动过的数据送p1口显示
ACALL DELAY ;调用延时子程序
DJNZ R0,LOOP ;没有移动够7次继续移动
AJMP START ;移动完7次后跳到开始重来,以达到循环流动效果
DELAY: ;延时子程序
MOV R0,#255 ;延时一段时间
D1: MOV R1,#255
DJNZ R1,$
DJNZ R0,D1
RET ;子程序返回
END ;程序结束
3.3查表法
上面的两个程序都是比较简单的流水灯程序,“流水”花样只能实现单一的“从左到右”流方式。运用查表法所编写的流水灯程序,能够实现任意方式流水,而且流水花样无限,只要更改流水花样数据表的流水数据就可以随意添加或改变流水花样,真正实现随心所欲的流水灯效果。我们首先把要显示流水花样的数据建在一个以TAB为标号的数据表中,然后通过查表指令“MOVC A,@A+DPTR”把数据取到累加器A中,然后再送到P1口进行显示。具体源程序如下,TAB标号处的数据表可以根据实现效果的要求任意修改。
ORG 0000H ;单片机上电后从0000H地址执行
AJMP START ;跳转到主程序存放地址处
ORG 0030H ;设置主程序开始地址
START:MOV SP,#60H ;设置堆栈起始地址为60H
MOV DPTR,# TAB ;流水花样表首地址送DPTR
LOOP: CLR A ;累加器清零
MOVC A,@A+DPTR ;取数据表中的值
CJNE A,#0FFH,SHOW;检查流水结束标志
AJMP START ;所有花样流完,则从头开始重复流
SHOW: MOV P1,A ;将数据送到P1口
ACALL DELAY ;调用延时子程序
INC DPTR ;取数据表指针指向下一数据
AJMP LOOP ;继续查表取数据
DELAY: ;延时子程序
MOV R0,#255 ;延时一段时间
D1: MOV R1,#255
DJNZ R1,$
DJNZ R0,D1
RET ;子程序返回
TAB: ;下面是流水花样数据表,用户可据要求任意编写
DB 11111110B ;二进制表示的流水花样数据,从低到高左移
DB 11111101B
DB 11111011B
DB 11110111B
DB 11101111B
DB 11011111B
DB 10111111B
DB 01111111B
DB 01111111B ;二进制表示的流水花样数据,从高到低右移
DB 10111111B
DB 11011111B
DB 11101111B
DB 11110111B
DB 11111011B
DB 11111101B
DB 11111110B
DB 0FEH,0FDH,0FBH,0F7H ;十六进制表示的流水花样数据
DB 0EFH,0DFH,0BFH,7FH
DB 7FH,0BFH,0DFH,0EFH
DB 0F7H,0FBH,0FDH,0FEH
……
DB 0FFH ;流水花样结束标志0FFH
END ;程序结束
4.结语
当上述程序之一编写好以后,我们需要使用编译软件对其编译,得到单片机所能识别的二进制代码,然后再用编程器将二进制代码烧写到AT89C51单片机中,最后连接好电路通电,我们就看到LED1~LED8的“流水”效果了。本文所给程序实现的功能比较简单,旨在抛砖引玉,用户可以自己在此基础上扩展更复杂的流水灯控制,比如键盘控制流水花样、控制流水灯显示数字或图案等等。
相关问答
单片机 lcd 右移 显示原理?单片机右移只需把LCD的位选信号做不断增加或递减就可以了。单片机右移只需把LCD的位选信号做不断增加或递减就可以了。
单片机 C语言 右移 指令怎么用?用这种移位语句,就是这种结果。你试试:_crol_()和_cror_()移位函数。需要先加上头文件:#include用这种移位语句,就是这种结果。你试试:_crol_()和_cror_()移...
单片机 C语言编写点亮两盏led灯?可以通过左移函数_crol_()和右移函数_cror_()来实现LED等的来回流动。具体实现方法可以参考如下程序:#include#include#defineuintunsignedi...
单片机 编程用C语言如何实现循环左移两位?循环左移时,用从左边移出的位填充字的右端,而循环右移时,用从右边移出的位填充字的左侧。这种情况在系统程序中时有使用,在一些控制程序中用得也不少。设...循...
在51 单片机 中,用汇编语言,RLC A,为什么左移两位以后,不是两个灯点亮?用RLCA左移,其中包括了进位位Cy了,A左移两位以后不一定变成11111100,因为原来Cy的状态未知,所以,不是亮两个LED,当然需要是LED的负极接在I/O脚上,是0有效...
51 单片机 左移的问题?建议楼主认真读一下P2=_crol_(P2,1)中的左移函数,记得大概是整体左移,右边最高位补到左边最低位,区别于“建议楼主认真读一下P2=_crol_(P2,1)中的左移函数,记...
51 单片机 左移原理?左循环本征函数:函数原型:unsignedchar_crol_(unsignedchara,unsignedcharn);单片机左移函数用法:例如,P2=0xff;P2=_crol...
单片机 实验80C51外中断P1口接8个发光二极管,设计实验:S1加1...[最佳回答]既可用外部中断方式来实现;也可以用查询方式读键处理.灯的亮灭,就是对P1口的赋值操作,每次多一盏,可以让初值为0xff.此后,每次左移或右移实现.每次...
单片机 外部中断实验p1口接八个发光二极管,实现:s1加1键,s2减...[最佳回答]很容易写的,在INT0中断左移P1在INT1中断右移P1外部中断设为下降沿方式
单片机 中求两个数的平均值程序是怎么样的 - 懂得这个很好办,相加后除2,也就是右移一位,只是要注意对进位的处理。1、单字节:JUN:CLRCADDA,BRRCARET2、双字节:JUN:CLRCMOVA,30HADDA,32HMOV30H相加.....