- 單片機與電路繪圖自學手冊
- 蔡杏山
- 5972字
- 2019-10-23 16:39:32
1.3 C51語言基礎
C51語言是指51單片機編程使用的C語言,它與計算機C語言大部分相同,但由于編程對象不同,故兩者個別處略有區(qū)別。本節(jié)主要介紹C51語言的基礎知識,學習時若無法理解一些知識也沒關系,在后續(xù)章節(jié)有大量的C51編程實例,在學習這些實例時再到本節(jié)查看理解有關內容。
1.3.1 常量
常量是指程序運行時其值不會變化的量。常量類型有整型常量、浮點型常量(也稱實型常量)、字符型常量和符號常量。
1. 整型常量
(1)十進制數(shù):編程時直接寫出,如0、18、-6。
(2)八進制數(shù):編程時在數(shù)值前加“0”表示八進制數(shù),如“012”為八進制數(shù),相當于十進數(shù)的“10”。
(3)十六進制數(shù):編程時在數(shù)值前加“0x”表示十六進制數(shù),如“0x0b”為十六進制數(shù),相當于十進數(shù)的“11”。
2. 浮點型常量
浮點型常量又稱實數(shù)或浮點數(shù)。在C語言中可以用小數(shù)形式或指數(shù)形式來表示浮點型常量。
(1)小數(shù)形式表示:由數(shù)字和小數(shù)點組成的一種實數(shù)表示形式,例如0.123、.123、123.、0.0等都是合法的浮點型常量。小數(shù)形式表示的浮點型常量必須要有小數(shù)點。
(2)指數(shù)形式表示:這種形式類似數(shù)學中的指數(shù)形式。在數(shù)學中,浮點型常量可以用冪的形式來表示,如2.3026可以表示為0.23026×101、2.3026×100、23.026×10?1等形式。在C語言中,則以“e”或“E”后跟一個整數(shù)來表示以“10”為底數(shù)的冪數(shù)。2.3026可以表示為0.23026E1、2.3026e0、23.026e-1。C語言規(guī)定,字母e或E之前必須要有數(shù)字,且e或E后面的指數(shù)必須為整數(shù),如e3、5e3.6、.e、e等都是非法的指數(shù)形式。在字母e或E的前后以及數(shù)字之間不得插入空格。
3. 字符型常量
字符常量是用單引號括起來的單個普通字符或轉義字符。
(1)普通字符常量:用單引號括起來的普通字符,如'b'、'xyz'、'?'等。字符常量在計算機中是以其代碼(一般采用ASCII代碼)儲存的。
(2)轉義字符常量:用單引號括起來的前面帶反斜杠的字符,如'\n'、'\xhh'等,其含義是將反斜杠后面的字符轉換成另外的含義。表1-2列出一些常用的轉義字符及含義。
表1-2 一些常用的轉義字符及含義

4. 符號常量
在C語言中,可以用一個標識符來表示一個常量,稱之為符號常量。符號常量在程序開頭定義后,在程序中可以直接調用,在程序中其值不會更改。
符號常量在使用之前必須先定義,其一般形式為:
#define 標識符 常量
例如,在程序開頭編寫“#define PRICE 25”,就將PRICE被定義為符號常量,在程序中,PRICE就代表25。
1.3.2 變量
變量是指程序運行時其值可以改變的量。每個變量都有一個變量名,變量名必須以字母或下劃線“_”開頭。在使用變量前需要先聲明,以便程序在存儲區(qū)域為該變量留出一定的空間。例如,在程序中編寫“unsigned char num=123”,就聲明了一個無符號字符型變量num,程序會在存儲區(qū)域留出一個字節(jié)的存儲空間,將該空間命名(變量名)為num,在該空間存儲的數(shù)據(變量值)為123。
變量類型有位變量、字符型變量、整型變量和浮點型變量(也稱實型變量)。
(1)位變量(bit):占用的存儲空間為1位,位變量的值:0或1。
(2)字符型變量(char):占用的存儲空間為1個字節(jié)(8位),無符號字符型變量的數(shù)值范圍為0~255,有符號字符型變量的數(shù)值范圍為-128~+127。
(3)整型變量:可分為短整型變量(int或short)和長整型變量(long),短整型變量的長度(即占用的存儲空間)為2個字節(jié),長整型變量的長度為4個字節(jié)。
(4)浮點型變量:可分為單精度浮點型變量(float)和雙精度浮點型變量(double),單精度浮點型變量的長度(即占用的存儲空間)為4個字節(jié),雙精度浮點型變量的長度為8個字節(jié)。由于浮點型變量會占用較多的存儲空間,故單片機編程時盡量少用浮點型變量。
C51變量的類型、長度和取值范圍見表1-3。
表1-3 C51變量的類型、長度和取值范圍

