A. 51單片機匯編如何調用C函數
先聲明,後調出。
若C語言函數名為ABC,匯編的入口符號為_ABC。
例:CALL _ABC ,就調用的了ABC涵數。
至於如何聲明,如何傳函數參數,就要查編譯器的使用說明了。
我也沒這么做過,一般是高級語言調用低級語言,只是一個建議。
B. 51單片機上,C語言函數調用過程是怎樣 哪些東西需要壓堆棧保護起來,參數如何傳遞
就是直接跳到子程序那裡執行,至於堆棧的話,只有當用到中斷的時候再使用堆棧,一般像acc,dptr都會自動堆棧的,編譯的時候生成的
C. C51函數是如何調用
在你原來的函數基礎上,加上三個參數,分別是:
1 要操作的PORT口
2 要進行的操作
3 要操作的引腳
當然,如果你的目標很明確,可以把以上三個參數裁剪掉一些,利於系統的效率提高.
下面是我寫的示常式序,你可能參考一下:
#include<reg52.h>
#define Pin0 0x01
#define Pin1 0x02
#define Pin2 0x04
#define Pin3 0x08
#define Pin4 0x10
#define Pin5 0x20
#define Pin6 0x40
#define Pin7 0x80
#define OPT_CPL 0x00 //----取反某位操作
#define OPT_CLR 0x01 //----清零某位操作
#define OPT_SET 0x02 //----置一某位操作
void Operate(
/*這里寫你原來的參數,*/
unsigned char Port_Num,
unsigned char Opr_Style,
unsigned char Pins
)
{
//----如果在單片機PORT口范圍之內,剛讀取當前PORT口的狀
//----如果不在范圍之內,死循環
//----注意,為了效率起見,這個部分可以根據實際應用進行裁剪
if(Port_Num == 0)
{
Port_Num = P0;
}
else if(Port_Num == 1)
{
Port_Num = P1;
}
else if(Port_Num == 2)
{
Port_Num = P2;
}
else if(Port_Num == 3)
{
Port_Num = P3;
}
else
{
while(1);
}
//----如果是取反相應位,進行異或操作
//----如果清零相應位,則位與操作
//----如果置位相應位,則位或操作
//----如果都不在范圍之內,則死循環
//----這段代碼也根據實際情況裁剪
if(Opr_Style == OPT_CPL)
{
Port_Num ^= Pins;
}
else if(Opr_Style == OPT_CLR)
{
Port_Num &= ~Pins;
}
else if(Opr_Style == OPT_SET)
{
Port_Num |= Pins;
}
else
{
while(1);
}
//----如果在單片機PORT口范圍之內,剛讀取當前PORT口的狀
//----如果不在范圍之內,死循環
//----注意,為了效率起見,這個部分可以根據實際應用進行裁剪
if(Port_Num == 0)
{
P0 = Port_Num;
}
else if(Port_Num == 1)
{
P1 = Port_Num;
}
else if(Port_Num == 2)
{
P2 = Port_Num;
}
else if(Port_Num == 3)
{
P3 = Port_Num;
}
else
{
while(1);
}
//----以上的內容,可根據實際情況進行裁剪,以實現程序最優化
//----添加你的功能的其他代碼---------------
}
void main(void)
{
//----使用示例:函數功能的同時,置位P2口的P2.0,P2.5,P2.7
Operate(/*這里寫你原來的參數*/2,OPT_SET,(Pin0|Pin5|Pin7));
//----使用示例:函數功能的同時,清零P1口的P1.2,P1.5,P2.6
Operate(/*這里寫你原來的參數*/1,OPT_CLR,(Pin2|Pin5|Pin6));
}
D. 51單片機中,指針函數 在C語言程序 如何使用
你好,比較方便的實現方式是在函數的外部申請數組;在調用函數的時候傳入數組的地址進行操作。如果一定要在子函數內部申請空間並返回地址,那麼需要在子函數內部動態申請內存空間。具體的方法一般是使用標准庫中的malloc函數。對於c51函數庫,參考這個鏈接:http://www.keil.com/support/man/docs/c51/c51_malloc.htm
E. 51單片機中自定義函數調用時功能不能實現,將自定義函數寫在主函數內卻可以
自定義函數一定要放在主函數的前面,或者在主函數前聲明一下,否則不能調用,當然不能實現,還有自定義函數中盡量不要用全局變數。
F. 請問51單片機定時器延時的調用是怎麼調用的我有點不明白,謝謝
51單片機的幾種精確延時實現延時通常有兩種方法:一種是硬體延時,要用到定時器/計數器,這種方法可以提高CPU的工作效率,也能做到精確延時;另一種是軟體延時,這種方法主要採用循環體進行。 1 使用定時器/計數器實現精確延時 單片機系統一般常選用11.059 2 MHz、12 MHz或6 MHz晶振。第一種更容易產生各種標準的波特率,後兩種的一個機器周期分
別為1 μs和2 μs,便於精確延時。本程序中假設使用頻率為12 MHz的晶振。最長的延時時間可達216=65 536
μs。若定時器工作在方式2,則可實現極短時間的精確延時;如使用其他定時方式,則要考慮重裝定時初值的時間(重裝定時器初值佔用2個機器周期)。 在實際應用中,定時常採用中斷方式,如進行適當的循環可實現幾秒甚至更長時間的延時。使用定時器/計數器延時從程序的執行效率和穩定性兩方面考慮都是最佳的方案。但應該注意,C51編寫的中斷服務程序編譯後會自動加上PUSH ACC、PUSH PSW、POP PSW和POP ACC語句,執行時佔用了4個機器周期;如程序中還有計數值加1語句,則又會佔用1個機器周期。這些語句所消耗的時間在計算定時初值時要考慮進去,從初值中減去以達到最小誤差的目的。 2 軟體延時與時間計算 在很多情況下,定時器/計數器經常被用作其他用途,這時候就只能用軟體方法延時。下面介紹幾種軟體延時的方法。 2.1 短暫延時
可以在C文件中通過使用帶_NOP_( )語句的函數實現,定義一系列不同的延時函數,如Delay10us( )、Delay25us(
)、Delay40us( )等存放在一個自定義的C文件中,需要時在主程序中直接調用。如延時10 μs的延時函數可編寫如下: void Delay10us( ) { _NOP_( ); _NOP_( ); _NOP_( ); _NOP_( ); _NOP_( ); _NOP_( ); }
Delay10us( )函數中共用了6個_NOP_( )語句,每個語句執行時間為1 μs。主函數調用Delay10us(
)時,先執行一個LCALL指令(2 μs),然後執行6個_NOP_( )語句(6 μs),最後執行了一個RET指令(2
μs),所以執行上述函數時共需要10 μs。
可以把這一函數當作基本延時函數,在其他函數中調用,即嵌套調用\[4\],以實現較長時間的延時;但需要注意,如在Delay40us(
)中直接調用4次Delay10us( )函數,得到的延時時間將是42 μs,而不是40 μs。這是因為執行Delay40us(
)時,先執行了一次LCALL指令(2 μs),然後開始執行第一個Delay10us( ),執行完最後一個Delay10us(
)時,直接返回到主程序。依此類推,如果是兩層嵌套調用,如在Delay80us( )中兩次調用Delay40us(
),則也要先執行一次LCALL指令(2 μs),然後執行兩次Delay40us( )函數(84 μs),所以,實際延時時間為86
μs。簡言之,只有最內層的函數執行RET指令。該指令直接返回到上級函數或主函數。如在Delay80μs( )中直接調用8次Delay10us(
),此時的延時時間為82 μs。通過修改基本延時函數和適當的組合調用,上述方法可以實現不同時間的延時。 2.2 在C51中嵌套匯編程序段實現延時 在C51中通過預處理指令#pragma asm和#pragma endasm可以嵌套匯編語言語句。用戶編寫的匯編語言緊跟在#pragma asm之後,在#pragma endasm之前結束。 如:#pragma asm … 匯編語言程序段 … #pragma endasm 延時函數可設置入口參數,可將參數定義為unsigned char、int或long型。根據參數與返回值的傳遞規則,這時參數和函數返回值位於R7、R7R6、R7R6R5中。在應用時應注意以下幾點: ◆ #pragma asm、#pragma endasm不允許嵌套使用; ◆ 在程序的開頭應加上預處理指令#pragma asm,在該指令之前只能有注釋或其他預處理指令; ◆ 當使用asm語句時,編譯系統並不輸出目標模塊,而只輸出匯編源文件; ◆ asm只能用小寫字母,如果把asm寫成大寫,編譯系統就把它作為普通變數; ◆ #pragma asm、#pragma endasm和 asm只能在函數內使用。 將匯編語言與C51結合起來,充分發揮各自的優勢,無疑是單片機開發人員的最佳選擇。 2.3 使用示波器確定延時時間 利用示波器來測定延時程序執行時間。方法如下:編寫一個實現延時的函數,在該函數的開始置某個I/O口線如P1.0為高電平,在函數的最後清P1.0為低電平。在主程序中循環調用該延時函數,通過示波器測量P1.0引腳上的高電平時間即可確定延時函數的執行時間。方法如下: sbit T_point = P1^0; void Dly1ms(void) { unsigned int i,j; while (1) { T_point = 1; for(i=0;i<2;i++){ for(j=0;j<124;j++){;} } T_point = 0; for(i=0;i<1;i++){ for(j=0;j<124;j++){;} } } } void main (void) { Dly1ms(); } 把P1.0接入示波器,運行上面的程序,可以看到P1.0輸出的波形為周期是3 ms的方波。其中,高電平為2 ms,低電平為1 ms,即for循環結構「for(j=0;j<124;j++) {;}」的執行時間為1 ms。通過改變循環次數,可得到不同時間的延時。當然,也可以不用for循環而用別的語句實現延時。這里討論的只是確定延時的方法。 2.4 使用反匯編工具計算延時時間
用Keil
C51中的反匯編工具計算延時時間,在反匯編窗口中可用源程序和匯編程序的混合代碼或匯編代碼顯示目標應用程序。為了說明這種方法,還使用「for
(i=0;i<DlyT;i++) {;}」。在程序中加入這一循環結構,首先選擇build taget,然後單擊start/stop
debug session按鈕進入程序調試窗口,最後打開Disassembly window,找出與這部分循環結構相對應的匯編代碼,具體如下: C:0x000FE4CLRA//1T C:0x0010FEMOVR6,A//1T C:0x0011EEMOVA,R6//1T C:0x0012C3CLRC//1T C:0x00139FSUBBA,DlyT //1T C:0x00145003JNCC:0019//2T C:0x00160E INCR6//1T C:0x001780F8SJMPC:0011//2T
可以看出,0x000F~0x0017一共8條語句,分析語句可以發現並不是每條語句都執行DlyT次。核心循環只有0x0011~0x0017共6條語
句,總共8個機器周期,第1次循環先執行「CLR A」和「MOV
R6,A」兩條語句,需要2個機器周期,每循環1次需要8個機器周期,但最後1次循環需要5個機器周期。DlyT次核心循環語句消耗
(2+DlyT×8+5)個機器周期,當系統採用12 MHz時,精度為7 μs。 當採用while (DlyT--)循環體時,DlyT的值存放在R7中。相對應的匯編代碼如下: C:0x000FAE07MOVR6, R7//1T C:0x00111F DECR7//1T C:0x0012EE MOVA,R6//1T C:0x001370FAJNZC:000F//2T 循環語句執行的時間為(DlyT+1)×5個機器周期,即這種循環結構的延時精度為5 μs。 通過實驗發現,如將while (DlyT--)改為while (--DlyT),經過反匯編後得到如下代碼: C:0x0014DFFE DJNZR7,C:0014//2T 可以看出,這時代碼只有1句,共佔用2個機器周期,精度達到2 μs,循環體耗時DlyT×2個機器周期;但這時應該注意,DlyT初始值不能為0。 注意:計算時間時還應加上函數調用和函數返回各2個機器周期時間。
G. 單片機 C語言,如何調用外部自定義函數。
函數定義好以後,要被其它函數調用了才能被執行。C
語言的函數是能相互調用的,
但在調用函數前,必須對函數的類型進行說明,就算是標准庫函數也不例外。標准庫函數的
說明會被按功能分別寫在不一樣的頭文件中,使用時只要在文件最前面用#include
預處理語
句引入相應的頭文件。如前面一直有使用的
printf
函數說明就是放在文件名為
stdio.h
的
頭文件中。調用就是指一個函數體中引用另一個已定義的函數來實現所需要的功能,這個時候函
數體稱為主調用函數,函數體中所引用的函數稱為被調用函數。一個函數體中能調用數個
其它的函數,這些被調用的函數同樣也能調用其它函數,也能嵌套調用。筆者本人認為
主函數只是相對於被調用函數而言。在
c51
語言中有一個函數是不能被其它函數所調用的,
它就是
main
主函數。調用函數的一般形式如下:
函數名
(實際參數表)
「函數名」就是指被調用的函數。實際參數表能為零或多個參數,多個參數時要用逗
號隔開,每個參數的類型、位置應與函數定義時所的形式參數一一對應,它的作用就是把參
數傳到被調用函數中的形式參數,如果類型不對應就會產生一些錯誤。調用的函數是無參函
數時不寫參數,但不能省後面的括弧。
在以前的一些例子我們也能看不一樣的調用方式:
1.函數語句
如
printf
("Hello
World!n");
這是在
我們的第一個程序中出現的,它以
"Hello
World!n"為參數調用
printf
這個庫函數。在這里函數調用被看作了一條語句。
2.函數參數
「函數參數」這種方式是指被調用函數的返回值當作另一個被調用函數的實際參
數,如
temp=StrToInt(CharB(16));CharB
的返回值作為
StrToInt
函數的實際參數傳遞。
3.函數表達式
而在上一篇的例子中有
temp
=
Count();這樣一句,這個時候函數的調用作為一個運算
對象出現在表達式中,能稱為函數表達式。例子中
Count()返回一個
int
類型的返回
值直接賦值給
temp。注意的是這種調用方式要求被調用的函數能返回一個同類型的值,
不然會出現不可預料的錯誤。
前面說到調用函數前要對被調用的函數進行說明。標准庫函數只要用#include
引入已
寫好說明的頭文件,在程序就能直接調用函數了。如調用的是自定義的函數則要用如下形
式編寫函數類型說明
類型標識符
函數的名稱(形式參數表);
這樣的說明方式是用在被調函數定義和主調函數是在同一文件中。你也能把這些寫到
文件名.h
的文件中用#include
"文件名.h"引入。如果被調函數的定義和主調函數不是在同
一文件中的,則要用如下的方式進行說明,說明被調函數的定義在同一項目的不一樣文件之上,
其實庫函數的頭文件也是如此說明庫函數的,如果說明的函數也能稱為外部函數。
extern
類型標識符
函數的名稱(形式參數表);
函數的定義和說明是完全不一樣的,在編譯的角度上看函數的定義是把函數編譯存放在
ROM
的某一段地址上,而函數說明是告訴編譯器要在程序中使用那些函數並確定函數的地
址。如果在同一文件中被調函數的定義在主調函數之前,這個時候能不用說明函數類型。也就
是說在
main
函數之前定義的函數,在程序中就能不用寫函數類型說明了。能在一個函
數體調用另一個函數(嵌套調用),但不允許在一個函數定義中定義另一個函數。還要注意
的是函數定義和說明中的「類型、形參表、名稱」等都要相一致。
H. 51單片機 c語言里 _nop_ 函數怎麼用 具體一點 求高手指教
一個nop為1個指令周期,主要用於精確定時或者延時
nop指令的作用:
1)就是通過nop指令的填充(nop指令一個位元組),使指令按字對齊,從而減少取指令時的內存訪問次數。(一般用來內存地址偶數對齊,比如有一條指令,佔3位元組,這時候使用nop指令,cpu 就可以從第四個位元組處讀取指令了。)
2)通過nop指令產生一定的延遲,但是對於快速的CPU來說效果不明顯,可以使用rep前綴,多延遲幾個時鍾;-->具體應該說是佔用了3個時鍾脈沖!
3)i/o傳輸時,也會用一下 nop,等待緩沖區清空,匯流排恢復;
4)清除由上一個算術邏輯指令設置的flag位;
5)破解:)對於原程序中驗證部分使用nop來填充,使驗證失效;
6)有一個朋友說的比較厲害--在太空梭控製程序中防止程序跳飛!
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/erazy0/archive/2010/12/12/6071281.aspx
I. 如何調用單片機函數模塊
看你要調用的函數是什麼類型的咯。
1、如果是這種預設的,void可寫可不寫,如:
fuction()
//或者void
fuction()
或者fuction(
void
)
或者void
fuction(
void
)
{
//函數實體
}
這種既沒有入參,也沒有出參、返回值的,就在你要調用的地方直接這么寫fuction();
2、有入參,類型預設的,如
void
fuction(
unsigned
char
Data
)
//當然數據類型有很多,這個看用戶需要
{
//函數實體
}
調用的時候,就這么寫
fuction(DATA);//保證DATA和Data的數據類型一樣比較好
3、有返回值的,甚至有入參的,如
unsigned
char
fuction(
unsigned
char
Data
)
{
unsigned
char
n;
//函數實體
return
n;
}
調用的時候,把這個函數的返回值賦給其他的變數,如m
=
fuction(
DATA
);
//還是那句話,數據類型不要變來變去,最後保持一致,否則可能導致未知的錯誤。
以上字字手打,希望對你有幫助
J. 51單片機延時函數聲明和調用
聲明很簡單,例如延時 delay( x); 這是調用的,聲明就在這個前面加void delay( unsigned char x);