|
第一個(gè)實(shí)驗(yàn):keil軟件使用與點(diǎn)亮人生的第一只發(fā)光二極管
本實(shí)驗(yàn)教程的 pdf完整版下載及配套的的仿真工程文件和源碼下載地址:http://www.raoushi.com/bbs/dpj-85401-1.html
1.001.jpg (23.15 KB, 下載次數(shù): 162)
下載附件
2017-5-20 17:27 上傳
本章詳細(xì)介紹單片機(jī)程序常用編譯軟件 Keil 的用法,用一個(gè)完整的 C51 程序來操作發(fā)光二極管的點(diǎn)亮與熄滅,然后調(diào)用 C51 庫函數(shù)來方 便地實(shí)現(xiàn)流水燈,從這一章開始我們將手把手地講解單片機(jī) C 語言編 程。認(rèn)真學(xué)好本章,對(duì)于初學(xué)者來說將會(huì)是一個(gè)非常好的開頭。
用實(shí)操點(diǎn)亮一只燈程序來學(xué)會(huì)使用編程軟件 keil 的基本功能。
最終目標(biāo):點(diǎn)亮下圖 D8 發(fā)光二極管。
1 電路走線如下:
1.002.jpg (57.33 KB, 下載次數(shù): 171)
下載附件
2017-5-20 17:27 上傳
2 元件特性 發(fā)光二極管的原理
1.003.jpg (4.3 KB, 下載次數(shù): 162)
下載附件
2017-5-20 17:27 上傳
正極這邊為高電平,負(fù)極為低電平,發(fā)光二極管就行,兩邊為高電平, 發(fā)光二極管就不亮。
3 程序流程:把 P1.1~P1.7 置高電平,P1.0 置低電平即可。
4 程序的書寫與調(diào)試。 我們要書寫程序,需要一個(gè) keil 軟件。
Keil 的操作步驟。 詳細(xì)操作步驟:
1.004.jpg (16.07 KB, 下載次數(shù): 160)
下載附件
2017-5-20 17:27 上傳
從圖片中不難看出,我們寫的程序(子項(xiàng)目)都是圍繞總項(xiàng)目轉(zhuǎn)的, 然后從總項(xiàng)目輸出我們想要的單片機(jī)程序。
第一步:新建總項(xiàng)目(打開軟件跟著做,熟悉一下)
當(dāng)我們安裝好 Keil Uvision 3 編程軟件后,就點(diǎn) projec(t 項(xiàng)目)——new
prouect(新項(xiàng)目)來新建項(xiàng)目。
1.005.jpg (35.35 KB, 下載次數(shù): 153)
下載附件
2017-5-20 17:27 上傳
點(diǎn)擊完 new project 后,會(huì)有如下對(duì)話框。
1.006.jpg (22.51 KB, 下載次數(shù): 157)
下載附件
2017-5-20 17:27 上傳
從上面不難看出,我們新建的單片機(jī)程序項(xiàng)目后綴名字是 uv2,而且
當(dāng) uv2 項(xiàng)目產(chǎn)生的時(shí)候,會(huì)自動(dòng)附帶很多其它 uv2 需要的文件,為了 防止我們產(chǎn)生瀏覽混亂,這個(gè)時(shí)候我們就需要“新建一個(gè)文件夾”, 把 uv2 存在里面,那么附帶的文件也會(huì)自己存進(jìn)去這個(gè)文件夾里面去 方便我們?yōu)g覽和操作了。
1.007.jpg (33.48 KB, 下載次數(shù): 175)
下載附件
2017-5-20 17:27 上傳
我命名字為“點(diǎn)亮一只燈”,并且雙擊進(jìn)入這個(gè)文件夾里面。
1.008.jpg (26.56 KB, 下載次數(shù): 138)
下載附件
2017-5-20 17:27 上傳
1.009.jpg (27.39 KB, 下載次數(shù): 158)
下載附件
2017-5-20 17:27 上傳
CPU 選擇是找到 Atmel 并點(diǎn)擊其它+號(hào)。
1.010.jpg (32.4 KB, 下載次數(shù): 164)
下載附件
2017-5-20 17:27 上傳
往下拉,找到 AT89C52(選擇 51 類型的單片機(jī))
1.011.jpg (31.94 KB, 下載次數(shù): 160)
下載附件
2017-5-20 17:27 上傳
選擇后,點(diǎn)確定按鈕。
1.012.jpg (40.14 KB, 下載次數(shù): 151)
下載附件
2017-5-20 17:27 上傳
是否復(fù)制 51 標(biāo)準(zhǔn)代碼,這個(gè)暫時(shí)沒有什么用,點(diǎn)否就可以。
1.013.jpg (13.58 KB, 下載次數(shù): 152)
下載附件
2017-5-20 17:27 上傳
這個(gè)時(shí)候,我們才創(chuàng)建好總項(xiàng)目,從一開始的圖片我們看到,還需要
為總項(xiàng)目“添加子項(xiàng)目”。
下面圖片指針頭指的是,點(diǎn)亮一盞燈的總項(xiàng)目,通過上面的操作,已 經(jīng)創(chuàng)建完成。
1.014.jpg (29.37 KB, 下載次數(shù): 142)
下載附件
2017-5-20 17:27 上傳
第二步:為總項(xiàng)目添加子項(xiàng)目
為總項(xiàng)目添加子項(xiàng)目之前,我們需要新建一個(gè)文件(程序編輯窗口), 點(diǎn)擊軟件 file 下面那個(gè)文本圖標(biāo) create a newfile(創(chuàng)建一個(gè)新的文件)
1.015.jpg (23.12 KB, 下載次數(shù): 163)
下載附件
2017-5-20 17:27 上傳
得到如下圖的程序編輯窗口,在這里面編寫單片機(jī)的程序。
1.016.jpg (30.43 KB, 下載次數(shù): 196)
下載附件
2017-5-20 17:27 上傳
現(xiàn)在我們需要的是點(diǎn)亮一只燈的程序。
1.017.jpg (33.25 KB, 下載次數(shù): 139)
下載附件
2017-5-20 17:27 上傳
#include Main() { P1=0xfe; } 寫好后,我們還不知道子項(xiàng)目里的程序有沒有錯(cuò),現(xiàn)在我們需要把這 個(gè)子項(xiàng)目添加到“點(diǎn)亮一只燈.uv2”的總項(xiàng)目里,去讓軟件查錯(cuò),方 便我們修正,輸出我們想要的單片機(jī)代碼去讓單片機(jī)工作,那需要如 何做呢?
很顯然,當(dāng)我們新建一個(gè)子項(xiàng)目編輯窗口時(shí)(子項(xiàng)目),軟件是沒有
把這個(gè)子項(xiàng)目存到總項(xiàng)目當(dāng)中的,而是需要我們?nèi)耸痔砑舆M(jìn)去。
操作方法是:先保存,然后再把這個(gè)子項(xiàng)目添加到總項(xiàng)目去。
先保存。
需要點(diǎn)擊如下圖的圖標(biāo) save the active document(保存活動(dòng)文檔),就 是保存當(dāng)前編輯中的程序編輯窗口(子項(xiàng)目)。
1.018.jpg (32.86 KB, 下載次數(shù): 157)
下載附件
2017-5-20 17:27 上傳
或許有些朋友很聰明,看到窗口上的*號(hào)就知道還沒有保存的文件。
默認(rèn)保存在我們創(chuàng)建的“點(diǎn)亮一只燈”文件夾當(dāng)中,還有重要的一點(diǎn)
是,記得文件名后綴必須是“.c”,第二次:文件名后綴必須是“.c” 第三次:文件名后綴必須是“.c”,重要是事情說三遍,這樣后面的 操作就會(huì)萬無一失了。
1.019.jpg (30.62 KB, 下載次數(shù): 156)
下載附件
2017-5-20 17:27 上傳
保存后,某些字母是有顏色的,這個(gè)就是保存好的象征,如下圖所示:
1.020.jpg (31.85 KB, 下載次數(shù): 157)
下載附件
2017-5-20 17:27 上傳
保存后,現(xiàn)在我們需要把子項(xiàng)目添加到總項(xiàng)目當(dāng)中。
1.021.jpg (35.76 KB, 下載次數(shù): 145)
下載附件
2017-5-20 17:27 上傳
鼠標(biāo)右擊“source group1”選擇”add file to group ’source group1 ’”(添
加文件到組,根源組 1)
1.022.jpg (50.2 KB, 下載次數(shù): 172)
下載附件
2017-5-20 17:27 上傳
默認(rèn)打開的就是“點(diǎn)亮一只燈”文件夾下面的“點(diǎn)亮一點(diǎn)燈”的 C 語
言程序(就是我們剛剛保存的.c 文件) 然后點(diǎn)窗口上的 add(添加),
1.023.jpg (23.46 KB, 下載次數(shù): 160)
下載附件
2017-5-20 17:27 上傳
Source group1 下有了“點(diǎn)亮一只燈”的 C 語言程序
1.024.jpg (30.04 KB, 下載次數(shù): 161)
下載附件
2017-5-20 17:27 上傳
添加成功后,就退出上面那個(gè)添加窗口。
添加子項(xiàng)目到總項(xiàng)目后,我們還不知道我們寫的程序有沒有錯(cuò),現(xiàn)在
1.025.jpg (43.57 KB, 下載次數(shù): 149)
下載附件
2017-5-20 17:27 上傳
要做的是,讓軟件查錯(cuò),那要如何做呢? 如下圖所示。
如果總項(xiàng)目只有一個(gè)子項(xiàng)目的時(shí)候(就像點(diǎn)亮一只燈.c),我們就點(diǎn) built target,如果有二個(gè)或以上的子項(xiàng)目,就點(diǎn) built all target files, 就兩個(gè)按鈕就是這樣用,這就為什么叫總項(xiàng)目和子項(xiàng)目的原因,因?yàn)?總項(xiàng)目中可以包含多個(gè)子項(xiàng)目的。
來看看點(diǎn)擊后的效果。
這里只有一個(gè)子項(xiàng)目,只點(diǎn) build target 就行。
1.026.jpg (38.84 KB, 下載次數(shù): 148)
下載附件
2017-5-20 17:27 上傳
1.027.jpg (48.86 KB, 下載次數(shù): 146)
下載附件
2017-5-20 17:27 上傳
從上圖可以看到,build 完后,我們看到是 0 error (0 錯(cuò)誤),0 warning
(0 警告)。
如果我們把 P1=0xff;,后面這個(gè)“;”分號(hào)去掉,看看是怎么樣。
1.028.jpg (55.32 KB, 下載次數(shù): 134)
下載附件
2017-5-20 17:27 上傳
很明顯,它出來了一句,syntax error near (} 語法錯(cuò)誤在花括號(hào)附近),
target not created(目標(biāo)沒創(chuàng)建)。
雙擊 syntax error near }這條語句時(shí),光標(biāo)就會(huì)出來在附近,讓你改錯(cuò)。
1.029.jpg (61.5 KB, 下載次數(shù): 141)
下載附件
2017-5-20 17:27 上傳
現(xiàn)在我們把分號(hào)加上后,它編譯沒有錯(cuò)誤,證明程序可以運(yùn)用,但是
軟件還沒有輸出單片機(jī)運(yùn)行需要的代碼。
1.030.jpg (33.28 KB, 下載次數(shù): 150)
下載附件
2017-5-20 17:27 上傳
第三步:輸出單片機(jī)運(yùn)行需要的代碼
鼠標(biāo)右擊“target”點(diǎn)“options for target ‘target 1’”(選項(xiàng)對(duì)于目標(biāo) 1)
1.031.jpg (42.96 KB, 下載次數(shù): 140)
下載附件
2017-5-20 17:27 上傳
點(diǎn)第三列的 output “輸出”按鈕,然后把 create hex file“創(chuàng)建 16 進(jìn)
制文件”勾上后,點(diǎn)確定。
1.032.jpg (37.99 KB, 下載次數(shù): 127)
下載附件
2017-5-20 17:27 上傳
再點(diǎn) built target
1.033.jpg (16.52 KB, 下載次數(shù): 124)
下載附件
2017-5-20 17:27 上傳
這樣在編譯沒有錯(cuò)誤成功后,它就會(huì)產(chǎn)生一個(gè) hex 文件(單片機(jī)需要 的代碼),我們就可以用這個(gè) hex 文件讓我們的單片機(jī)工作啦!
它在什么位置?就在我們新建的“點(diǎn)亮一只燈”的文件夾里面。
1.034.jpg (22.49 KB, 下載次數(shù): 142)
下載附件
2017-5-20 17:27 上傳
需要用的時(shí)候,我們需要到這個(gè)文件夾找出來,這樣我們 P1.0 口的 發(fā)光二極管就可以點(diǎn)亮了。
1.035.jpg (38.74 KB, 下載次數(shù): 135)
下載附件
2017-5-20 17:27 上傳
查找方法:
如果你是用仿真軟件。 先雙擊 89C52
1.036.jpg (46.57 KB, 下載次數(shù): 136)
下載附件
2017-5-20 17:27 上傳
再點(diǎn)擊 program file 到點(diǎn)亮一盞燈文件夾里面,把點(diǎn)亮一只燈.hex 文 件,找出來就行。(如下圖)
1.037.jpg (40.3 KB, 下載次數(shù): 158)
下載附件
2017-5-20 17:27 上傳
找出來后,再點(diǎn)右上角的 OK 就可以了。
你可以復(fù)制下面程序去編程軟件,熟悉上面的功能,如果想要靠自己 記憶去寫,也可以嘗試一下。
#include
main()
{ P1=0xff; }
程序講解:
#include 包含這個(gè)頭文件,頭文件上面我們講解,就是為
單片機(jī)里面的地址命名字,方便我們直接用名字使用(每個(gè)程序的開 頭肯定有頭文件的)
main()
{
}
Main()這個(gè)是主函數(shù)入口,程序在花括號(hào){ }里面執(zhí)行,之于 main 旁邊 的括號(hào)是什么東西,我們以后用到再講解,現(xiàn)在明白它是固定格式 main(),mian 括號(hào)就行。
P1=0xfe;
P1=1111 1110,把 P1.0 位置低電平,點(diǎn)亮 D8 發(fā)光二極管。
需要注意的是,這里的 P1 不可隨意寫,P 是大寫,若寫成 p,編譯程 序時(shí)將報(bào)錯(cuò),因?yàn)榫幾g器并不認(rèn)識(shí) p1,它只認(rèn)識(shí) P1,這是因?yàn)槲覀?在頭文件中定義的是“sfr P1= 0x90;”。 P1=0xfe 后面的分號(hào)“;”也不要漏掉,不然程序會(huì)報(bào)錯(cuò), 這些也是大多初學(xué)者編寫第一個(gè)程序時(shí)常犯的錯(cuò)誤,希望大家留意一 下。
注釋問題。
知識(shí)點(diǎn):C 語言中注釋的寫法
在 C 語言中,注釋有兩種寫法:
(1)// 兩個(gè)斜扛后面跟著的為注釋語句。這種寫法只能注釋一行, 當(dāng)換行時(shí),又必須在新行上重新寫兩個(gè)斜扛。
(2)/*…*/ 斜扛與星號(hào)結(jié)合使用,這種寫法可以注釋任意行,即斜 扛星號(hào)與星號(hào)斜扛之間的所有文字都作為注釋。
下圖是第二種。
1.038.jpg (25.15 KB, 下載次數(shù): 145)
下載附件
2017-5-20 17:27 上傳
所有注釋都不參與程序編譯,編譯器在編譯過程會(huì)自動(dòng)刪去注釋,注
釋的目的是為了我們讀程序方便,一般在編寫較大的程序時(shí),分段加 入注釋,這樣當(dāng)我們回過頭來再次讀程序時(shí),因?yàn)橛辛俗⑨專浯a 的意義便一目了然了。若無注釋,我們不得不特別費(fèi)力地將程序 重新閱讀一遍方可知道代碼含義。養(yǎng)成良好的書寫代碼格式的習(xí)慣, 經(jīng)常為自己編寫的代碼加入注釋,以后定能方便許多。
練習(xí):
把 P1.1~P1.7 口逐個(gè)點(diǎn)亮。
把 P1.0~P1.3 點(diǎn)亮,其它四個(gè)不亮。
while語句 通過上面一節(jié)的學(xué)習(xí),想必大家已經(jīng)對(duì)點(diǎn)亮實(shí)驗(yàn)板上的任意發(fā)光二極 管非常熟悉了,但是,先不要高興得太早,上面的程序并不完善,任 何一個(gè)程序都要有頭有尾才對(duì),而上面我們寫的程序似乎只有頭而無 尾。我們分析一下看,當(dāng)程序運(yùn)行時(shí),首先進(jìn)入主函數(shù),順序執(zhí)行里 面的所有語句,因?yàn)橹骱瘮?shù)中只有一條語句,當(dāng)執(zhí)行完這條語句后, 該執(zhí)行什么了?
因?yàn)槲覀儧]有給單片機(jī)明確指示下一步該做什么,所以單片機(jī)在運(yùn)行 時(shí)就很有可能會(huì)出錯(cuò)。
根據(jù)經(jīng)驗(yàn),當(dāng) Keil 編譯器遇到這種情況時(shí),它會(huì)自動(dòng)從主函數(shù)開始處 重新執(zhí)行語句,所以單片機(jī)在運(yùn)行上面兩個(gè)程序時(shí),實(shí)際上是在不斷 地重復(fù)點(diǎn)亮發(fā)光二極管的操作,而我們的意圖是讓單片機(jī)點(diǎn)亮二極管 后就結(jié)束,也就是讓程序停止在某處,這樣一個(gè)有頭有尾的程序才完
整。
那么如何讓程序停止在某處呢?我們用 while 語句就可以實(shí)現(xiàn)。 知識(shí)點(diǎn):while()語句的應(yīng)用
格式:
while(表達(dá)式)
{
內(nèi)部語句(內(nèi)部可為空)
}
特點(diǎn):先判斷表達(dá)式是真還是假,再執(zhí)行或者不執(zhí)行內(nèi)部語句。 在 C 語言的判斷條件中,1 或以上為真,0 為假。 判斷原則:若表達(dá)式不是 0,即不是 while(0)這樣的形式。這樣說就 是 while(1),while(2),while(3 或以上),即為真,那么執(zhí)行 while 花括 號(hào)的內(nèi)部語句,如果是 while(0)即為假,跳過while,不執(zhí)行 while 花 括號(hào)的內(nèi)部語句。
while 有兩種形式:
1 如果語句只有一條。 直接用表達(dá)式+執(zhí)行語句+分號(hào)結(jié)束就行。 如:
While(1) 表達(dá)式。
P1=0xfe; 執(zhí)行語句+分號(hào)。
While(1)是表達(dá)式,用來判斷是真是假。 因?yàn)檫@里是真,所以語句就無限循環(huán)于 P1=0xfe,后面再加上一個(gè)分 號(hào)表示這是一條結(jié)束。
1.039.jpg (8.4 KB, 下載次數(shù): 134)
下載附件
2017-5-20 17:27 上傳
2 如果有兩條以上表達(dá)式。 如:
While(1) P1=0xfe; P1=0xfa;
它也只是無限循環(huán)于 P1=0xfe 這條語句,而不往下執(zhí)行 P1=0xfa,這
樣的程序格式顯然是滿足不了多少功能,沒有什么意義的,那我們要 怎么寫才能讓 while 執(zhí)行多些語句呢?
從上面可以觀察到,我們還有花括號(hào)可用。 是的,
while(1)
{
}
“While(1)+花括號(hào)”就可以實(shí)現(xiàn)我們想要的功能。
While(1)
{ P1=0xfe; P1=0xfa; }
這樣就可以執(zhí)行完 P1=0xfe,又繼續(xù)執(zhí)行 P1=0xfa,如果后面還有語句
就會(huì)接著一條條繼續(xù)執(zhí)行,直到 } 的這個(gè)結(jié)尾,繼續(xù)又重新開始到
{ 這個(gè)開始繼續(xù)執(zhí)行,無限循環(huán)。
1.040.jpg (8.57 KB, 下載次數(shù): 131)
下載附件
2017-5-20 17:27 上傳
現(xiàn)在我們可以了解到,while 有無限循環(huán)執(zhí)行它內(nèi)部語句的用法,如
果只有一條語句,直接在這條語句加分號(hào)就行,如果有兩條語句或以 上就需要加{}花括號(hào)。
如果 while(0) P1=0xfe; P1=0xfa;
因?yàn)楝F(xiàn)在 while 為假,所以它不會(huì)執(zhí)行 P1=0xfe,而往下執(zhí)行 P1=0xfa, 因?yàn)?P1=0xfa;是不屬于 while 的內(nèi)部語句。
花括號(hào)原理也是一樣。
while(0)
{ P1=0xfe; P1=0xfa; } P1=0x0f;
不執(zhí)行 while 花括號(hào)里面的語句,執(zhí)行 P1=0x0f;
通過這些認(rèn)識(shí) 我們來編寫一個(gè)完整的點(diǎn)亮第一個(gè)發(fā)光二極管的程序。 #include //52 系列單片機(jī)頭文件
void main() //主函數(shù)
(
P1=0xfe;
while(1);
)
這里的 main 前面多了一個(gè) void,void 有空的意思,在 main 前面加上
void 這個(gè)東西,實(shí)際意義并不大,只是讓程序具體點(diǎn),你直接用 main()
也可以。
然后到 P1=0xfe,再停止在 while(1);這里,while 里面,如果有一條語 句就執(zhí)行完這個(gè)語句,停止到分號(hào),如果沒有語句就直接在分號(hào)這里 無限循環(huán),相當(dāng)于停止標(biāo)記,所以以后一看到 while(1);,就知道是停 止標(biāo)記了。
知識(shí)點(diǎn):for語句 格式:
for(表達(dá)式 1;表達(dá)式 2;表達(dá)式 3)
{
內(nèi)部語句
}
例子:
for(i=0;i<3;i++)
{ P1=0xfe; }
語句解說:
1.041.jpg (16.58 KB, 下載次數(shù): 134)
下載附件
2017-5-20 17:27 上傳
執(zhí)行過程:
1.042.jpg (27.71 KB, 下載次數(shù): 133)
下載附件
2017-5-20 17:27 上傳
上圖文字說明:
1 判斷:判斷 i 是否少于 3。
2 執(zhí)行:執(zhí)行 for 內(nèi)部語句。
3 i++:i 自加 1。
從上面圖片可以看到 第一輪: 第 1 步:初始化 i=0(i 賦值等于 0)。 第 2 步:判斷 i 是否少于 3。 第 3 步:現(xiàn)在 i=0 是少于 3,就執(zhí)行 for 花括號(hào)的內(nèi)部語句一次。
第 4 步:當(dāng)執(zhí)行完一次內(nèi)部語句后,i++(i++的意思就是 i 自己加 1)。
第二輪:
第 5 步:因?yàn)樯厦?i 從 0 加了一次,現(xiàn)在 i=1。 第 6 步:判斷 i 是否少于 3。 第 7 步:現(xiàn)在 i=1 是少于 3,就執(zhí)行 for 花括號(hào)的內(nèi)部語句一次。
第 8 步:當(dāng)執(zhí)行完一次內(nèi)部語句后,i++(i++的意思就是 i 自己加 1)。
第三輪:
第 9 步:因?yàn)樯厦?i 從 1 加了一次,現(xiàn)在 i=2。 第 10 步:判斷 i 是否少于 3。 第 11 步:現(xiàn)在 i=1 是少于 3,就執(zhí)行 for 花括號(hào)的內(nèi)部語句一次。 第 12 步:當(dāng)執(zhí)行完一次內(nèi)部語句后,i++(i++的意思就是 i 自己加 1)。
第四輪:
第 13 步:因?yàn)樯厦?i 從 2 加了一次,現(xiàn)在 i=3。 第 14 步:判斷 i 是否少于 3。 第 15 步:現(xiàn)在 i=3 不少于 3,就不執(zhí)行 for 內(nèi)部語句了,退出 for 語 句繼續(xù)往下面執(zhí)行。
1.043.jpg (15.18 KB, 下載次數(shù): 123)
下載附件
2017-5-20 17:27 上傳
要點(diǎn):
1 當(dāng) for 初始化完一次后,就沒有它的事了。
2 因?yàn)?i 初始化是 0,從第 0 次開始執(zhí)行,就算 i<3 也是執(zhí)行 3 次(第
0 次,第 1 次,第 2 次,共三次)
3 i++是 i 自加 1 的意思。
如果上面的理解。 那么
for(i=3;i>0;i--)
{ P1=0xfe; }
也是一樣的原理,這里是 i 首先等于 3,如果 i>0,就執(zhí)行內(nèi)部語句, 然后 i--,這里是 i 自減 1 次。這個(gè)也是共執(zhí)行 3 次,執(zhí)行完后就退出 for 語句
通過以上步驟,這個(gè) for 語句就執(zhí)行完了,單片機(jī)在執(zhí)行這個(gè) for
語句的時(shí)候是需要時(shí)間的,上面 i 的初值較小,所以執(zhí)行的步數(shù)就少,
當(dāng)我們給 i 賦的初值越大,它執(zhí)行所需的時(shí)間就越長(zhǎng),因此我們就可
以利用單片機(jī)執(zhí)行這個(gè) for 語句的時(shí)間來作為一個(gè)簡(jiǎn)單延時(shí)語句。
很多初學(xué)者容易犯的錯(cuò)誤是,想用 for 語句寫一個(gè)延時(shí)比較長(zhǎng)的語句, 那么他可能會(huì)這樣寫:
unsigned char i;(unsigned char 無符號(hào)字符型,這是是定義 i 為無 符號(hào)字符型,數(shù)值范圍是 0~255)
for(i=0;i<3000;i--)
{
;
}
但是結(jié)果卻發(fā)現(xiàn)這樣寫并不能達(dá)到延長(zhǎng)時(shí)間的效果,因?yàn)樵谶@里 i 是 一個(gè)字符型變量,它的最大值為 255,當(dāng)你給它賦一個(gè)比最大值都大 的數(shù)時(shí),這里 i 賦值是 3000,程序自然就出錯(cuò)誤了。
因此我們尤其要注意,每次給變量賦初值時(shí),都要首先考慮變量類型, 然后根據(jù)變量類型賦一個(gè)合理的值,我們所指的變量類型,就是字符
型(8 位),和整型(16 位),等,而且這兩個(gè)在 51 單片機(jī)最常用,
理解這兩個(gè),其它的都已收入囊中。
如果我們想用 for 語句做一個(gè)秒的延時(shí),我們?cè)撛趺磳懩兀?秒是我們?nèi)粘S玫臅r(shí)間單位,如果單片機(jī)也用秒的時(shí)間來一句句執(zhí)行 程序語句,這樣就非常沒有效率,還不如直接用人手操作,我們創(chuàng)造 出單片機(jī)代替人手的根本原因,就是讓它自動(dòng)化,而且快速。
那單片機(jī)到底有多快?
我們用 s(秒),單片機(jī)用的時(shí)間是 us(微秒) 而且
1s=1000ms=1000000us
1 秒=1000 毫秒=1 百萬微秒。 很明顯,單片機(jī)用的時(shí)間是我們的時(shí)間的 1 百萬倍。
如果我們知道單片機(jī)執(zhí)行一條語句需要多少時(shí)間,就可以用 for 語句 編寫出一個(gè)一秒的延時(shí)程序了。
我們來看看執(zhí)行一個(gè)分號(hào)需要多少時(shí)間。因?yàn)榫д袷菦Q定時(shí)間的,我 們單片機(jī)常用的是 11.0592M,想計(jì)算準(zhǔn)確的時(shí)間,先在軟件里面設(shè) 置一下。
1.044.jpg (37.26 KB, 下載次數(shù): 108)
下載附件
2017-5-20 17:27 上傳
右擊 target,點(diǎn) option for target ,點(diǎn) target,在 xtal 窗口輸入“11.0592”,
后點(diǎn)確定。
然后通過 keil 軟件——start/stop debug 可以監(jiān)測(cè)到程序執(zhí)行流程,進(jìn) 入 debug(調(diào)試)后(看下圖),按鍵盤F10 或者 F11 一步步執(zhí)行, F10 是跨越式執(zhí)行,F(xiàn)11 是細(xì)節(jié)語句執(zhí)行,說的多不如動(dòng)手試一試, 就會(huì)明白很多了。
1.045.jpg (28.62 KB, 下載次數(shù): 102)
下載附件
2017-5-20 17:27 上傳
來看看執(zhí)行分號(hào)之前的時(shí)間。
1.046.jpg (32.58 KB, 下載次數(shù): 114)
下載附件
2017-5-20 17:27 上傳
從上圖可以看到,執(zhí)行一個(gè)分號(hào)之前的時(shí)間是,0.00044162 s(左邊 的 sec 那里看到),0.00044162 s=0.00044162s*100 萬=441.62us(小數(shù) 點(diǎn)向右移六位就行)
執(zhí)行一次分號(hào)后的時(shí)間。
1.047.jpg (31.25 KB, 下載次數(shù): 115)
下載附件
2017-5-20 17:27 上傳
從 上 圖 可 以 看 到, 執(zhí) 行 完 一 次 分號(hào) 之 后 的 時(shí) 間 是: 0.00044596
s=445.96us
分號(hào)之前的時(shí)間=441.62us 分號(hào)之后的時(shí)間=445.96us 分號(hào)用的時(shí)間=445.96us - 441.62us=4.34us。 所以執(zhí)行一次分號(hào)的時(shí)間是 4.34 微秒。
從我們上面圖片程序可以看到。
For(j=0;j<230;j++)
{
;
}
為什么是執(zhí)行 230 次分號(hào)呢?
因?yàn)?230*4.34us(一次分號(hào)的時(shí)間)= 998.2us=0.9982ms 約等于 1ms,
(因?yàn)?1s=1000ms,1ms=1000us,牢記這個(gè)時(shí)間關(guān)系)
現(xiàn)在我們知道。
For(j=0;j<230;j++)
{
;
}
這個(gè) for 語法是執(zhí)行了 1ms(1 毫秒)的時(shí)間,但是這還沒有達(dá)到我 們想要的 1S 的時(shí)間,或許有些朋友很聰明可以想出,把這個(gè) 1ms 執(zhí) 行多 1000 次不就是 1S 的時(shí)間了?
好家伙,現(xiàn)在動(dòng)手。
for(i=0;i<1000;i++)
{
For(j=0;j<230;j++)
{
;
}
}
1.048.jpg (21.66 KB, 下載次數(shù): 103)
下載附件
2017-5-20 17:27 上傳
很明顯,C 語言是可以用于內(nèi)嵌語句執(zhí)行的,從上面圖片不難看到, 執(zhí)行完 230 次分號(hào)后(花 1ms),還要重復(fù)執(zhí)行 1000 次 1ms 就是 1s 了。
一盞燈的一秒亮與滅
目標(biāo):一盞燈的一秒亮與滅
1 電路流程圖:
2 元件特性 發(fā)光二極管的原理
正極這邊為高電平,負(fù)極為低電平,發(fā)光二極管就行,兩邊為高電平, 發(fā)光二極管就不亮。 。
3 程序流程的概括
1.049.jpg (19.32 KB, 下載次數(shù): 109)
下載附件
2017-5-20 17:27 上傳
從上面圖片可以看到,讓一只燈亮滅的原理還是比如容易的,首先是 點(diǎn)亮一只燈,然后一秒延時(shí),再滅燈,再一秒延時(shí),再回到點(diǎn)亮一只 燈這樣無限循環(huán)的重復(fù)。
來看看程序。
#include //頭文件
#define uchar unsigned char //把 unsigned char 命名字為 uchar
#define uint unsigned int //把 unsigned int 命名字為 uchar
uint i; //整型 i 變量
uchar j; //字符型 j 變量
sbit led=P1^0; //把 P1 的第 0 個(gè)位命名字為 led
main() //主函數(shù)入口
{
while(1) //無限循環(huán)入口
{
led=0; //點(diǎn)亮 P1.0
for(i=0;i<1000;i++) //延時(shí) 1 秒
{
for(j=0;j<230;j++)
{
;
}
}
led=1; 滅燈
for(i=0;i<1000;i++) 延時(shí)一秒
{
for(j=0;j<230;j++)
{
;
}
}
}
}
看看這前面部分是什么東西
#include //頭文件
#define uchar unsigned char //把 unsigned char 命名字為 uchar
#define uint unsigned int //把 unsigned int 命名字為 uchar uint i; //整型 i 變量 uchar j; //字符型 j 變量
sbit led=P1^0; //把 P1 的第 0 個(gè)位命名字為 led
#include //頭文件 頭文件每個(gè)程序開頭肯定有的。
#define 也很好理解的,也是作命名字用,因?yàn)楫?dāng)引入頭文件 reg52
后,單片機(jī)也只是知道什么是 unsigned char,unsigned int 等。
而我們覺得太長(zhǎng)不好寫,就有了#define uchar unsigned char ,把 unsigned char(無符號(hào)字符型)命名字為uchar,#define uint unsigned int 也是同樣的道理,uint(無符號(hào)整型)
1.050.jpg (10.83 KB, 下載次數(shù): 105)
下載附件
2017-5-20 17:27 上傳
還記得我們上面學(xué)過的 8 位,16 位嗎?8 個(gè)位的二進(jìn)制最大的數(shù)是十 進(jìn)制 255,當(dāng)超過 255 后,它就又會(huì)回歸到 0重新開始,而我們的 uchar 就是用于表明是 8 個(gè)位的水杯(最大十進(jìn)制數(shù)是 255)。
而 uint 是 16 位的水杯,最大的十進(jìn)制數(shù)可以表達(dá)到 65535,6 萬多。
那么現(xiàn)在 uint i,和 uchar j 現(xiàn)在明白了麼?
uint i,聲明一個(gè) 16 位的變量 i,方便程序內(nèi)用。I 的數(shù)值范圍在 0~65535
內(nèi)都可以。
uchar j,聲明一個(gè) 8 位的變量 j,方便程序內(nèi)用。J 的數(shù)值范圍在 0~255
內(nèi)都可以。
聲明完后,I, j 這些變量位置哪里來?當(dāng)你定義好,單片機(jī) RAM(動(dòng) 態(tài)存儲(chǔ)器)自動(dòng)分配的,這不用你操心。
從上面程序你可以看到 I, j 在哪里用嗎? 延時(shí)程序 for(i=0;i<1000;i++) 延時(shí)一秒
{
for(j=0;j<230;j++) 延時(shí) 1 毫秒
{
;
}
}
很明顯,j 少于 255,所以用 uchar 就行,i>255<6 萬用 uint
sbit led=P1^0; 也很好理解的,聲名特殊功能寄存器的位,把 P1.0 這 個(gè)位命名字為 led,現(xiàn)在看到^這個(gè)符號(hào)了吧?很常用。
命名字方式,我們學(xué)過四種。 特殊功能寄存器的位命名:sbit 特殊功能寄存器 8 位地址命名:sfr P1=0x90; 特殊功能寄存器 16 位地址命名:sfr16 TC=0x91;(連續(xù)用 0x91,0x92 這兩個(gè)地址,只聲名第一個(gè)地址就可以)Define:把什么名字命什么名字(多數(shù)用于英文字母的定義,方便我 們記憶運(yùn)用)
再看看我們程序編寫時(shí)常用的四種(牢記)。
1 特殊功能寄存器位命名:sbit
2 Define:把什么名字命什么名字(多數(shù)用于英文字母的定義,方便 我們記憶運(yùn)用)
3 Uchar 字符型。
4 Uint 整型。
如何區(qū)分特殊功能寄存器和普通寄存器?原理很簡(jiǎn)單的,當(dāng)你這個(gè)寄 存器是特殊功能的,比如 P1(廠家告訴你這個(gè)寄存器有什么用,就
是特殊功能),如果定義它的位來運(yùn)用,就用 sbit(特殊功能寄存器
位命名)。
如果廠家沒有告訴你這個(gè)寄存器具體有什么用,就是普通寄存器,比 如 uchar i, uint j,等等,當(dāng)你聲明好后,單片機(jī)會(huì)自動(dòng)分配寄存器的, 如果你想用普通的位,直接用 bit 就行,如 bit flag,為 flag 這個(gè)名字 定義為位功能,這個(gè)時(shí)候 flag 也是只能在 0~1,這兩個(gè)數(shù)內(nèi)變化,現(xiàn) 在稍微了解就行,以后用就的時(shí)候你就明白了。
再來看看程序,和我們的流程圖是一模一樣。
1.051.jpg (28.44 KB, 下載次數(shù): 102)
下載附件
2017-5-20 17:27 上傳
從上面圖片我們發(fā)現(xiàn),延時(shí)程序是一模一樣的,那我們有沒有方法把
同樣的代碼放在別處,需要的時(shí)候才調(diào)用出來,這樣就可以減少很多 代碼重寫,不用浪費(fèi)那么多單片機(jī)內(nèi)部資源。
有兩種方式: 第一種是在主程序(main)上面書寫。 第二種是在主程序(main)下面書寫。
來看看第一種,在主程序上面書寫。
1.052.jpg (37.92 KB, 下載次數(shù): 91)
下載附件
2017-5-20 17:27 上傳
從上面圖片可以看到,當(dāng)定義好頭文件后和其它相應(yīng)的名字后,子程 序就可以開始書寫了。
延時(shí)子程序講解
void del_ms(uint k) // 延時(shí)子程序
{
for(i=0;i<k;i++)[ size][="" align]
{
for(j=0;j<230;j++)
{
;
}
}
}
Void 是空的意思,相當(dāng)于從這個(gè)子程序中,沒有東西(數(shù)值)返回的 意思吧,現(xiàn)在不理解,你可以暫時(shí)忽略它,直接書寫就行,以后你見 到有東西(數(shù)值)返回的,對(duì)比一下,就一目了然了。 del_ms(uint k)
del_ms 是子程序名字, del 是我們把英文單詞 delay(延時(shí))的縮寫, 加_符號(hào),再加 ms(毫秒),這樣從字面上就可以直接理解到是延時(shí) 1
毫秒的子程序,其實(shí)這個(gè)子程序名字你可以自己定義的,以后慢慢你
就懂。
叫做 ms 的原因是現(xiàn)在我們沒有像上面那樣直接賦值 1000 次的一毫 秒延時(shí),而是把這個(gè) 1000 變成可變的數(shù)字,如下圖所示的 uint k:
1.053.jpg (11.2 KB, 下載次數(shù): 130)
下載附件
2017-5-20 17:27 上傳
可以看到,現(xiàn)在我們上面的 1000 改變成可變的變量整型 k,uint(無符 號(hào)整型)可在 0~65535 之間隨意賦值,定義完后,k 就可以在 0~65535 隨意賦值。
如果是少于 255 的話,用無符號(hào)字符型(uchar)就行,這里大于 255, 就用了整型,而且這個(gè) k,只能在延時(shí)子程序花括號(hào)范圍內(nèi)使用,就 是
del_ms(uint k)
{
K 在這里隨意使用,在這范圍外使用是無效的。
}
你在主程序(main)內(nèi)定義,就是主程序(main)花括號(hào)內(nèi)可以使用,其 它范圍無效,如果你是一開頭就定義了,子程序和主程序都可以使用。
就是下面的 uint i 和 ichar j 可以在子程序和主程序的花括號(hào)里隨意使 用,理解沒?
1.054.jpg (24.7 KB, 下載次數(shù): 142)
下載附件
2017-5-20 17:27 上傳
回歸正傳。
1.055.jpg (21.46 KB, 下載次數(shù): 123)
下載附件
2017-5-20 17:27 上傳
del_ms 這名字在英文或符號(hào)之間(不是中文就行,因?yàn)檫@軟件不懂
中文),你可以隨你懂的命名字,比如你不太懂英文,直接寫 yan_shi
也行,只要做到一看這名字就知道是什么樣的子程序就行。
延時(shí)子程序調(diào)用方法,在主程序內(nèi)調(diào)用。
1.056.jpg (19.46 KB, 下載次數(shù): 123)
下載附件
2017-5-20 17:27 上傳
del_ms(多少數(shù)字你定義);
記得后面不要漏了分號(hào),這樣做只要是告訴軟件,你已經(jīng)寫完一條語 句,不然的話,程序會(huì)出錯(cuò)。
第二種:子程序在主程序下面寫。
1.057.jpg (37.45 KB, 下載次數(shù): 123)
下載附件
2017-5-20 17:27 上傳
這種方式除了位置不同和加多一句“告訴單片機(jī)主程序”下面有子程
序外,其它一樣,如果你在主程序下面寫子程序而沒有首先告訴單片 機(jī),程序編譯中會(huì)出錯(cuò)的,你可以自己試試,試過就知道了。
詳細(xì)請(qǐng)打開編程軟件和仿真軟件瀏覽效果。
本實(shí)驗(yàn)配套的的仿真工程文件和源碼下載地址: http://www.raoushi.com/bbs/dpj-85401-1.html
|
|