單片機原理及應(yīng)用:第4章 單片機的C語言編程_第1頁
單片機原理及應(yīng)用:第4章 單片機的C語言編程_第2頁
單片機原理及應(yīng)用:第4章 單片機的C語言編程_第3頁
單片機原理及應(yīng)用:第4章 單片機的C語言編程_第4頁
單片機原理及應(yīng)用:第4章 單片機的C語言編程_第5頁
已閱讀5頁,還剩106頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第4章 單片機的C語言編程4.1 C51的程序結(jié)構(gòu)4.2 C51的數(shù)據(jù)類型及運算符4.3 C51的函數(shù)4.4 C51程序設(shè)計本章要點 介紹C語言的基礎(chǔ)知識。 掌握C語言程序的基本結(jié)構(gòu),學(xué)會編制一些簡單的單片機應(yīng)用序,并能在Windows環(huán)境下使用C51編譯器進行編譯操作。 由于8051單片機的應(yīng)用程序用的是C51編譯器,應(yīng)注意在存儲類型、對片內(nèi)硬件資源的定義等方面與標(biāo)準(zhǔn)C語言的區(qū)別。概述 單片機C51語言是由C語言繼承而來的。 和C語言不同的是,C51語言運行于單片機平臺,而C語言則運行于普通的桌面平臺。 C51語言具有C語言結(jié)構(gòu)清晰的優(yōu)點,便于學(xué)習(xí),同時具有匯編語言的硬件操作能力。 對于具有

2、C語言編程基礎(chǔ)的讀者,能夠輕松地掌握單片機C51語言的程序設(shè)計。 4.1 C51的程序結(jié)構(gòu) C51程序結(jié)構(gòu)同ANSI C一樣,必須有一個主函數(shù)main( ),從主函數(shù)main( )開始執(zhí)行程序,默認情況下主函數(shù)是一個“死循環(huán)”結(jié)構(gòu),不停地循環(huán)執(zhí)行。 例:C51程序基本結(jié)構(gòu)在此處定義全局變量; /所有函數(shù)都可以使用void main( ) /* 定義主函數(shù)*/ 在此處定義局部變量; /只能在本函數(shù)范圍內(nèi)使用 bgn: goto bgn;C語言程序的組成結(jié)構(gòu)如下所示:注釋說明;頭文件包含命令;宏定義;全局變量定義 /*可被各函數(shù)引用*/用戶自定義函數(shù)聲明; main() /*主函數(shù)*/ 局部變量定

3、義 /*只在本函數(shù)引用*/執(zhí)行語句 /*包括函數(shù)調(diào)用語句*/ 用戶自定義函數(shù);中斷服務(wù)程序定義;用“/”符號開頭來注釋一行,如“/變量聲明”。用“/*”符號開頭,并以“*/”符號結(jié)束。采用這種方法,可以對C51源程序中的任何部分進行注釋,如“/*聲明整型變量count */”。 一、注釋說明返回 庫函數(shù)是編譯系統(tǒng)系統(tǒng)的標(biāo)準(zhǔn)函數(shù)。在使用時,只需在源程序的開始處使用預(yù)處理命令#include將有關(guān)的頭文件包含進來即可。 下面便介紹C51常用庫函數(shù)。本證庫函數(shù) 直接訪問存儲區(qū)宏定義 字符串操作庫函數(shù) 字符轉(zhuǎn)換和字符分類庫函數(shù) 數(shù)學(xué)庫函數(shù) 輸入輸出庫函數(shù) 二、頭文件包含命令格式: #include (

4、一)、本征庫函數(shù) 頭文件intrins.h_crol_,_cror_:將char型變量循環(huán)向左(右)移動指定位數(shù)后返回。_iror_,_irol_:將int型變量循環(huán)向左(右)移動指定位數(shù)后返回。_lrol_,_lror_:將long型變量循環(huán)向左(右)移動指定位數(shù)后返回。_nop_:相當(dāng)于插入?yún)R編指令NOP。_testbit_:相當(dāng)于JBC bitvar測試該位變量并跳轉(zhuǎn)同時清除。_chkfloat_: 測試并返回源點數(shù)狀態(tài)。例:#include “intrins.h”Void main() unsigned int a,b; bit test_falg,brlt; a=0 x1234; b

5、=_irol_(a,4) /a變量循環(huán)左移4位 test_flag=1; brlt=_testbit_(test_flag) /測試位變量test_flag,并將其請0, /brlt=1,test_flag=0;練習(xí):利用上述庫函數(shù)編寫LED燈流水燈程序(二)、直接訪問存儲區(qū)的宏定義 C51編譯器提供了一組宏定義來對51系列單片機的code、data、pdata和xdata空間進行絕對尋址。規(guī)定只能以無符號數(shù)方式訪問,定義了8個宏定義: CBYTE以字節(jié)形式對code區(qū)尋址, DBYTE以字節(jié)形式對data區(qū)尋址 PBYTE以字節(jié)形式對pdata區(qū)尋址, XBYTE以字節(jié)形式對xdata區(qū)尋址

6、, CWORD以字形式對code區(qū)尋址, DWORD以字形式對data區(qū)尋址, PWORD以字形式對pdata區(qū)尋址, XWORD以字形式對xdata區(qū)尋址。 這些函數(shù)原型放在absacc.h文件中。使用時須用預(yù)處理命令把該頭文件包含到文件中,形式為:#include 。 訪問形式如下: 宏名地址 宏名為CBYTE、DBYTE、PBYTE、XBYTE、CWORD、DWORD、PWORD或XWORD。地址為存儲單元的絕對地址,一般用十六進制形式表示。注意:CWORD、DWORD、PWORD和XWORD地址中的地址不是所訪問存儲單元的實際地址,所訪問存儲單元的地址=2*地址,WORD類型為兩個字節(jié)

