KeilC51使用詳解 (三)
C51強大功能及其高效率的重要體現之一在于其豐富的可直接調用的庫函數,多使用庫函數使程序代碼簡單,結構清晰,易于調試和維護,下面介紹C51的庫函數系統。
本文引用地址:http://m.butianyuan.cn/article/201611/315905.htm第一節(jié) 本征庫函數(intrinsic routines)和非本征證庫函數
C51提供的本征函數是指編譯時直接將固定的代碼插入當前行,而不是用ACALL和LCALL語句來實現,這樣就大大提供了函數訪問的效率,而非本征函數則必須由ACALL及LCALL調用。C51的本征庫函數只有9個,數目雖少,但都非常有用,列如下:_crol_,_cror_:將char型變量循環(huán)向左(右)移動指定位數后返回_iror_,_irol_:將int型變量循環(huán)向左(右)移動指定位數后返回_lrol_,_lror_:將long型變量循環(huán)向左(右)移動指定位數后返回_nop_: 相當于插入NOP_testbit_: 相當于JBC bitvar測試該位變量并跳轉同時清除。_chkfloat_: 測試并返回源點數狀態(tài)。使用時,必須包含#inclucle
第二節(jié) 幾類重要庫函數
1. 專用寄存器include文件
例如8031、8051均為REG51.h其中包括了所有8051的SFR及其位定義,一般系統都必須包括本文件。
2. 絕對地址include文件absacc.h
該文件中實際只定義了幾個宏,以確定各存儲空間的絕對地址。
3. 動態(tài)內存分配函數,位于stdlib.h中
4. 緩沖區(qū)處理函數位于“string.h”中
其中包括拷貝比較移動等函數如:memccpy memchr memcmp memcpy memmove memset這樣很方便地對緩沖區(qū)進行處理。
5. 輸入輸出流函數,位于“stdio.h”中
流函數通8051的串口或用戶定義的I/O口讀寫數據,缺省為8051串口,如要修改,比如改為LCD顯示,可修改lib目錄中的getkey.c及putchar.c源文件,然后在庫中替換它們即可。
第三節(jié) Keil C51庫函數原型列表
1. CTYPE.H
bit isalnum(char c); bit isalpha(char c); bit iscntrl(char c); bit isdigit(char c); bit isgraph(char c); bit islower(char c); bit isprint(char c); bit ispunct(char c); bit isspace(char c); bit isupper(char c); bit isxdigit(char c); bit toascii(char c); bit toint(char c); char tolower(char c); char __tolower(char c); char toupper(char c); char __toupper(char c);
2. INTRINS.H
unsigned char _crol_(unsigned char c,unsigned char b); unsigned char _cror_(unsigned char c,unsigned char b); unsigned char _chkfloat_(float ual); unsigned int _irol_(unsigned int i,unsigned char b); unsigned int _iror_(unsigned int i,unsigned char b); unsigned long _irol_(unsigned long l,unsigned char b); unsigned long _iror_(unsigned long L,unsigned char b); void _nop_(void); bit _testbit_(bit b);
3. STDIO.H
char getchar(void); char _getkey(void); char *gets(char * string,int len); int printf(const char * fmtstr[,argument]…); char putchar(char c); int puts (const char * string); int scanf(const char * fmtstr.[,argument]…); int sprintf(char * buffer,const char *fmtstr[;argument]); int sscanf(char *buffer,const char * fmtstr[,argument]); char ungetchar(char c); void vprintf (const char *fmtstr,char * argptr); void vsprintf(char *buffer,const char * fmtstr,char * argptr);
4. STDLIB.H
float atof(void * string); int atoi(void * string); long atol(void * string); void * calloc(unsigned int num,unsigned int len); void free(void xdata *p); void init_mempool(void *da
5. STRING.H
void *memccpy (void *dest,void *src,char c,int len); void *memchr (void *buf,char c,int len); char memcmp(void *buf1,void *buf2,int len); void *memcopy (void *dest,void *SRC,int len); void *memmove (void *dest,void *src,int len); void *memset (void *buf,char c,int len); char *strcat (char *dest,char *src); char *strchr (const char *string,char c); char strcmp (char *string1,char *string2); char *strcpy (char *dest,char *src); int strcspn(char *src,char * set); int strlen (char *src); char *strncat (char 8dest,char *src,int len); char strncmp(char *string1,char *string2,int len); char strncpy (char *dest,char *src,int len); char *strpbrk (char *string,char *set); int strpos (const char *string,char c); char *strrchr (const char *string,char c); char *strrpbrk (char *string,char *set); int strrpos (const char *string,char c); int strspn(char *string,char *set);
第六章 Keil C51例子:Hello.c
Hello位于/C51/excmples/Hello/目錄,其功能是向串口輸出“Hello,world”整個程序如下:#pragma DB OE CD#indule
第一節(jié) uVision for Windows的使用步驟
(1) file_new新建一個hello.c文件,輸入如上內容或直接用目錄下源文件。(2) file_save或工具欄將文件存盤。(3) project_new project創(chuàng)建一個project名為hello,并在其中加入hello.c。這時該project已是打開狀態(tài),或用open project打開已存在的project。(4) option_C51 compiler中選出至少包括兩項DB OE。(5) option_dscope Debugger選中hello/DS51.INI查看DS51.INI看其是否為: “load…/…/BIN/8051.DLL map 0, 0xffff”否則修改。(6) 在option_make選make文件順序。(7) project選Build project,看是否有語法錯誤,若無則生成HEX文件,若有則修改源文件后重復以上部分步驟。(8) run_dScope debugger進入dScope51后裝入hello則可用go直接運行看serial窗口有無輸出,正常每系統運行一次,serial窗口均出現一個“Hello,world”表明運行無誤。
第二節(jié) Ishell for Dos使用步驟
(1) 進入Ishell 用Setup editer選擇編輯器。然后單擊Edit或用Edit命令編輯hello.c源文件,存盤,也可以在files窗口中直接選中hello.c。(2) 用cd改換project目錄至hello目錄。(3) 在setup_target一項目選8051。(4) 在setup_C51中輸出DB OE。(5) 在setup_project輸入project名hello。(6) 在setup_save保存Ishell.CFG文件。(7) 編輯一個Link文件hello.lin中有“hell.obj”一行。(8) 由光標落在files菜單中的Hello.c上,單擊“translate”,如無語法錯,再擊“link”,則Hex文件生成。(9) 單擊Simulate如在8051.CDF中選Simulate為dScope則進入dScope調試直接“Go”,看serial窗口輸出為“Hello.world”。(10) 如程序有誤修改源代碼后不必再translate或link了,只要一步Amake即可。若project中包括不止一個文件,在DOS的Ishell中不能用Translate編譯,而應建立bat文件,直接在命令窗編譯,然后link連接。如還需用Translate則只能多個文件分別編譯,然后連接。
第七章 Keil C51的代碼效率
C51程序編譯生成匯編代碼的效率,是由許多因素共同決定的,對于Keil C51,主要受以下兩種因素影響:
第一節(jié) 存儲模式的影響
存儲模式決定了缺省變量的存儲空間,而訪問各空間變量的匯編代碼的繁簡程度決定了代碼率的高低。例如:一個整形變量i,如放于內存18H、19H空間,則++i的操作編譯成四條語句:INC 0x19MOV A,0x19JNZ 0x272DINC 0x180x272D:而如果放于外存空間0000H、0001H則++i的操作編譯成九條語句:MOV DPTR,0001MOVX A,@ DPTRINC AMOVX @ DPTR,AJNz #5MOV OPTR,#0000MOVX A,@DPTRINC AMOVX @ DPTR,A就匯編之后的語句而言,對外部存儲器的操作較內部存儲器操作代碼率要低得多,生成的語句為內存的兩倍以上,而程序中有大量的這種操作,可見存儲模式對代碼率的響了。因此程序設計的原則是1、存儲模式從small-Compact-large依次選擇,實在是變量太多,才選large模式。2、即使選擇了large模式,對一些常用的局部的或者可放于內存中的變量,最好放于內存中,以盡量提高程序的代碼率。
第二節(jié) 程序結構的影響
程序的結構單元包括模塊、函數等等。同樣的功能,如果結構越復雜,其所涉及的操作、變量、功能模塊函數等就越多,較之結構性好,代碼簡單的程序其代碼率自然就低得多。此外程序的運行控制語句,也是影響代碼率的關鍵因素,例如:switch -case語句,許多編譯器都把它們譯得非常復雜,Keil C51也不例外,相對較為簡易的Switch-case語句,編譯成跳轉指令形式,代碼率較高,但對較為復雜的Switch-Case,則要調用一個系統庫函數?C?ICASE進行處理,非常復雜。再如if( ),while( ),等語句也是代碼相對較低的語句,但編譯以后比switch-case要高得多。因此建議設計者盡量少用switch-case之類語句來控制程序結構,以提高代碼率。除以上兩點外,其它因素也會對代碼率產生影響,例如:是否用寄存器傳遞參數 即NOAREGS選項是否有是否包括調試信息:即DEBUG選項是否包括擴展的調試信息:即BJECTEXTEND
第八章 dScope for Windows使用詳解
第一節(jié) 概述
1. 主窗口(Mainframe Window)
可設置其它各種調試窗口,設置斷點、觀察點,修改地址空間,加載文件等等;
2. 調試窗口(DEBUG Window)
支持用戶程序的各種顯示方式,可連續(xù)運行,單步運行用戶程序,并可在線 匯編;
3. 命令窗口(Command Window)
支持命令行的輸入;
4. 觀察窗口(Watch Window)
可設置所要觀察的變量、表達式等;
5. 寄存器窗口(Registe Window)
顯示內部寄存器的內容,程序運行次數等;
6. 串口窗口(Serical Windows)
顯示串口接收和發(fā)送的數據;
7. 性能分析窗口
顯示所要觀察的各程序段占用CPU的空間;
8. 內存窗口(Memory Window)
顯示所選擇的內存中的數據;
9. 符號瀏覽窗口(Symbol Browser Window)
顯示各種符號名稱,包括專有符號,用戶自定義符號(函數名、變量、標號)等;
10. 調用線窗口(Call-Stack Window)
動態(tài)顯示當前執(zhí)行的程序段的函數調用關系;
11. 代碼覆蓋窗口
提供當前模塊內各程序段中被執(zhí)行代碼的比率;。
12. 外圍設備窗口(peripherals)
可顯示I/O口,定時器,中斷,串口等外圍設備狀態(tài);
第二節(jié) dScope for Windows基本操作
1. 指定初始化文件
在uVision的Option菜單dScope Debugger中指定dScope的初始化文件,用uVision的RUN啟動dScope將自動加載此初始化文件,自動執(zhí)行其中命令;下面是一個例子,可以看出調入一個調試代碼的過程。Ds51.ini:load 8051.dllload testslog>>test.logxtal=11.0592define button "go to main","g,main"ws RevCounterws rm.rg,mainPA RESETPA serialPA timer0
2. 觀察變量
方法1:命令行WS expr
3. 顯示RAM的值
d i(x,d):起始地址,終止地址d 變量名
4. 觀察堆棧
View->Call-stack->Show invocation,可以跟蹤調用過程;
5. 中斷處理程序調試
在裝入8051.dll后,在dScope的主菜單中將增加Peripherial,其有4個字菜單:I/0 port:Pi端口狀態(tài)Interrupt:中斷設置Timer:定時器中斷狀態(tài)Serial:串口中斷狀態(tài)設置相應的中斷請求標志位即可產生中斷。
6. 性能分析(Performance Analyzer:PA)
PA用來分析一段代碼執(zhí)行占用CPU的百分比。定義:命令行 PA func_name
第三節(jié) dScope for Windows命令文件的編制
dScope除了用命令行的方式進行調試以外,還可將各種調試命令匯集于一個調試文件中,然后調用該文件,就可達到自動測試用戶源代碼的目的。dScope的命令文件支持C/PL/M的格式,因而編制調試命令文件與編制C語言程序有些類似。
1. 地址空間及地址空間類型
(1) 地址空間分段
dScope提供的最大可用空間為16M,實際上我們只用以下三段:① 內部數據空間段(0X00段或D段)0X00:0X0000~0X00:0XFFFF(對MSC51而言為0X00:0X00FF)② 外部數據空間段(0X01段式或X段)0X01:0X0000~0X01~0XFFFF③ 程序空間段(0XFF段或C段)0XFF:0X0000~0XFF:0XFFFF
(2) 地址空間類型
C:代碼空間D:內部直接尋址空間I: 內部間接尋址空間X:外部數據空間B:位尋址空間P:I/O口EB:擴展的位尋址空間(MCS251專有)ED:擴展的數據空間(MCS251專有)CO:常數空間(MCS251專有)HC:正常數空間(MCS251專有)
2. 常量
dScope支持十六進制、八進制、十進制、二進制常數,其后綴分別為H、Q(O)、T(或無)、Y;dScope不區(qū)分常量的大、小寫。
(1) 整型常量
分為整型(int),無符號整型(uint,00rd),長整型(long),無符號長整型(Wlong、Word)。
(2) 浮點型常量
與ANSI C相同。
(3) 字符串常量
與ANSI C相同
(4) 字符常量
分為字符型(Char)和無符號字符型(Uchar)一種。
(5) 行號常數
指用戶程序中的行號,實際上是個地址
(6) 位常量(Bit):
0和1
(7) 地址常數
地址常數的種類很多,地址常數不同于行號常數,行號常數就是一個地址,而地址數被引用時,實際上是取該地址中的數據。C:代碼地址常數,如C:0X0012或0XFF:0X0012D:內部直接尋址地址常數,如D:0X0068或0X00:0X0068I:內部間按尋址地址常數,如I:0X0010或0X00:0X0010X:外部數據空間地址常數,如X:0X0028或0X01:0X0028B:位地址常數,如B:0X20或B:0X24.0EB:擴展的位地址常數(MCS251專有), ED:擴展的數據空間地址常數(MCS251專有)CO:常數空間地址常數(MCS251專有)HC:正常數空間地址常數(MCS251專有)
(8) 標識符常量
即用戶源程序中的標號、函數名等,實際上代表某一地址。
(9) 用戶源程序中定義的常數
3. 變量
dScope所支持的變量名或標識符最多可由31個字符組成,第一個字母為A~Z,a~z,下劃線或問號,后續(xù)字符可為字母、數字、下劃線和問號。除CPU變量和系統變量外,dScope不支持全局變量,但可視“define”命令定義的變量為全局變量。Dscope所, 支持的變量分為以下幾種(變量名稱不區(qū)分大、小寫),支持類型轉換:
(1) 整型變量
分為整型變量(int)、無符號整型變量(uint/word),長整型(Long) 、無符號長整型(Ulong/dword)。
(2) 浮點型變量(float)
與ANSI C相同。
(3) 字符型變量L
分為字符型(char)變量和無符號字符型(Uchar)
(4) 位變量(Bit)
(5) 系統變量
dScope自己定義了一系列內部變量,用戶可對這些變量進行讀或讀/寫操作, 可被用戶自定義數所引用。a. Cycles (Read On
(6) CPU變量
即R0~R7、A、C(位變量)、B、DPTR及特殊功能寄存器變量,對這些變量均可進行讀、寫操作。
(7) 用戶源程序中定義的變量、數組、結構等
4. 運算符
dScope支持ANSI C的運算符,包括算術運算符,邏輯運算符,關系運算符。
5. 表達式
以運算符將dScope所支持的常量、變量、函數等連接在一起,就構成了dScope的表達式。
6. 數組
dScope不支持在命令文件中定義數組,但可引用用戶程序中的數組,引用方式如同C。
7. 結構和聯合
dScope不支持在命令文件中定義結構和聯合,但可引用用戶程序中的結構和聯合,引用方式如同C,但如要輸出整個結構或聯合的結果,就要用命令“OBJ”。
8. 指針:
不可自定義指針,但支持用戶源程序中的指針變量。
9. dScope命令語句
dScope提供了一系列調試命令。在命令文件中,dScope只支持這些語句及前述定義的表達式,C語言的語句均不被支持,但在命令文件所包含的用戶自定義函數(非用戶源程序中的函數)中支持C語句,但用戶自定義函數中同樣不支持數組、結構、聯合和指針。
(1) ASM
在線匯編命令,格式如下:ASM C:0Xnnnn (或標號);設定插入匯編指令的地址ASM 匯編指令ASM 匯編指令插入完畢后,在debug窗口內選擇“Assemble->Assemble”完成編譯。
(2) Assign
串行口分配指令,格式如下:Assign channel
(3) Define
用戶自定義變量指令,格式如下:Define <類型> <變量名>類型一為如前所述的變量類型,Define指令定義的變量可能為全局變量,可為用戶自定義函數所引用。
(4) Display
內存顯示命令,格式如下二:D 起始地址,結束地址地址如前所述的地址常數,標識符常量。
(5) Enter
內存修改指令,格式如下:E 類型地址=表達式 [表達式2],[……]類型如前所述,地址如前所述的地址常數。表達式如前所述,但如果是函數名稱(含標號、指針變量),則關鍵字E→EP
(6) Map/Reset map
Map為內存段修改指令,Reset map將內存段復位或缺省值。
(7) Object
用以引用用戶源程序中的結構(聯合)、數組、格式如下:Obj表達式 [n,],[Line]表達式為用戶源程序中的數組,結構(聯合)名稱。當Line缺省時,數目、結構(聯合)的內容按n行輸出;如有Line,則單行輸出。
(8) U
反匯編命令,格式如下: U [地址]地址包括地址常 數及標識符常量,指明反匯編的起始地址。
(9) WK
觀察點刪除命令,格式如下: WK n1[n2 ],[……] ;刪除指定的觀察點,n為字符型,整型 常數 WK * ;刪除所有的觀察點
(10) WS
觀察點設置命令,格式如下:WS 表達式[,n][LINE]關鍵字LINE存在時,觀察點表達式單行輸出LINE缺省時,觀察點表達式n行輸出。
(11) G
連續(xù)運行命令,格式如下: G [起始地址],[終止地址]地址為標識符常量或地址常數,地址缺省時,為連續(xù)運行。
(12) T/P
單步運行指令,格式如下: T/P n ;n指至單行運行的步數,P指給用戶當調用某函數時,把它作為一步處理,并不進入該函數運行。
(13) PA
性能分析操作指令,其分以下幾種:PA顯示當前所設置的性能分析程度段PA Kill *刪除當前所設置的所有性能分析程序段PA Kill n1 [,n2],[……]刪除指定的性能分析程序段PA 地址范圍設置性能分析程序段,地址范圍可以起始地址和結束地址的方式給出,也可給出函數名,行號范圍。PA Reset復位性能分析窗口(PA Windows),清除所有的記錄。
(14) BD
斷點失效命令,格式如下:BD n1 [,n2],[,……] ;disable指定的斷點DB * ;disable所有的斷點
(15) BE
斷點使能命令,格式如下:BE M [,n2],[,……] ;使能指定的斷點BE * ;使能所有的斷點
(16) BK
斷點刪除指令,格式如下:BK M[,n2],[,……] ;刪除指定的斷點BK * ;刪除所有的斷點
(17) BL
斷點顯示指令,顯示所有被定義的斷點。
(18) BS
斷點定義指令,dScope支持多達40個斷點,具體格式如下:a.BS 表達式[,count] [,“cmd”]count:經過該斷點的次數 [選項]“cmd”:斷點到達后附帶執(zhí)行的dScope命令(連項)表達式一個條件表達式,此時該斷點稱為條件斷點(運算符為&.&&,<<=>,>=,= =,!=)BS READ 表達式 [,count] [,“cmd”]BS WRITE 表達式 [,count] [“cmd”]BS READWRITE 表達式 [,count] [,“cmd”]以上三種斷點稱訪問式(Access斷點),當某一址或變量被訪問(R/W)或某些值被讀寫時,程序被中斷。
(19) Define button
圖標定義指令,用于當窗口(Toolbox)
(20) !
DOS窗口Open命令,以“EXIT”命令退出DOS窗口。
(21) Include
文件包含命令,格式如下:Include [路徑] 文件名dScope支持以文件包含的方式調入并執(zhí)行調試命令文件,用戶自定義函數文件,調試命令文件可以有后綴,也可無后綴。
(22) Load
加載命令,格式如下:Load [路徑] 文件名 Load指令能夠加載的文件必須具有以下格式之一。Intel Hex/Hex 386格式Intel Object (OMF_51) 格式Intel Object (OMF-251) 格式dScope的CPU驅動文件(.DLL)
(23) LOG
Command Window存盤指令,用于將Command Windows中的內容輸出到指定的文件中,格式如下:LOG > [路徑]文件名 ;創(chuàng)建一個新文件LOG >> [路徑]文件名 ;將Command Windows的內容輸出到某個已 存在的文件中。LOG OFF 完成輸出操作并開閉該文件LOG指令只將LOG>或LOG>>與LOG OFF指令之間的操作命令存入該指定文件。
(24) Reset
復位指令,具體格式如下:Reset ;執(zhí)行dScope的復位Reset Map ;復位外部數據空間Reset Var ;復位SET指令定義的變量
(25) Save
該指令將一段內存映象以19EX386/HEX的格式存盤,具體格式如下:Save 路徑 文件名:地址1、地址2地址1、地址2指所要保存的空間范圍,既可是標識符,也可是址常數。
(26) SET
該指令回來定義dScope目標代碼預定義變量的含義,這些預定義變量包括以下二種:SRC ;指出所在的路徑F1~F12;對應于鍵盤上的12個功能鍵,定義這些功能鍵的 含義。SET指令的格式為:SET 變量=“字符串”SET 變量
10. 函數
dScope支持三種函數,即dScope預定義函數,用戶自定義函數和信號函數,分別詳述如下:
(1) dScope預定義函數
dScope號提供8個預定義函數(可視為dScope的庫函數)①Void Printf(“String”,輸出表列)屏幕打印函數,與ANSI C的Printf ( ) 函數相同②Void exec(“Command__String”)Command__String為一有效的命令字符串,此函數用于在運行用戶自定義函數的過程中執(zhí)行dScope命令,這個函數提供了一個很重要的編制測試命令文件的方法。③int getint(“Prompt__String”);從鍵盤輸入一個整數int getlong (“Prompt__String”);從鍵盤輸入一個長整數float getfloat (“Prompt__String”);從鍵盤輸入一個浮點數以上這三個函數被執(zhí)行時,dScope會彈出一個dialog box等待用戶輸入數據,其標題欄上是“Prompt__String”,利用這個函數,不僅可以為變量賦值,也可使用戶得以看清前一階段的測試結果。④int rand (int seed) 該函數會輸出一個隨機數(-32768~32768)⑤Void memeset (ulorg start , ulong end ,uchar val) 該函數用于給地址范圍(Start__end)內的內存賦值(Val)⑥Void twatch (Long cycles)定時函數,時間由(Long cycles)決定,它是以指令周期計數的,它也 用于產生一個信號波形,該函數必須用于信號函數中。
(2) 用戶自定義函數
這類函數不同于用戶源程序中的數函,其定義格式為Func 返回類型 函數名(參數序列) { 語句}返回類型如前所述的變量類型用戶自定義函數中的語句與ANSI C相似,只是不支持數組結構、聯合、指針,可引用dScope系統變量,define語句定義的變量和用戶源程序變量,不支持dScope命令,如想在函數中執(zhí)行dScope命令,要借助于exec(“Command__String”)函數,可引用dScope預定義的函數(除了twatch ( )函數),不支持ANSI C的庫函數。
(3) 信號函數
用于產生具有某一波形的信號,定義格式為:Signal返回類型函數名(參數長列){ 語句 }信號函數主要是利用twatch ( )函數,目前dScope版本在提供這一功能上面還有一定問題。
(4) dScope函數與ANSI函數的區(qū)別
① 不支持條件匯編② 不支持頭文件③ 無變量的初始化④ 不支持數組、結構、指針⑤ 調用方式不同,自定義函數和信號函數首先要包含一個函數文件之中,然而在測試命令文件中以Inclule指令調用該函數文件,最后才能以函數名調用之。⑥ 函數調用只支持傳值方式。
評論