古詩詞大全網 - 成語查詢 - C51語言中為什麽需要包含頭文件

C51語言中為什麽需要包含頭文件

我來回答妳的問題吧,前幾天對這個方面有壹定的深入了解,也寫下了大量的筆記

雖然C編程的時候,對於不同的芯片,有不同的頭文件,但是,萬變不離其宗。

只要學會了寫自己的頭文件,就可以應付各類型號單片機了,就算妳用的是AT89C2052,還是AT89C51,STC12C等等,都可以用壹個頭文件reg51.h 不過要做相應的修。

以下是我對reg51.h個人的見解:(對於妳很有用的) 後面帶上了在編寫C51時帶用的頭文件,及其內部函數和宏定義的詳細解說。

想了解如下方面的知識來來郵amwjie72@163.com

壹, C51內存結構深度剖析

二, reg51.頭文件剖析

三, 淺淡變量類型及其作用域

四, C51常用頭文件

五, 淺談中斷

六, C51編譯器的限制

七, 小淡C51指針

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

reg51.頭文件剖析

我們平時寫單片機應用程序的時候,所使用的頭文件大多都是用的的reg51.h或是用reg52.h。會寫C51的人都會用,但對其頭文件內部的定義有所了解的人確並不多。

下面對其內部做詳細解釋,方便讀者作進壹步的了解,並能運用各類型號的單片機。因為增強型號的單片機的增強功能都是通過特殊功能寄存器控制。

打開 reg52.h 頭文件,會發現是由大量的 sfr ,sbit的聲明組成,甚至於還有sfr16.其實這樣的聲明都是與單片機內部功能寄存器(特殊功能寄存器)聯系起來的,下面對其做出詳細解釋

sfr: 聲明變量

SFR 聲明壹個變量,它的聲明與其它的C變量聲明基本相同,唯壹的區別,SFR在聲明的同時為其指定特殊功能寄存器作為存儲地址,而不同於C變量聲明的整型,字符型等等由編譯器自動分配存儲空間。

如reg52.h頭文件,第壹條聲明就是sfr P0 = 0x80;

此處聲明壹個變量P0,並指定其存儲地址為特殊功能寄存器0x80;,在加入reg52.h頭文件後。編寫應用程序時P0就可以直接使用而無需定義,對P0的操作就是,對內部特殊功能寄存器(0x80對應用MCU的P0口)的操作,可進行讀寫操作。

如果將第壹條聲明改為sfr K0 = 0x80; 那麽,如果要把單片機的P0口全部拉低,則不能寫P0=0x00;而應保存後再在應用程序中寫成K0=0x00;否則編譯器會提示“P0為未定義標識符”

使用方法:

sfr [variable] = [address] //為變量分配壹個特殊功能寄存器。

1 等號右邊,只能是十進制,十六進制整型的數據常量,,不允許帶操作符的表達式

經典的8051內核支持的SFR地址從0x80H~0xFF 飛利浦80C51MX系列0x180H~0x1FF

2 SFR不能聲明於任何函數內部,包括main函數。只能聲明於函數外。

3 用SFR聲明壹個變量後,不能用取地址運算符&獲取其地址, 編譯無法通過,編譯器會提示非法操作。

4 有壹點須特別註意,51內核0x80~0xff,為特殊功能寄存器地址區間,但並不是所有的地址都有定義,如果說妳所用的MCU芯片上對於某個地址沒有定義,那麽用sfr在定義變量的時候,不要把變量的地址分配到未定義的特殊功能寄存器上,雖然編譯時能通過,用KEIL仿真時貌似是沒有問題,但下載到芯片裏運行時,是會出問題的。比如說,向壹個未定義的特殊功能寄存器執行讀操作,讀出來的就是壹個未知的數。(讀者可自行測試,先把串口通信調通,然後做壹個簡單的人機交互。讀出壹個數後,再發給計算機,用串口調試助手或是串口監控查看。這用方法在仿真的時候很有用。)所以具體那些特殊功能寄存器能夠用,就要查看妳使用的芯片手冊。

