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