3.4.1 硬件电路
硬件电路采用实验开发板上的电路,如图3.6所示。用S1~S4组成的键盘分别控制P1口发光二极管发光。
图3.6 AT89S51单片机P1口外接8只LED发光二极管
3.4.2 程序设计
ORG 0000H
LJMP MAIN
ORG 0030H
MAIN: ORL P3,#3CH
MOV A,P3
ANL A,#3CH
MOV R0,A
CJNE A,#3CH,MAIN1
SJMP MAIN
MAIN1: MOV R1,#10
PDO: LCALL DELAY
DJNZ R1,PDO
MOV A,P3
CJNE A,R0,DODO
K_S1: JB P3.2,K_S2
LJMP KEY_1
K_S2: JB P3.3,K_S3
LJMP KEY_2
K_S3: JB P3.4,K_S4
LJMP KEY_3
K_S4: JB P3.5,DODO
LJMP KEY_4
DODO: SJMP MAIN
KEY_1: MOV P1,#0FDH
SJMP MAIN
KEY_2: MOV P1,#0FBH
SJMP MAIN
KEY_3: MOV P1,#0FEH
SJMP MAIN
KEY_4: MOV R1,#10
SPK2: MOV R2,#50H
SPK1: CPL P3.2
LCALL DELAY ;调用延时程序
DJNZ R2,SPK1
DJNZ R1,SPK2
SJMP MAIN
DELAY: MOV R3,#10
DEL: MOV R4,#50
DJNZ R4,$
DJNZ R3,DEL
END
3.4.3 源程序的编辑、编译、下载
打开“伟福”模拟仿真软件进行程序的编辑、编译。
打开“ISP下载软件”将目标文件下载到ISP-4实验开发板上的AT89S51单片机芯片,观察程序运行结果。
3.4.4 相关知识
1. 如何用按键控制灯?
按键是单片机常用的输人控制设备,用于信息和命令的输人,当按键与灯的对应关系建立后,单片机程序不断轮流检测S1~S4按键是否有键按下,当有某键按下时,单片机点亮相应的灯。也就是说,每个按键都对应了一个程序段,按下不同按键,程序就执行相应程序段,怎样才能实现这种转移呢?原来单片机中专门有一类控制转移类指令。
2. MCS-51单片机有哪些控制转移指令?
控制转移指令用于控制程序的流向,所控制的范围即为程序存储器区间,MCS-51系列单片机的控制转移指令相对丰富,有可对64kB程序空间地址单元进行访问的长调用、长转移指令,也有可对2kB字节进行访问的绝对调用和绝对转移指令,还有在一页范围内短相对转移及其它无条件转移指令,这些指令的执行一般都不会对标志位有影响。
(1) 无条件转移指令(4条)
这组指令执行完后,程序就会无条件转移到指令所指向的地址上去。长转移指令访问的程序存储器空间为16地址64kB,绝对转移指令访问的程序存储器空间为11位地址2kB空间。
LJMP addr16 ;addr16→(PC),给程序计数器赋予新值的16位地址。
AJMP addr11 ;(PC)+2→(PC),addr11→(PC10-0)程序计数器赋予新值(11位地址),(PC15-11)不改变。
SJMP rel ;(PC)+ 2 + rel→(PC)当前程序计数器先加上2再加上偏移量给程序计数器赋予新值。
JMP @A+DPTR ;(A)+ (DPTR)→(PC),累加器所指向地址单元的值加上数据指针的值给程序计数器赋予新值。
如:任务中的 LJMP MAIN 指令,就属无条件转移指令。
(2) 条件转移指令(8条)
程序可利用这组丰富的指令根据当前的条件进行判断,看是否满足某种特定的条件,从而控制程序的转向。
JZ rel ; A=0,(PC)+ 2 + rel→(PC),累加器中的内容为0,则转移到偏移量所指向的地址,否则程序往下执行。
JNZ rel ; A≠0,(PC)+ 2 + rel→(PC),累加器中的内容不为0,则转移到偏移量所指向的地址,否则程序往下执行。
CJNE A, data, rel ; A≠(data),(PC)+ 3 + rel→(PC),累加器中的内容不等于直接地址单元的内容,则转移到偏移量所指向的地址,否则程序往下执行。
CJNE A, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),累加器中的内容不等于立即数,则转移到偏移量所指向的地址,否则程序往下执行。
CJNE Rn, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),工作寄存器Rn中的内容不等于立即数,则转移到偏移量所指向的地址,否则程序往下执行。
CJNE @Ri, #data, rel ; A≠#data,(PC)+ 3 + rel→(PC),工作寄存器Ri指向地址单元中的内容不等于立即数,则转移到偏移量所指向的地址,否则程序往下执行。
DJNZ Rn, rel ; (Rn)-1→(Rn),(Rn)≠0,(PC)+ 2 + rel→(PC)工作寄存器Rn减1不等于0,则转移到偏移量所指向的地址,否则程序往下执行。
DJNZ data, rel ; (Rn)-1→(Rn),(Rn)≠0,(PC)+ 2 + rel→(PC)直接地址单元中的内容减1不等于0,则转移到偏移量所指向的地址,否则程序往下执行。
在上面任务中就有此类指令,大家找一找,并且分析他们的功能。
(3) 子程序调用指令(1条)
子程序是为了便于程序编写,减少那些需反复执行的程序占用多余的地址空间而引入的程序分支,从而有了主程序和子程序的概念,需要反复执行的一些程序,我们在编程时一般都把它们编写成子程序,当需要用它们时,就用一个调用命令使程序按调用的地址去执行,这就需要子程序的调用指令和返回指令。
LCALL addr16 ; 长调用指令,可在64kB空间调用子程序。此时(PC)+ 3→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr16→(PC),即分别从堆栈中弹出调用子程序时压入的返回地址。
ACALL addr11 ; 绝对调用指令,可在2kB空间调用子程序,此时(PC)+ 2→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr11→(PC10-0)。
RET ; 子程序返回指令。此时(SP)→(PC15-8),(SP)- 1→(SP),(SP)→(PC7-0),(SP)- 1→(SP)。
RETI ; 中断返回指令,除具有RET功能外,还具有恢复中断逻辑的功能,需注意的是,RETI指令不能用RET代替。
如:任务中的 LCALL DELAY 指令,请你分析这条指令的执行过程。
(4) 空操作指令(1条)
这条指令将累加器中的内容清0。
NOP ; 这条指令除了使PC加1,消耗一个机器周期外,没有执行任何操作。可用于短时间的延时。
3. 控制转移指令应用举例
【例3.10】 将外部数据RAM的一个数据块传送到内部数据RAM,两者的首址分别为DATA1和DATA2,遇到传送的数据为零时停止。
解:外部RAM的数据传送一定要以累加器A作为过渡,利用判零条件转移正好可以判别是否要继续传送或者终止。完成数据传送的参考程序如下:
MOV R0,#DATA1 ;外部数据块首址送R0
MOV R1,#DATA2 ;内部数据块首址送R1
LOOP:MOV A,@ R0 ;取外部RAM数据入A
HERE: JZ HERE ;数据为零则终止传送
MOV @ R1, A ;数据传送至内部RAM单元
INC R0 ;修改地址指针,指向下一数据地址
INC R1
SJMP LOOP ;循环取数
注意:以上程序中,写在指令SJMP LOOP 中的LOOP处的8位相对转移偏移量rel,而地址标号LOOP 表示MOVX指令的16位单元地址。
【例3.11】 将内部数据RAM中从DATA单元开始的10个无符号数相加,相加结果送SUM单元保存。
解:设相加结果不超过8位二进制数,则相应的程序如下:
MOV R0,#0AH ;给R0置计数器初值
MOV R1,#DATA ;数据块首址送R1
CLR A ;A清零
LOOP:ADD A,@ R1 ;加1个数
INC R1 ;修改地址,指向下一个数
DJNZ R0,LOOP ;R0减1,不为零循环
MOV SUM,A ;存10个数相加和