對于需要精確計時的場景,用C語言開發單片機應用就有些困難了,本文將在開源軟件SDCC環境下對延時程序進行深入分析,不正確的地方請大家指正。
首先是單片機的三個周期:
先看這個延時程序代碼:
void delay(unsigned int val) { unsigned int j = 0; for (; val>0; val--) { for (j=0; j<125; j++) { ; } } }
通過SDCC對其進行編譯,生成*.asm(sdcc -c *.c)。雖然我們可以使用C語言開發單片機應用,但是并不代表我們不需要掌握匯編語言,在很多場合下雖然不需要我們編寫匯編語言代碼,但是看懂編譯器生成的匯編語言代碼的能力還是需要具備的。
_delay:
ar2 = 0x02
ar3 = 0x03
ar4 = 0x04
ar5 = 0x05
ar6 = 0x06
ar7 = 0x07
ar0 = 0x00
ar1 = 0x01
mov r2,dpl ; 寄存器尋址方式,將DPTR低字節存入r2中,2個機器周期
mov r3,dph; 寄存器尋址方式,將DPTR低字節存入r3中,2個機器周期
; comm.c:7: unsigned int j = 0;
00104$:
; comm.c:8: for (; val>0; val--)
mov a,r2; 寄存器尋址,2個機器周期
orl a,r3; r3與a進行邏輯或操作,1個機器周期
jz 00110$; 如果是零,則將r4置0,并傳給a,在jz 00108$將跳到結束,2個機器周期
mov r4,#0x01; 否則執行內循環,立即數尋址,1個機器周期
sjmp 00111$; 短無條件跳轉指令,2個機器周期
00110$:
movr4,#0x00; 立即數尋址,1個機器周期
00111$:
mov a,r4; 寄存器尋址,2個機器周期
jz 00108$; 判斷外循環是否結束,2個機器周期
; comm.c:10: for (j=0; j<125; j++)
mov r4,#0x7D; 0x7D為125,立即數尋址,1個機器周期
mov r5,#0x00; 立即數尋址,1個機器周期
00103$:
dec r4; 把內循環改為for (j=125; j>0; j--)了,寄存器尋址,1個機器周期
cjne r4,#0xff,00121$; r4與0xff比較,不等于轉移到00121$處,等于時表明需要向上借位,2個機
; 器周期
dec r5; 寄存器尋址,1個機器周期
00121$:
mov a,r4; 寄存器尋址,2個機器周期
orl a,r5; r3與a進行邏輯或操作,1個機器周期
jnz 00103$; 不為零轉到內循環開始處,2個機器周期
; comm.c:8: for (; val>0; val--)
dec r2; 寄存器尋址,1個機器周期
cjne r2,#0xff,00123$; 判斷是非需要借位,2個機器周期
dec r3; 寄存器尋址,1個機器周期
00123$:
sjmp 00104$; 短無條件跳轉指令,2個機器周期
00108$:
ret; 2個機器周期
val*34+2個機器周期,如果采用f_osc=11.0592MHz晶振,機器周期Tcy=1.085us,則delay函數的精度為(1*34+2)*1.085us=39.06us。
|