7、例、絕對地址對存儲單元的訪問#include /*將絕對地址頭文件包含在文件中*/#include /*將寄存器頭文件包含在文件中*/#define uchar unsigned char #define uint unsigned int void main(void)uchar var1;uint var2;var1=XBYTE0 x0005; /*XBYTE0 x0005訪問片外RAM的0005字節(jié)單元*/var2=XWORD0 x0002; /*XWORD0 x0002訪問片外RAM的0004字單元*/.while(1); 在上面程序中,其中XBYTE0 x0005就是以絕對地址方式訪

8、問的片外RAM 0005字節(jié)單元;XWORD0 x0002就是以絕對地址方式訪問的片外RAM 0004字單元。 (三)、字符串操作 頭文件string.h,包括字符串比較、連接、復(fù)制、統(tǒng)計字符串長度、查找定位字符等功能函數(shù)等。#include “string.h”Void main() Char str=“today is”, wstr=sunny,weather20; strcopy ( weather, str); /執(zhí)行后weather=“today is” strcat( weather, wstr); /執(zhí)行后weather=“today is sunny”; (四)、字符轉(zhuǎn)換和字符

9、分類 頭文件stype.h,包括判斷類別,如:isdigit,islower和isupper等功能函數(shù)等。#include “ctype.h”Void main()Char c, cupp;Bit i; c=h; /執(zhí)行后c=0 x86 i= isdigit(c); /執(zhí)行后i=0; cupp=_toupper(c); /執(zhí)行后 cupp=0 x48,即H的ASCII碼(五)、數(shù)學(xué)函數(shù) 頭文件math.h,包括判斷類別,如:sin,cos和abs等功能函數(shù)等。#include “math.h”Void main()int x,y;flaot z;Begin: x=-100; y=abs(x);

10、 /執(zhí)行后y=100; z=log10(y); /執(zhí)行后 z=2Goto begin;三、宏定義宏定義語句屬于C51語言的預(yù)處理命令,使用宏定義可以使變量的書寫簡化,增加程序的可讀性、可維護性和可移植性。簡單的宏定義格式如下:#define 宏替換名 宏替換體例如:#define uchar unsigned char在編譯時可由C51編譯器把“unsigned char”用“uchar”來替代返回 變量在程序運行中其值可以改變的量。 一個變量由變量名和變量值構(gòu)成,變量名即是存貯單元地址的符號表示,而變量的值就是該單元存放的內(nèi)容。定義一個變量,編譯系統(tǒng)就會自動為它安排一個存貯單元,具體的地址值

11、用戶不必在意。 變量的定義的一般格式為 數(shù)據(jù)類型 存儲類型 變量名 C51中定義變量除了定義數(shù)據(jù)類型外,還應(yīng)定義存儲類型 例:int data x , y ; 表示x , y 為16位整數(shù)并指定放在片內(nèi)數(shù)據(jù)存儲區(qū)四、全局變量與局部變量定義inti,j;/整型變量charch;/字符型變量short int shi;/短整型變量unsigned int ut;/無符號整型變量float fset,st;/浮點型變量1、 數(shù)據(jù)類型 C51編譯器兼容ANSI C,支持ANSI C的基本數(shù)據(jù)類型,并對數(shù)據(jù)類型進行了擴展 (1)C51支持的ANSI C數(shù)據(jù)類型變量名稱符號類型數(shù)據(jù)長度值域范圍位型量bit

12、1位0,1字符型有符號signed char 8位-128+127無符號unsigned char8位0255整數(shù)型有符號signed int16位-32768+32767無符號unsigned int16位065535長整型有符號signed long32位-231231-1無符號unsigned long32位232-1浮點型float32位3.4E-383.4E+38 (2)C51擴展數(shù)據(jù)類型 Sfr,sfr16、sbit 用于訪問特殊功能的寄存器SFR,這三種類型的變量只能聲明為全局變量,并且在定義時必須指定變量訪問的SFR地址。 sfr 變量可以訪問指定地址的8位SFR 格式:sfr

13、 變量名=SFR地址例如: sfr P0=0X80; sfr P1=0X90; sfr P2=0XA0; sfr P3=0XB0; sfr16 變量可以訪問指定地址的16位SFR 格式:sfr16 變量名=變量地址 變量地址為16位特殊功能寄存器的低8位地址。 例如: sfr16 T2=0XCC; sfr T2-L=0XCC; sfr T2-H=0XCD; 定義sfr16和sfr類型的變量用于訪問單片機定時器2的16位計數(shù)寄存器 sbit 變量可以訪問可位尋址的SFR中的某一位 格式: sbit變量名=位地址 sbit變量名=SFR地址位序號 sbit變量名=Sfr變量位序號 sbit變量名=

