教你单片机流水灯实验(详解)
单片机易入门教学
---------------------------------------------------------------------------------------------------------------
每当夜幕降临,我们都能看到街上各种广告牌上美丽的霓虹灯,看起来赏心悦目,为夜晚的城市增添了许多美丽的色彩。事实上,这些霓虹灯的工作原理与单片机流水灯相同,但霓虹灯的图案更多,看起来更漂亮。我们将结合这门课YL-51单片机开发板教您详细学习单片机流水灯实验。
实验硬件设备硬件设备:YL-51单片机开发板
YL-51单片机开发板上有8个高亮度发光二极管(见图1所示),可用作单片机流水灯和跑马灯。。。实验如下图3所示。
图3
从原理图可以看出,如果我们想要连接P1.0口的LED1亮起来,所以我们只需要P1.0口的电平可以变成低电平;相反,如果要连接的话P1.0口的LED熄灭,必须把它熄灭P1.0口的电平可以变成高电平;同样,连接P1.1~P1.7口的其他7个LED照明和熄灭方法相同LED1.因此,为了实现流水灯的功能,我们只需要LED2~LED8依次点亮熄灭,依次类推LED流水灯变得一亮一暗。
实现8个LED流水灯程序用中文表示:P1.0低、延时、P1.0高、P1.1低、延时、P1.1高、P1.2低、延时、P1.2高、P1.3低、延时、P1.3高、P1.4低、延时、P1.4高、P1.5低、延时、P1.5高、P1.6低、延时、P1.6高、P1.7低、延时、P1.7.返回到开始和程序结束。
从上面的中文来看,实现单片机流水灯很简单,但我们不能说P1.如果你变低,它就会变低。因为单片机听不懂我们的汉语,只能接受二进制的1、0......机器代码。我们如何让单片机按照我们的意思工作?为了让单片机工作,我们只能将程序写成二进制代码给其执行;早期的单片机开发人员使用手动编写的二进制代码交给单片机工作。今天,我们不必使用恼人的二进制来编写程序。我们可以通过翻译软件将易于理解的程序语言翻译成单片机所需的二进制代码,然后交给单片机执行。目前,这里的程序语言主要包括汇编语言和C两种语言;我们在这里提到的翻译软件被称为编译器,通过编译器生成单片机的程序语言的二进制代码的过程被称为编译。正如前面提到的,如果你想使用它LED1变亮,只需将相应的单片机引脚电平变为低电平即可。现在让我们把上面提到的8个LED流水灯实验写为汇编语言程序。
实现8个LED流水灯汇编语言程序 liu01.asm
;----- 主程序开始 -----
START: CLR P1.0 ;P1.输出低电平,使LED1点亮
ACALL DELAY ;调用延时子程序
SETB P1.0 ;P1.输出高电平,使LED1熄灭
CLR P1.1 ;P1.输出低电平,使LED2点亮
ACALL DELAY ;调用延时子程序
SETB P1.1 ;P1.输出高电平,使LED2熄灭
CLR P1.2 ;P1.输出低电平,使LED3点亮
ACALL DELAY ;调用延时子程序
SETB P1.2 ;P1.输出高电平,使LED3熄灭
CLR P1.3 ;P1.输出低电平,使LED4点亮
ACALL DELAY ;调用延时子程序
SETB P1.3 ;P1.输出高电平,使LED4熄灭
CLR P1.4 ;P1.输出低电平,使LED5点亮
ACALL DELAY ;调用延时子程序
SETB P1.4 ;P1.4输出高电平,使LED5熄灭
CLR P1.5 ;P1.输出低电平,使LED6点亮
ACALL DELAY ;调用延时子程序
SETB P1.5 ;P1.输出高电平,使LED6熄灭
CLR P1.6 ;P1.输出低电平,使LED7点亮
ACALL DELAY ;调用延时子程序
SETB P1.6 ;P1.输出高电平,使LED7熄灭
CLR P1.7 ;P1.输出低电平,使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 ;程序结束
五个汇编语言指令用于上述主程序:CLR、ACALL、SETB、LJMP、END。
CLR: 将后面指定的位置清除为0,并在程序中输出相应的端口
ACALL:是子程序调用指令,在程序中调用DELAY延时子程序
SETB:将后面指定的位置变成1,在程序中输出相应的端口
AJMP:是无条件跳转指令,意思是:跳转到指定的标号处继续运行
END: 是程序结束的伪指令,即告诉编译器程序结束。伪指令只告诉编译器程序的要求或条件,它不参与和影响程序的执行。
在上面的源程序中"ACALL DELAY"指令的作用是调用DELAY延迟子程序。为什么要使用这个指令?如果没有这个指令可以实现"流水"效果好吗?答案是肯定的。我们必须使用这个指令才能看到我们需要什么。"流水"效果。如果不用该指令,则由于8个LED发光和熄灭的时间很短,肉眼看不见LED凭肉眼看到的熄灭和点亮LED1~LED8同时亮(半亮),但看不到流水的效果!注:初学者可以在上述源程序中使用所有内容"ACALL DELAY"删除指令行,然后编译,烧写到单片机验证。
这种现象主要是由于单片机执行每个指令的时间很短,我们知道实验板上单片机的时钟高达11.0592MHz,在此时钟信号(即晶体振荡信号)下,一个机器周期只有1左右.08uS(微秒)。我们在这个程序中使用的SETB P.x和CLR P.x都属于单周期指令,也就是说,执行 SETB P.x 用时仅1.08uS(微秒),CLR P.x 也是1.08uS(微秒).08uS(微秒)在如此高速的流水速度下,有8个LED发光熄灭的时间很短,当然肉眼看不到流水的效果!
需要注意的是,根据汇编语法的要求,编制的程序(以下简称源程序)的格式和书写要求必须遵循以下原则:
1.源程序必须是纯文本格式文件,如果使用Windows用附件中的记事本编写的文本文件UltraEdit编辑文本编辑器;
2、源程序的扩展名应是 *.ASM;
3.一行只能写一个句子,以回车为句子结尾。每个句子的长度应小于80个字符(即40个汉字)。
4.每行格式应为:标签: 命令 参数 ;注释 。也就是说,一行由四个部分组成,每个部分的顺序不能错误。根据实际要求,可以省略其中一个或多个部分,甚至全部省略,即空白线。当需要使用标签时,标签背后必须有:(冒号),命令句和参数之间必须有空格。如果命令中有多个参数,则必须在参数和参数之间使用,(逗号),在需要注释时,必须在注释前使用;(分号);后面的句子可以写任何字符,包括汉字来解释前面的汇编句子。它不会参与汇编或生成代码。由于汇编程序对我们来说并不直观,我们在编写源程序时应该养成多写注释的习惯,这有助于将来阅读和维护源程序。
标签是标签程序中某一行的符号名,编译后的标签值是标签所在行代码的地址。在宏汇编写ASM51中标号的长度不受限制,但标号不能包含:或其他特殊符号,也不能使用汉字,可以使用数字作为标号,但必须从字母开始。当标号作为参数(如标号作为转移地址)时,必须放弃:(如上述程序中的 AJMP START中的START不能再有了:)。每行只能有一个标签,一个标签只能在一个地方使用。如果两行使用相同的标签,则在汇编过程中会出错。由于标签的长度没有限制,您可以用有意义的英语或汉语拼音来解释行,使源程序更容易阅读。源程序中的字母不区分大小写,即 start 和 START 是一样的,请不要用大小写来区分不同的标签。
嗯!我们知道汇编语言程序的规则,现在就开始编辑源程序。立即启动Keil单片机集成开发环境,建立新项目liu01.UV2.上述源程序liu01.asm设置导入工程Keil获得工程编译参数和编译参数HEX目标文件的格式liu01.hex,将目标文件liu01.hex烧写到AT89S在51单片机中,下一步是烧写AT89S从编程器上取下51,放入YL-我们可以看到51单片机开发板 上通电LED1~LED8的"流水"效果了。
到目前为止,我们制作的流水灯已经成功,工作原理也很清楚。如果您完全掌握了上述程序,您可以改变流水灯的流向"左向右流"改为从"右向左流",也可以改为"两边向内流"、"内部向外流"......,我想你可以用你以前学到的方法来实现这些功能。有些专家可能会说,前面的编程方法是最愚蠢的!但初学单片机初期可以不必讲究语言的简练,只要能实现预先要求就好,最主要的是学好基本指令(111条)的用法,清楚各个指令的功能,这是初学者要知道的。那么还有更好的编程思路吗?当然有!请跟随站长继续学习下面的内容。
在前面学习的程序中我们让LED流水是去逐个控制P1端口的每个位来实现的,因此程序显得有点复杂,下面我们就采用新的思路来编程。新的编程思路如下:我们在程序一开始就给P1口送一个数,这个数本身就让P1.0先低,其他位为高,然后让这个数据向高位移动不就实现“流水”效果啦?的确如此!8051指令中没有让P1数据移动的指令,但有对累加器ACC中数据左移或右移的指令,ACC在指令中常写为A,累加器A数据左移指令为"RL A",累加器数据右移指令为"RR A",累加器在数据传输和数据处理过程中作用十分重要,累加器ACC为8位。他可与片内所有单字节寄存器交换数据,实际上P1和其他端口在单片机中也是一个寄存器。这样我们可以将需移动的数据先放到ACC中,让其移动,然后将ACC移动后的数据再转送到P1口,这样同样可以实现“流水”效果。下面程序就是采用新的编程思路源程序liu02.asm。
实现8个LED流水灯汇编语言程序 liu02.asm
;----- 主程序开始 -----
START: MOV ACC,#0FEH ;ACC中先装入LED1亮的数据(二进制的11111110)
MOV P1,ACC ;将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 ;程序结束
接下来,我们将上述程序编译,并烧写到实验芯片中,放到实验板上可以看到程序的"流水"效果是一样的,但源程序看起来更加简洁,直观。其实8051单片机有111条指令,有的指令常用,有的指令不常用,只要遵守语法规则,你可以用这些指令“组合”成你想象到的任何程序。当然,有时一条指令可以替代很多条指令,这样会使程序简洁,程序代码减少,在编写较大程序时可以让程序存储器放得下你需要的代码,这也是单片机高手所追求的“程序简洁高效”。当然,初学者不必刻意去追求程序的简洁高效,主要是要全面地掌握各种指令的应用,只要你对基本指令都熟悉了,那么你也就可以编出简洁高效的程序了,不过这编程“内功”是需要你勤学苦练,日积月累的练习、实验才能达到的哦!马上拿起你的实验板,现在就开始动手吧:)
上面我们学习的两个程序都是比较简单的流水灯程序,"流水"花样只能实现单一的"从左到右"流方式。下面介绍一个实用的流水灯程序,程序能够实现任意方式流水,而且流水花样无限,只要更改流水花样数据表的流水数据就可以随意添加或改变流水花样,真正实现随心所欲的流水。只要将下面的程序稍稍修改一下,通过S51增强型单片机实验板的扩展接口连接到霓虹灯高压驱动接口板就可以驱动真正的霓虹灯了。
实用的查表方式多功能流水灯程序 liu03.asm
;----- 主程序开始 -----
ORG 0000H ;上电复位,程序从0000H开始执行
START: MOV SP,#60H ;堆栈初始化为60H
MOV DPTR,#LIU_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 ;子程序返回
;----- 下面是流水花样数据表 -----
LIU_TAB:
DB 01111111B ;二进制表示的流水花样数据
DB 10111111B
DB 11011111B
DB 11101111B
DB 11110111B
DB 11111011B
DB 11111101B
DB 11111110B
DB 11111110B
DB 11111101B
DB 11111011B
DB 11110111B
DB 11101111B
DB 11011111B
DB 10111111B
DB 01111111B
DB 7FH,0BFH,0DFH,0EFH,0F7H,0FBH,0FDH,0FEH ;十六进制表示
DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,7FH
DB 7EH,0BDH,0DBH,0E7H,0E7H,0DBH,0BDH,7EH
DB 7FH,3FH,1FH,0FH,07H,03H,01H,00H
DB 0FFH ;流水花样结束标志0FFH
END ;程序结束