1.3.3 運算符
C51的運算符可分為算術運算符、關系運算符、邏輯運算符、位運算符和復合賦值運算符。
1. 算術運算符
C51的算術運算符見表1-4。在進行算術運算時,按“先乘除模,后加減,括號最優(yōu)先”的原則進行,即乘、除、模運算優(yōu)先級相同,加、減優(yōu)先級相同且最低,括號優(yōu)先級最高,在優(yōu)先級相同的運算時按先后順序進行。
表1-4 C51的算術運算符

在C51語言編程時,經常會用到加1符號“++”和減1符號“--”,這兩個符號使用比較靈活。常見的用法如下。
y=x++(先將x賦給y,再將x加1)
y=x--(先將x賦給y,再將x減1)
y=++x(先將x加1,再將x賦給y)
y=--x(先將x減1,再將x賦給y)
x=x+1可寫成x++或++x
x=x-1可寫成x--或—x
%為模運算,即相除取余數(shù)運算,如9%5結果為4。
^為乘冪運算,如2^3表示2的3次方(23),2^表示2的平方(22)。
2. 關系運算符
C51的關系運算符見表1-5。<、>、<=和>=運算優(yōu)先級高且相同,==、!=運算優(yōu)先級低且相同,例如“a>b!=c”相當于“(a>b)!=c”。
表1-5 C51的關系運算符

用關系運算符將兩個表達式(可以是算術表達式、關系表達式、邏輯表達式或字符表達式)連接起來的式子稱為關系表達式,關系表達式的運算結果為一個邏輯值,即真(1)或假(0)。
例如:a=4、b=3、c=1,則
a>b的結果為真,表達式值為1;
b+c<a的結果為假,表達式值為0;
(a>b)==c的結果為真,表達式值為1,因為a>b的值為1,c值也為1;
d=a>b,d的值為1;
f=a>b>c,由于關系運算符的結合性為左結合,a>b的值為1,而1>c的值為0,所以f值為0。
3. 邏輯運算符
C51的邏輯運算符見表1-6。“&&”、“||”為雙目運算符,要求兩個運算對象,“!”為單目運算符,只需要有一個運算對象。&&、||運算優(yōu)先級低且相同,!運算優(yōu)先級高。
表1-6 C51的邏輯運算符

與關系表達式一樣,邏輯表達式的運算結果也為一個邏輯值,即真(1)或假(0)。
例如:a=4、b=5,則
!a的結果為假,因為a=4為真(a值非0即為真),!a即為假(0);
a||b的結果為真(1);
!a&&b的結果為假(0),因為!優(yōu)先級高于&&,故先運算!a的結果為0,而0&&b的結果也為0。
在進行算術、關系、邏輯和賦值混合運算時,其優(yōu)先級從高到低依次為:!(非)→算術運算符→關系運算符→&&和||→賦值運算符(=)。
4. 位運算符
C51的位運算符見表1-7。位運算的對象必須是位型、整型或字符型數(shù),不能為浮點型數(shù)。
表1-7 C51的位運算符

位運算舉例如下:
5. 復合賦值運算符
復合賦值運算符就是在賦值運算符“=”前面加上其他運算符,C51常用的復合賦值運算符見表1-8。
表1-8 C51常用的復合賦值運算符

