Freescale MC9S08AW60汇编学习笔记(六)
2021-08-13 来源:eefocus
延时,汇编中经常要用到的功能,也就是MCU什么也不做,仅仅是拖延一段时间而已。MCU本身就有定时器、计数器,用来实现延时当然不在话下,但是一个编程的人自然更希望要实现的功能更加易于掌控,我们就用代码、用程序来实现延时,也就是采用软件进行延时。具体做法是:通过A、H:X增减指令、空操作指令nop和brn以及相应的转移指令,再利用循环结构就可以实现延时功能。既然是延时,能知道延时多长时间最好了,我们知道的是:MCU总线时钟频率为4MHz,所以一个总线周期占用的时间为0.25us,这样,只要知道每条指令所占用的总线周期就可以计算我们的程序运行了多久。实现延时自然也是这样,这些当然要用到数学知识了,放心的是还不至于用到微积分,只要耐心一点精确地计算出延时的时间并不是难事。
例子:设计一个延时10ms的延时子程序,已知MCU总线时钟频率为4MHz。
分析:由于总线时钟频率为4MHz,故一个总线周期占用的时间为0.25us,10ms延时需要执行相当于40000个总线周期的指令。我们可以先设计一个实现较小延时的子程序Re_cycle,然后多次循环调用该子程序来实现较长的时延。代码如下:
org $0070
num ds.b 1
count1 ds.b 1
org $1860
re_cycle: ;4+7*70+6=500T=125us
mov #70T,num ;4T
dbnz num,* ;7T
rts ;6T
delay_10ms: ;[4+78*(5+7+500)]+4+7*7+6=39999T
mov #78T,count1 ;4T
re_call:
bsr re_cycle ;5T
dbnz count1,re_call ;7T
mov #07T,count1 ;4T
dbnz count1,* ;7T
rts ;6T
main:
bsr delay_10ms ;5~6T
again:
nop
jmp again
org $fffe
dc.w main
每一条指令所占用的时间皆已标出,需要的就是精巧的设计和精准的计算,比如Re_cycle子程序的设计三条指令刚好500T,这里要解释一下DBNZ这个指令,它所实现的功能就是前面变量中的数自减1与0比较,不等就转移到后面的地址并执行,相等就结束该指令(也就是减1不为0转移指令)。这里肯定要问*代表什么,它代表的就是它本身所在指令的地址,dbnz num,* 指令就可以解释为num自减1不等于0就回来再执行该语句,知道num自减1等于0后结束。由注释看出,delay_10ms子程序执行完所占用的总时间为39999T,再加上在main主程序中对delay_10ms子程序的调用占用5~6T,这样没调用delay_10ms一次,便可以实现40004~40005个总线周期约10ms的延时。当然,如果设计足够好,还可以更精确,越靠近40000个T越好。
上面实现了延时10ms,那如果要实现100ms,500ms,1ms,0.1ms呢,同样的办法,全靠精巧的设计和精准的计算。下面给出延时1ms和500ms的子程序:
org $0070
num ds.b 1
count1 ds.b 1
count2 ds.b 1
org $1860
re_cycle: ;4+7*70+6=500T=125us
mov #70T,num
dbnz num,*
rts
delay_1ms: ;[4+(5+7+500)*8+6]=4106T
mov #08t,count
re_call:
bsr re_cycle
dbnz count,re_call
rts
delay_10ms: ;39999T
mov #78T,count1
re_call:
bsr re_cycle
dbnz count1,re_call
mov #07T,count1
dbnz count1,*
rts
delay_500ms: ;想法是将delay_10ms重复执行50次,这样肯定有不精确的地方,还请见谅。
mov #50T,count2
re:
bsr delay_10ms
dbnz count2,re
rts
main:
bsr delay_1ms
bsr delay_10ms
bsr delay_500ms
again:
nop
jmp again
org $fffe
dc.w main