这段程序是要求用定时器/计数器T0工作在方式1,在p1.0上输出一个周期为2ms的方波,晶振频率为6Mhz,经计算,T0的初值为TH0=0FEH,TL0=OCH,下面是程序: ORG 0000HRESET :AJMP MAIN ;转主程序 ORG 000BH ;T0的中断入口 AJMP IT0P ;转T0中断处理程序IT0P ORG 0100H MAIN :MOV SP,#60H ;设堆栈指针 MOV TMOD,#01H ;设T0为方式1 ACALL PT0M0 ;调用子程序PT0M0 HERE :AJMP HERE;自身跳转 PT0M0:MOV TL0,#OCH ;T0中断服务程序,T0重新置初值 MOV TH0,#0FEH SETB TR0 ;启动T0 SETB ET0 ;允许T0开中断 SETB EA;CPU开中断 RET ITOP:MOV TL0,#0CH ;T0中断服务子程序,T0置初值 MOV TH0,#0FEH CPL P1.0 ;P1.0状态取反 RETI 我对这段程序的理解是这样的,在RESET部分,相当于声明,第一行是说跳转到主程序MAIN,第二、三行是说跳转到中断处理程序IT0P,地址是000BH,第四行是说MAIN程序的地址是0100H,请问为什么要设堆栈指针?#60H是怎么确定的?自身跳转在这有什么用?还有在PT0M0已经给T0设过初值了,为什么在IT0P部分还要设初值,请朋友们帮忙分析下这个程序,我对程序的执行过程不太了解,最好说详细些,谢谢了!
ORG 0000H ;声明从地址0000H开始读出指令。其实这里不声明也是从0000H开始读出指令。RESET: AJMP MAIN ;指令内容是转到MAIN的程序去工作。地址是0000H ORG 000BH ;声明指向T0的中断入口的地址 AJMP IT0P ;这时的指令内容是转到IT0P的程序(T0中断处理程序)去工作。地址是000BH ORG 0100H ;声明现在的是地址0100H,之前没用到的保留。编译器认为是内容是00HMAIN: MOV SP,#60H ;设堆栈指针.复位时是07H。系统中如用不到堆栈将占用的寄存器可以不重新设置。例如在这个程序中可以不设置堆栈指针。 MOV TMOD,#01H ;设T0为方式1 ACALL PT0M0 ;调用子程序PT0M0 HERE: AJMP HERE ;自身跳转PT0M0: MOV TL0,#OCH ;T0中断服务程序,T0重新置初值 MOV TH0,#0FEH ;定时器0启动后每个机器周期数值都+1.在溢出后T0从0000H重新开始并进入中断服务程序。 SETB TR0 ;启动T0 SETB ET0 ;允许T0开中断 SETB EA ;CPU开中断 RETITOP: MOV TL0,#0CH ;T0中断服务子程序,T0置初值 MOV TH0,#0FEH ;进入中断服务程序T0的值已经不是要求的数值。必须要重新给初值 CPL P1.0 ;P1.0状态取反 RETI END
堆栈指针是默认是为#07H的,这个#60H一般情况下可以随便设置,它的范围是RAM的大小范围。主要是用来压栈用的。那个自身跳转是用来等待中断的到来的。定时器T0有四种工作方式。同TMOD来设置,此为方式1,为16位计数器,不会自动重装。所以在中断处理的程序里应该重新赋值。如果你想不用重新赋初值给它,可以用方式2,8位自动重装计数器。
1,单片机复位时堆栈指针在内存(RAM)07H地址处,08H-1FH是寄存器区,而寄存器区是单片机使用较频繁的区域,为了避开这个区域,有时需要调整堆栈指针的位置,使之指向大于1FH的位置,8051单片机的内存只有128(80H)个字节,堆栈也只有8级,堆栈是向上增长的,所以将堆栈指针设置在60H,这样做既保证了足够的堆栈空间,又可以放心使用60H以下的内存单元,避免发生内存冲突。2,自身跳转就是反复执行这条指令的死循环,在这里死循环的作用是等待中断的发生,隔离了后续程序,便于观察中断程序运行结果。3,PT0M0是对定时器T0包括开放中断在内的初始化,而ITPO是刷新定时器初值,每次定时器中断时对定时器初值的刷新,可以保证定时时间的一致性,也就保证了P1.0的2ms周期脉冲的准确性。