5 若遇到增強性的單片機,只要知道其擴展的特殊功能寄存器的地址,用SFR定

就可以很方便進行編程。

sbit: 聲明變量

sbit 同樣是聲明壹個變量,和SFR 使用方法類似,但是SBIT是用來聲明壹個位變量,因為,在51系列的應用中,非常有必要對SFR的單個位進行存取,而通過bit 數據類型,使其具備位尋址功能。

如,在reg52.h中有如下聲明

sfr IE = 0xA8;

sbit EA = IE^7;

sbit ET2 = IE^5; //8052 only

sbit ES = IE^4;

sbit ET1 = IE^3;

sbit EX1 = IE^2;

sbit ET0 = IE^1;

sbit EX0 = IE^0;

所以,對EA的操作即是對IE最高位的操作。

但如果想讓 SP DPL DPH PCON TMOC TL0 TL1 TH0 TH1 SBUF這些特殊功能寄存器具備位尋址,采用上述如IE類似的定義,是不行的,雖然修改後,在編譯的時候不會出現錯誤,但只要用到妳定義的位變量名時就會出錯。原因是,只有特殊功能寄存器的地址是8的倍數(十六進制以0或8結尾)才能進行位尋址。

打開reg52.h頭文件可以看到,所有用sbit聲明了的特殊功能寄存器的地址均是以0或8結尾

如硬要達到上述要求,可用帶參的宏定義來完成。此處不做詳細說明(意義並不大)。

下面對sbit的使用做詳細介紹:

隨著8051的應用,非常有必要對特殊功能寄存器的單個bit位進行存取,C51編譯器通過sbit 數據類型,提供了對特殊功能寄存器的位操作。

以下是sbit的三種應用形式:

壹, sbit name = sfr-name^bit-position;

sfr PSW =0xD0;

sfr IE =0xA8;

sbit OV= PSW^2;

sbit CY=PSW^7;

sbit EA= IE^7;

二, sbit name= sft-address^bit-position;

sbit OV =0xD0^2;

sbit CY =0xD0^7;

sbit EA =0xA8^7;

三, sbit name= sbit-address;

sbit OV =0xD2;

sbit CY =0xD7;

sbit EA =0xAF;

現對上述三種形式的聲明做必要的說明

第壹種形式sbit name = sfr-name^bit-position;如sbit OV= PSW^2; 當中的這個特殊功能寄存器必須在此之前已經用sfr 定義,否則編譯會出錯。

bit-position範圍從0~7;

第二種形式 sbit name= sft-address^bit-position如sbit OV =0xD0^2; 與第壹種形式不同之外在於,此處直接使用PSW的地址.第壹種形式須先定義PSW

第三種形式. sbit name= sbit-address 如sbit OV =0xD2 是直接用的OV的地址

OV的地址計算方式,是OV所在的寄存器地址加上OV的bit-position

註意:

不是所有的SFR都可位尋址。只有特殊功能寄存器的地址是8的倍數(十六進制以0或8結尾)才能進行位尋址,並且sbit聲明的變量名,雖可以是任意取,但是最好不要以下劃線開頭,因為以下劃線開頭的都保留給了C51的頭文件做保留字。

sfr16: 聲明變量

許多8051的派生型單片機,用兩個連續地址的特殊功能寄存器,來存儲壹個16bit的值。例如,8052就用了0xCC和0xCD來保存定時/計數寄存器2的高字節和低字節。編譯器提供sfr16這種數據類型,來保存兩個字節的數據。虛擬出壹個16bit的寄存器。

如下:

sfr16 T2 = 0xCC

存儲方面為小端存儲方式,低字節在前,高字節在後。定義時,只寫低字節地址,如上,則定義T2為壹個16位的特殊功能寄存器。 T2L= 0CCh, T2H= 0CDh

