超易單片機入門 (學單片機一定要看)
( 向作者致敬!)
一.
話說人間事物的學習,不外兩類:一類入門易精通難,比如礦石機,再比如練書法誰都會寫兩下,可寫好卻不是一朝一夕的事兒。另一類則入門難精通易,比如超外差收音機,學會需要各種放大、振蕩、反饋、混頻、中頻、統(tǒng)調等等,但是一旦你學會,做出一個高質量的收音機,確也不是難事。單片機屬于后者,所以無論如何,你得用些時間,學習一些新名詞并理解,甚至還得花一些小錢。但是,一旦你掌握,其樂趣也像收音機一樣,很有吸引力的。 單片機不同于收音機,收音機的任務最終就是聽好聲音一個,單片機可以做很多事情,要你來安排它的工作。安排它就先的認識它,熟悉它。大家自己查看一下單片機的外形,不妨將它看成是一個8條腿的小螃蟹,這個8條腿的小螃蟹就是我們的第一頓飯,只要把它吃下去,以后的大餐就好辦了。 第1、8條腿接電源 +5V和地線。頭兩條腿是螃蟹鉗子,好吃的很?,F(xiàn)在已經(jīng)剩下6條腿了。 第2、3條腿使用時外接一個叫作晶振的東西,我們接一個4MHz的晶振(這還不知道?還是看一下:單片機之路(www.)里面對晶振的介紹吧)。 第4條腿是復位腳,是一個信號輸入腳。單片機正常運行時接高電平。當有一個低電平脈沖輸入到這個腳時單片機就復位。所謂復位就是單片機內部所有的工作部件統(tǒng)統(tǒng)回到規(guī)定的狀態(tài),程序也復位到頭一句上開始逐條運行。例如,你設計的一個報警鎖定的LED紅燈亮后,當需要解除報警時,用一個按鈕給這個腳瞬時接地一下,相當于給它一個夫脈沖,系統(tǒng)就復位了,led燈就熄滅了,程序從頭開始。 以上5個腳,幾乎所有單片機都有,包括世界上最復雜的,和世界比較簡單的單片機-PIC12CE519。 輪到底幾條腿啦?奧,是第5條腿,這條叫單片機的I/O腳。就是輸入輸出腳。你可通過程序動態(tài)地控制它作為輸入或輸出,作為輸出時可以程序控制它的輸出電平為高1或低0。所以,他的工作狀態(tài)有四種: 剩下的兩條腿和第5腳功能一個樣。 現(xiàn)在要控制使用這兩只腿了,這不得不首先要講一下軟件,要想講明白軟件又不得不涉及到單片機的內部結構??赡苡信笥颜f啦,可別提這軟件和結構了,以前俺就是讓它們打敗的,現(xiàn)在聽到這個心里就打鼓。嘿嘿,不要緊,果真如你所說,那你就不妨跟著我再失敗一次,反正多一次失敗又不納稅嗎,嘿嘿。不過你也要有思想準備,徹底弄明白是個漸進的過程。 要說起這程序和單片機內部結構,還真是老大難,不過蟹黃蟹肉可都在里面。我現(xiàn)在要是給你說PIC單片機是哈佛結構的,51系列是馮-諾伊曼結構的話,恐怕你要立馬走人了。所以我得用點心思不讓你溜號。 好在PIC系列的制造商(microchip 微芯公司)理解我等苦衷,全部只有35條指令,而且有一些指令我們一般很少使用,常用的也就十幾句,用的時候查手冊,無需記憶。就算我們兩天學習一句,也就兩三個月時間,總比到老了還怕它們強啊。廢話少說先看下面的兩個例語: my_name006: movlw 02h '常數(shù)2進入w 每行只能寫一句話; 標號: 操作指令 操作數(shù) '程序注釋 下面我結合例子把這四部分解釋一下。 第一部分 my_name006: 叫做標號,它是由字母或數(shù)字組成,由冒號結束。標號可有可無,比如第二句就沒有標號。 第二個例句中,省略了標號,當然注釋也可以省略。他的指令是movwf,操作數(shù)是GPIO。操作數(shù)不一定是數(shù)字,也可能是一個由字母組成的字符串 這兩句話的作用是把 2 這個常數(shù)寫入到 GPIO 這個寄存器里。 每個寄存器可以儲存一個八位的二進制數(shù)。這八個位的每一位都有名稱,從左向右的名稱是: 而每一個位對應一個管腳的電平,例如當GPIO寄存器的D0位等于1時表示管腳GP0的電平是高電平。D0位等于0時表示管腳GP0的電平是低電平。常數(shù)2的八位二進制表示是“00000010” 所以,GPIO寄存器存放的8位2進制數(shù)的每個位的值以及管腳電平是: 截止到現(xiàn)在,你已經(jīng)學會如何控制管腳的電平高低了。盡管還有一些疑問,比如怎樣定義管腳為輸出腳(以后會說),我得說,如果事先GP1,GP0這兩個管腳處于輸入狀態(tài),這兩個例句無效,因為在這種狀態(tài)下它們是控制不了電平的。 無論如何,這一會兒,你就學會了兩個指令,35條我看也沒啥難的。 下面再加深一下對寄存器的認識: 要把一個常數(shù)存儲到寄存器,或者說寫到一個寄存器中,僅用一條指令是辦不到的,必須通過一個特殊的寄存器W,把數(shù)據(jù)倒過去. 這就應該使用到下面兩個語句: movlw 02H 指令的意思是把一個常數(shù)存入特殊寄存器W, 這個常數(shù)是3,后面的H是表示十六進制 這里涉及到兩個概念,常數(shù)和寄存器: 常數(shù)好說,比如說十進制數(shù)35,26。但要注意,在單片機系統(tǒng)里我們一般不用十進制,而使用十六進制。有關數(shù)制轉換方面的知識,是計算機的基礎,必須會熟練地在二進制、十六進制、十進制之間轉換,此處不再羅索。 寄存器也叫單片機的內存,一個寄存器可以存儲的數(shù)值范圍是0--255,用十六進制表示就是0--FFH.用二進制表示就是00000000----11111111。“單片機之路”提醒您:以后要養(yǎng)成習慣用十六進制表示數(shù)。 那么,一個單片機里有多少個這樣的寄存器哩,pic12ce512里面有1024個這樣的寄存器可以供你使用,為了使用方便生產(chǎn)商已經(jīng)給它們編上了號碼,第一號碼是000H,往下依照次序為 001H,002H........3FFH.(怎么樣,開始用十六進制說事了吧,如果你不熟悉熟制轉換趕緊補課還來得及。)有了編號就像我們居住的房間有了房間號碼,使用就方便的多了.房間號碼在郵政行業(yè)叫地址,因此我們稱這些號碼叫做寄存器地址,或稱地址數(shù)。例如:名稱為GPIO的寄存器,它的地址或地址數(shù)是06H。所以我們的兩個例句完全等同于: my_name006: movlw 02h '常數(shù)2進入w 有兩個寄存器比較特殊,它們沒有地址,一個名字叫做W,另一個叫做TRIS.所以他們兩個在存儲數(shù)據(jù)的時候比較快,一個指令就可以解決問題,例如:movlw 03H 一條指令就把常數(shù)3寫入到W寄存器了。關于TRIS寄存器,我們以后用到它再說。除了他們兩個以外的其他所有寄存器,在寫入數(shù)據(jù)時一般都要用兩條指令進行。 本文雖然只有兩個指令,但主要目的是讓大家接觸一下指令,建立寄存器的概念以及他們同硬件部件的聯(lián)系。增強學習的信心。能有這些體會,這一節(jié)就算過關了。 隨著以后的深入,你會發(fā)現(xiàn)小小單片機里面是一個大世界,興趣也由此而生。 在PIC單片機系列中,改變I/O口的輸入輸出依靠寫入寄存器TRIS的值,相應位寫0,表示對應管腳被定義成了輸出,寫1,就是輸入。 現(xiàn)在假如預把GP1、GP2管腳定義成輸出,其他腳全是輸入。那就應該向TRIS寄存器寫入二進制數(shù) 11111001,換算成十六進制就是F9H. 依照以前我們學到的知識,在PIC系列單片機里,本來應該用下列的語句來完成我們的設定: movlw 0F9H '常數(shù)進W,以字母開頭的常數(shù)前面必須加0 實際上PIC系列的單片機也都是這么寫的,后面加的A,表示第一個8位的口(有的單片機不僅一個口,還有好幾個8位的I/O口如TRISB、TRISC、TRISD等等). 但是,記住了,PIC12系列的單片機必須改寫成為: 寫法不同,意思是一樣的.這樣你就又學了一個指令TRIS,不過這個指令的實質還是你曾經(jīng)學過的movwf 只是寫法不同罷了.在PIC12系列里TRIS作為指令, 在其他系列(PIC16\17\18)里把TRIS作為普通寄存器看待.因為我們現(xiàn)在講的就是PIC12CE519,所以我們暫時用tris GPIO 這個格式,等以后進入PIC16C877 我們再寫成 movwf TRISA,至于理解按照后者進行. 如果我們要控制GP1、GP2管腳的輸出電平, 其他管腳作為輸入.并且讓GP1輸出低電平,GP2輸出高電平.完整的程序如下: movlw 0F9H '常數(shù)進W 更多的情況是:某個口內的某一個管腳需要改變電平,其他腳電平不變.例如我們僅需要GPIO口上的GP1這個管腳的電平拉高,其他管腳電平不發(fā)生變化.這時候位操作指令為我們提供了方便,假如我們事先已經(jīng)把GP1管腳定義過輸出了(方法見前面講過的): bcf GPIO,GP1 '注釋:GPIO口上GP1管腳電平拉低,我們行話叫清除。 怎么樣,這樣控制某一個管腳的電平就方便多了,你的編程效率將會大大提高. 記住:PIC所有單片機所有寄存器都是可以位操作的,這在51的單片機上是不能完全實現(xiàn)的.不僅如此,PIC所有單片機所有管腳的單腿驅動輸出電流可以高達25mA,所以如果你驅動一個5到10mA電流的LED發(fā)光二極管,根本不用加三極管,串個電阻直接掛在單片機上就得了,這在51的單片機上也是不能實現(xiàn)的,要加驅動三極管或驅動芯片. 怎么樣?學PIC有好處吧.別急,好處還有。。。。。。 一不小心,已經(jīng)學會 5 個指令了,還有30個,加油啊。 五. 寄存器的英文是RAM. PIC12CE519里面共有48個寄存器供我們操作使用,它們每一個都有固定的地址編碼。地址編碼并不是連續(xù)的號碼,而是分成了兩段: 第一段: 從00H 開始, 依次是01H, 02H, 03H ....0AH, 0BH......到1FH 結束. 計32個寄存器 這種地址不是連續(xù)編號,而是要跳過一段的做法, 對于我們新手來說很是不習慣.為了讓我們容易入門, 我們暫時先不管第二段RAM, 只當它不存在,所有程序我們只涉及到第一段連續(xù)的RAM地址.等我們熟練的掌握好了RAM的使用,再涉及第二段地址的RAM, 那時,你就會理解單片機設計者把它們分成兩段的苦心了. 為了規(guī)范,我們今后一律把RAM的分段, 叫做分頁.第一地址段叫00頁面,第二地址段叫01頁面.例如:我們學過的I/O口電平控制寄存器GPIO,它的地址編碼是06H,屬于00頁面. 所有這32+16=48個寄存器除了在地址上分成了兩個頁面以外,又把它們分成兩類: 一類專用寄存器,一類通用寄存器. 所謂專用,就是這個寄存器的功能已經(jīng)由系統(tǒng)分配好了.例如:地址為06H的名稱就做GPIO寄存器的功能,它的每個位都對應到一個I/O腳的電平.另一類是通用寄存器,你可以理解成它的功能系統(tǒng)沒有事先預定,而是由你在編程序的時候隨機使用. pic12ce519的專用寄存器有7個,位置在我們第00頁面的最前面.這7個專用寄存器的地址編碼是:00H,01H, 02H, ----06H,剩下的所有寄存器包括所有第01頁面,全部都是通用寄存器. 例子:在兩個通用寄存器09H、0AH內寫入常數(shù)FCH movlw 0FCH '常數(shù)進W 從00H到06H都已經(jīng)起好了名稱,它們是專用寄存器,用處各有不同。以后我們會逐個介紹它們.剩下的都是通用寄存器或者叫普通寄存器(General Purpose Registers),意思是一般用途的寄存器。 內存圖譜,不要求記下來,但是應該有個大體印象,用的時候會察看就可以了。等編程時間一長,就那么幾個字節(jié),自然就記住了。 所謂字節(jié)是衡量二進制數(shù)據(jù)長度的一個單位。一個寄存器剛好能記住一個字節(jié)的數(shù)據(jù)。如果你要存儲的數(shù)據(jù)比較大超過了255,那就要占2個存儲器甚至更多。描述的時候通常我們不說這個數(shù)值占了多少個寄存器,而是說這個數(shù)據(jù)是幾個字節(jié)的。字節(jié)的英文是byte,一個二進制數(shù)的一位,叫比特,英文bit。1byte包含8bit。 六. nop '什么事情也不做,但執(zhí)行這個指令也要消耗掉一點時間。它沒有操作數(shù)。 如果你需要一個很短時間的延時,可以采用一連串的空操作。注意每個nop也是占一行,例如: movlw 0F9H '常數(shù)進W 運行的效果是接在管腳GP1上的LED燈先亮一段時間,再熄滅一段時間的閃爍。 七. movlw 02H '常數(shù)2進入W movlw 0FFH '常數(shù)255進入W 如果你事先定義好了地址為09H的這個寄存器里存儲的數(shù)字大小代表電視機節(jié)目頻道的話,你會很喜歡這兩個指令的。并且當節(jié)目頻道到達最大值255或最小值0的時候無需擔心,寄存器在0時減1會得255,255狀態(tài)下增1會得0。 至于為什么會這樣,學過環(huán)形計數(shù)器的人不會感到奇怪的。你要是沒有學過計數(shù)器電路也不要緊,記住一個寄存器的最大存儲數(shù)值是255=0FFH就可以了,加減法都會導致它“進位”。 當然控制音量時這個程序不能使用,因為它在0和255之間變化,音量忽大忽小怎們行。為解決這個問題,我們必須再學習兩條指令incfsz和decfsz。 它們與上兩個功能基本相同,不同的是:寄存器增1或減1操作以后,該指令會自動判定寄存器內的結果是否為零,如果不為零,繼續(xù)正常執(zhí)行該指令后面的語句.但如果結果為零的話,則程序會"跳一步".繞過緊挨著它下面的一條指令,繼續(xù)執(zhí)行更下面的語句,舉例子說明。 假定我們操作的寄存器還是09H: OK: nop '繼續(xù)運行 yanshi: movlw 5EH ' 常數(shù)5E進W 標號是延時 jixu: decfsz 0AH '0A寄存器內的數(shù)減1,如果結果為0跳步 先打個比方,如果你做一頓飯,要做湯,炒菜,燉魚,汆丸子,奧,忘了還有炒小螃蟹,期間有一個動作在我看來不斷的重復,這個動作就是放鹽,放鹽的過程描述是這樣的: 放鹽:用一把小勺子深入鹽罐 如果我們把做飯定義為主任務,那么放鹽這個動作就叫做子任務。 這樣定義的一個好處就是描述主任務的時候比較方便,當你用語言文字描述主任務的時候,無論哪一道菜,到了該加鹽的時候不必細說用一把小勺子深入鹽罐......,因為很多菜都有同樣的這個過程,所以,你用 “放鹽” 兩個字就可以了。但是在你使用 放鹽 這個詞之前或者之后,你應該解釋一下放鹽這個詞的具體過程是什么。 我們單片機的程序也是一樣的,如果你設計一個電視機的自動搜索頻道的程序,程序要求電視機每搜索成功一個頻道,它面板上的發(fā)光二極管就眨一次眼睛,也就說,先熄滅一段時間然后再點亮。這樣就會遇到很多這樣的眨眼動作,為了簡化主程序我們可以把眨眼這樣一個過程定義為一段子程序,以后每次遇到需要眨眼的時候就調用一次子程序就可以了。 子程序的定義是這樣的: 這樣,子程序就定義完了,如果想在程序的某個位置需要led燈熄滅以下(眨眼一次),只需在那個程序位置調用一下子程序就可以了。調用的方法是用 call 命令。 主程序:
疑問2 嗯,那繼續(xù)往下調用下去,有限制么? 疑問3 在同一層程序空間里,例如在我的某個子程序之中,調用另一個子程序的次數(shù)有限制么? 疑問4 我聽說單片機在調用子程序以前,好像需要程序“堆棧”訪問什么的,要進行一些程序計數(shù)器的保存保護,以保證子程序返回來得時候,程序能夠正確回到原來位置和環(huán)境。是這樣的么? 九. 單片機的中斷,概念并不難以理解。只是要真正理解運用編程處理一些實際中斷的例子,卻也不是很容易,甚至是單片機學習、入門的攔路虎。要想學會實際的中斷處理編程,也還需要清楚一些程序存儲器,程序結構,程序計數(shù)器,硬件堆棧,現(xiàn)場保護等這些個另雜碎概念。因此,我們在學習中斷以前、以后和學習中斷過程中,都有必要介紹回顧復習一些有關上述關鍵詞的概念和知識,否則,盡管你學了中斷,用起來可還是不能得心應手,以至于茫然。 還是用比喻的方法介紹一下中斷的概念: 你的主程序任務是做一桌可口的飯菜,期間可能要多次調用子程序“撒鹽”。盡管子程序下邊還有更小的子任務,比如“計算食鹽的量”等過程,盡管這些子過程很復雜,但他們的出場時間和順序是可以預料的,是可以預先安排的。也就說你肯定知道在什么時候放鹽。 有一類子程序,他的出場時間是不確定的,突然的,處理他們的時間刻不容緩,必須趕緊的。我們稱這一類子程序為中斷子程序。也就是我們所說的“中斷”。 你正在做菜的過程中,隔壁鄰居小孩突然敲門說他的二大爺在他房間里摔倒了,請你幫忙把二大爺扶起來。這是急迫的,必須處理的事務。 你肯定關掉爐子一溜煙跑出去幫忙,等回來以后再點著爐子繼續(xù)做菜。 這個事件的特點就是發(fā)生的時間你無法預先知道,而這個任務必須得停下當前工作去處理,并且是刻不容緩。從開始關爐子到回來點著爐子的這段時間里以及你的救人行為,就叫做“中斷子程序”。 在單片機里,中斷的例子也是很多的。我舉一個你手里的手機的例子,你的GSM手機正工作在賦閑,屏幕上也就顯示個時間日期中國電信什么的,表面看沒有什么。其實它內部的cpu高速運行忙碌地工作在諸如聯(lián)絡無線網(wǎng)絡,查詢是否有短消息發(fā)來,計算當前信號強度,時間等任務。你突然按下數(shù)字鍵“8”,此時內部cpu必須停下它正在干的工作來應付你,也就是清屏,顯示你按下的數(shù)字8,然后再回到它原來的任務接著運行。(當然,這個例子不一恰當,現(xiàn)在有操作系統(tǒng)Windows-ce windows-mobile的手機的工作機制遠沒有如此的簡單). |
|