结果是用了5个脉冲,其中一个是调用计数器本身用的,也就是说调用一个空函数用了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,$要循环100次每次用2个机器周期,这样算来共是201个脉冲再加上刚才我们计算过的调用函数要4个脉冲和开关计数器用1个,总共是206个。编译,烧写,运行!
看来计算的没错呀!我们再循环多些:
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
这次的计算应该是1+100+50×100×2+100×2+5=10306。再次编译烧写运行!
高位数值为40,低位数值为66,则总数=40×256+66=10306。精准吧!好了!无参函数的调用就讨论到此。
#define uchar unsigned char
#define uint unsigned int
uint add(uchar aa,uchar bb)
{
uint cc;
cc=aa+bb;
return(cc);
}
我们主要目的是为了表达清楚怎样在C程序里去调用汇编子函数,所以程序还是很简单,就是把主程序传过来的无符号字符型变量aa和bb相加,相加的结果交给无符号整型变量cc返回给主程序。编译前我们还是点取add.c文件属性,让它产生src文件。上面的图已显示了编译的过程信息。现在我们打开这个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
现在我们首先来看函数名,上面我们讲过的那个无参数函数delay()的调用,产生的汇编子函数名就是delay,而这次我我们原来C的函数名add变成了汇编的_add。前面多了个下划线,这就是有参数函数的特征。C语言函数名转变为汇编函数名的规律为:无参数传递时void func(void)----FUNC。寄存器参数传递时char func(char)----_FUNC。再入函数使用时void func(void) reentrant----_?FUNC。
不过这些名字的变化规律记没记住好象关系并不大。我们想要用到汇编调用时,就先用C做个假函数然后产生汇编文件名字就自然出来,并不用我们去管它的命名,然后去修改成我们想做的汇编程序就行了。
但是,这参数传递的位置规律就必须得知道,否则你就无法使用这个汇编了,我们看上面的汇编程序,第一句是将寄存器R5的值传到A中,第二句将A与寄存器R7相加,第三句将相加的结果A的值传给R7,后面的几句是将刚才相加的进位值C,传给R6,然后返回。对照本篇最上面给的那两张表我们可以看出C子函数add.c的第一个参数aa被传到了汇编的R7,第二个参数bb被传到了R5,将它们相加后,返回值的低位交给了R7,高位交给了R6。完全符合参数传递表和返回值表所述。下面我们将汇编子程序另存为asm文件后替换掉原来的C子程序:
编译、烧写后运行:
这个加法函数我们没有改动任何参数当然运行起来是不会错的,下面我们将在汇编里将它改成乘法试试,
将标号_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
上面的改动我们已将原来的加法依照寄存器的传递规律改为乘法函数,看看是否还能正常运行并正确,改完后仍编译烧写运行: