結(jié)果是用了5個脈沖,其中一個是調(diào)用計數(shù)器本身用的,也就是說調(diào)用一個空函數(shù)用了4個脈沖時間。好!我們再來修改一下匯編程序:
NAME DELAY
?PR?delay?DELAY SEGMENT CODE
PUBLIC delay
RSEG ?PR?delay?DELAY
delay:
mov r7,#100
djnz r7,$
RET
END
在標號delay:下面我加了兩行,我們計算一下,第一行MOV r7,#100要用一個機器周期,也就是一個脈沖。第二行djnz r7,$要循環(huán)100次每次用2個機器周期,這樣算來共是201個脈沖再加上剛才我們計算過的調(diào)用函數(shù)要4個脈沖和開關(guān)計數(shù)器用1個,總共是206個。編譯,燒寫,運行!
看來計算的沒錯呀!我們再循環(huán)多些:
NAME DELAY
?PR?delay?DELAY SEGMENT CODE
PUBLIC delay
RSEG ?PR?delay?DELAY
delay:
mov r7,#100 ;1
loop:mov r6,#50 ;100
djnz r6,$ ;50×100×2
djnz r7,loop ;100×2
RET
END
這次的計算應(yīng)該是1+100+50×100×2+100×2+5=10306。再次編譯燒寫運行!
高位數(shù)值為40,低位數(shù)值為66,則總數(shù)=40×256+66=10306。精準吧!好了!無參函數(shù)的調(diào)用就討論到此。
#define uchar unsigned char
#define uint unsigned int
uint add(uchar aa,uchar bb)
{
uint cc;
cc=aa+bb;
return(cc);
}
我們主要目的是為了表達清楚怎樣在C程序里去調(diào)用匯編子函數(shù),所以程序還是很簡單,就是把主程序傳過來的無符號字符型變量aa和bb相加,相加的結(jié)果交給無符號整型變量cc返回給主程序。編譯前我們還是點取add.c文件屬性,讓它產(chǎn)生src文件。上面的圖已顯示了編譯的過程信息。現(xiàn)在我們打開這個add.src文件:
; .\add.SRC generated from: add.c
; COMPILER INVOKED BY:
; E:\old_pc\txz001\單片機c51\KEIL2_70\Keil\C51\BIN\C51.EXE add.c BROWSE DEBUG OBJECTEXTEND SRC(.\add.SRC)
NAME ADD?
?PR?_add?ADD SEGMENT CODE
PUBLIC _add
; #define uchar unsigned char
; #define uint unsigned int
;
; uint add(uchar aa,uchar bb)
RSEG ?PR?_add?ADD
_add:
USING 0
; SOURCE LINE # 4
;---- Variable 'bb?041' assigned to Register 'R5' ----
;---- Variable 'aa?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 5
; uint cc;
; cc=aa+bb;
; SOURCE LINE # 7
MOV A,R5
ADD A,R7
MOV R7,A
CLR A
RLC A
MOV R6,A
;---- Variable 'cc?042' assigned to Register 'R6/R7' ----
; return(cc);
; SOURCE LINE # 8
; }
; SOURCE LINE # 9
?C0001:
RET
; END OF _add
END
我們還是將注釋的部分刪去,這樣便于我們分析:
NAME ADD?
?PR?_add?ADD SEGMENT CODE
PUBLIC _add
RSEG ?PR?_add?ADD
_add:
USING 0
MOV A,R5
ADD A,R7
MOV R7,A
CLR A
RLC A
MOV R6,A
RET
END
現(xiàn)在我們首先來看函數(shù)名,上面我們講過的那個無參數(shù)函數(shù)delay()的調(diào)用,產(chǎn)生的匯編子函數(shù)名就是delay,而這次我我們原來C的函數(shù)名add變成了匯編的_add。前面多了個下劃線,這就是有參數(shù)函數(shù)的特征。C語言函數(shù)名轉(zhuǎn)變?yōu)閰R編函數(shù)名的規(guī)律為:無參數(shù)傳遞時void func(void)----FUNC。寄存器參數(shù)傳遞時char func(char)----_FUNC。再入函數(shù)使用時void func(void) reentrant----_?FUNC。
不過這些名字的變化規(guī)律記沒記住好象關(guān)系并不大。我們想要用到匯編調(diào)用時,就先用C做個假函數(shù)然后產(chǎn)生匯編文件名字就自然出來,并不用我們?nèi)ス芩拿缓笕バ薷某晌覀兿胱龅膮R編程序就行了。
但是,這參數(shù)傳遞的位置規(guī)律就必須得知道,否則你就無法使用這個匯編了,我們看上面的匯編程序,第一句是將寄存器R5的值傳到A中,第二句將A與寄存器R7相加,第三句將相加的結(jié)果A的值傳給R7,后面的幾句是將剛才相加的進位值C,傳給R6,然后返回。對照本篇最上面給的那兩張表我們可以看出C子函數(shù)add.c的第一個參數(shù)aa被傳到了匯編的R7,第二個參數(shù)bb被傳到了R5,將它們相加后,返回值的低位交給了R7,高位交給了R6。完全符合參數(shù)傳遞表和返回值表所述。下面我們將匯編子程序另存為asm文件后替換掉原來的C子程序:
編譯、燒寫后運行:
這個加法函數(shù)我們沒有改動任何參數(shù)當然運行起來是不會錯的,下面我們將在匯編里將它改成乘法試試,
將標號_add:下面的語句全都改掉,程序如下?
NAME ADD?
?PR?_add?ADD SEGMENT CODE
PUBLIC _add
RSEG ?PR?_add?ADD
_add:
USING 0
MOV A,R7
MOV B,R5
MUL AB ;A與B相乘,乘積的高位值在B中,低位值在A中
MOV R7,A ;將低位值傳給R7
MOV R6,B ;將高位值傳給R6
RET
END
上面的改動我們已將原來的加法依照寄存器的傳遞規(guī)律改為乘法函數(shù),看看是否還能正常運行并正確,改完后仍編譯燒寫運行: