2.1 數據類型與運算符
課件 C51語言中的基本數據類型

視頻 C51語言中的基本數據類型

單片機C51語言是由C語言繼承而來的。和C語言不同的是,C51語言運行于單片機平臺,而C語言運行于普通的桌面平臺。與C語言相同的是,C51語言具有和C語言類似的語法結構,便于學習,同時具有匯編語言的硬件操作能力。因此,具有C語言編程基礎的人,能夠很輕松地掌握單片機C51語言的程序設計。
C語言本身的常用語法就不多,而支持51單片機的C51語言常用語法更少。這里首先介紹一些C51語言的初步語法知識。隨著學習的深入,在后面的章節中,邊用邊學,會把當前程序應用到的C51語言相關語法知識再進行深入介紹。
1.基本數據類型
數據類型通常指一個值的集合以及定義在這個值集上的一組操作。數據類型是編譯程序進行存儲器分配的主要依據,編程的時候會根據需要來申請內存,大數據用大內存,小數據就用小內存,這樣就可以充分地利用有限的內存,使之效用最大化。尤其是對單片機而言,其內存很小,準確地設定數據類型就顯得很有必要。
C51語言中的基本數據類型如表2-1所示。
表2-1 C51語言中的基本數據類型

注:此外還有一些數據類型,如枚舉型、短整型、單精度浮點型等。在本書中基本沒有應用,所以不多做介紹,遇到時可查閱相關資料。
帶有signed符號的類型稱為有符號類型,signed符號通常省略,如signed char也可以簡略地寫成char,它占用1字節(8位)的空間,因為這個類型有符號位所以用來表示數值大小的空間只有7個二進制位,因此它所能表示的數值范圍是-128~127。而unsigned表示無符號類型,不能夠省略,unsigned char同樣占用1字節(8位)的空間,因為這個類型沒有符號,所以全部8位都用來表示整數值,因此它所能表示的數值范圍是0~255。其他int、long等類型的signed、unsigned符號標識與此含義相同。
在使用C51變量時,尤其要注意變量的數據類型所能表達的最大數值范圍,不要超出其界限值。假設定義了某個變量a為unsigned char型(0~255),當a的值為255,此時進行a=a+1操作,得到a的值并不會是256;同樣,若當a=0時,進行a=a-1的操作,也不會得到-1;這二者的操作均會產生溢出,造成計算結果錯誤。因此,在使用變量時,必須要明確地知道其對應的數據類型的數值范圍,確保運算不會超出界限范圍。
在單片機程序中經常需要直接訪問各種功能模塊,如串、并行接口,定時/計數器,中斷系統等,這要求C51語言必須提供直接訪問硬件資源的手段。C51中可以通過定義sfr、sfr16、sbit等數據類型的變量,實現對硬件資源的訪問和操作。sbit、sfr和sfr16是專門為訪問51單片機中SFR(特殊功能寄存器)中的控制位以及8位SFR和16位SFR所特有的類型,它們并不是標準C中的類型。
C51語言中對于特殊功能寄存器已經預先進行了定義,這個定義包含在頭文件(reg51.h)中,編程時直接引入這個頭文件就可以使用其中定義的符號來訪問特殊功能寄存器了。比如在這個頭文件中使用P0、P1、P2、P3分別代表51單片機的4個并行端口等。引入了該頭文件后,就可以用訪問SFR的形式實現對硬件的訪問。因此,熟悉頭文件中的SFR定義,在程序設計中直接使用預定義的符號來操作相應的設備或端口,在很大程度上簡化了對單片機的操作。reg51.h頭文件內容如圖2-1所示。

圖2-1 reg51.h頭文件內容
2.常量與變量
課件 C51語言中常量與變量

視頻 C51語言中常量與變量

C51語言中的數據有常量和變量之分。所謂常量是指在程序運行過程中,其值不能改變的量,稱為常量。常量無名,也不會長期存在,使用過一次就會被釋放掉,常量存在的意義一般來講就是為了給對應的變量賦值。所謂變量就是指在程序運行過程中,其值是可以動態改變的量。常量和變量都需要有數據類型,只有確定了它們的數據類型,系統才能為其分配相應的存儲運行空間。每一個變量都必須要有一個名字,這個名字不僅是一個簡單的稱謂代號,其實也是變量所在空間的地址代號,通過這個地址代號就能夠在內存空間中找到這個變量,并讀取其中存放的數值。在變量空間存放的數值就是變量值。這個變量值的大小不能超過變量數據類型的界限范圍。
1)定義變量
C51語言中對變量的要求必須是“先定義,后使用”。使用某個變量之前必須先對它進行定義。必須指明該變量的數據類型,以便在內存當中分配適當大小的空間。
定義變量的語法形式有兩種:

變量命名時一般要用小寫字母,變量名不要過長。變量命名的原則最好是見名知意,可以選用有含義的英文單詞作為標識。一定要注意不要與C51語言的關鍵字重復。C51語言中的關鍵字很少。所謂關鍵字,是指C51語言保留的一些有特殊作用的詞語,由于這些關鍵字都有著特殊的含義,因此不能用作變量或常量等的命名。
如果定義了某種類型的變量,但未賦初值,C51中會對部分類型自動賦予初值。
如:int a; //定義了整形變量a,但未對a賦初值,系統默認賦初值為0
int a=1; //定義了整型變量a,并對a賦了初始值為1
2)定義訪問硬件的位變量
使用單片機進行程序設計時經常要訪問硬件,如果需要對于特殊功能寄存器(SFR)的某一位訪問,就可以使用前面講過的sbit類型,使用sbit類型變量可以直接訪問到具體指定位(引腳)的內容。
定義sbit類型的變量語法如下:

賦值號(=)右側的特殊功能寄存器就是在頭文件中定義過的SFR,請讀者查閱reg51.h文件,熟悉預定義的SFR。位序是指要訪問的功能位處于特殊功能寄存器的第幾位,注意這個位序是從右向左排列的,最右邊的位序為0。
比如欲操作端口P0的1號引腳,先查閱reg51.h文件,見圖2-1,找到P0端口的定義為P0,這是一個BYTE型的SFR,共有8位。其內容與引腳編號一一對應排列,如圖2-2所示,其1號引腳位于第D1位。

圖2-2 P0端口內部引腳排列順序
則定義語句為:

這個語句含義就是定義了一個sbit類型的變量名為led,該變量映射到P0端口的1號引腳,這樣就可以使用led這個變量可以直接操作P0端口的1號引腳。假設這個引腳接了一個發光二極管,如下命令就能控制二極管的亮滅了。

3)符號常量與預定義代碼
常量一般沒有名字,但有數據類型的區別,這個類型可以通過字面的書寫形式直接分辨。如12、0等是整型常量,'a'、'b'等為字符型常量等等。這種常量通常被稱為字面常量或直接常量,是C51語言中出現較多的常量表現形式,這些常量主要用來給對應的變量賦值。除此之外,還有一種常量稱為符號常量,需要使用#define命令進行定義。
定義符號常量的語法形式為:

符號常量名通常都用大寫字母。使用符號常量不僅可以增加程序的易讀性,而且在系統升級或修改時,還可實現“牽一發動全身”,只做符號常量定義處的修改即可。如
#define PI 3.1415926 //這里定義了符號常量PI,它的值是3.1415926
今后當系統移植時,如果因硬件不同,要對PI的取值長度修改,則只在這里進行修改即可,簡化了程序的修改工作。
另外,在程序設計中,還經常使用#define進行一些預定義代碼來簡化程序中數據類型的輸入。比如unsigned char、unsigned int等數據類型輸入比較麻煩,通過預定義后可分別用uchar和uint來代替,以此簡化程序錄入時數據類型名稱過長帶來的輸入麻煩。

需要注意的是,使用#define的預定義語句后面是沒有任何標點符號的。
3.常用運算符
課件 C51語言中常用運算符

視頻 C51語言中常用運算符

C51語言中提供了算術運算符、關系運算符、邏輯運算符、位運算符等多種運算。
1)算術運算符
運用算術運算符可以完成所有的算術運算。另外,靈活運用算術運算符可以完成諸如動態獲取組成某多位數的各位數字。C51語言中的算術運算符如表2-2所示。
表2-2 算術運算符

“/”兩數相除,如果除數與被除數都是整數,則結果一定是整數,如10/4=2;如果除數或被除數有一個是浮點數,則結果是浮點數,如10/2.5=4.0。
在單片機程序設計中,除了普通的數據運算要用到算術運算符外,利用取余和整除運算還能實現獲取多位數中每一位數字的運算效果。
如:已知某測溫系統獲取到的動態溫度值n為3位數,現需要分別求出組成該3位數的百位、十位、個位數字并在數碼管中顯示出來。
使用算術運算符可以輕松完成這類任務。

2)關系運算符和邏輯運算符
關系運算和邏輯運算的結果均為真或假。C51中通常1代表真,0代表假。在關系運算中,關系成立其結果為真就是1,關系不成立其結果為假就是0。邏輯運算中參與運算的操作數凡是不為0的數字均代表真,0代表假;邏輯運算的結果同樣是條件成立就是真結果為1,條件不成立就是假結果為0。關系運算符和邏輯運算符見表2-3。
表2-3 關系運算符和邏輯運算符

