中职汇编延时程序初探
2011-12-29李公昕
成才之路 2011年16期
在应用单片机编制各种程序时,经常会遇到实现精确延时的问题,时间从几十微秒到几秒,甚至更高的精度。单片机实现延时通常有两种方法:一种是用定时器/计数器硬件延时,这种方法可以提高CPU的工作效率,也能做到精确延时,另一种是采用循环体进行软件延时。
一、使用定时器/计数器
单片机系统若使用频率为12MHz的晶振,一个机器周期为1μs,最长的延时时间可达2的16次方。在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时,从程序的执行效率和稳定性两方面考虑,都是最佳的方案,但需要注意的是,用C51编写的中断服务程序,编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时将占用4个机器周期,如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间要从初值中减去,以达到最小误差的目的。
二、使用软件嵌套循环程序
在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。常用的软件延时的方法有:
1. 短暂延时
通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10μs( )、Delay25μs( )等存放在一个自定义的文件中,需要时在主程序中直接调用。如延时10μs可编写如下:
void Delay10μs ( ) {
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
}
上面函数中共用了6个_NOP_( )语句,每个语句执行时间为1μs。主函数调用Delay 10μs( )时,先执行一个LCALL指令(2 μs),然后执行6个_NOP_( )语句(6μs),最后执行了一个RET指令(2μs),所以执行上述函数时共需要10μs。可以把这一函数当做基本延时函数,在其他函数中调用,即嵌套调用,以实现较长时间的延时。
2. C51中嵌套汇编程序段实现延时
在C51中通过嵌套汇编语言语句,实现多次循环达到延时的目的。例1:50ms 延时子程序:
DELAY:MOVR7,#200①
LOOP1:MOVR6,#125 ②
LOOP2:DJNZR6,L00P2③
DJNZR7,LOOP1④
RET⑤
精确延时时间为:1+(1×200)+(2×125×200)+(2×200)+2=(2×125+3)×200+3 =50603us≈50ms⑥
由⑥整理出公式:延时时间=(2×内循环+3)×外循环+3 ⑦
详解:DELAY这个子程序共有五条指令,现在分别就每一条指令被执行的次数和所耗时间进行分析。第一句:MOVR7,#200在整个子程序中只被执行一次,且为单周期指令,所以耗时1us。第二句:MOVR6,#125从②看到④只要R7-1不为0,就会返回到这句,共执行了R7次,共耗时200us。第三句:DJNZ R6,LOOP2,只要R6-1不为0,就反复执行此句(内循环R6次),又受外循环R7控制,所以共执行R6×R7次,因是双周期指令,所以耗时2×R6×R7us。
例2:1秒延时子程序:
DELAY:MOV R7,#10 ①
LOOP1:MOV R6,#200②
LOOP2:MOV R5,#248③
DJNZ R5,$ ④
DJNZ R6,LOOP2 ⑤
DJNZ R7,LOOP1 ⑥
RET⑦
对每条指令进行计算得出精确延时时间为:1+(1×10)+(1×200×10)+(2×248×200×10)+(2×200×10)+(2×10)+2=[(2×248+3)×200+3]×10+3=998033us≈1s ⑧
由⑧整理得:延时时间=[(2×第一层循环+3)×第二层循环+3]×第三层循环+3 ⑨
此式适用三层循环以内的程序,也验证了例1中式⑦(第三层循环相当于1)的成立。注意,要实现较长时间的延时,一般采用多重循环,有时会在程序里加入NOP指令。
三、使用其他方法实现延时
如示波器、反汇编工具、性能分析器等确定延时时间。
四、总结
中职学生对单片机编程掌握较为薄弱。本文所介绍的多种实现并计算延时程序执行时间的方法,使用定时器进行延时是最佳的选择,可以提高MCU工作效率。编写延时程序是一项很烦琐的任务,需要多次修改才能满足要求。
(河南省经济管理学校)
注:“本文中所涉及到的图表、公式、注解等请以PDF格式阅读”