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