使用方法:

sfr [variable] = [low_address]

1 等號右邊,只寫兩個特殊功能寄存器的低地址,且只能是十進制,十六進制的整型數據常量,不允許帶操作符的表達式

2 SFR不能聲明於任何函數內部,包括main函數。只能聲明於函數外。

3 用SFR聲明壹個變量後,不能用取地址運算符&獲取其地址, 編譯無法通過,編譯器會提示非法操作。

4 當妳向壹個sfr16寫入數據的時候,KEIL CX51 編譯器生成的代碼,是先寫高字節,後寫低字節,(可通過返匯編窗口查看)在有些情況下,這並非我們所想要的操作順序。使用時,須註意。

5 當妳所要寫入sfr16的數據,當是高字節先寫還是低字節先寫非常重要的時候,就只能用sfr 這個關鍵字來定義,並且任意時刻只保存壹個字節,這樣操作才能保證寫入正確。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

C51常用頭文件

在KEIL 中,對於單片機所使用的頭文件,除了reg51 reg52以外,還有壹些從各芯片制商的官網下載與reg51,reg52功能類似的頭文件,需了解透外,還要對各類型單片機均可通用且相當有用的的頭文件,做相應的了解。因為,內部所包含的函數與宏定義,可以及大的方便我們編寫應用程序。

1字符函數 ctype.h

1 extern bit isalpha(char);

功能:檢查參數字符是否為英文字母,是則返回1

2 extern bit isalnum(char)

功能:檢查字符是否為英文字母或數字字符,是則返回1

3 extern bit iscntrl(char)

功能:檢查參數值是否在0x00~0x1f 之間或等於0x7f,是則返回1

4 extern bit isdigit(char)

功能: 檢查參數是否為數字字符,是則返回1

5 extern bit isgraph(char)

功能: 檢查參數值是否為可打印字符,是則返回1,可打印字符為0x21~0x7e

6 extern bit isprint(char)

功能:除了與isgraph相同之外,還接受空格符0x20

7 extern bit ispunct(char)

功能:不做介紹。

8 extern bit islower(char)

功能:檢查參數字符的值是否為小寫英文字母,是則返回1

9 extern bit isupper(char)

功能:檢查參數字符的值是否為大寫英文字母,是則返回1

10 extern bit isspace(char)

功能:檢查字符是否為下列之壹,空格,制表符,回車,換行,垂直制表符和送紙。如果為真則返回1

11 extern bit isxdigit(char)

功能:檢查參數字符是否為16進制數字字符,是則返回1

12 extern char toint(char)

功能:將ASCII字符0~9 a~f(大小寫無關)轉換成對應的16進制數字,

返回值00H~0FH

13 extern char tolower(char)

功能:將大寫字符轉換成小寫形式,如字符變量不在A~Z之間,則不作轉換而直接返回該字符

14 extern char toupper(char)

功能:將小寫字符轉換成大寫形式,如字符變量不在a~z之間,則不作轉換而直接返回該字符

15 define toascii(c) ((c)&0x7f)

功能:該宏將任何整形數值縮小到有效的ASCII範圍之內,它將變量和0x7f相與從而去掉第7位以上的所有數位

16 #define tolower(c) (c-‘A’+’a’)

功能:該宏將字符與常數0x20 逐位相或

17 #define toupper(c) ((c)-‘a’+’A’)

功能:該宏將字符與常數0xdf 逐位相與

2數學函數 math.h

extern int abs (int val);

extern char cabs (char val);

extern long labs (long val);

extern float fabs (float val);

功能:返回絕對值。上面四個函數,除了形參和返回值不壹樣之外,

其它功能完全相同。

extern float exp (float val);

extern float log (float val);

extern float log10 (float val);

功能: exp 返回eval

log 返回 val 的自然對數

log10 返回 以10為底,val的對數

extern float sqrt (float val);

