给初学者讲授“DIY计算机”的书稿——LED流水灯
人们时常看到户外动画广告,一会儿从左到右地显示,一会儿又从右到左地显示,这就是流水灯效果,其特征是将想要显示的画面切割成N份,且每次只让其中的一个画面显示,同时让肉眼能够看得清楚。
假设先让其中的一幅画面显示,接着“立刻”点亮与其相邻的另一幅画面,且同时熄灭前一幅画面,画面切换间隔时间为µs级,由于人眼的反应速度非常之慢,所以无法看清楚画面切换的过程,以至于看起来的效果就是一幅全部点亮的画面,比如,电视画面,这就是人们常说的视觉暂存效应。
如果在点亮第一幅画面后,延时等待一个固定的时间值(假设延迟时间为ms或s级),再在点亮与其相邻的画面的同时熄灭前一幅画面,接着再延时等待一个固定的时间值……那么就能看到画面象流水一样显示的效果。
下面将用LED来模拟从右到左的流水灯的显示效果,将“与发光二极管D17-D24相连的JP4”用并行排线连接到“与单片机的P1.0-P1.7口相连的JP31”,然后短接JP39_5与JP39_6,即硬件电路连接完毕(省略图)。由此可以看出,只要单片机I/O口输出高电平1,那么经过反相器转变为低电平后,即可驱动LED发光,反之LED熄灭。
很显然如果想先点亮最右边第一个LED(D17),那么只要将数据01H传送到P1口即可。通过查看传送指令集,发现可以直接使用“MOV direct,#data”(MOV P1,#01H)指令来实现,那么只要在灯“流动”显示的过程中插入延时程序即可,程序清单1.1就是实现LED流水灯的程序,MAIN为主程序标号,就是程序计数器的PC,即起始地址0000 0000。
程序清单 1.1 LED流水灯程序范例(1) MAIN: MOV P1,#01H ;01H = 0000 0001 ,P1.0为高电平1,D17发光
;执行延时程序Delay
MOV P1,#02H ;02H = 0000 0010,P1.1为高电平1,D18发光
;执行延时程序Delay
……
MOV P1,#80H ;80H = 1000 0000,P1.7为高电平1,D24发光
;执行延时程序Delay
AJMP MAIN ;跳转到MAIN,循环执行程序
虽然这种编程方法也能够达到目的,但效率却很低。通过分析上面的程序可以看出其中的规律,即数据01H、02H、04H、08H、10H、20H、40H、80H中的“1”不断地从右向左移动。由此可见,如果将数据01H存放在累加器A中,即使用“MOV A,#01H”指令,接着将A中的数据传递给P1,然后再想办法让A中的数据01H中的“1”从右向左移动即可,其应用实例如下:
MOV direct,A ;MOV P1,A
通过查看逻辑运算指令集,发现“RLC A”移位运算指令刚好满足要求。其功能是将累加器A的内容全部向左移动1位,当移位8次之后,最高位D7移到标志位CY,而CY原来的内容则移到累加器最低位D0中,其数据结构为1 0000 0000,即CY=1所有的LED全部熄灭,这就是实现“流水”灯的基本思路,详见程序清单1.2。
程序清单 1.2 LED流水灯程序范例(2) MAIN:MOV A,#01H
Loop: MOV P1,A
RLC A ;带进位累加器A循环左移
;执行延时程序Delay
AJMP Loop ;跳转到Loop处,循环执行程序
接着开始编写延时程序,那么一条指令的执行时间是多少呢?循环延时程序详见程序清单 6.13。
程序清单 1.3 延时程序范例(1) MOV R7,#0FFH ;1个机器周期
Delay2:DJNZ R7,Delay2 ;2个机器周期(*)
在执行指令之前R7先减1,然后判断R7是否为0。如果R7≠0,则R7继续做减1操作。与此同时因为延时参数寄存器R7保存的数据为255(0FFH),由于执行1条指令(标有“*”号的指令)为2个机器周期,所以这2个机器周期会重复执行255次。程序实际所耗的准确机器周期为:1+2×255=511个机器周期,延时时间为511×1.1µs =562.1µs。很显然由于人眼的视觉暂存效应,以至于最终看到的效果是LED全部被点亮,因此必须再延长扫描时间,那么最好的办法是使用DJNZ指令再增加一个延时循环,详见程序清单 1.4。
程序清单 1.4 延时程序范例(2) Delay: MOV R6,#0FFH ;1个机器周期
Delay1: MOV R7,#0FFH ;1个机器周期
Delay2: DJNZ R7,Delay2 ;2个机器周期
DJNZ R6,Delay1 ;2个机器周期
延时时间为[1+(1+2×255+2)×255]×1.1µs=143897.6µs=143.8mS,由此可见,如果觉得延时时间不合适,由于R7处于内层循环,因此修改R7的初值对延时的影响太小,那么可以修改R6寄存器的初值。程序清单 1.5为改进后的LED流水灯程序,程序清单 1.6为翻译为机器码后对应的程序。
程序清单 1.5 LED流水灯程序范例(3) MAIN: MOV A,#01H
Loop: MOV P1,A
RLC A
Delay:MOV R6,#0FFH ;延时时间为143.8mS
Delay1:MOV R7,#0FFH
Delay2 DJNZ R7,Delay2
DJNZ R6,Delay1
AJMP Loop
;
END
程序清单 1.6 LED流水灯程序范例(4) 地址 指令 助记符 注释
0000 0000 0111 0100 MOV A,#01H ;该指令为2字节
0000 0001 0000 0001
0000 0010* 1111 0101 MOV P1,A ;该指令为2字节
0000 0011 1001 0000
0000 0100 0011 0011 RLC A ;该指令为1字节
0000 0101 0111 1110 MOV R6,#0FFH ;该指令为2字节
0000 0110 1111 1111
0000 0111* 0111 1111 MOV R7,#0FFH ;该指令为2字节
0000 1000 1111 1111
0000 1001* 1101 1111 DJNZ R7,0009H ;该指令为2字节,跳转到0009H
0000 1010 1111 1110
0000 1011 1101 1110 DJNZ R6,0007H ;该指令为2字节,跳转到0007H
0000 1100 1111 1010
0000 1101 0000 0001 AJMP 0002H ;该指令为2字节
0000 1110 0000 0010
待程序输入正确无误之后,只要将A3实验区的运行开关K11拨到RUN档运行,即可看到LED流水灯效果。
思考题:如果将“RLC A”指令改为“RL A”,请仔细观察流水灯的效果。 |