在单片机P2口外接8个发光二极管(低电平驱动)。试编写一个汇编程序,实现LED循环点亮功能:P2.0-P2.1-P2.2-P2.3-…-P2.7-P2.6-P25-…-P2.0的顺序,无限循环。要求采用软件延时方式控制闪烁时间间隔(约50ms)。
首先进行电路设计
电路原理图设计
利用 Proteus 软件的ISIS 模块绘制原理图。虑到LED低电平驱动要求,硬件电路设计时需使LED的阴极应接P2口,阳极通过限流电阻与+5V 电源相接。电路原理图如下:
XTAL1和XTAL2是晶振的输入和输出端口。C1和C2电容被连接到这些端口,以提供晶振所需的稳定电压和电流。这两个电容组成了一个串联谐振电路,可以帮助晶振产生稳定的振荡信号。这样,微控制器或其他设备就可以使用这个稳定的时钟信号来进行精确的计时和同步操作。
RST引脚连接C3电容器和电阻的目的是为了实现复位电路。当微控制器系统中存在异常或故障时,可以通过将RST引脚拉低来进行强制复位操作,将系统恢复到初始状态。C3和1K欧姆电阻组成了一个简单的延迟元件,在复位期间提供了一个短暂的时间延迟,并消除了可能存在的任何噪声或干扰信号,从而确保复位信号的稳定性和可靠性。
程序设计
编程思路:P2口的亮灯编码初值应能保证 P2.0 位输出低电平,其余位均为高电平。根据电路要求,这一编码初值应为 OFEH(二进制1111 1110),即D1 为亮,D2~D8 皆为暗。此后,不断将亮灯编码值进行循环左移输出,亮灯位将随之由上向下变化;循环左移7次后改为循环右移,则亮灯位将随之由下向上变化。如此反复进行便可实现题意要求的流水灯功能。
图 所示为编程思路的程序流程图。
汇编代码如下:
ORG 30H
CYC1 EQU 200
CYC2 EQU 125MOV A,#0FEH ;LED亮灯编码初值
MOV P2,A
MOV R2,#7 ;计数器 7次换方向DOWN: RL A ;下行方向ACALL DEL50 ;延时50msMOV P2,ADJNZ R2,DOWNMOV R2,#7UP: RR A ;上行方向ACALL DEL50MOV P2,ADJNZ R2,UPMOV R2,#7SJMP DOWNDEL50: MOV R7,#CYC1;延时50ms
DEL1: MOV R6,#CYC2DJNZ R6,$DJNZ R7,DEL1RETEND
下面进行一些解释:
-
ORG 30H:设置代码的起始地址为 30H。
-
CYC1 EQU 200:定义常数 CYC1 的值为 200,用于延时操作。
-
CYC2 EQU 125:定义常数 CYC2 的值为 125,用于延时操作。
-
MOV A,#0FEH:将二进制数 0xFE(1111 1110)存储到 A 寄存器中,这是一个控制 LED 灯亮灭的编码初值。
-
MOV P2,A:将 A 寄存器的值传送到 P2 引脚上,控制 LED 灯亮灭。
-
MOV R2,#7:初始化计数器 R2 的值为 7,用于实现循环功能。
-
DOWN: RL A;ACALL DEL50;MOV P2,A;DJNZ R2,DOWN;MOV R2,#7:这段代码实现了一个循环结构,在每次循环中逐行读取 P2 引脚的输入信号并将其输出给其他设备。具体来说,它执行以下步骤:
将 A 寄存器中的值向左循环移位一位,并将最高位的值保存在 Carry 标志位中;
将 A 寄存器的值传送到 P2 引脚上,输出给其他设备;
延时一定时间(由 DEL50 子程序控制);
将 R2 寄存器的值减去 1,并检查是否等于 0。如果不为 0,则跳转到标记为 DOWN 的代码行,继续执行下一次循环;否则,将 R2 的值重新设置为 7,结束循环。
-
UP: RR A;ACALL DEL50;MOV P2,A;DJNZ R2,UP;MOV R2,#7:这段代码与上面的 DOWN 循环结构类似,但是它是用来逆向读取 P2 引脚的输入信号并输出给其他设备。
-
SJMP DOWN:无条件跳转到标记为 DOWN 的代码行,实现无限循环。
-
DEL50: MOV R7,#CYC1;延时 50ms
-
DEL1: MOV R6,#CYC2;将常数 CYC2 存储到寄存器 R6 中,用于延时操作。
-
DJNZ R6,:将 R6 寄存器的值减去 1,并检查是否等于 0。如果 R6 不为 0,则跳转到当前代码行(:将R6寄存器的值减去1,并检查是否等于0。如果R6不为0,则跳转到当前代码行(),实现一个短暂的延时操作。
-
DJNZ R7,DEL1:将 R7 寄存器的值减去 1,并检查是否等于 0。如果 R7 不为 0,则跳转到标记为 DEL1 的代码行,继续执行延时操作。
-
RET:从子程序中返回主程序。
-
END:表示程序结束。
延时子程序
如何实现延时的:
CYC1 EQU 200
CYC2 EQU 125
DEL50: MOV R7,#CYC1;延时50msDEL1: MOV R6,#CYC2DJNZ R6,$DJNZ R7,DEL1
首先设置CYC1 和 CYC2C 的值是 200 和125 ,类似常量
然后设置DEL50子程序: R7寄存器赋值,将CYC1的值200存储到R7寄存器中。
DEL1子程序标签也是这样,将CYC2的值125存储到R6寄存器中。
下面 DJNZ R6,$
:
将R6寄存器的值减1,如果结果不为零,则跳转到当前标签(即DEL1)所在的位置,继续执行循环。这样就可以实现循环CYC2(125)次的功能。
同样,DJNZ R7,DEL1
的意思是将R7寄存器的值减一,如果结果不为零,则跳转到DEL1标签所在的位置,继续执行循环。这样就可以实现循环CYC1次的功能,从而实现50ms的延时。
有点像循环里面再嵌套一个
for
if if
这样
最后计算时间延时:
以后汇编计算延时可以类似这样
仿真结果
汇编实现LED循环点亮(延时子程序模板)