本帖最后由 zlg315 于 2009-12-27 00:54 编辑
初学者写程序关键在于理清思路,这是我给学生上课的内容,可供参考!
人们时常看到户外动画广告,一会儿从左到右地显示,一会儿又从右到左地显示,这就是流水灯效果,其特征是将想要显示的画面切割成N份,且每次只让其中的一个画面显示,同时让肉眼能够看得清楚。
假设先让其中的一幅画面显示,接着“立刻”点亮与其相邻的另一幅画面,且同时熄灭前一幅画面,画面切换间隔时间为µs级,由于人眼的反应速度非常之慢,所以无法看清楚画面切换的过程,以至于看起来的效果就是一幅全部点亮的画面,比如,电视画面,这就是人们常说的视觉暂存效应。
如果在点亮第一幅画面后,延时等待一个固定的时间值(假设延迟时间为ms或s级),再在点亮与其相邻的画面的同时熄灭前一幅画面,接着再延时等待一个固定的时间值……那么就能够看到画面象流水一样显示的效果。
下面将用LED来模拟从右到左的流水灯的显示效果,将“与发光二极管D17~D24相连的JP4”用并行排线连接到“与单片机的P1.0~P1.7口相连的JP31”,然后短接JP39_5与JP39_6,即硬件电路连接完毕,详见图 5.14。由此可以看出,只要单片机I/O口输出高电平1,那么经过反相器转变为低电平0后,即可驱动LED发光,反之LED熄灭。
很显然如果想先点亮最右边第一个LED(D17),那么只要将数据01H传送到P1口即可。通过查看表 5.6所示的传送指令集,发现可以直接使用“MOV direct,#data”(MOV P1,#01H)指令来实现,那么只要在灯“流动”显示的过程中插入延时程序即可,程序清单 5.8就是实现LED流水灯的程序,MAIN为主程序标号,就是程序计数器的PC,即起始地址0000 0000。
程序清单 5.8 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的数据01H中的“1”从右向左移动即可,然后再通过A将数据传递给P1,即就是传送指令:
MOV direct,A ;MOV P1,A
通过查看逻辑运算指令集,发现“RLC A”移位运算指令刚好满足要求。其功能是将累加器A的内容全部向左移动1位,当移位8次之后,最高位D7移到标志位CY,而CY原来的内容则移到累加器最低位D0中,其数据结构为1 0000 0000,即CY=1所有的LED全部熄灭,这就是实现“流水”灯的基本思路,详见程序清单 5.9。
程序清单 5.9 LED流水灯程序范例(2)
MAIN:MOV A,#01H
Loop: MOV P1,A
RLC A ;带进位累加器A循环左移
;执行延时程序Delay
AJMP Loop ;跳转到Loop处,循环执行程序
接着开始编写延时程序,那么一条指令的执行时间是多少呢?循环延时程序详见程序清单 5.10。
程序清单 5.10 延时程序范例(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指令再增加一个延时循环,详见程序清单 5.11。
程序清单 5.11 延时程序范例(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寄存器的初值。程序清单 5.12为改进后的LED流水灯程序,程序清单 5.13为翻译为机器码后对应的程序。
程序清单 5.12 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
思考题:将“RLC A”改为“RL A”,请观察流水灯的效果和现象。
|