復合運算就是變量與表達式先按運算符運算,再將運算結果值賦給參與運算的變量。凡是雙目運算(兩個對象運算)都可以用復合賦值運算符去簡化表達。
復合運算的一般形式為:
變量 復合賦值運算符 表達式
例如:a+=28相當于a=a+28。
1.3.4 關鍵字
在C51語言中,會使用一些具有特定含義的字符串,稱之為“關鍵字”,這些關鍵字已被軟件使用,編程時不能將其定義為常量、變量和函數(shù)的名稱。C51語言關鍵字分兩大類:由ANSI(美國國家標準學會)標準定義的關鍵字和Keil C51編譯器擴充的關鍵字。
1. 由ANSI標準定義的關鍵字
由ANSI(美國國家標準學會)標準定義的關鍵字有char、double、enum、float、int、long、short、signed、struct、union、unsigned、void、break、case、continue、default、do、else、for、goto、if、return、switch、while、auto、extern、register、static、const、sizeof、typedef、volatile等。這些關鍵字可分為以下幾類。
(1)數(shù)據類型關鍵字:用來定義變量、函數(shù)或其他數(shù)據結構的類型,如unsigned char、int等。
(2)控制語句關鍵字:在程序中起控制作用的語句,如while、for、if、case等。
(3)預處理關鍵字:表示預處理命令的關鍵字,如define、include等。
(4)存儲類型關鍵字:表示存儲類型的關鍵字,如static、auto、extern等。
(5)其他關鍵字:如const、sizeof等。
2. Keil C51編譯器擴充的關鍵字
Keil C51編譯器擴充的關鍵字可分為兩類。
(1)用于定義51單片機內部寄存器的關鍵字:如sfr、sbit。
sfr用于定義特殊功能寄存器,如“sfr P1=0x90;”是將地址為0x90的特殊功能寄存器名稱定義為P1; sbit用于定義特殊功能寄存器中的某一位,如“sbit LED1=P1^1;”是將特殊功能寄存器P1的第1位名稱定義為LED1。
(2)用于定義51單片機變量存儲類型的關鍵字。這些關鍵字有6個,見表1-9。
表1-9 用于定義51單片機變量存儲類型的關鍵字