14、Sfr16變量位序號 例如:sfr P0=0X80; sbit P0-0=0X80; sbit P0-1=P012、存儲類型 (1) 程序存儲器 如某變量需要存放在程序存儲器中,定義時用存儲類型標(biāo)識符code,程序運行中不可以改變用code定義的變量的值 (2)數(shù)據(jù)存儲器 內(nèi)部數(shù)據(jù)存儲器 Data:片內(nèi)數(shù)據(jù)存儲區(qū)的低128字節(jié)中,直接尋址,訪問速度快 bdata :可位尋址片內(nèi)數(shù)據(jù)存儲區(qū),允許位與字節(jié)混合訪問(16字節(jié)) ,必須定義為全部變量 idata :片內(nèi)數(shù)據(jù)存儲區(qū)整個(256字節(jié)) ,間接訪問 外部數(shù)據(jù)存儲器 間接訪問,存取速度比較慢 pdata :分頁尋址片外數(shù)據(jù)存儲區(qū)(256字節(jié))

15、 由MOVX R0,A指令訪問 xdata :片外數(shù)據(jù)存儲區(qū)(64K) 由MOVX DPTR,A指令訪問 存儲類型 與存儲空間的對應(yīng)關(guān)系 data 直接尋址片內(nèi)數(shù)據(jù)存儲區(qū),訪問速度快(128字節(jié)) bdata 可位尋址片內(nèi)數(shù)據(jù)存儲區(qū),允許位與字節(jié)混合訪問(16字節(jié)) idata 間接尋址片內(nèi)數(shù)據(jù)存儲區(qū),可訪問片內(nèi)全部RAM地址空間(256字節(jié)) pdata 分頁尋址片外數(shù)據(jù)存儲區(qū)(256字節(jié))由MOVX R0,A指令訪問 xdata 片外數(shù)據(jù)存儲區(qū)(64K),由MOVX DPTR,A指令訪問 code 代碼存儲區(qū)(64K),由MOVC A,A+DPTR指令訪問 表 C51存儲類型存儲模式 默認

16、的存儲類型 SMALL 默認的存儲類型為data,最大為128字節(jié) COMPACT 默認的存儲類型為pdata,每頁256字節(jié) LARGE 默認的存儲類型為xdata,最大為64K 3、 存儲模式 小模式,緊湊模式,大模式 變量若未定義存儲類型,則C51編譯器自動選擇默認存儲類型返回五、用戶自定義函數(shù)聲明當(dāng)用戶自定義的函數(shù)放在main函數(shù)的后面時,需要進行函數(shù)聲明當(dāng)用戶自定義的函數(shù)放在main函數(shù)的前面時,不需要進行函數(shù)聲明函數(shù)聲明的方法:只需要將自定義函數(shù)的函數(shù)頭復(fù)制到該位置即可;例如:用戶定義了以下函數(shù)Void delay()Unsigned char i;For(i=0;i (大于);

17、= (大于或等于); var2); result =(var1=var2); result =( var1var2 ); result =( var1=var2 ); goto bgn; 4、邏輯運算符及其表達式& 邏輯與 (兩個操作數(shù)都為真時,結(jié)果才為真,否則 為假) 邏輯或 (只要兩個操作數(shù)中有一個為真,結(jié)果便為真,否則為假)! 邏輯非 (對操作數(shù)的值取反) &和 要求有兩個操作對象,而!是單目運算符,只要求有一個運算對象。例、void main( ) unsigned int var1, var2 ,result; gbn: var1=0 x5555; var2=0 xAAAA; res

18、ult =var1&var2; result =var1|var2; result =var1var2; result =var1; var1=0 x1234; var2=0 x0002; result =var12; goto bgn; 5、位操作運算符及其表達式 &按位與; 按位或; 按位異或; 按位取反。 位右移6、特殊運算符C51中支持的位運算符有:(1)?運算:格式:?表達式2:表達式3;若表達式1的值為真,就返回表達式2的值,否則返回表達式3的值(2)&運算:返回操作數(shù)的地址(3)*運算:操作數(shù)為指針,所做的操作均是針對指針?biāo)赶虻淖兞?。例、void main( ) unsigne

19、d int var1, var2 ,result,*spt; gbn: var1=100; var2=200; result =var1var2? Var1:var2; var1=300; var2=200; spt =&result; *spt =var1+var2; var2=*spt; goto bgn; 例:若i=5 則j=i+; (執(zhí)行后i=6,j=?) j=+i; (I=6,j=6)7、自增減運算符及其表達式 作用:使變量的值增1或減l, 如:+i (使用i之前,先使i值增1) -i (使用i之前,先使i值減1) i+ (在使用i之后,使i值增l) i- (在使用i之后,使i值減1

20、)(二)分支與循環(huán)程序結(jié)構(gòu)1、分支控制語句 實現(xiàn)分支控制語句的有if語言和switch語言 (1)if 語句 形式1: if(表達式) 語句; 形式2: if(表達式) 語句1; else 語句2;形式3:if(表達式1)語句1;else if(表達式2)語句2;else if(表達式3)語句3;.else(語句n;)八、執(zhí)行語句(2)switch 語句switch語句的格式如下:switch(表達式1)case 常量表達式1:語句1;break;case 常量表達式2:語句2;break;case 常量表達式3:語句3;break;.case 常量表達式n:語句n;break;default

21、:語句n+1;2、循環(huán)控制語句 實現(xiàn)循環(huán)控制語句的有while語句、do-while語句和for語句 (1)while語句 while(表達式) 循環(huán)體語句; (2)do-while語句 do 循環(huán)體語句; while表達式(3)for語句 for(表達式1;表達式2;表達式3) 循環(huán)體語句; 表達式1:循環(huán)變量初值設(shè)定 表達式2:循環(huán)條件表達式 表達式3:循環(huán)變量更新表達式返回練習(xí):1、編寫程序使LED閃爍/* 名稱:閃爍的LED;說明:LED 按設(shè)定的時間間隔閃爍*/#includesbit LED=P10;/延時void DelayMS(uint x) unsigned char i;w

