




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、'單片機(jī) c 語言學(xué)習(xí)心得相信很多愛好電子的朋友 , 對單片機(jī)這個詞應(yīng)該都不會陌生了吧。 不過有些朋友可能只聽 說他叫單片機(jī),他的全稱是什么也許并不太清楚,更不用說他的英文全稱和簡稱了。單片機(jī) 是一塊在集成電路芯片上集成了一臺有一定規(guī)模的微型計算機(jī)。簡稱為:單片微型計算機(jī)或 單片機(jī)(Single Chip Computer)。單片機(jī)的應(yīng)用到處可見,應(yīng)用領(lǐng)域廣泛,主要應(yīng)用在智能 儀表、實時控制、通信、家電等方面。不過這一切都沒什么關(guān)系,因為我(當(dāng)然也包括任何 人)都是從不知道轉(zhuǎn)變成知道的,再轉(zhuǎn)變成精通的?,F(xiàn)在我只想把我學(xué)習(xí)單片機(jī)的經(jīng)歷,詳 細(xì)地講敘給大家聽聽,可能有些大蝦會笑話我,想:那
2、么簡單的東西還在這里賣弄。但是你 錯了,我只是把我個人學(xué)習(xí)的經(jīng)歷講述一遍而已,僅僅對那些想學(xué)習(xí)單片機(jī),但又找不到好 方法或者途徑的朋友,提供一個幫助,使他們在學(xué)習(xí)過程中,盡量少走些彎路而已! 首先,你必須有學(xué)習(xí)單片機(jī)的熱情, 不是說今天去圖書館看了一個下午關(guān)于單片機(jī)的書, 而明天玩上半天,后天就不知道那個本書在講什么東西了。還是先說說我吧,我從大二的第 一個學(xué)期期末的時候才開始接觸單片機(jī),但在這之前,正如上面所說的:我知道有種芯片叫 單片機(jī),但是具體長成什么樣子,卻一點也不知道!看到這里很多朋友一定會忍不住發(fā)笑。 嘿嘿,你可千萬別笑,有些大四畢業(yè)的人也同樣不知道單片機(jī)長成什么樣子呢!而我對單片
3、 機(jī)的癡迷更是常人所不能想象的地步,大二的期末考試,我全放棄了復(fù)習(xí),每當(dāng)室友拿著書 在埋頭復(fù)習(xí)的時候,我卻捧著自己從圖書館借的單片機(jī)書在那看,雖然有很多不懂,但是我 還是堅持了下來,當(dāng)時我就想過,為了單片機(jī)值不值得我這樣去付出,或許這也是在一些三 流學(xué)校的好處吧,考試掛科后,明年開學(xué)交上幾十元一門的補考費,應(yīng)該大部分都能過了。 于是,我橫下一條心,堅持看我的單片機(jī)書和資料。C51還是A51呢?匯編在我們大二當(dāng)你明白了單片機(jī)是這么一回事的時候,顯而易見的問題出來了:我要選擇那種語言為 單片機(jī)編寫程序呢?這個問題,困擾了我好久。具體選擇之前并沒有開過課,雖然看著人家的講解,很容易明白單片機(jī)的每一時
4、刻的具體工作情況, 但是一合上書或者資料,自己卻什么也不知道了,根本不用說自己寫程序了。于是,我最終 還是決定學(xué)C51,畢竟C51和我們課上講的 C語言,有些類似,編程的思想可以說是相通的。 而且 C51 還有更大的優(yōu)點就是編寫大程序時的優(yōu)越性更不言而喻,當(dāng)然在那時,我并沒有想 的那么深遠(yuǎn),C51的特點,還是在后來的實踐過程中,漸漸體會到的!朋友如果你選擇了 C51,呵呵A A那么請繼續(xù)往下看,如果你選擇了 A51,那么你可以不要看了 !因為下面講的全是 C方面的,完 全在浪費你的時間 !第二,既然你想學(xué)好單片機(jī),你必須得舍得花錢,如果不買些芯片回來自己動手焊焊拆 拆的 (但是在后期會介紹給大
5、家一個很好用的硬件仿真軟件 , 并不需要你用實驗板和仿真器了 直接在你的 PC 上完成 , 但是軟件畢竟是軟件 , 從某個特定的意義上來說是并不能代替硬件 的),即使你每天捧著本書,把那本書翻爛,也永遠(yuǎn)學(xué)不會單片機(jī)的!剛接觸單片機(jī)的朋友, 看了資料, 一定會對以下幾個詞見的比較多, 但是具體的概念還是比較模糊, 現(xiàn)作如下說明:(1)編程器 編程器是用來燒單片機(jī)芯片的,是把HEX或者BIN文件燒到單片機(jī) ROM里的。( 2)實驗板 實驗板是專為初學(xué)者根據(jù)某些要求而特做的板,一般上面就有一個單片機(jī) 的最小系統(tǒng),使用者只需寫好程序,燒好芯片,放到上面加以驗證的這么一個工具。有了實 驗板,對與初學(xué)者來
6、說,省去了焊個最小系統(tǒng)的麻煩。但是對于電子開發(fā)人員來說,作用并 不是很大(3)仿真器 仿真器是直接把 HEX或者BIN文件暫時放在一個芯片里,再通過這個芯片 的引腳連接到實驗板或者系統(tǒng)上工作。這樣以來,可以省去了來回插拔芯片帶來的不必要麻煩。我一開始也不知道上面 3 個的概念和作用 , 嘿嘿, 原本想買個實驗板 (不想焊板 , 因為不可 能為了點亮幾個流水燈 , 而去焊個單片機(jī)的最小系統(tǒng) )的, 可是結(jié)果 , 確和我想的正好相反 , 人 家出售的是編程器。等貨物寄到后,才知道自己搞錯了!汗。 。嘿嘿?,F(xiàn)在想想實在是又氣 又笑。我花了 160大樣買了個編程器(很不幸的是,這個編程器更本用不了,一
7、燒芯片,芯 片就燒壞了)把我給氣的,這個編程器,現(xiàn)在還躺在我的抽屜里呢不過,現(xiàn)在想想,唯一讓 我覺得欣慰的是,那個老板每次能解答我的問題,連那種超級幼稚的問題,他也能不嫌麻煩 地盡量幫我解答!這點讓我很感動!第三,想學(xué)單片機(jī)的必需品-PC。因為寫程序,編譯或者是仿真都是通過 PC完成的。如 果沒有PC,什么也做不了! ! !有了 PC最好還要可以上網(wǎng),因為如果你沒有可以和你交流單 片機(jī)的人,遇到自己解決不了的問題,一直都想不通,那么估計你學(xué)習(xí)單片機(jī)的熱情就會隨 著時間的推移而慢慢耗盡。如果你能上網(wǎng)通過論壇或者 QC群,問題就很快得到解決。這樣的 學(xué)習(xí)效率一定很高!真正的高手是從論壇中泡出來的!
8、有了上述 3個條件后,你就可以開始學(xué)你的單片機(jī)了。但是,真的做起來并沒有我所說 的那么簡單。你一定會遇到很多很多的問題。比如為了讓單片機(jī)實現(xiàn)某個功能,你可能不知 道怎么去寫某個程序。或是你看懂了資料上某個相似的程序,你自己卻寫不出來。遇到類似 的情況,記住:千萬不要急噪,就行!說了這么多了, 相信你也看了很多資料了, 手頭應(yīng)該也有必備的工具了吧! (不要忘了上 面講過幾個條件的哦) 。那個單片機(jī)究竟有什么功能和作用呢?先不要著急! 接下來讓我們點 亮一個LED(搞電子的應(yīng)該知道 LED是什么吧A_A)我們在單片機(jī)最小系統(tǒng)上接個LED,看我們能否點亮它!對了,上面也有好幾次提到過單片機(jī)最小系統(tǒng)了
9、,所謂單片機(jī)最小系統(tǒng)就是在單片機(jī)上接上最少的外圍電路元件讓單片機(jī)工 作。一般只須連接晶體、VCC GND RST即可,一般情況下, AT89C51的31腳須接高電平。#include<reg51.h> /頭文件定義?;蛴?#include<at89x51.h> 其具體的區(qū)別在于:后者定義了更多的地址空間。/在 Keil 安裝文件夾中,找到相應(yīng)的文件,比較一下便知!sbit P1_0 = P1 A 0;void main (void)while(1)低電平有效,如果把 LED反過來接那么就是高電平有效P1_0 = 0;/LED點亮了,當(dāng)然LED是低電平,才能點亮。0賦給單
10、片機(jī)的P1_0引腳,讓它輸出相應(yīng)while(1) 語句只是讓單片機(jī)工作在死循環(huán)LED,也類似上述語句。這里就不再就那么簡單,我們就把接在單片機(jī) P1_0上的 因為我們把LED的正通過電阻接至 VCCP1_0= 0;類似與C語言中的賦值語句,即把的電平。那么這樣就能達(dá)到了我們預(yù)先的要求了。 狀態(tài),即一直輸出低電平。如果我們要試著點亮其他的講了。LED滅點亮了幾個LED后,是不是讓我們聯(lián)想到了繁華的街區(qū)上流動的彩燈。我們是不是也可 以讓幾個LED依次按順序亮呢?答案是肯定的!其實顯示的原理很簡單,就是讓一個 后,另一個立即亮,依次輪流下去。假設(shè)我們有8個LED分別接在P1 口的8個引腳上。硬件連接
11、,在P1_1-P1_7上再接7個LED即可。例程如下:#include<reg51.h>sbit P1_0 = P1 A 0; sbit P1_1 = P1 A 1; sbit P1_2 = P1 A 2; sbit P1_3 = P1 A 3; sbit P1_4 = P1 A 4; sbit P1_5 = P1 A 5; sbit P1_6 = P1 A 6; sbit P1_7 = P1 A 7;void Delay(unsigned char a) unsigned char i;while( -a != 0)一個 ; 表示空語句 ,CPU 空轉(zhuǎn)。從0加到125, CPU大
12、概就耗時1毫秒for(i = 0; i < 125; i+); / /ivoid main(void)while(1)P1_0 = 0;Delay(250);P1_0 = 1;P1_1 = 0;Delay(250);P1_1 = 1;P1_2 = 0;Delay(250);P1_2 = 1;P1_3 = 0;Delay(250);P1_3 = 1;P1_4 = 0;Delay(250);P1_4 = 1;P1_5 = 0;Delay(250);P1_5 = 1;P1_6 = 0;Delay(250);P1_6 = 1;P1_7 = 0;Delay(250);P1_7 = 1;定義位變量,
13、un sig ned char a定義無符字符型變量 a,以節(jié)省單片機(jī)內(nèi)部資源,LED持續(xù)點亮后,sbit其有效值為0-255。main函數(shù)調(diào)用Delay()函數(shù)。Delay函數(shù)使單片機(jī)空轉(zhuǎn), 再滅,下一個 LED亮。while(1)產(chǎn)生循環(huán)。上面我們講了如何使 LED產(chǎn)生流動,但是你是否發(fā)現(xiàn)一個問題:寫的太冗長了!能不能 再簡單點呢?可以!可以使用 C51 的內(nèi)部函數(shù) INTRINS.H 實現(xiàn)。函數(shù) unsigned char _crol_(unsigned char a, unsigned char n)可以使變量 a 循環(huán)左移 n 位,如果我們先給P1 口賦0000 0001那么當(dāng)n為1
14、時,便會產(chǎn)生和上面一樣的效果!#include<intrins.h>#include<reg51.h>void Delay(unsigned char a) unsigned char i;while( -a != 0)for(i = 0; i < 125; i+);void main(void)unsigned char b, i; while(1)b = 0xfe;for(i = 0; i < 8; i+) P1 = _crol_(b, 1); b = P1;Delay(250);右移INTRINS.H 函數(shù)中的 unsigned char _cror_
15、(unsigned char a, unsigned char n) 也可以實現(xiàn)同樣的效果!這里就不再累述。流水燈的花樣很多,我還寫過那種拉幕式的流動等,程序很簡單,有興趣的朋友,可以 自己試著寫寫!對了,講了那么多,有些朋友一定還不知道編譯軟件怎么用?這里給大家介紹幾個吧?WAVIE偉福)大家一定聽說過吧!還有一個就是 KEIL2,我用的就是KEIL2,下面就來講講如 何使用 KEIL2 這個編譯軟件!1. 安裝軟件,這個應(yīng)該不用再講了吧!2. 安裝完后,啟動 KEIL 軟件左擊 Project->New Project->輸入文件名 -> 選擇我們所以使用的芯片(這里我們
16、一般用到Atmel的AT89C51或AT89C2051,點確定。3. 點 File->New-> 輸入我們編寫的程序,保存為 .C 文件。(一般情況下,我們保存的文 件名和前面的工程名一樣。 )4. 展開 Target 1 -> 右擊 Source Group 1 ->Add Files to Group 'Source Group 1'->'Target在 Create HEX Files前打上鉤,點確定。點 Project->Rebuild All Traget Filescreating hex file from "
17、XXX"."XXX" - 0 Error(s), 0 Waring(s).表示編譯和生成HEX文件成功!接下來的就是把是否達(dá)到預(yù)先的目的!選擇剛才保存的.C文件點擊ADD后,關(guān)閉對話框。這樣.C文件就被加到了 Source Group 1下。1' ->Target 中填寫晶體的大小, Output5. 右擊 Target 1->Options for 中,若提示HEX文件燒到單片機(jī)中,或是仿真器上,看6.嘿嘿! 現(xiàn)在是否自己好有成就感了, 如果讓你去做個流水彩燈, 開發(fā)一個簡單的產(chǎn)品, 只 要加上驅(qū)動電路,就可以做出漂亮的流動彩燈了!到現(xiàn)在為止
18、,你應(yīng)該知道單片機(jī)的功能有 多強(qiáng)大了吧,如果單純的用數(shù)字電路或模擬電路的知識去設(shè)計一個流動彩燈,可能要花點工 夫和時間才行,有了單片機(jī),那就不一樣了,你只要寫程序控制他就行!有人說過這樣一句 話,也并不無道理的,學(xué)單片機(jī),程序思想很重要!四)呵呵,朋友!相信你的流水燈也做的不錯了吧,現(xiàn)在能玩出幾種花樣了?你可能會說, 只要你想得到,想怎么流就怎么流!呵呵,是的。但是工程師們設(shè)計這么一個單片機(jī),并不 是只為了讓它做流水燈的,那樣也太浪費點了吧學(xué)過數(shù)字電路的朋友,一定動手做過8 路或者 6 路的搶答器。用純粹的數(shù)字電路知識來做, 自己設(shè)計電路, 感到比較困難! 搶答器上用的顯示器多為 7 段數(shù)碼管
19、, 這里我們來講講, 如何用單片機(jī)讓數(shù)碼管顯示 O-8 。搶答器的實現(xiàn),我們放到后面再來探討,因為搶答器還涉 及了鍵盤的內(nèi)容。8段數(shù)碼管分為共陰和共陽兩種。8段數(shù)碼管是由8個LED組成(還包括一個小數(shù)點)。若為共陽,則8個LED的陽級是連接在一起的,同理若為共陰,則陰極連接在一起。8個LED對應(yīng)的標(biāo)號如下:|g | c e |_| . dp da-dp 依次接到單片機(jī)某個口上的賦一個值,則相應(yīng)LED,所以我們一般情況下,為了計算或取碼的方便,我們把PO 口需接P0 = 0X3F;1111 11OO,PX.0-Px.7 上。x表示0,1,2,3其中的一個。這樣我們只要給某個口, 的LED段就被點
20、亮,但是在硬件連接上要注意了:單片機(jī)可能不能直接驅(qū)動 可以通過控制三級管的導(dǎo)通或截止,來控制LED的亮與滅!上,注意:那么比如:如果我們把共陰的數(shù)碼管的a-dp 依次接到單片機(jī)的 P0.0-P0.7上拉電阻。 何為上拉電阻, 簡單的說, 就是把電平拉高, 以提高驅(qū)動能力。則顯示為數(shù)字 0 。因為 0X3F 即為2進(jìn)制的 0011 1111 我們低位往高位數(shù), 依次為 其 I/O 的電平分別為高、高、高、高、高、高、低、低,即對應(yīng)的a-dp 為亮、亮、亮、亮、亮、亮、滅、滅,由上圖我們可以看出g和dp段不亮其他段均亮,即為我們所看到的數(shù)字0字樣。其他的數(shù)字或字符,也同理可以得到。但是有些朋友就會
21、問,那我們每取一個字模, 豈不是很麻煩?還有自己考慮高低電平什么的?7 呵呵,其實網(wǎng)上有很多 LED取模軟件,如果有一定計算機(jī)編程語言的朋友, 也可以試著自己寫個取模的程序, 讓計算機(jī)為我們計算, 諸如上述0X3F的數(shù)值。#include<reg51.h>void Delay(unsigned char a) unsigned char i;while( -a != O)for(i = O; i < 125; i+);void main(void)顯示 0PO = OX3F; /Delay(250);/P0 = 0X00;/P0 = 0X06; /Delay(250);P0
22、= 0X00;顯示 1. / 以下顯示數(shù)字 2-F ,略。延時短暫的關(guān)閉顯示,若不關(guān)閉,可能會造成顯示模糊不清。看到這里,想必大家一定可以把 0-F 顯示出來了吧!但是如果要你顯示兩位數(shù),三位數(shù) 呢?或許,有的朋友會這么想:在P0 口上接一個數(shù)碼管,再在 P1 口上接個數(shù)碼管!但是,如果要顯示4位、5位的數(shù)字呢?那豈不是一塊 AT8951都接不過來!難到就不能接 4位或5 位以上的嗎?肯定不是的!說到這里,我們來講講數(shù)碼管的顯示方式,可分為兩種:動態(tài)掃描和靜態(tài)顯示。上面我 們所說的即為靜態(tài)顯示。但是如果我們采用動態(tài)掃描顯示,那么就可以解決上面的問題,即 可以顯示多個數(shù)碼管了。上面我們所說的靜態(tài)
23、顯示把數(shù)碼管的COM卻接至VCC或GND端,其a-dp控制6 個數(shù)他的接至PX口上,這樣只要 PX口上輸出相應(yīng)的高低電平,就可以顯示對應(yīng)的數(shù)字或字符。 但是如果我們采用動態(tài)掃描的方法,比如顯示 6 個數(shù)碼管,硬件連接可以這樣解決: 還是接至P0.0-P0.7 上,還有6個COM卻再接至另外口的 P2.0-P2.5 。 P0 口作段選 數(shù)字字符)P2 口作位選(選通哪個數(shù)碼管導(dǎo)通)這樣我們控制P0和P2 口就可以控制碼管了。但是,細(xì)心的朋友,會問這樣的問題:P2位選,是讓數(shù)碼管一個一個亮的,那還是不能控制6個一起亮或滅嘛???想想好象是對的哦?怎么辦 .難道錯了?嘿嘿,問你個問題?黑夜里,拿著一支
24、煙,在你面前快速的晃動,你會發(fā)現(xiàn)什么樣的現(xiàn) 象?是不是原本不連續(xù)的點變成了一條看上去連續(xù)的曲線或者直線!再回過頭來,仔細(xì)想想 我們的數(shù)碼管!原理是一樣的,你可別忘了,我們的單片機(jī)可是一個計算機(jī)哦,計算機(jī)的運 算速度,大家可想而知吧!所謂機(jī)器周期就是訪問一次存儲器12M晶體下,那么一個時鐘時鐘周期和機(jī)器周期1 個周期、 2 個這里再說說 51 單片機(jī)的機(jī)器周期和時鐘周期等概念。6M,有的時間。 而 1 個機(jī)器周期包括 12 個時鐘周期。 如果單片機(jī)工作在 周期為: 1/12 微妙。一個機(jī)器周期 12*1/12 = 1 微妙。如果晶體為 各是多少呢?在匯編中,我們還要關(guān)心,指令執(zhí)行的機(jī)器周期長短不
25、一, 周期和 4 個周期等。P2也看作上面的哈哈, 原來如此 . 你是真明說著說著,跑了這么遠(yuǎn)了 . 還是回到原來的話題,如果我們把位選的 “煙” 一劃而過,那么我們看到的是不是 6個一起亮或一起滅了!A_A記住,在任何某一時刻,有且只有一個數(shù)碼管能發(fā)光。如果你能把這句話理解了, 白我的意思了!朋友,現(xiàn)在給你個任務(wù),讓 6個數(shù)碼管分別顯示 1、 2、 3、 4、 5、 6??茨阕?己可以搞定不?你自己先試著寫寫看咯 .#include<reg51.h>void Delay(unsigned char a) unsigned char i;while( -a != 0)for(i =
26、 0; i < 125; i+); void main(void)P0 = 0x06;/1P2 = 0x01;/ Delay(20);/P0 = 0X00;/的碼段 選通一位,或者 延時約 20 毫秒 關(guān)閉顯示P0 = 0x5b;/2P2 = 0x02; / Delay(20);P0 = 0X00;的碼段選通一位,或者P0 = 0x4f;/3 P2 = 0x04; / Delay(20);P0 = 0X00;的碼段選通一位,或者P0 = 0x66;/4P2 = 0x08; / Delay(20);P0 = 0X00;的碼段選通一位,或者P0 = 0x6d;/5P2 = 0x10;/ De
27、lay(20);P0 = 0X00;的碼段選通一位,或者P0 = 0x7d;/6P2 = 0x20;/ Delay(20);P0 = 0X00;的碼段選通一位,或者P2_1 = 1;P2_2 = 1;P2_3 = 1;P2_5 = 1;P2_0 = 1;P2_4 = 1;while(1)五)相信大家一定見過數(shù)字時鐘,教學(xué)樓大廳一定有吧。每次路過,基本上只是隨便瞟上一 眼,根本沒去想過他的工作原理什么。但是今天你也可以把他做出來了,是不是覺得自己很 有成就感呢!呵呵!接上面所講的, 我們先來做個簡單的實驗: 在一個數(shù)碼管上輪流顯示 0-9 這 10 個數(shù)字。 還楞著干什么,快動手寫程序呀!好象有
28、點難哦,要不先不要往下看了,嘿嘿,關(guān)機(jī)吧,自 己先去想想,怎么樣?#include<reg51.h>SEG_TAB數(shù)字unsigned char code0-32768=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f; /0-9void Delay(unsigned int a) /unsigned int 定義為無符整形,取值范圍為unsigned char i;while( -a != 0)for(i = 0; i < 125; i+);void main(void)unsigned char i;while(1)for
29、(i = 0; i < 10; i+) P0 = SEG_TAB i ; / P2 = 0X01;Delay(1000);取SEG_TAB組中的值是不是顯示從 0-9 ,跳動顯示,你的心是不是也跟著一起跳呀,離我們的目標(biāo)又邁進(jìn)了 一步!不錯,繼續(xù)努力!0-9 ,但是怎么樣要讓他顯示 6 個數(shù)字呢?這樣我們就P2 口的位選作用! 嘿嘿,沒忘記就好!上面只顯示了一個數(shù)碼管的數(shù)字 可以做個時鐘出來玩玩了! 還記不記得我們前面講過的#include<reg51.h>unsigned char hour = 12, min = 0, sec = 0;SEG_TAB數(shù)字unsigned
30、char code 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f; /0-9void Delay(unsigned char a) unsigned char i;while( -a != 0)for(i = 0; i < 125; i+);void disp(void)P0 = SEG_TAB sec % 10 ;/P2 = 0X01;Delay(15);P2 = 0;顯示秒的個位P0 = SEG_TAB sec / 10 ;/ P2 = 0X02;Delay(15);P2 = 0;顯示秒的十位P0 = SEG_TAB min %
31、10 ;/P2 = 0X04;Delay(15);P2 = 0;顯示分的個位P0 = SEG_TAB min / 10 ;/ P2 = 0X08;Delay(15);P2 = 0;顯示分的十位P0 = SEG_TAB hour % 10 ;/ P2 = 0X10;Delay(15);P2 = 0;顯示時的個位P0 = SEG_TAB hour / 10 ;/P2 = 0X20;Delay(15);P2 = 0;顯示時的十位void main(void)while( 1 )disp( );編譯燒錄芯片后,觀察運行現(xiàn)象。矣 . 怎么一直顯示 12: 00: 00,難道是時鐘沒有啟 動?還是, 另外
32、的原因呢?哦, 原來是 3 個變量 sec,min,hour 初始化后, 其值一直沒有改變!那我們怎么樣才能讓他改變數(shù)值呢?有的朋友一定會這么認(rèn)為:讓秒個位延時 1 秒, 后加 1,而秒十位延時 10 秒后,再加 1,一直加到 6,分個位加 1,依次類推 . 這樣的想法 是不錯,但是朋友你有沒有想過 C語言的一般延時(除非你把他放到中斷里)極不精確!這 樣累計下來,一天 24 小時的誤差,肯定很大很大,我曾經(jīng)也用延時的方法寫過時鐘, 1 個小 時誤差 8 秒,那是個什么概念!一天 24 小時就要 24*8=192,約為 3 分鐘,一個月就是 10 分 鐘. 有沒有其他的方法可以改進(jìn)些呢?有!
33、這里就要涉及到單片機(jī)中另一個比較重要的核心 部分:單片機(jī)的中斷和定時器的運用!想寫出比較精確(這里說的只的相對前面的做法而言比較精確而已,如果要做更加精確的時鐘, 用時鐘芯片比較好點,常用的有DS12887和DS1302 等)的時鐘程序,就一定要調(diào)用中斷和定時器。還是大家先看看教材和書吧,畢竟人家出的 書,肯定比我要寫的系統(tǒng)多了,下面我們再來簡單的講講!六)什么是中斷呢?講個比較通俗的例子:比如你正在家中看電視,突然電話響了,你的第 一反應(yīng)是什么?是不是先跑過去接電話!接完電話后,繼續(xù)看電視。這就是個中斷的例子, 中斷是由電話引起了,你跑過去就是響應(yīng)中斷,接電話就是中斷的處理!接完電話后,接續(xù)
34、 看電視,即恢復(fù)中斷,等待下個中斷的到來!但是這個好象和單片機(jī)沒什么聯(lián)系呀?有的朋友或許會這樣疑問。是的。單片機(jī)當(dāng)然不 會看電視了,也不會接電話了!但是,類比一下:比如單片機(jī)正在執(zhí)行某個任務(wù),突然要有更重要的事件, 要求單片機(jī)響應(yīng), 單片機(jī)就會應(yīng)答響應(yīng), 去執(zhí)行更為重要的任務(wù) (中 斷處理),原來的任務(wù)就繼續(xù)等待(現(xiàn)場的保護(hù)) 。執(zhí)行完更重要的任務(wù)后,回到中斷的入口 處,繼續(xù)執(zhí)行原來的任務(wù)(現(xiàn)場中斷的恢復(fù)) 。51 系列的單片機(jī)共有 5 個中斷源,分別為: 外中斷 0 、定時器 T0 中斷、外中斷 1 、定時器 T1 中斷、串口中斷。或許,有些朋友已經(jīng)大概領(lǐng)會了其中的意思,有些朋友還迷迷糊糊。
35、不過不要緊,我們 繼續(xù)往下看,下面我們來講講單片機(jī)的定時器是什么?如何工作的?定時器,大家從字面上 就可以看出其大概的意思吧?簡單的說:就是起定時作用!也就是讓單片機(jī)計數(shù)。定時器分 為:方式 0 方式 1 、方式 2 和方式 3 等 4 種工作方式。 有些朋友一定會問: 定時器如何啟動? 風(fēng)扇的定時器,相信大家一定都用過吧!但是單片機(jī)的定時器,該如何啟動呢?總不該也用 手一擰定時器吧!當(dāng)然不是,我們只要給單片機(jī)一些指令,就可以啟動定時器了! 下面0。0 工作方式 0 載入高 8 位初值 載入低 8 位初值我們就定時器 0,來說說怎么啟動定時器TMOD = 0X01;/ 設(shè)置定時器TH0 = (
36、65536 - 5000) / 256;/TL0 = (65536 - 5000) % 256;/TR0 = 1;/啟動定時器,簡單吧,這樣我們就可以把定時器啟動了。其中TMOD為T/C方式控制寄存器:D7 D6D5D4 D3 D2D1 D0GATEC/TM1 M0GATE C/T M1 M0| T/C1| | T/C0|C/T 就是 counter (記數(shù)器)和 timer (定時器)的選擇位,若值為 1 ,則作計數(shù)器用。 為0,則為定時期用! GATE為門控位。M1和M0工作方式的選擇:若M1=Q M0=0則為方式 13位定時/記數(shù)器。若M1=0; M0=1則為方式1,16定時/記數(shù)器。若
37、 M1=1; M0=0則為方式 自動裝載8位定時/記數(shù)器。若M1=1; M0=1則為方式3,只適用于T/C0,2個8位定時/記數(shù) 器。說了一大堆,感到有點困惑了吧。那我們還是來說說上面的。TMOD= 0X01;/ 至于為什么是0X01,大家看:我們選擇的是定時器0方式0,所以T/C1全為0,而T/C0的M1為0。M0為1,所以D0-D7為0X01; 0X01表示的是16進(jìn)制數(shù),這個大家應(yīng)該都知道吧! 表示的是 2 進(jìn)制數(shù)。還需要轉(zhuǎn)換一下!TH0 = (65536 - 5000) / 256;/載入高8位初值。若在 12M晶體下,定時 5000微秒,即為5毫秒;但是如果不是在12M下,那又該怎么
38、計算了呢?如果是 11.0592M呢?還記不記 得,我們前面講過的機(jī)器周期和時鐘周期的概念?A_A忘了,還是看看前面吧!呵呵!沒事,學(xué)習(xí)嘛,忘了再翻翻書,看看就可以了!其實上訴的5000 = 1 * C 很顯然C=5000,但是如果是11.0592M那么就不是 1 了,應(yīng)該是1.085 了,那么5000 = 1.085 * C,貝U C就為5000 / 1.085 = ?具體多少,大家自己去算算吧?同理 TL0也是一樣的! 網(wǎng)上或者是資料上的 TH0, TL0 并不是和上面一樣的,而是直接 不是和上面的一樣的,別忘了單片機(jī)也是計算機(jī)的一種哦。用 行,計算就交給單片機(jī)完成。TR0 = 1 ;這句
39、就是啟動定時器 0,開始記數(shù)!哦,還有一點, 是哪里來的呢?呵呵你可別忘了: 設(shè)置定時器 0 工作方式 0 是 16 位的(2 的 16 次方是多少, 自己算算就知道了)簡單吧?但是如何和中斷一起使用呢?請繼續(xù)看下面的講解!0:2,還有 D0-D7但是,細(xì)心的朋友會發(fā)現(xiàn)TH0 = 0XEC; TL0 = 0X78 是C 的話,直接寫上計算公式就有些朋友會問,你是 65536TMOD = 0X01;/ 設(shè)置定時器TH0 = (65536 - 5000) / 256;/TL0 = (65536 - 5000) % 256;/TR0 = 1;/啟動定時器0 工作方式 0 載入高 8 位初值 載入低
40、8 位初值EA = 1 ; / 開總中斷ET0 = 1;/ 開定時器中斷。若為 0 則表示關(guān)閉!這樣我們, 就初始化定時器 T0 和中斷了, 也就是定時器滿 5 毫秒后, 生中斷后,我們怎么處理呢?嘿嘿!仔細(xì)想想? 每次中斷后,我們可以讓一個變量自加1,那么 200 次中斷后,不就是起上面我們說的延時來出來是不是更加精確多了呢?那是肯定的!但是想想 讓單片機(jī)產(chǎn)生那么多次的中斷, 單片機(jī)會不會累著呢?恩, 那么不好。產(chǎn)生一次中斷。 產(chǎn)秒的時間了嗎?比1 秒種的時間就如果在12M的晶體下,T0 每次中斷不是可以產(chǎn)生最多 65.336 毫秒的時間嗎?那么我們讓他每 50 毫秒中斷一次好 了!這樣我們
41、就20次搞定一秒的時間了!爽-好了,講了那么多,現(xiàn)在我們來寫個時間的程序吧!#include<at89x51.h>#define HI(65536 - 50000) / 256)#define LO(65536 - 50000) % 256)#define _TH0_TL0_ (65536 - 50000)#define M 20 /(1000/25) /* */unsigned hou = 12, min = 0, sec = 0;unsigned char SEG_TAB_B = 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90
42、; /0-9 數(shù)字?jǐn)?shù)字unsigned char SEG_TAB_A 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10;/0.-9./*延時程序 a*1MS*/ void Delay(unsigned char a)/unsigned char j;while(a- != 0)for (j = 0; j < 125; j+);/* */ void Disp(void)/ 數(shù)碼管顯示P2_0 = 1;P1 = SEG_TAB_B hou / 10 ;Delay(5);P2_0 = 0;P2_1 = 1;P1 = SEG_TAB_A hou
43、% 10 ;Delay(5);P2_1 = 0;P2_2 = 1;P1 = SEG_TAB_B min / 10 ;Delay(5);P2_2 = 0;P2_3 = 1;P1 =S EG_TAB_A min % 10 ;Delay(5);P2_3 = 0;P2_4 = 1;P1 = SEG_TAB_B sec / 10 ;Delay(5);P2_4 = 0;P2_5 = 1;P1 = SEG_TAB_B sec % 10 ;Delay(5);P2_5 = 0;/* */定時 50ms定義靜態(tài)變量 countvoid IsrTimer0(void) interrupt 1 using 1 / s
44、tatic unsigned char count = 0; /count+; if(count = M) count = 0;sec+;if(sec = 60)min+;sec = 0;if(min = 60) hou+; min = 0; if(hou = 24) hou = 0; /if /if /if /* */定時器 0void Timer0Init(void) / TMOD = 0x01;TH0 = HI;TL0 = LO;TR0 = 1;ET0 = 1; EA = 1;/*主函數(shù)*/ void main(void) / Timer0Init();while(1)Disp();簡單
45、吧,還是有點看不懂哦,那你自己慢慢體會吧,如果你自己能寫個時鐘程序來,那 么你的 51 單片機(jī)也就學(xué)了 80 % 了。中斷和定時 /記數(shù)器器,是個很重要的東西,幾乎用到 單片機(jī)的地方都會涉及到中斷和定時!所以大家要好好掌握哦!哈哈,趕緊編譯 HEX文件,搭好硬件,燒入單片機(jī),上電看看效果先!呵呵,現(xiàn)在你應(yīng) 該有成就感了吧, 想不到一個時鐘居然那么簡單, 嘿嘿!但是問題來了! 時鐘雖然做出來了, 但是他的精度怎么樣呢?一兩個小時,或許看不出什么誤差,但是一天或者一年呢?暈,我 的天呀,要是按年來算的話,那這個時鐘根本沒有實用價值!人家都說用C寫不出,精度高的時鐘程序來的! !是不是有點后悔了,去
46、學(xué)匯編吧! 嘿嘿,想想 C 的高級語言,怎么會輸給匯編呢但是既然選擇了C,那么就不要后悔!呵呵!看下面這段代碼:static unsigned char count = 0;TRO = O;TLO += (_THO_TLO_ + 9) % 256;THO += (_THO_TLO_ + 9) / 256 + (char)CY;TRO = 1;count+;在中斷處理服務(wù)程序中,我們加入上面的代碼。給THO和TLO賦值,再開啟TR0 = 1;燒入單片機(jī)看看效果,怎么樣,你第一次精確多了吧。 但是還是有誤差!郁悶!為什么呢?那是硬件造成的誤差,我們可以用軟件來彌補!我們先 把時鐘點亮, 讓他走上幾
47、個小時或者是幾天, 看看到底誤差是多少! 取個平均值。 (這里比如 我們10小時快1秒)那么可以通過以下語句if(hour % 1O = O)sec-; 來彌補!這樣可能會出現(xiàn)這樣的現(xiàn)象:秒直接跳變!我們可以再通過細(xì)分來實現(xiàn),不要 小時那么大,小些的就行!具體的操作還是留給朋友們吧!TRO = 0;先關(guān)閉定時器TO,然后重新10七)這回我們來講講鍵盤,大家肯定見過銀行柜員機(jī)吧,取錢輸入密碼就要用到鍵盤,超市 購物取回寄存物品要輸入密碼,還有你現(xiàn)在在用的 PC 機(jī)的鍵盤。但是鍵盤的是怎么工作的 呢? 一般有2種方式:(1)掃描法,不斷掃描鍵盤的狀態(tài),送CPU判斷并處理。如果鍵盤數(shù)目一大的話,顯然
48、不適合( 2)線反轉(zhuǎn)法,通過行列狀態(tài)的改變來判斷有無鍵被按下!現(xiàn)在我們在P1 口接個4*4的鍵盤,P1.0 P1.3接行,P 1.4-P1.7接列,再接4個4K7的上拉電阻至 VCC代碼如下:/ 鍵盤掃描法程序 / 用數(shù)碼管顯示相應(yīng)的鍵值/P1.O P1.3 接行 /P1.4-P1.7接列 #include<reg51.h>unsigned char code tab =Ox3F,OxO6,Ox5B,Ox4F,Ox66,Ox6D,Ox7D,OxO7,Ox7F,Ox6F,Ox77,Ox7C,Ox39,Ox5E,Ox79,Ox71;/O到 F 的 16 個鍵植/*/延時函數(shù)void D
49、elayt(unsigned char t)/ unsigned char i;for(t=0;i<=t;t+) for(i=0;i<255;i+);/*/ bit pkey(void)/ 判斷鍵的否被按下,通過返回值確定 P1=0xf0;if(P1!=0xf0)Delayt(25);if(P1!=0xf0)return 1;elsereturn 0;elsereturn 0; /*/ void main(void)/ 主函數(shù)unsigned char key,j,k,s;while(1) if(pkey()=1)P1=0xfe;k=0xfe; for(j=0;j<4;j+)
50、 s=P1&0xf0;switch(s)case 0xe0: key=4*j+0; break; case 0xd0: key=4*j+1; break;case 0xb0: key=4*j+2; break;case 0x70: key=4*j+3; break;default: break; k=(k<<1)|0x01; P1=k;/for/if /if(P1&0xf0)=0xf0) P0=tabkey;P2=1;Delayt(50);/while還有一種就是線反轉(zhuǎn)法,實現(xiàn)如下:1. 和掃描法相同,把列線置低電平,行置高,讀行狀態(tài)2. 與 1 相反,把行置低,列置高,讀列狀態(tài)3. 若有鍵按下,則為 2 次所讀狀態(tài)的結(jié)果即為鍵所在的位置,這樣2次輸出和 2次讀入可以完成鍵的識別! !子函數(shù)如下:unsigned char key_vscan(void) unsigned char row, col;P1 = 0xF0;row = P1&0xF0;row = row&0xF0;P1 = 0x0F; col = P1&0x0F;col = col&0x0F;return(key_val(row|col);面我
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 玻璃吊橋led施工方案
- 弧形閘門專項施工方案
- 斜井隧道施工方案
- 水庫鉆孔注漿施工方案
- 涵洞水管架空施工方案
- 承接彩燈施工方案
- 小麥島內(nèi)部施工方案
- 電梯梯井施工方案
- 橡膠地面景觀施工方案
- 電梯采購合同范本
- 2025年山東泰山財產(chǎn)保險股份有限公司招聘筆試參考題庫含答案解析
- 高一英語完形填空專項訓(xùn)練100(附答案)及解析
- 2024年八年級語文下冊《經(jīng)典常談》第一章《說文解字》練習(xí)題卷附答案
- 華為基建項目管理手冊
- 建設(shè)工程規(guī)劃放線、驗線申請表
- 二年級科學(xué)上冊期末考試質(zhì)量分析
- WE-100B300B600B1000B型萬能材料試驗機(jī)使用說明書
- 相聲《治病》
- 盾構(gòu)施工標(biāo)準(zhǔn)化手冊
- 貴州省義務(wù)教育階段中小學(xué)生轉(zhuǎn)學(xué)申請表
評論
0/150
提交評論