1.3.5 數(shù)組
數(shù)組也常稱作表格,是指具有相同數(shù)據類型的數(shù)據集合。在定義數(shù)組時,程序會將一段連續(xù)的存儲單元分配給數(shù)組,存儲單元的最低地址存放數(shù)組的第一元素,最高地址存放數(shù)組的最后一個元素。
根據維數(shù)不同,數(shù)組可分為一維數(shù)組、二維數(shù)組和多維數(shù)組;根據數(shù)據類型不同,數(shù)組可分為字符型數(shù)組、整型數(shù)組、浮點型數(shù)組和指針型數(shù)組。在用C51語言編程時,最常用的是字符型一維數(shù)組和整型一維數(shù)組。
1. 一維數(shù)組
(1)數(shù)組定義
一維數(shù)組的一般定義形式如下。
類型說明符 數(shù)組名[下標]
方括號(又稱中括號)中的下標也稱為常量表達式,表示數(shù)組中的元素個數(shù)。
一維數(shù)組定義舉例如下。
unsigned int a[5];
以上定義了一個無符號整型數(shù)組,數(shù)組名為a,數(shù)組中存放5個元素,元素類型均為整型,由于每個整型數(shù)據占2個字節(jié),故該數(shù)組占用了10個字節(jié)的存儲空間,該數(shù)組中的第1~5個元素分別用a[0]~a[4]表示。
(2)數(shù)組賦值
在定義數(shù)組時,也可同時指定數(shù)組中的各個元素(即數(shù)組賦值),形式如下。
unsigned int a[5]={2,16,8,0,512}; unsigned int b[8]={2,16,8,0,512};
在數(shù)組a中,a[0]=2,a[4]=512;在數(shù)組b中,b[0]=2,b[4]=512,b[5]~b[7]均未賦值,全部自動填0。
在定義數(shù)組時,要注意以下幾點。
① 數(shù)組名應與變量名一樣,必須遵循標識符命名規(guī)則,在同一個程序中,數(shù)組名不能與變量名相同。
② 數(shù)組中的每個元素的數(shù)據類型必須相同,并且與數(shù)組類型一致。
③ 數(shù)組名后面的下標表示數(shù)組的元素個數(shù)(又稱數(shù)組長度),必須用方括號括起來,下標是一個整型值,可以是常數(shù)或符號常量,不能包含變量。
2. 二維數(shù)組
(1)數(shù)組定義
二維數(shù)組的一般定義形式如下。
類型說明符 數(shù)組名[下標1] [下標2]
下標1表示行數(shù),下標2表示列數(shù)。
二維數(shù)組定義舉例如下。
unsigned int a[2] [3];
以上定義了一個無符號整型二維數(shù)組,數(shù)組名為a,數(shù)組為2行3列,共6個元素,這6個元素依次用a[0] [0]、a[0] [1]、a[0] [2]、a[1] [0]、a[1] [1]、a[1] [2]表示。
(2)數(shù)組賦值
二維數(shù)組賦值有兩種方法。
① 按存儲順序賦值。如下所示。
unsigned int a[2] [3]={1,16,3,0,28,255};
② 按行分段賦值。如下所示。
unsigned int a[2] [3]={{1,16,3},{0,28,255}};
3. 字符型數(shù)組
字符型數(shù)組用來存儲字符型數(shù)據。字符型數(shù)組可以在定義時進行初始化賦值。如下所示。
char c[4]={ 'A', 'B', 'C', 'D'};
以上定義了一個字符型數(shù)組,數(shù)組名為c,數(shù)組中存放4個字符型元素(占用了4個字節(jié)的存儲空間),分別是A、B、C、D(實際上存放的是這4個字母的ASCII碼,即0x65、0x66、0x67、0x68)。如果對全體元素賦值時,數(shù)組的長度(下標)也可省略,即上述數(shù)組定義也可寫成如下所示。
char c[]={ 'A', 'B', 'C', 'D'};
如果要在字符型數(shù)組中存放一個字符串“good”,可采用以下3種方法。
char c[]={ 'g', 'o', 'o', 'd', '\0'}; //“\0”為字符串的結束符 char c[]={"good"}; //使用雙引號時,編譯器會自動在后面加結束符'\0',故數(shù)組長度應較字符數(shù)多一個 char c[]="good";
如果要定義二維字符數(shù)組存放多個字符串時,二維字符數(shù)組的下標1為字符串的個數(shù),下標2為每個字符串的長度,下標1可以不寫,下標2則必須要寫,并且其值應較最長字符串的字符數(shù)(空格也算一個字符)至少多出一個。如下所示。
char c[][20]={{"How old are you?",\n}, {"I am 18 years old.",\n},{"and you?" }};
上例中的“\n”是一種轉義符號,其含義是換行,將當前位置移到下一行開頭。
1.3.6 循環(huán)語句(while、do while、for語句)
在編程時,如果需要某段程序反復執(zhí)行,可使用循環(huán)語句。C51的循環(huán)語句有3種:while語句、do while語句和for語句。
1. while語句
while語句的格式為“while(表達式){語句組;}”,編程時為了書寫閱讀方便,一般按以下方式編寫。
while(表達式) { 語句組; }
while語句在執(zhí)行時,先判斷表達式是否為真(非0即為真)或表達式是否成立,若為真或表達式成立則執(zhí)行大括號(也稱花括號)內的語句組(也稱循環(huán)體),否則不執(zhí)行大括號內的語句組,直接跳出while語句,執(zhí)行大括號之后的內容。
在使用while語句時,要注意以下幾點。
① 當while語句的大括號內只有一條語句時,可以省略大括號,但使用大括號可使程序更安全可靠。
② 若while語句的大括號內無任何語句(空語句)時,應在大括號內寫上分號“;”,即“while(表達式){:}”,簡寫就是“while(表達式);”。
③ 如果while語句的表達式是遞增或遞減表達式,while語句每執(zhí)行一次,表達式的值就增1或減1。例如“while(i++){語句組;}”。
④ 如果希望某語句組無限次循環(huán)執(zhí)行,可使用“while(1){語句組;}”。如果希望程序停在某處等待,待條件(即表達式)滿足時往下執(zhí)行,可使用“while(表達式);”。如果希望程序始終停在某處不往下執(zhí)行,可使用“while(1);”,即讓while語句無限次執(zhí)行一條空語句。
2. do while語句
do while語句的格式如下。
do { 語句組; } while(表達式)
do while語句在執(zhí)行時,先執(zhí)行大括號內的語句組(也稱循環(huán)體),然后用while判斷表達式是否為真(非0即為真)或表達式是否成立,若為真或表達式成立則執(zhí)行大括號內的語句組,直到while表達式為0或不成立,直接跳出do while語句,執(zhí)行之后的內容。
do while語句是先執(zhí)行一次循環(huán)體語句組,再判斷表達式的真假以確定是否再次執(zhí)行循環(huán)體,而while語句是先判斷表達式的真假,以確定是否執(zhí)行循環(huán)體語句組。
3. for語句
for語句的格式如下。
for(初始化表達式; 條件表達式; 增量表達式) { 語句組; }
for語句執(zhí)行過程:先用初始化表達式(如i=0)給變量賦初值,然后判斷條件表達式(如i<8)是否成立,不成立則跳出for語句,成立則執(zhí)行大括號內的語句組,執(zhí)行完語句組后再執(zhí)行增量表達式(如i++),接著再次判斷條件表達式是否成立,以確定是否再次執(zhí)行大括號內的語句組,直到條件表達式不成立才跳出for語句。
1.3.7 選擇語句(if、switch…case語句)
C51常用的選擇語句有if語句和switch…case語句。
1. if語句
if語句有3種形式:基本if語句、if…else…語句和if…else if…語句。
(1)基本if語句
基本if語句格式如下。
if(表達式) { 語句組; }
if語句執(zhí)行時,首先判斷表達式是否為真(非0即為真)或表達式是否成立,若為真或表達式成立則執(zhí)行大括號(也稱花括號)內的語句組(執(zhí)行完后跳出if語句),否則不執(zhí)行大括號內的語句組,直接跳出if語句,執(zhí)行大括號之后的內容。
(2)if…else…語句
if…else…語句格式如下。
yuan if(表達式) { 語句組1; } else { 語句組2; }
if…else…語句執(zhí)行時,首先判斷表達式是否為真(非0即為真)或表達式是否成立,若為真或表達式成立則執(zhí)行語句組1,否則執(zhí)行語句組2,執(zhí)行完語句組1或語句組2后跳出if…else…語句。
(3)if…else if…語句(多條件分支語句)
if…else if…語句格式如下。
if(表達式1) { 語句組1; } else if(表達式2) { 語句組2; } …… else if(表達式n) { 語句組n; }
if…else if…語句執(zhí)行時,首先判斷表達式1是否為真(非0即為真)或表達式是否成立,為真或表達式成立則執(zhí)行語句組1,然后判斷表達式2是否為真或表達式是否成立,為真或表達式2成立則執(zhí)行語句組2,……最后判斷表達式n是否為真或表達式是否成立,為真或表達式n成立則執(zhí)行語句組n,如果所有的表達式都不成立或為假時,跳出if…else if…語句。
2. switch…case語句
switch…case語句格式如下。
switch(表達式) { case 常量表達式1; 語句組1;break; case 常量表達式2; 語句組2;break; …… case 常量表達式n; 語句組n;break; default:語句組n+1; }
switch…case語句執(zhí)行時,首先計算表達式的值,然后按順序逐個與各case后面的常量表達式的值進行比較,當與某個常量表達式的值相等時,則執(zhí)行該常量表達式后面的語句組,再執(zhí)行break而跳出switch…case語句;如果表達式與所有case后面的常量表達式的值都不相等,則執(zhí)行default后面的語句組n+1,并跳出switch…case語句。