22、hile(x-)for(i=0;i120;i+);/主程序void main()while(1)LED=LED;DelayMS(150);2、編寫程序使LED左右來回點亮/* 名稱:8 只LED 左右來回點亮說明:程序利用循環(huán)移位函數(shù)_crol_和_cror_形成來回滾動的效果*/#include#includevoid DelayMS(uint x) /延時uchar i;while(x-)for(i=0;i120;i+);/主程序void main() unsigned char i; P2=0 x01; while(1)for(i=0;i7;i+)P2=_crol_(P2,1); /P2

23、 的值向左循環(huán)移動DelayMS(150);for(i=0;i7;i+)P2=_cror_(P2,1); /P2 的值向右循環(huán)移動DelayMS(150);(3)編寫程序,用數(shù)碼管顯示按鍵的編號#include unsigned char code DSY_CODE=0 xc0,0 xf9,0 xa4,0 xb0,0 x99,0 x92,0 x82,0 xf8,0 x80,0 x90;void main() unsigned char a,b;while(1) a=P1;switch(a)case 0 xfe:b=1;break;case 0 xfd:b=2;break;case 0 xfb:

24、b=3;break;case 0 xf7:b=4;break;case 0 xef:b=5;break;case 0 xdf:b=6;break;case 0 xbf:b=7;break;case 0 x7f:b=8;break;default:break; P2=DSY_CODEb;3、交通燈:東西向綠燈亮若干秒,黃燈閃爍5 次后紅燈亮, 紅燈亮后,南北向由紅燈變?yōu)榫G燈,若干秒后南北向黃燈閃爍5 此后變紅燈,東西向變綠燈,如此重復(fù)。/* 名稱:LED 模擬交通燈說明:東西向綠燈亮若干秒,黃燈閃爍5 次后紅燈亮, 紅燈亮后,南北向由紅燈變?yōu)榫G燈,若干秒后南北向黃燈閃爍5 此后變紅燈,東西向變綠

25、燈,如此重復(fù)。*/#include#define uchar unsigned char#define uint unsigned intsbit RED_A=P00; /東西向燈sbit YELLOW_A=P01;sbit GREEN_A=P02;sbit RED_B=P03; /南北向燈sbit YELLOW_B=P04;sbit GREEN_B=P05;uchar Flash_Count=0,Operation_Type=1; /閃爍次數(shù),操作類型變量/延時void DelayMS(uint x)uchar i;while(x-) for(i=0;i120;i+);void Traffi

26、c_Light()switch(Operation_Type)case 1: RED_A=1;YELLOW_A=1;GREEN_A=0; RED_B=0;YELLOW_B=1;GREEN_B=1; DelayMS(2000);Operation_Type=2;break;case 2: DelayMS(300); YELLOW_A=YELLOW_A;GREEN_A=1; if(+Flash_Count!=10) return; /閃爍5 次 Flash_Count=0;Operation_Type=3;break;case 3: RED_A=0;YELLOW_A=1;GREEN_A=1; RE

27、D_B=1;YELLOW_B=1;GREEN_B=0; DelayMS(2000); Operation_Type=4;break;case 4: DelayMS(300); YELLOW_B=YELLOW_B;GREEN_B=1; if(+Flash_Count!=10) return; Flash_Count=0;Operation_Type=1;/主程序void main()while(1) Traffic_Light();4、數(shù)碼管從左到右依次滾動顯示07,程序通過每次僅循環(huán)選通一只數(shù)碼管/*名稱:8 只數(shù)碼管滾動顯示單個數(shù)字說明:數(shù)碼管從左到右依次滾動顯示07,程序通過每次僅循環(huán)選通

28、一只數(shù)碼管*/#include#includeUnsigned char code DSY_CODE=0 xc0,0 xf9,0 xa4,0 xb0,0 x99,0 x92,0 x82,0 xf8,0 x80,0 x90;/延時void DelayMS(uint x)Unsigned char t;while(x-) for(t=0;t120;t+);/主程序void main()uchar i,wei=0 x80;while(1)for(i=0;i8;i+)wei=_crol_(wei,1);P0=DSY_CODEi; /發(fā)送數(shù)字段碼P2=wei; /發(fā)送位碼DelayMS(300);P2=

29、0 xff; /關(guān)閉顯示八、用戶自定義函數(shù)及中斷服務(wù)程序C51可以自定義任意多個函數(shù)。C51程序從main主函數(shù)開始執(zhí)行。C51的編譯環(huán)境提供了多種庫函數(shù)供用戶使用。合理使用函數(shù)來設(shè)計程序,可以有利于代碼的模塊化,促進團隊協(xié)作和資源共享。 函數(shù)定義的一般格式如下:函數(shù)類型 函數(shù)名(參數(shù)表)reentrantinterrupt musing n局部變量定義函數(shù)體前面部件稱為函數(shù)的首部,后面稱為函數(shù)的尾部,格式說明:1、函數(shù)類型函數(shù)類型說明了函數(shù)返回值的類型。2、函數(shù)名函數(shù)名是用戶為自定義函數(shù)取的名字以便調(diào)用函數(shù)時使用。3、形式參數(shù)表形式參數(shù)表用于列錄在主調(diào)函數(shù)與被調(diào)用函數(shù)之間進行數(shù)據(jù)傳遞的形式參

