一、实验目的
1.掌握编译工具keil和单片机模拟器proteus的使用。
2.掌握简单位操作指令写法。
3.掌握单片机I/O口的输入输出功能。
4.学习延时子程序的编写和使用。
二、实验设备
预装了keil及proteus的PC机。
三、实验内容
监视开关K1(接在P3.0端口上),用发光二极管L1(接在单片机P1.0端口上)显示开关状态,如果开关合上,L1开始闪烁N次(N为学号最后位4xxxxxxxxxN)后熄灭,闪烁时间间隔不少于0.5秒。如果开关未合上,L1熄灭。N为0时,闪烁10次。电路原理图如下图所示:
四、实验要求
根据实验任务要求,编写源程序。
五、实验源程序及关键步骤
使用keil编辑程序,生成hex文件,打开DSN文件,把hex文件加入到单片机中,观察发光二极管的闪烁情况。
源程序
ORG 0000H
MOV A,#0 ; 初始化A寄存器为0
MAIN:
JB P3.0,LIG ; 检测开关状态,如果开关合上则跳转到LIG标签
JZ MAIN ; 如果开关未合上,则继续循环等待
MOV A,#0 ; 如果开关合上但A寄存器不为1,则将A寄存器设置为0
MOV R6,#04H ; 设置循环次数为4
XH:
CLR P1.0 ; 灭
LCALL DELAY ; 延时一段时间
SETB P1.0 ; 亮
LCALL DELAY ; 延时一段时间
DJNZ R6,XH ; 循环次数减1,如果不为0则继续闪烁
LJMP MAIN ; 跳转回主循环
LIG:
SETB P1.0 ; 亮
MOV A,#1 ; 设置A寄存器为1,避免重闪
LJMP MAIN ; 跳转回主循环
DELAY:
PUSH ACC ; 保存ACC寄存器的值
MOV R0,#40 ; 设置延时计数器初值为40
DELAY1:
MOV R1,#40 ; 设置延时计数器初值为40
DELAY2:
MOV R2,#248 ; 设置延时计数器初值为248
DJNZ R2,$ ; 延时计数器R2减1,如果不为0则继续延时
DJNZ R1,DELAY2 ; 延时计数器R1减1,如果不为0则继续延时
DJNZ R0,DELAY1 ; 延时计数器R0减1,如果不为0则继续延时
POP ACC ; 恢复ACC寄存器的值
RET ; 返回调用位置
END ; 程序结束
六、运行结果
七、思考
要求任务中,将延时时间改为1分钟,则该程序将作如何的修改?
答:使用了两个计数器R4和R5来实现60秒的延时,我将外层循环次数设置为234,内层循环次数设置为232,然后对两个循环进行嵌套,完成总共60000000次的循环,从而实现60秒的延时,因为在循环执行过程中,DJNZ指令本身也需要一些时间,如果计数器初值设得过大,可能会导致总延时时间偏短,为了保证延时时间的准确性,我在计算内层循环次数时将计数器初值设为220。
ORG 0000H
MOV A,#0
MAIN:
JB P3.0,LIG
JZ MAIN
MOV A,#0
MOV R6,#04H
XH:
CLR P1.0
LCALL DELAY
SETB P1.0
LCALL DELAY
DJNZ R6,XH
LJMP MAIN
LIG:
SETB P1.0
MOV A,#1
LJMP MAIN
DELAY:
PUSH ACC
MOV R5,#234
DELAY1:
MOV R4,#232
DO_DELAY:
MOV R0,#220
DELAY_LOOP2:
MOV R1,#220
DELAY_LOOP1:
MOV R2,#248
DJNZ R2,$
DJNZ R1,DELAY_LOOP1
DJNZ R0,DELAY_LOOP2
DJNZ R4,DO_DELAY
DJNZ R5,DELAY1
POP ACC
RET
END
八、实验总结
通过这次实验,我学会了使用编译工具Keil和单片机模拟器Proteus,在实验中,我掌握了简单位操作指令的写法,我通过MOV指令将特定的数值加载到寄存器中,以实现对寄存器的初始化或者赋值操作;我还学习了条件跳转指令JB和JZ的使用,它们可以根据特定的条件跳转到程序的其他部分,从而实现分支控制;学习了单片机I/O口的输入输出功能,可以通过SETB和CLR指令,设置某个引脚为高电平或低电平,从而控制外部设备的状态,在这个实验中,通过控制P1口的输出,我成功实现了对发光二极管的闪烁;学习了延时子程序的编写和使用,通过循环嵌套的方式,我实现了一个简单的延时函数,调整循环次数和计数器的初值,我可以控制延时的时间。
在实验过程中,我也遇到了一些问题,延时时间不准确和闪烁频率不符合预期,经过我仔细检查代码,我发现是由于计数器的初值设置不合理导致的,通过调整计数器的初值,实现了预期的闪烁效果。