dlyram1 equ 30h ;定义延时用的变量,在RAM中
dlyram2 equ 31h
dlyram3 equ 32h
org 0000h ;程序从51单片机的0000地址开始执行
jmp main ;跳转到MAIN
org 0050h ;程序执行的地址到50H
main:
mov sp,#55h ;设置特殊寄存器堆栈的地址
main_01:
mov a,p1 ;将P1端口的状态读出
anl a,#00000001b ;与01H相与,看是否为0
jnz main_01 ;不为0,跳转到main_01,继续判断
mov a,p0 ;为0,为点亮第一个灯准备,将P0端口的状态读出
and a,#11111101b ;与FDH相与,即将P0.1输出0
mov p0,a ;将上面的值给P0端口,P0.1灯亮
call delay_500ms ;延时500ms
mov a,p0 ;再将P0的值读出
and a,#11011111b ;与DFH相与,将P0.5清0
mov p0,a ;将得到的值给端口P0
call delay_500ms ;延时500ms
mov a,p0 ;将P0端口的状态读出
orl a,#00100010b ;与22H相或,将P0.1和P0.5值给1
mov p0,a ;将值给端口P0
jmp $ ;程序始终在这里执行
delay_500ms: ;延时500MS,由于500MS很大,因此将延时程序中的一些语句忽略不计,可得延时50x100x100=500000US=500MS
mov dlyram1,#50
delay_500ms_00:
mov dlyram2,#100
delay_500ms_01:
mov dlyram3,#100
delay_500ms_02:
djnz dlyram3,delay_500ms_02
djnz dlyram2,delay_500ms_01
djnz dlyram1,delay_500ms_00
ret
end
你用的是跳转指令进入程序段,而不是子程序调用,所以不能用RET返回,只能同样跳回去
用LCALL或者ACALL命令调用子程序时会把当前的程序地址压入堆栈当前点,在遇到RET指令时就会把保存的断点地址弹回PC寄存器,继续调用之前的执行,但是JMP系列指令不会保存断点地址,所以RET时就会把堆栈当前点数据装入PC,上电后RAM中未初始化的单元都是0,所以就会把0装入PC,于是程序就回到0地址了。
ORG 0000H
AJMP MAIN
ORG 000BH
MAIN: JB P1.0,MAIN ;判断输入为1则转,重新判断
CLR P0.1 ;置0,灯P0.1亮
ACALL DEL ;延时0.5S
CLR P0.5 ;置0,灯P0.5亮
ACALL DEL ;延时0.5S
SETB P0.1 ;置1,两灯灭
SETB P0.5
SJMP $
DEL: MOV R7,#10 ;延时0.5S子程序,晶振12M,[(248X2+3)X100+3]X10+3=499033=500MS
DEL1: MOV R6,#100
DEL2: MOV R5,#248
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
MOV R7,#10
RET
END
很简单,调试过。不过我想你要编的不可能只是这么一点,希望对你有帮助。
楼上一定是骗人!!绝对没调试过,第二行的
LJMP的L写成A了,这都好意思说调试过。。BS它
我给你一个12M下带比较精准的0.5秒的延时函数的C程序,程序在keil中调试
#include "at89x51.h"
#define uint8 unsigned char
#define uint16 unsigned int
void delay_500ms_12M(uint16 t)
{
uint8 i;
for(;t>0;t--)
for(i=249;i>0;i--);
}
void main(void)
{
P0_1=1; //一开始,两灯都不亮
P0_5=1;
while(!P1_0) //只要P1.0检测到0,就执行下面的代码
{
P0_1=0;
delay_500ms_12M(980); /*比较精准的0.5秒延时,从函数
调用到函数退出,实际运行了
0.499818秒*/
P0_5=0;
delay_500ms_12M(980);
P0_1=1;
P0_5=1;
}
}