30、數(shù)。(一)、函數(shù)及中斷服務(wù)程序定義4reentrant修飾符 這個修飾符用于把函數(shù)定義為可重入函數(shù)。所謂可重入函數(shù)就是允許被遞歸調(diào)用的函數(shù)。函數(shù)的遞歸調(diào)用是指當(dāng)一個函數(shù)正被調(diào)用尚未返回時,又直接或間接調(diào)用函數(shù)本身。一般的函數(shù)不能做到這樣,只有重入函數(shù)才允許遞歸調(diào)用。 5interrupt m修飾符 interrupt m是C51函數(shù)中非常重要的一個修飾符,這是因為中斷函數(shù)必須通過它進行修飾。在C51程序設(shè)計中,當(dāng)函數(shù)定義時用了interrupt m修飾符,系統(tǒng)編譯時把對應(yīng)函數(shù)轉(zhuǎn)化為中斷函數(shù),自動加上程序頭段和尾段,并按MCS-51系統(tǒng)中斷的處理方式自動把它安排在程序存儲器中的相應(yīng)位置。 在該修

31、飾符中,m的取值為031,對應(yīng)的中斷情況如下:0外部中斷01定時/計數(shù)器T02外部中斷13定時/計數(shù)器T14串行口中斷5定時/計數(shù)器T2 其它值預(yù)留。編寫89C51中斷函數(shù)注意如下:(1)中斷函數(shù)不能進行參數(shù)傳遞,如果中斷函數(shù)中包含任何參數(shù)聲明都將導(dǎo)致編譯出錯。(2)中斷函數(shù)沒有返回值,如果企圖定義一個返回值將得不到正確的結(jié)果,建議在定義中斷函數(shù)時將其定義為void類型,以明確說明沒有返回值。(3)在任何情況下都不能直接調(diào)用中斷函數(shù),否則會產(chǎn)生編譯錯誤。因為中斷函數(shù)的返回是由8051單片機的RETI指令完成的,RETI指令影響8051單片機的硬件中斷系統(tǒng)。如果在沒有實際中斷情況下直接調(diào)用中斷函

32、數(shù),RETI指令的操作結(jié)果會產(chǎn)生一個致命的錯誤。【例】編寫一個用于統(tǒng)計外中斷0的中斷次數(shù)的中斷服務(wù)程序extern int x;void int0() interrupt 0 using 1 x+;6using n修飾符 修飾符using n用于指定本函數(shù)內(nèi)部使用的工作寄存器組,其中n的取值為03,表示寄存器組號。 對于using n修飾符的使用,注意以下幾點:(1)加入using n后,C51在編譯時自動的在函數(shù)的開始處和結(jié)束處加入以下指令。 PUSH PSW ;標(biāo)志寄存器入棧 MOV PSW,#與寄存器組號相關(guān)的常量 POP PSW ;標(biāo)志寄存器出棧(2)using n修飾符不能用于有返回

33、值的函數(shù),因為C51函數(shù)的返回值是放在寄存器中的。如寄存器組改變了,返回值就會出錯。聲明函數(shù)的注意事項 在聲明函數(shù)時,應(yīng)該注意如下幾點:如果沒有類型說明符出現(xiàn),函數(shù)返回一個整型值。如果函數(shù)沒有返回值,則可以采用void說明符。函數(shù)類型的說明必須處于對它的首次調(diào)用之前。當(dāng)函數(shù)被調(diào)用時,形式參數(shù)列表中的變量用來接收調(diào)用參數(shù)的值。如果函數(shù)沒有返回值,則可以省略return語句。函數(shù)與變量一樣,在使用前必須先定義。 函數(shù)的參數(shù)包括兩類:形參實參(二)、C51函數(shù)參數(shù)傳遞及返回值傳遞 函數(shù)參數(shù)用于主調(diào)函數(shù)與被調(diào)函數(shù)間進行的數(shù)據(jù)交換。 函數(shù)的形參和實參在使用時需要注意如下幾點:形參變量只有在被調(diào)用時才分配

34、內(nèi)存單元。實參可以是常量、變量、表達式等。在C51語言中,實參和形參都可以采用多種數(shù)據(jù)類型。實參的類型和個數(shù)應(yīng)該與形參的定義類型和個數(shù)完全相同。形參和實參在順序上應(yīng)保持嚴(yán)格一致。在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實參中的值不會變化。在函數(shù)調(diào)用時,數(shù)據(jù)傳送是單向的從實參傳送給形參。1、函數(shù)參數(shù)傳遞2、函數(shù)返回值的傳遞 函數(shù)的返回值是指函數(shù)被調(diào)用執(zhí)行之后,最終返回給主調(diào)函數(shù)的計算結(jié)果。函數(shù)的返回值通過return語句返回給主調(diào)函數(shù)。C51編譯器通過寄存器傳遞函數(shù)的返回值return語句的一般形式如下: return 表達式;return (表達式); 例:定義函數(shù)sum,實現(xiàn)兩個參數(shù)求和功能。

35、unsigned int sum(unsigned int var1, var2);void main( )unsigned int rlt;bgn: rlt=sum(100,200); goto bgn;unsigned int sum(unsigned int var1, var2) return(var1+var2);在C51中,使用return語句應(yīng)該注意如下幾點:函數(shù)只能有一個返回值。函數(shù)返回值的類型和函數(shù)定義中的類型應(yīng)保持一致。如函數(shù)返回值為整型,在函數(shù)定義時可省去類型說明。凡不要求返回值的函數(shù)都應(yīng)定義為空類型。一旦函數(shù)被定義為空類型后,就不能使用return語句。return語句

36、的注意事項(三)、函數(shù)的調(diào)用 函數(shù)調(diào)用的方式就是我們在程序中如何使用函數(shù)的問題。在C51語言中,函數(shù)調(diào)用的一般形式如下: 函數(shù)名(實參列表) 初步總結(jié)一下,函數(shù)可以有以下幾種調(diào)用方式:函數(shù)語句。示例如下:delay();函數(shù)表達式。示例如下:z=min(x,y);/函數(shù)min求x、y中的最小值函數(shù)參數(shù)。示例如下:z=min(x,min(y,z);/函數(shù)min求x、y、z中的最小值 程序中需要定義多個函數(shù)時,可以在另一個文件中集中定義函數(shù),而將相關(guān)函數(shù)聲明放在一個頭文件中,主程序只要用#include語句包含頭文件,便可調(diào)用文件中聲明的函數(shù)文件myfunc.c#include /包含特殊功能寄存

37、器庫bit func_cmp(long var1,long var2) if (var1var2) return 1; else return 0; 頭文件myfunc.h#ifndef _myfunc_def_h#define _myfunc_def_hExtern bit func_cmp(long var1,long var2); /聲明函數(shù)func_cmp#endif文件main.c#include /包含特殊功能寄存器庫#include extern serial_initial();void main(void) long var1=100,var2=50; bit rtn; rt

38、n= func_cmp(var1, var2); while(1);返回*2、通過函數(shù)指針調(diào)用函數(shù): 將函數(shù)的地址賦值給指針 char code *pfun pfun=(void*)fun 通過指針調(diào)用函數(shù)時,其指令格式為 (返回值類型(code*)(形參說明)函數(shù)指針)(實參說明) int fun_add(int var1,int var2); void main() char code *pfun; int rtn=0; pfun=(void *)fun_add; rtn=(int(code*)(int,int)pfun)(200,100);int fun_add(int var1,int

39、 var2) return(var1+var2);練習(xí):利用下圖所示的電路實現(xiàn)以下功能:按第一個鍵,實現(xiàn)兩個變量相加按第二個鍵,實現(xiàn)兩個變量相鍵按第三個鍵,實現(xiàn)兩個變量相乘按第四個鍵,實現(xiàn)兩個變量相除將運算結(jié)果通過數(shù)碼管顯示出來說明:變量相加、相減、相乘、相除、鍵盤掃描及顯示編寫成用戶自定義函數(shù),主程序只需調(diào)用上述函數(shù)即可#include unsigned char code leddata=0 xc0,0 xf9,0 xa4,0 xb0,0 x99,0 x92,0 x82,0 xf8,0 x80,0 x90;unsigned char code ledsel=0 x01,0 x02,0 x0

40、4,0 x08,0 x10,0 x20; void delay()unsigned char i;for(i=0;i200;i+);unsigned int sum(unsigned char a,b)return(a+b);unsigned int mul(unsigned char a,b)return(a*b);unsigned char sub(unsigned char a,b)return(a-b);unsigned int div(unsigned char a,b)return(a/b);void display(unsigned int d)unsigned char aa5

41、;unsigned char j; aa0=d/10000;aa1=d%10000/1000;aa2=d%1000/100;aa3=d%100/10;aa4=d%10;for(j=0;j5;j+)P0=leddataaaj;P2=ledselj;delay();P2=0 x00;unsigned char keyscan()unsigned char bb;unsigned char keyvalue;bb=P1;switch(bb)case 0 xfe:keyvalue=2;break;case 0 xfd:keyvalue=3;break;case 0 xfb:keyvalue=4;bre

42、ak;case 0 xf7:keyvalue=5;break;default:break;return keyvalue; void main()unsigned char key;unsigned int num;while(1)key=keyscan();switch(key)case 2:num=sum(200,100);break;case 3:num=sub(200,100);break;case 4:num=mul(200,100);break;case 5:num=div(200,100);break;default:break;display(num);4.2、C51的指針 變

43、量名對應(yīng)于內(nèi)存單元的地址,變量值則是放在內(nèi)存單元中的數(shù)據(jù)。同時把存放變量x的地址稱為指針,使用指針前也必須定義。 指針是一種特殊的數(shù)據(jù)類型,用指針聲明的變量稱為指針變量。 指針變量的值實際上是一個地址,是單片機內(nèi)存單元的編號。 聲明一個指針變量具有特殊的形式,如下所示: 數(shù)據(jù)類型 指向存儲區(qū)*存儲位置指針變量名1、通用指針 指向任何存儲類型的變量 占3個字節(jié),第一個字節(jié)說明存儲類型,第二個字節(jié)為變量地址的高8為;第三個字節(jié)為變量地址的低8位。void main() unsigned char code HZ=0 x88; unsigned char data var_data=0 x12; u

44、nsigned char *ptr; /通用指針ptr,指針存放在默認存儲區(qū)中 unsigned char *idata iptr; /通用指針iptr,指針存放在idata存儲區(qū)中 char idata myvar=0 x0A; ptr=&HZ; iptr=&var_data; myvar=myvar+*ptr; myvar=myvar+*iptr;2、指向固定存儲區(qū)變量的指針指向固定存儲區(qū)的變量void main() int code HZ=0 x0101; int data var_data=0 x12; int code *ptr; /指向code存儲區(qū)的指針ptr,指針存放在默認存儲

45、區(qū)中 int idata *pdata iptr; /指向idata存儲區(qū)的指針iptr,指針存放在pdata存儲區(qū)中 int idata myvar=0 xFF; ptr=&HZ; iptr=&var_data; myvar=myvar+*ptr; myvar=myvar+*iptr; return;一、變量絕對地址定位 在定義變量時使用 _at_ 關(guān)鍵字加上地址就可.格式為:數(shù)據(jù)類型 存儲類型 變量名 (空格)_at_ (空格)地址常數(shù)例如:unsigned char idata myvar _at_ 0 x40;把變量 myvar 定義在 idata 的 0 x40 處4.3、 C51對

46、擴展外設(shè)的訪問使用_at_定義的變量必須為全局變量 MCS-51系列單片機并行I/O接口除了芯片上的4個I/O口(P0 P3)外,還可以在片外擴展I/O口。MCS-51單片機I/O口與數(shù)據(jù)存儲器統(tǒng)一編址,即把一個I/O口當(dāng)作數(shù)據(jù)存儲器中的一個單元來看待。因此定義變量訪問外部擴展I/O地址時,將變量的數(shù)據(jù)類型說明為xdata或pdata,并需要指定變量在存儲區(qū)中的絕對地址。 P0、P1、P2和P3的定義在頭文件REG51.h和REG52.h中,擴展的外部RAM單元和外部I/O需要用戶自己定義。 二、C51對外設(shè)的訪問例、#define uchar unsigned char /*定義符號ucha

47、r為數(shù)據(jù)類型符unsigned char*/#define uint unsigned int /*定義符號uint為數(shù)據(jù)類型符unsigned int*/uchar data x1 _at_ 0 x40; /*在data區(qū)中定義字節(jié)變量x1,它的地址為40H*/uint xdata x2 _at_ 0 x2000; /*在xdata區(qū)中定義字變量x2,它的地址為2000H*/void main(void)x1=0 xff;/*將數(shù)據(jù)ffH寫入內(nèi)部數(shù)據(jù)存儲器地址為0 x40的存儲單元*/x2=0 x34;/*將數(shù)據(jù)34H寫入外部數(shù)據(jù)存儲器地址為0 x2000的存儲單元或I/O端口*/.whil

48、e(1);4.4 C51程序設(shè)計用戶自定義頭文件有利于合作開發(fā)用戶自定義頭文件的內(nèi)容主要包括函數(shù)聲明和宏定義導(dǎo)入方式:#include “頭文件名稱”C51程序設(shè)計實例例1:編程實現(xiàn):1905+7453的加法運算,并將運算結(jié)果通過LED顯示器顯示(數(shù)碼管的段選信號和位選信號分別通過P1和P2口控制)模塊分析:1、算數(shù)運算模塊(函數(shù)定義和聲明分別放在math.c和math.h中)2、顯示模塊(函數(shù)定義和聲明放在display.c和display.h中)1、文件 mymain.c#include “display.h”#inlcude “mymath.h”void main()unsigned i

49、nt rlt; rlt=sum(1905,7543);dspint(rlt);2、文件 mymath.cunsigned int sum(unsigned int x,y)return(x+y);頭文件mymath.h#ifndf_mymath_def_h#define_mymath_def_hextern unsigned int sum(unsigned int x,y);#endif;3、文件 display.c#include unsigned char code ledsel=0 xfe, 0 xfd, 0 xfb,0 xf7, 0 xef, 0 xdf;unsigned char

50、code ledcode=0 x3F,0 x06,0 x5B,0 x4F,0 x66,0 x6D,0 x7D,0 x07,0 x7F,0 x6F,0 x77,0 x7C,0 x39,0 x5E,0 x79,0 x71;void delay(unsigned int t)unsigned int i;for(i=0;i0)stri-=x%10;x=x/10;for(i=0;i0;x-) for(y=110;y0;y-);uchar keyscan() /鍵盤掃描程序,返回uchar型參數(shù)uchar i; for(i=0;i4;i+) P1=_crol_(0 xfe,i); temp=P1; te

51、mp=temp&0 xf0; while(temp!=0 xf0) delay(5); /延時消抖 temp=P1; temp=temp&0 xf0; while(temp!=0 xf0) temp=P1; switch(temp) case 0 xee:num=1;break; case 0 xde:num=2;break; case 0 xbe:num=3;break; case 0 x7e:num=4;break; case 0 xed:num=5;break; case 0 xdd:num=6;break; case 0 xbd:num=7;break; case 0 x7d:num=

52、8; break; case 0 xeb:num=9;break; case 0 xdb:num=10;break; case 0 xbb:num=11;break; case 0 x7b:num=12;break; case 0 xe7:num=13;break; case 0 xd7:num=14;break; case 0 xb7:num=15;break; case 0 x77:num=16;break; while(temp!=0 xf0) /等待按鍵釋放 temp=P1; temp=temp&0 xf0; return num;例2:P1端口接一支共陰數(shù)碼管SLED,在P2、P3端

53、口接16個按鍵,分別編號為KEY_0、KEY_1到KEY_F,操作時只能按一個鍵,按鍵后SLED顯示對應(yīng)鍵編號。#include unsigned char code Seg7Code16=0 x3f,0 x06,0 x5b,0 x4f,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f,0 x77,0 x7c,0 x39,0 x5e,0 x79,0 x71;void main()unsigned char a,b,i;while(1)a=P2;switch(a)case 0 xfe:i=0;break;case 0 xfd:i=1;break;case 0 xfb:i=2

54、;break;case 0 xf7:i=3;break;case 0 xef:i=4;break;case 0 xdf:i=5;break;case 0 xbf:i=6;break;case 0 x7f:i=7;break;default:break;b=P3;switch(b)case 0 xfe:i=8;break;case 0 xfd:i=9;break;case 0 xfb:i=10;break;case 0 xf7:i=11;break;case 0 xef:i=12;break;case 0 xdf:i=13;break;case 0 xbf:i=14;break;case 0 x

55、7f:i=15;break;default:break;P1=Seg7Codei;例3、LED模擬交通燈 說明:東西向綠燈亮若干秒,黃燈閃爍 5 次后紅燈亮, 紅燈亮后,南北向由紅燈變?yōu)榫G燈,若干秒后南北向黃燈閃爍 5 此后變紅燈,東西向變綠燈,如此重復(fù)。 #include sbit dred=P00;sbit dyellow=P01;sbit dgreen=P02;sbit nred=P03;sbit nyellow=P04;sbit ngreen=P05;void delay(unsigned int i)unsigned char a;while(i-)for(a=0;a120;a+);

56、void main()unsigned char n;while(1)dred=1;dyellow=1;dgreen=0;nred=0;nyellow=1;ngreen=1;delay(4000);dred=1; dgreen=1;for(n=0;n=4;n+)dyellow=dyellow;delay(400);dred=0;dyellow=1;dgreen=1;nred=1;nyellow=1;ngreen=0;delay(4000);nred=1; ngreen=1;for(n=0;n=4;n+)nyellow=nyellow;delay(400);練習(xí)題: 1、請根據(jù)下圖所示的電路,編

57、寫一個程序,使八個LED燈左右來回點亮2、請根據(jù)下圖所示的電路,編寫一個程序,使八個數(shù)碼管滾動顯示0-7C51語言習(xí)題一、填空題1Data存儲類型可以直接尋址( ),共( )字節(jié),訪問速度快。2、sfr16存儲類型用于( )尋址,定義( ) ,且該16位必須低位在低字節(jié),高位在緊跟的高字節(jié)才行。3、在keil uVision編譯系統(tǒng)中,支持的8051單片機存儲模式共有如下三種( )、 ( )和( )4、 ( )是指向特定的存儲區(qū)的指針類型,其在聲明時指定了存儲類型5、片內(nèi)低128字節(jié)RAM區(qū)的地址范圍為 ( ) 6、在C51語言程序中,注釋一般采用( )和( )來實現(xiàn)。7、字符char型變量的