關系運算符主要用來判定兩個操作數數量上的關系(大、小、等于、不等于)。當關系運算符和賦值符號相連時,要先進行關系運算然后再進行賦值。如a=5>7,因為5小于7,所以5>7這個關系運算的結果為假(即0),原式變為a=0,則a最終結果為0。
邏輯運算主要是與運算、或運算和非運算。參與邏輯運算的操作數通常為關系表達式或純數字,在C51中參與邏輯運算的數字,如果不為0則代表真;如果為0則代表假,邏輯運算的結果非0即1。當邏輯運算與關系運算混合時,先進行關系運算再進行邏輯運算。如表達式5>7&&6<8||23中,因為5并不大于7其值為0,而6確實小于8其值為1,23為數字參與邏輯運算可以表示為真1,所以原式可以變為0&&1||1,最終結果為1。其實這里涉及了運算符的優先級問題,關系運算優先于邏輯運算。
3)位運算符
位運算是指二進制位的運算。位運算中除了取反(~)運算外,都要求運算符號兩側各有一個操作數。這里位運算的符號與操作規則和上一模塊中的位運算敘述完全相同。位運算符見表2-4。
表2-4 位運算符

在單片機程序中靈活使用位運算可以非常方便地實現對端口和引腳的控制。如需要將P0口的高3位清0但其余各位保持原狀態,就可以使用P0=P0&0x1f實現,類似地,如果要將P0口的高3位置1但其余各位保持原狀態,就可以使用P0=P0|0xe0實現;實現P0口的低4位翻轉,高4位不變,則可用P0=P0^0x0f實現。這樣的操作還有很多,需要讀者在日后的使用中,多動腦多練習,結合C51的分支、循環語句可以控制硬件實現更多有趣的操作。
4)其他運算符
C51中除了上述常用的運算符外,以下幾種運算符也經常出現,如表2-5所示。
(1)復合賦值運算符。給變量賦值,最簡單的寫法是“變量名=常量”,如a=5表示向變量a賦值,使其值為5。如果稍微復雜一點,將表達式的值賦值給變量,如P1=P1*2這樣寫有些麻煩,于是出現了復合型的賦值運算符,即將算術、關系、邏輯、位運算等運算符與賦值號寫在一起,既表達賦值也表達運算,如上式可簡化為P1*=2;再比如P0=P0&0x1f,可簡化為P0&=0x1f。也就是說,凡是賦值運算符兩側變量同名并進行其他運算的,均可以采用復合賦值運算符進行簡化書寫。更多的復合賦值運算符見表2-5中序號1的部分。
(2)條件運算符。條件運算符在今后的編程實踐中會有廣泛應用。這個運算符只用了兩個符號就解決了條件分支判斷的問題。靈活運用這個運算符會大大簡化代碼,提高程序可讀性。其使用形式比較簡單,如下所示:

其含義是:如果條件成立,則返回結果1作為整個表達式的結果;如果條件不成立,則返回結果2作為整個表達式的結果。可以應用這個運算符,快速返回兩個數中的較大數,如c=a>b?a:b,c中存放的就是a和b中的較大數。
(3)自加與自減。自加與自減也是很多語言中都有的運算符,其含義是變量在自身的基礎上自加1或自減1。下面以++運算符為例進行說明,--運算符的道理與之相同,請自行對照。
++i:表示先進行i=i+1計算,然后再把此時i的值作為表達式的值返回。如i=3;y=++i;計算時i先進行自加i=i+1(此時i值為4),然后再把i的值賦值給y(即y值為4)。
i++:表示先將i的初始值返回作為表達式的值,然后再進行i=i+1。如i=3;y=i++;計算時i初始值是3作為表達式值返回并賦值給y(即y值為3),然后再進行i=i+1(此時i值為4)。
表2-5 其他運算符

上述各類運算符的優先級如下所示:
有括號先算括號→單目運算(自加、自減、取反等)→算術運算符→關系運算符→邏輯運算符(不含?。鷹l件運算符→賦值運算符→逗號運算符。
同一優先級的運算符,運算次序由結合方向決定。例如*與/具有相同的優先級,其結合方向為自左至右,因此3*4/5的運算次序是先乘后除。而-和++為同一優先級,結合方向為自右至左,因此-i++相當于-(i++)。
- Learning Cocos2d-x Game Development
- 基于Proteus和Keil的C51程序設計項目教程(第2版):理論、仿真、實踐相融合
- 計算機組裝與系統配置
- Intel FPGA/CPLD設計(高級篇)
- 電腦常見故障現場處理
- 硬件產品經理手冊:手把手構建智能硬件產品
- AMD FPGA設計優化寶典:面向Vivado/SystemVerilog
- OUYA Game Development by Example
- Mastering Adobe Photoshop Elements
- 計算機組裝與維護(第3版)
- 筆記本電腦使用、維護與故障排除從入門到精通(第5版)
- 基于網絡化教學的項目化單片機應用技術
- The Deep Learning with PyTorch Workshop
- FPGA實戰訓練精粹
- 微服務架構基礎(Spring Boot+Spring Cloud+Docker)