功能: 返回val的正平方根

extern int rand();

extern void srand(int n);

功能: rand返回壹個0到32767之間的偽隨機數,srand用來將隨機數發生器初始化成壹個已知的(期望)值。

Keil uVision3中的math.h庫中,不包含此函數。

extern float sin (float val);

extern float cos (float val);

extern float tan (float val);

功能: 返回val的正弦,余弦,正切值。val為弧度 fabs(var) <=65535

extern float asin (float val);

extern float acos (float val);

extern float atan (float val);

extern float atan2 (float y, float x);

功能: asin 返回val的反正弦值。acos 返回val的反余弦值。

atan 返回val的反正切值。

asin atan acos的值域均為 -π/2~+π/2

atan2返回x/y,的反正切值,其值域為-π~+π

extern float sinh (float val);

extern float cosh (float val);

extern float tanh (float val);

功能:cosh返回var的雙曲余弦值,sinh返回var的雙曲正弦值,

tanh返回var的雙曲正切值。

extern float ceil (float val);

功能: 向上取整,返回壹個大於val的最小整數。

extern float floor (float val);

功能: 向下取整,返回壹個小於val的最大整數。

extern float pow (float x, float y);

功能: 計算計算xy的值。當(x=0,y<=0)或(x<0.y不是整數)時會發生錯誤。

extern void fpsave(struct FPBUF *p)

extern void fprestore(struct FPBUF *p)

功能:fpsave 保存浮點了程序的狀態,fprestore恢復浮點子程序的原始狀態,當中斷程序中需要執行浮點運算時,這兩個函數是很有用的。

註: Keil uVision3中的math.h庫中,不包含此函數。

3絕對地址訪問 absacc.h

#define CBYTE ((unsigned char volatile code *) 0)

#define DBYTE ((unsigned char volatile data *) 0)

#define PBYTE ((unsigned char volatile pdata *) 0)

#define XBYTE ((unsigned char volatile xdata *) 0)

功能:CBYTE 尋址 CODE區

DBYTE 尋址 DATA區

PBYTE 尋址 XDATA(低256)區

XBYTE 尋址 XDATA區

例: 如下指令在對外部存儲器區域訪問地址0x1000

xvar=XBYTE[0x1000];

XBYTE[0x1000]=20;

#define CWORD ((unsigned int volatile code *) 0)

#define DWORD ((unsigned int volatile data *) 0)

#define PWORD ((unsigned int volatile pdata *) 0)

#define XWORD ((unsigned int volatile xdata *) 0)

功能:與前面的壹個宏相似,只是它們指定的數據類型為unsigned int .。

通過靈活運用不同的數據類型,所有的8051地址空間都是可以進行訪問。

DWORD[0x0004]=0x12F8;

即內部數據存儲器中(0x08)=0x12; (0x09)=0xF8

4 內部函數 intrins.h

extern unsigned char _cror_ (unsigned char var, unsigned char n);

extern unsigned int _iror_ (unsigned int var, unsigned char n);

extern unsigned long _lror_ (unsigned long var, unsigned char n);

功能:將變量var 循環右移 n 位。

上三個函數的區別在於,參數及返回值的類型不同

extern unsigned char _crol_ (unsigned char var, unsigned char n);

extern unsigned int _irol_ (unsigned int var, unsigned char n);

extern unsigned long _lrol_ (unsigned long var, unsigned char n);

功能:將變量var 循環左移 n 位。

上三個函數的區別在於,參數及返回值的類型不同

例如:

#include<intrins.h>

void main()

{

unsigned int y;

y=0x0ff0;

y=_irol_(y,4); //y=0xff00

y=_iror_(y,4); //y=0x0ff0

}

void _nop_(void);

功能:_nop_產生壹個8051單片機的NOP指令,C51編譯器在程序調用_nop_ 函數的地方,直接產生壹條NOP指令。

另外,站長團上有產品團購,便宜有保證