51系列單片機(jī)學(xué)習(xí)5—C編程程序語(yǔ)句
#include
#include
void main(void)
{
unsigned int I = 1;
unsigned int SUM = 0; //設(shè)初值
SCON = 0x50; //串行口方式 1,允許接收
TMOD = 0x20; //定時(shí)器 1 定時(shí)方式 2
TCON = 0x40; //設(shè)定時(shí)器 1 開始計(jì)數(shù)
TH1 = 0xE8; //11.0592MHz 1200 波特率
TL1 = 0xE8; TI = 1;
TR1 = 1; //啟動(dòng)定時(shí)器
while(I<=10)
{
SUM = I + SUM; //累加
printf ("%d SUM=%d",I,SUM); //顯示
I++;
}
while(1); //這句是為了不讓程序完后,程序指針繼續(xù)向下造成程序“跑飛”
}
//最后運(yùn)行結(jié)果是 SUM=55;
do while 語(yǔ)句
do while 語(yǔ)句能說(shuō)是 while 語(yǔ)句的補(bǔ)充,while 是先判斷條件是否成立再執(zhí)行循環(huán)體,
而 do while 則是先執(zhí)行循環(huán)體,再根據(jù)條件判斷是否要退出循環(huán)。這樣就決定了循環(huán)體無(wú)論在任何條件下都會(huì)至少被執(zhí)行一次。它的語(yǔ)法如下:
do 語(yǔ)句 while (條件表達(dá)式)
用 do while 怎么寫上面那個(gè)例程呢?先想一想,再參考下面的程序。
#include
#include
void main(void)
{
SUM = I + SUM; //累加
printf ("%d SUM=%d",I,SUM); //顯示 I++;
}在上面的程序看來(lái) do while 語(yǔ)句和 while 語(yǔ)句似乎沒(méi)有什么兩樣,但在實(shí)際的應(yīng)用中要注
意任何 do while 的循環(huán)體一定會(huì)被執(zhí)行一次。如把上面兩個(gè)程序中 I 的初值設(shè)為 11,那么前一個(gè)程序不會(huì)得到顯示結(jié)果,而后一個(gè)程序則會(huì)得到 SUM=11。
for 語(yǔ)句
#include
#include
void main(void)
{
unsigned int I;
unsigned int SUM = 0; //設(shè)初值
SCON = 0x50; //串行口方式 1,允許接收 TMOD = 0x20; //定時(shí)器 1 定時(shí)方式 2
TCON = 0x40; //設(shè)定時(shí)器 1 開始計(jì)數(shù)
TI = 1;
TR1 = 1; //啟動(dòng)定時(shí)器
for (I=1; I<=10; I++) //這里能設(shè)初始值,所以變量定義時(shí)能不設(shè)
{
printf ("%d SUM=%d",I,SUM); //顯示
}
while(1);
}
如果我們把程序中的 for 改成 for(; I<=10; I++)這樣條件的初值會(huì)變成當(dāng)前 I 變量的
值。如果改成 for(;;)會(huì)怎么樣呢?試試看。
continue 語(yǔ)句
continue 語(yǔ)句是用于中斷的語(yǔ)句,通常使用在循環(huán)中,它的作用是結(jié)束本次循環(huán),跳過(guò)循環(huán)體中沒(méi)有執(zhí)行的語(yǔ)句,跳轉(zhuǎn)到下一次循環(huán)周期。語(yǔ)法為:continue;
continue 同時(shí)也是一個(gè)無(wú)條件跳轉(zhuǎn)語(yǔ)句,但功能和前面說(shuō)到的 break 語(yǔ)句有所不一樣, continue 執(zhí)行后不是跳出循環(huán),而是跳到循環(huán)的開始并執(zhí)行下一次的循環(huán)。在上面的例子 中的循環(huán)體加入 if (I==5) continue;看看什么結(jié)果?
return 語(yǔ)句
return 語(yǔ)句是返回語(yǔ)句,不屬于循環(huán)語(yǔ)句,是要學(xué)習(xí)的最后一個(gè)語(yǔ)句所以一并寫下了。 返回語(yǔ)句是用于結(jié)束函數(shù)的執(zhí)行,返回到調(diào)用函數(shù)時(shí)的位置。語(yǔ)法有二種:
return (表達(dá)式);
return; 語(yǔ)法中因帶有表達(dá)式,返回時(shí)先計(jì)算表達(dá)式,再返回表達(dá)式的值。不帶表達(dá)式則返回的
值不確定。下面是一個(gè)同樣是計(jì)算 1-10 的累加,所不一樣是的用了函數(shù)的方式。
#include
#include
int Count(void); //聲明函數(shù)
void main(void)
{
unsigned int temp;
TCON = 0x40; //設(shè)定時(shí)器 1 開始計(jì)數(shù)
TH1 = 0xE8; //11.0592MHz 1200 波特率 TL1 = 0xE8;
TI = 1;TR1 = 1; //啟動(dòng)定時(shí)器
temp = Count();
printf ("1-10 SUM=%d",temp); //顯示
while(1);
}
int Count(void)
{
unsigned int I, SUM;
for (I=1; I<=10; I++)
{
SUM = I + SUM; //累加
}
return (SUM);
上一篇的最后一個(gè)例子中有用到函數(shù),其實(shí)一直出現(xiàn)在例子中的 main()也算是一個(gè)函數(shù),只不過(guò)它比較特殊,編譯時(shí)以它做為程序的開始段。有了函數(shù) C 語(yǔ)言就有了模塊化的優(yōu)點(diǎn),一般功能較多的程序,會(huì)在編寫程序時(shí)把每項(xiàng)單獨(dú)的功能分成數(shù)個(gè)子程序模塊,每個(gè)子程序就能用函數(shù)來(lái)實(shí)現(xiàn)。函數(shù)還能被反復(fù)的調(diào)用,因此一些常用的函數(shù)能做成函數(shù)庫(kù)以供在編寫程序時(shí)直接調(diào)用,從而更好的實(shí)現(xiàn)模塊化的設(shè)計(jì),大大提高編程工作的效率。
一.函數(shù)定義
通常 C 語(yǔ)言的編譯器會(huì)自帶標(biāo)準(zhǔn)的函數(shù)庫(kù),這些都是一些常用的函數(shù),Keil uv 中也不例外。標(biāo)準(zhǔn)函數(shù)已由編譯器軟件商編寫定義,使用者直接調(diào)用就能了,而無(wú)需定義。但是 標(biāo)準(zhǔn)的函數(shù)不足以滿足使用者的特殊要求,因此 C 語(yǔ)言允許使用者根據(jù)需要編寫特定功能的 函數(shù),要調(diào)用它必須要先對(duì)其進(jìn)行定義。定義的模式如下:
函數(shù)類型函數(shù)名稱(形式參數(shù)表)
{
函數(shù)體
}
函數(shù)類型是說(shuō)明所定義函數(shù)返回值的類型。返回值其實(shí)就是一個(gè)變量,只要按變量類型來(lái)定義函數(shù)類型就行了。如函數(shù)不需要返回值函數(shù)類型能寫作“void”表示該函數(shù)沒(méi)有返回值。注意的是函數(shù)體返回值的類型一定要和函數(shù)類型一致,不然會(huì)造成錯(cuò)誤。函數(shù)名稱的定義在遵循 C 語(yǔ)言變量命名規(guī)則的同時(shí),不能在同一程序中定義同名的函數(shù)這將會(huì)造成編譯錯(cuò)誤(同一程序中是允許有同名變量的,因?yàn)樽兞坑腥趾途植孔兞恐郑P问絽?shù)是指調(diào)用函數(shù)時(shí)要傳入到函數(shù)體內(nèi)參與運(yùn)算的變量,它能有一個(gè)、幾個(gè)或沒(méi)有,當(dāng)不需要形式參數(shù)也就是無(wú)參函數(shù),括號(hào)內(nèi)能為空或?qū)懭?ldquo;void”表示,但括號(hào)不能少。函數(shù)體中能包含有局部變量的定義和程序語(yǔ)句,如函數(shù)要返回運(yùn)算值則要使用 return 語(yǔ)句進(jìn)行返回。在函數(shù)的{}號(hào)中也能什么也不寫,這就成了空函數(shù),在一個(gè)程序項(xiàng)目中能寫一些空函數(shù),在以后的修改和升級(jí)中能方便的在這些空函數(shù)中進(jìn)行功能擴(kuò)充。
二.函數(shù)的調(diào)用
函數(shù)定義好以后,要被其它函數(shù)調(diào)用了才能被執(zhí)行。C 語(yǔ)言的函數(shù)是能相互調(diào)用的,但在調(diào)用函數(shù)前,必須對(duì)函數(shù)的類型進(jìn)行說(shuō)明,就算是標(biāo)準(zhǔn)庫(kù)函數(shù)也不例外。標(biāo)準(zhǔn)庫(kù)函數(shù)的說(shuō)明會(huì)被按功能分別寫在不一樣的頭文件中,使用時(shí)只要在文件最前面用#include 預(yù)處理語(yǔ)句引入相應(yīng)的頭文件。如前面一直有使用的printf 函數(shù)說(shuō)明就是放在文件名為 stdio.h 的頭文件中。調(diào)用就是指一個(gè)函數(shù)體中引用另一個(gè)已定義的函數(shù)來(lái)實(shí)現(xiàn)所需要的功能,這個(gè)時(shí)候函數(shù)體稱為主調(diào)用函數(shù),函數(shù)體中所引用的函數(shù)稱為被調(diào)用函數(shù)。一個(gè)函數(shù)體中能調(diào)用數(shù)個(gè)其它的函數(shù),這些被調(diào)用的函數(shù)同樣也能調(diào)用其它函數(shù),也能嵌套調(diào)用。筆者本人認(rèn)為 主函數(shù)只是相對(duì)于被調(diào)用函數(shù)而言。在 c51 語(yǔ)言中有一個(gè)函數(shù)是不能被其它函數(shù)所調(diào)用的, 它就是 main 主函數(shù)。
調(diào)用函數(shù)的一般形式如下:
函數(shù)名 (實(shí)際參數(shù)表) “函數(shù)名”就是指被調(diào)用的函數(shù)。實(shí)際參數(shù)表能為零或多個(gè)參數(shù),多個(gè)參數(shù)時(shí)要用逗號(hào)隔開,每個(gè)參數(shù)的類型、位置應(yīng)與函數(shù)定義時(shí)所的形式參數(shù)一一對(duì)應(yīng),它的作用就是把參數(shù)傳到被調(diào)用函數(shù)中的形式參數(shù),如果類型不對(duì)應(yīng)就會(huì)產(chǎn)生一些錯(cuò)誤。調(diào)用的函數(shù)是無(wú)參函數(shù)時(shí)不寫參數(shù),但不能省后面的括號(hào)。
在以前的一些例子我們也能看不一樣的調(diào)用方式:
1.函數(shù)語(yǔ)句
如 printf ("Hello World!"); 這是在 我們的第一個(gè)程序中出現(xiàn)的,它以 "HelloWorld!"為參數(shù)調(diào)用 printf 這個(gè)庫(kù)函數(shù)。在這里函數(shù)調(diào)用被看作了一條語(yǔ)句。
2.函數(shù)參數(shù) “函數(shù)參數(shù)”這種方式是指被調(diào)用函數(shù)的返回值當(dāng)作另一個(gè)被調(diào)用函數(shù)的實(shí)際參數(shù),如 temp=StrToInt(CharB(16));CharB 的返回值作為 StrToInt 函數(shù)的實(shí)際參數(shù)傳遞。
3.函數(shù)表達(dá)式
而在上一篇的例子中有 temp = Count();這樣一句,這個(gè)時(shí)候函數(shù)的調(diào)用作為一個(gè)運(yùn)算對(duì)象出現(xiàn)在表達(dá)式中,能稱為函數(shù)表達(dá)式。例子中 Count()返回一個(gè) int 類型的返回 值直接賦值給 temp。注意的是這種調(diào)用方式要求被調(diào)用的函數(shù)能返回一個(gè)同類型的值, 不然會(huì)出現(xiàn)不可預(yù)料的錯(cuò)誤。
前面說(shuō)到調(diào)用函數(shù)前要對(duì)被調(diào)用的函數(shù)進(jìn)行說(shuō)明。標(biāo)準(zhǔn)庫(kù)函數(shù)只要用#include 引入已寫好說(shuō)明的頭文件,在程序就能直接調(diào)用函數(shù)了。如調(diào)用的是自定義的函數(shù)則要用如下形式編寫函數(shù)類型說(shuō)明類型標(biāo)識(shí)符
這樣的說(shuō)明方式是用在被調(diào)函數(shù)定義和主調(diào)函數(shù)是在同一文件中。你也能把這些寫到文件名.h 的文件中用#include "文件名.h"引入。如果被調(diào)函數(shù)的定義和主調(diào)函數(shù)不是在同一文件中的,則要用如下的方式進(jìn)行說(shuō)明,說(shuō)明被調(diào)函數(shù)的定義在同一項(xiàng)目的不一樣文件之上,其實(shí)庫(kù)函數(shù)的頭文件也是如此說(shuō)明庫(kù)函數(shù)的,如果說(shuō)明的函數(shù)也能稱為外部函數(shù)。
extern 類型標(biāo)識(shí)符 函數(shù)的名稱(形式參數(shù)表);
三.中斷函數(shù)
中斷服務(wù)函數(shù)是編寫單片機(jī)應(yīng)用程序不可缺少的。中斷服務(wù)函數(shù)只有在中斷源請(qǐng)求響應(yīng)中斷時(shí)才會(huì)被執(zhí)行,這在處理突發(fā)事件和實(shí)時(shí)控制是十分有效的。例如:電路中一個(gè)按鈕,要求按鈕后 LED 點(diǎn)亮,這個(gè)按鈕何時(shí)會(huì)被按下是不可預(yù)知的,為了要捕獲這個(gè)按鈕的事件,通常會(huì)有三種方法,一是用循環(huán)語(yǔ)句不斷的對(duì)按鈕進(jìn)行查詢,二是用定時(shí)中斷在間隔時(shí)間內(nèi)掃描按鈕,三是用外部中斷服務(wù)函數(shù)對(duì)按鈕進(jìn)行捕獲。在這個(gè)應(yīng)用中只有單一的按鈕功能,那么第一種方式就能勝任了,程序也很簡(jiǎn)單,但是它會(huì)不停的在對(duì)按鈕進(jìn)行查詢浪費(fèi)了CPU 的時(shí)間。實(shí)際應(yīng)用中一般都會(huì)還有其它的功能要求同時(shí)實(shí)現(xiàn),這個(gè)時(shí)候能根據(jù)需要選用第 二或第三種方式,第三種方式占用的 CPU 時(shí)間最少,只有在有按鈕事件發(fā)生時(shí),中斷服務(wù)函 數(shù)才會(huì)被執(zhí)行,其余的時(shí)間則是執(zhí)行其它的任務(wù)。
函數(shù)類型 函數(shù)名 (形式參數(shù)) interrupt n [using n]
interrupt 關(guān)鍵字是不可缺少的,由它告訴編譯器該函數(shù)是中斷服務(wù)函數(shù),并由后面的
n 指明所使用的中斷號(hào)。n 的取值范圍為 0-31,但具體的中斷號(hào)要取決于芯片的型號(hào),像 AT89c51 實(shí)際上就使用 0-4 號(hào)中斷。每個(gè)中斷號(hào)都對(duì)應(yīng)一個(gè)中斷向量,具體地址為 8n+3, 中斷源響應(yīng)后處理器會(huì)跳轉(zhuǎn)到中斷向量所處的地址執(zhí)行程序,編譯器會(huì)在這地址上產(chǎn)生一個(gè)無(wú)條件跳轉(zhuǎn)語(yǔ)句,轉(zhuǎn)到中斷服務(wù)函數(shù)所在的地址執(zhí)行程序。下表是 51 芯片的中斷向量和中 斷號(hào)。
中斷號(hào) | 中斷源 | 中斷向量 |
0 | 外部中斷 0 | 0003H |
1 | 定時(shí)器/計(jì)數(shù)器 0 | 000BH |
2 | 外部中斷 1 | 0013H |
3 | 定時(shí)器/計(jì)數(shù)器 1 | 001BH |
4 | 串行口 | 0023H |
表 9-1 AT89c51 芯片中斷號(hào)和中斷向量
使用中斷服務(wù)函數(shù)時(shí)應(yīng)注意:中斷函數(shù)不能直接調(diào)用中斷函數(shù);不能通過(guò)形參傳速參數(shù); 在中斷函數(shù)中調(diào)用其它函數(shù),兩者所使用的寄存器組應(yīng)相同。限于篇幅其它與函數(shù)相關(guān)的知識(shí)這里不能一一加以說(shuō)明,如變量的傳遞、存儲(chǔ),局部變量、全部變量等,有興趣的朋友可 以訪問(wèn)筆者的網(wǎng)站 閱讀更多相關(guān)文章。
下面是簡(jiǎn)單的例子。首先要在前面做好的實(shí)驗(yàn)電路中加多一個(gè)按鈕,接在 P3.2(12 引腳外 部中斷 INT0)和地線之間。把編譯好后的程序燒錄到芯片后,當(dāng)接在 P3.2 引腳的按鈕接下 時(shí),中斷服務(wù)函數(shù) Int0Demo 就會(huì)被執(zhí)行,把 P3 當(dāng)前的狀態(tài)反映到 P1,如按鈕接下后 P3.7(之前有在這腳裝過(guò)一按鈕)為低,這個(gè)時(shí)候 P1.7 上的 LED 就會(huì)熄滅。放開 P3.2 上的按鈕后,
P1LED 狀態(tài)保持先前按下 P3.2 時(shí) P3 的狀態(tài)。
#include
unsigned char P3State(void); //函數(shù)的說(shuō)明,中斷函數(shù)不用說(shuō)明
void main(void)
{
IT0 = 0; //設(shè)外部中斷 0 為低電平觸發(fā)
EX0 = 1; //允許響應(yīng)外部中斷 0
EA = 1; //總中斷開關(guān)
while(1);
}
//外部中斷 0 演示,使用 2 號(hào)寄存器組
void Int0Demo(void) interrupt 0 using 2
{
unsigned int Temp; //定義局部變量
P1 = ~P3State(); //調(diào)用函數(shù)取得 p2 的狀態(tài)反相后并賦給 P1
for (Temp=0; Temp<50; Temp++); //延時(shí)這里只是演示局部變量的使用
}
//用于返回 P3 的狀態(tài),演示函數(shù)的使用
unsigned char P3State(void)
{
unsigned char Temp;
Temp = P3; //讀取 P3 的引腳狀態(tài)并保存在變量 Temp 中,這樣只有一句語(yǔ)句實(shí)在沒(méi)必要做成函數(shù),這里只是學(xué)習(xí)函數(shù)的基本使用方法
return Temp;
數(shù)據(jù)類型 | 數(shù)組名 | [常量表達(dá)式]; |
數(shù)據(jù)類型 | 數(shù)組名 | [常量表達(dá)式 1]...... [常量表達(dá)式 N]; |
unsigned int xcount [10]; //定義無(wú)符號(hào)整形數(shù)組,有 10 個(gè)數(shù)據(jù)單元
char inputstring [5]; //定義字符形數(shù)組,有 5 個(gè)數(shù)據(jù)單元
float outnum [10],[10];//定義浮點(diǎn)型數(shù)組,有 100 個(gè)數(shù)據(jù)單元
在 C 語(yǔ)言中數(shù)組的下標(biāo)是從 0 開始的而不是從 1 開始,如一個(gè)具有 10 個(gè)數(shù)據(jù)單元的數(shù)組 count,它的下標(biāo)就是從 count[0]到 count[9],引用單個(gè)元素就是數(shù)組名加下標(biāo),如 count[1] 就是引用 count 數(shù)組中的第 2 個(gè)元素,如果錯(cuò)用了 count[10]就會(huì)有錯(cuò)誤出現(xiàn)了。還有一點(diǎn)要 注意的就是在程序中只能逐個(gè)引用數(shù)組中的元素,不能一次引用整個(gè)數(shù)組,但是字符型的數(shù)組就能一次引用整個(gè)數(shù)組。
數(shù)據(jù)類型 [存儲(chǔ)器類型] 數(shù)組名 [常量表達(dá)式] = {常量表達(dá)式};
數(shù)據(jù)類型 [ 存儲(chǔ)器類型] 數(shù)組名 [ 常量表達(dá)式 1]...... [ 常量表達(dá)式 N]={{ 常量表達(dá) 式}...{常量表達(dá)式 N}};
在定義并為數(shù)組賦初值時(shí),開始學(xué)習(xí)的朋友一般會(huì)搞錯(cuò)初值個(gè)數(shù)和數(shù)組長(zhǎng)度的關(guān)系,而致使編譯出錯(cuò)。初值個(gè)數(shù)必須小于或等于數(shù)組長(zhǎng)度,不指定數(shù)組長(zhǎng)度則會(huì)在編譯時(shí)由實(shí)際的初值 個(gè)數(shù)自動(dòng)設(shè)置。
unsigned char LEDNUM[2]={12,35}; //一維數(shù)組賦初值
int Key[2][3]={{1,2,4},{2,2,1}}; //二維數(shù)組賦初值
unsigned char IOStr[]={3,5,2,5,3}; //沒(méi)有指定數(shù)組長(zhǎng)度,編譯器自動(dòng)設(shè)置
unsigned char code skydata[]={0x02,0x34,0x22,0x32,0x21,0x12}; //數(shù)據(jù)保存在 code 區(qū)
下面的一個(gè)簡(jiǎn)單例子是對(duì)數(shù)組中的數(shù)據(jù)進(jìn)行排序,使用的是冒泡法,一來(lái)了解數(shù)組的使用,二來(lái)掌握基本的排序算法。冒泡排序算法是一種基本的排序算法,它每次順序取數(shù)組中的兩個(gè)數(shù),并按需要按其大小排列,在下一次循環(huán)中則取下一次的一個(gè)數(shù)和數(shù)組中下一個(gè)數(shù) 進(jìn)行排序,直到數(shù)組中的數(shù)據(jù)全部排序完成。
#include
#include
void taxisfun (int taxis2[])
{
unsigned char TempCycA,TempCycB,Temp;
for (TempCycA=0; TempCycA<=8; TempCycA++)
for (TempCycB=0; TempCycB<=8-TempCycA; TempCycB++)
{//TempCycB<8-TempCycA 比用 TempCycB<=8 少用很多循環(huán)
if (taxis2[TempCycB+1]>taxis2[TempCycB]) //當(dāng)后一個(gè)數(shù)大于前一個(gè) 數(shù)
{
Temp = taxis2[TempCycB]; //前后 2 數(shù)交換
taxis2[TempCycB] = taxis2[TempCycB+1];
taxis2[TempCycB+1] = Temp; //因函數(shù)參數(shù)是數(shù)組名調(diào)用形參的變動(dòng)影響實(shí)參
}
}
}
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車電子
- 轉(zhuǎn)換器
- 電源管理
- 信號(hào)放大器
評(píng)論