58、取值范圍為 ( ) 。8、“?”運算符是 ( ) 目運算符。9、在C51語言中,單目運算符為 ( ) 結(jié)核性,雙目運算符為 ( ) 結(jié)合性,三目運算符為 ( ) 結(jié)合性。10 、 ( ) 單片機存儲器中最小的存儲單元,通常 ( ) 稱為一個內(nèi)存單元。單片機內(nèi)存單元的編號也就是 ( )11、在定義指針變量時,指針名前的 ( ) 不能省略,同一個指針變量只能指向 ( )12、指針變量的專用運算符包括 ( ) 和 ( ) 。13、指針變量可以參與 ( ) 和 ( ) 運算。14、通過( )可以訪問字符串常量中的內(nèi)容,但( )對其進行修改15、在指針變量說明中,*是( ),表示其后是( )16、表達式

59、中出現(xiàn)“*”則是( ),用來表示指針變量所指向的地址中的數(shù)據(jù)。17、無返回值的函數(shù)使用( )來聲明18、跳轉(zhuǎn)語句goto,只能在( )使用,而不能( ) 19、在C51語言中,除了( )函數(shù)外,各個函數(shù)都是平行的20、函數(shù)調(diào)用方式包括( )、 ( ) 、 ( )和( )21、形參變量只有在( )才分配內(nèi)存單元,在( )結(jié)束后,將立即釋放內(nèi)存單元。22、函數(shù)的返回值只能通過 ( ) 語句返回給主調(diào)函數(shù)。23、在C51語言的程序中,循環(huán)語句一般采用 ( ) 、 ( ) 和 ( ) 來實現(xiàn)。24、字符在c51語言的程序中,跳轉(zhuǎn)語句一般采用 ( ) 、 ( ) 和 ( ) 來實現(xiàn)。25、Do whil

60、e語句在執(zhí)行時,先執(zhí)行 ( ) ,然后執(zhí)行 ( )。26、返回語句由關(guān)鍵字 ( ) 來表示,用用于 ( )。27、C51的存儲類型有 ( ) , ( ) , ( ) , ( ) , ( ) , ( ) ,存儲模式有 ( ) ( ) , ( ) 。28、修飾符interrupt m中m的取值為0對應(yīng)的中斷情況是( ),1對應(yīng)的中斷情況是( ),2對應(yīng)的中斷情況是( ),3對應(yīng)的中斷情況是( ),4對應(yīng)的中斷情況是( ),5對應(yīng)的中斷情況是( ),修飾符using n的功能是( )。29、定義變量a、b、c,a為內(nèi)部RAM的可位尋址區(qū)的字符變量;b為外部數(shù)據(jù)存儲區(qū)浮點型變量;c為指向int型xda

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論