电竞比分网-中国电竞赛事及体育赛事平台

分享

超易單片機(jī)入門

 ccbupt 2009-06-25
超易單片機(jī)入門 (學(xué)單片機(jī)一定要看)
 
(  向作者致敬!)

一.

話說(shuō)人間事物的學(xué)習(xí),不外兩類:一類入門易精通難,比如礦石機(jī),再比如練書(shū)法誰(shuí)都會(huì)寫(xiě)兩下,可寫(xiě)好卻不是一朝一夕的事兒。另一類則入門難精通易,比如超外差收音機(jī),學(xué)會(huì)需要各種放大、振蕩、反饋、混頻、中頻、統(tǒng)調(diào)等等,但是一旦你學(xué)會(huì),做出一個(gè)高質(zhì)量的收音機(jī),確也不是難事。單片機(jī)屬于后者,所以無(wú)論如何,你得用些時(shí)間,學(xué)習(xí)一些新名詞并理解,甚至還得花一些小錢。但是,一旦你掌握,其樂(lè)趣也像收音機(jī)一樣,很有吸引力的。

單片機(jī)不同于收音機(jī),收音機(jī)的任務(wù)最終就是聽(tīng)好聲音一個(gè),單片機(jī)可以做很多事情,要你來(lái)安排它的工作。安排它就先的認(rèn)識(shí)它,熟悉它。大家自己查看一下單片機(jī)的外形,不妨將它看成是一個(gè)8條腿的小螃蟹,這個(gè)8條腿的小螃蟹就是我們的第一頓飯,只要把它吃下去,以后的大餐就好辦了。

1、8條腿接電源 +5V和地線。頭兩條腿是螃蟹鉗子,好吃的很?,F(xiàn)在已經(jīng)剩下6條腿了。

2、3條腿使用時(shí)外接一個(gè)叫作晶振的東西,我們接一個(gè)4MHz的晶振(這還不知道?還是看一下:?jiǎn)纹瑱C(jī)之路(www.)里面對(duì)晶振的介紹吧)。

4條腿是復(fù)位腳,是一個(gè)信號(hào)輸入腳。單片機(jī)正常運(yùn)行時(shí)接高電平。當(dāng)有一個(gè)低電平脈沖輸入到這個(gè)腳時(shí)單片機(jī)就復(fù)位。所謂復(fù)位就是單片機(jī)內(nèi)部所有的工作部件統(tǒng)統(tǒng)回到規(guī)定的狀態(tài),程序也復(fù)位到頭一句上開(kāi)始逐條運(yùn)行。例如,你設(shè)計(jì)的一個(gè)報(bào)警鎖定的LED紅燈亮后,當(dāng)需要解除報(bào)警時(shí),用一個(gè)按鈕給這個(gè)腳瞬時(shí)接地一下,相當(dāng)于給它一個(gè)夫脈沖,系統(tǒng)就復(fù)位了,led燈就熄滅了,程序從頭開(kāi)始。

以上5個(gè)腳,幾乎所有單片機(jī)都有,包括世界上最復(fù)雜的,和世界比較簡(jiǎn)單的單片機(jī)-PIC12CE519。

輪到底幾條腿啦?奧,是第5條腿,這條叫單片機(jī)的I/O腳。就是輸入輸出腳。你可通過(guò)程序動(dòng)態(tài)地控制它作為輸入或輸出,作為輸出時(shí)可以程序控制它的輸出電平為高1或低0。所以,他的工作狀態(tài)有四種:
   
   
輸入0,輸入1,輸出0,輸出1

剩下的兩條腿和第5腳功能一個(gè)樣。
二.
 
PIC系列單片機(jī)入門并不難(1)中,我們已經(jīng)把8條腿消化掉了,其實(shí)我們要弄明白的也就3只腿,我們?cè)俸?jiǎn)單一些,先整明白兩條腿,即GP0,GP1.這兩條腿低級(jí)一點(diǎn)的用法,可以控制繼電器,LED燈,高級(jí)一些的用法可以進(jìn)行I2C總線,RS232總線的通信,作為擴(kuò)展輸入可以模擬出來(lái)A/D轉(zhuǎn)換器(6--7bit),可以測(cè)量一個(gè)電阻的粗略值。作為輸出也可以直接推動(dòng)揚(yáng)聲器奏出音樂(lè)。這是后話暫且不提。

現(xiàn)在要控制使用這兩只腿了,這不得不首先要講一下軟件,要想講明白軟件又不得不涉及到單片機(jī)的內(nèi)部結(jié)構(gòu)??赡苡信笥颜f(shuō)啦,可別提這軟件和結(jié)構(gòu)了,以前俺就是讓它們打敗的,現(xiàn)在聽(tīng)到這個(gè)心里就打鼓。嘿嘿,不要緊,果真如你所說(shuō),那你就不妨跟著我再失敗一次,反正多一次失敗又不納稅嗎,嘿嘿。不過(guò)你也要有思想準(zhǔn)備,徹底弄明白是個(gè)漸進(jìn)的過(guò)程。

要說(shuō)起這程序和單片機(jī)內(nèi)部結(jié)構(gòu),還真是老大難,不過(guò)蟹黃蟹肉可都在里面。我現(xiàn)在要是給你說(shuō)PIC單片機(jī)是哈佛結(jié)構(gòu)的,51系列是馮-諾伊曼結(jié)構(gòu)的話,恐怕你要立馬走人了。所以我得用點(diǎn)心思不讓你溜號(hào)。

好在PIC系列的制造商(microchip 微芯公司)理解我等苦衷,全部只有35條指令,而且有一些指令我們一般很少使用,常用的也就十幾句,用的時(shí)候查手冊(cè),無(wú)需記憶。就算我們兩天學(xué)習(xí)一句,也就兩三個(gè)月時(shí)間,總比到老了還怕它們強(qiáng)啊。廢話少說(shuō)先看下面的兩個(gè)例語(yǔ):

my_name006:   movlw  02h      '常數(shù)2進(jìn)入w
                          movwf  GPIO  'W
的數(shù)進(jìn)入寄存器GPIO
         
這就是我們編的程序里的兩個(gè)句子,也叫源程序。有以下特點(diǎn):

每行只能寫(xiě)一句話;
每句話由四部分組成:

標(biāo)號(hào):  操作指令   操作數(shù)        '程序注釋

下面我結(jié)合例子把這四部分解釋一下。

第一部分 my_name006: 叫做標(biāo)號(hào),它是由字母或數(shù)字組成,由冒號(hào)結(jié)束。標(biāo)號(hào)可有可無(wú),比如第二句就沒(méi)有標(biāo)號(hào)。
   
第二部分movlw 叫做操作指令。它是必須有的,不能省略。PIC 系列的單片機(jī)共有 35 條指令。
   
第三部分02h   叫做操作數(shù)。有的指令沒(méi)有操作數(shù)或者操作數(shù)是默認(rèn)的,也不用寫(xiě)。
   
第四部分是程序注釋,必須以單引號(hào)開(kāi)頭,主要作用是提醒和備忘。注釋也是可有可無(wú)。

第二個(gè)例句中,省略了標(biāo)號(hào),當(dāng)然注釋也可以省略。他的指令是movwf,操作數(shù)是GPIO。操作數(shù)不一定是數(shù)字,也可能是一個(gè)由字母組成的字符串
  
知道了語(yǔ)句格式以后,我們下面就學(xué)習(xí)一些常用語(yǔ)句。我們先把這兩個(gè)例句弄清楚。

這兩句話的作用是把 2 這個(gè)常數(shù)寫(xiě)入到 GPIO 這個(gè)寄存器里。
   
單片機(jī)里有一些部件需要我們使用和操作,都是通過(guò)讀寫(xiě)寄存器來(lái)實(shí)現(xiàn)的。每個(gè)部件都對(duì)應(yīng)有操控它的寄存器,例如我們要控制使用的管腳GP0,GP1 這兩個(gè)管腳對(duì)應(yīng)的寄存器就叫做GPIO。對(duì)GPIO寄存器讀操作,實(shí)際等效察看管腳電平的高低;對(duì)GPIO寄存器相應(yīng)的位寫(xiě)1操作,實(shí)際等效讓管腳輸出高電平。寫(xiě)0,輸出低電平。

每個(gè)寄存器可以儲(chǔ)存一個(gè)八位的二進(jìn)制數(shù)。這八個(gè)位的每一位都有名稱,從左向右的名稱是:
   
左端第首位名稱叫D7,
   
左端第二位名稱叫D6,
   
左端第三位名稱叫D5,
   
左端第四位名稱叫D4,
   
左端第五位名稱叫D3,
   
左端第六位名稱叫D2,
   
左端第七位名稱叫D1,
   
最后一位叫D0,

而每一個(gè)位對(duì)應(yīng)一個(gè)管腳的電平,例如當(dāng)GPIO寄存器的D0位等于1時(shí)表示管腳GP0的電平是高電平。D0位等于0時(shí)表示管腳GP0的電平是低電平。常數(shù)2的八位二進(jìn)制表示是“00000010  所以,GPIO寄存器存放的82進(jìn)制數(shù)的每個(gè)位的值以及管腳電平是:
    D7
對(duì)應(yīng)于內(nèi)部總線管腳的電平        D7=0  內(nèi)部總線管腳輸出低電平             
    D6
對(duì)應(yīng)于內(nèi)部總線管腳的電平        D6=0  內(nèi)部總線管腳輸出低電平
    D5
對(duì)應(yīng)于GP5 管腳的電平            D5=0   GP5 管腳輸出低電平
    D4
對(duì)應(yīng)于GP4 管腳的電平            D4=0   GP4 管腳輸出低電平
    D3
對(duì)應(yīng)于GP3 管腳的電平            D3=0   GP3 管腳輸出低電平
    D2
對(duì)應(yīng)于GP2 管腳的電平            D2=0   GP2 管腳輸出低電平
    D1
對(duì)應(yīng)于GP1 管腳的電平            D1=1   GP1 管腳輸出低電平     
    D0
對(duì)應(yīng)于GP0 管腳的電平            D0=0   GP0 管腳輸出低電平
   
    D7
、D6對(duì)應(yīng)的內(nèi)部時(shí)鐘和數(shù)據(jù)總線我們現(xiàn)在暫且不要管它。以后本事大了再調(diào)教它們。在我們的例句中,向GPIO寄存器寫(xiě)入了2,常數(shù)2的八位二進(jìn)制表示是“00000010”,如果此時(shí)GP0, Gp1等都已經(jīng)被定義成輸出的話,那么GP1輸出高電平(接LED燈亮),GP0輸出低電平(所接LED燈熄) 。

截止到現(xiàn)在,你已經(jīng)學(xué)會(huì)如何控制管腳的電平高低了。盡管還有一些疑問(wèn),比如怎樣定義管腳為輸出腳(以后會(huì)說(shuō)),我得說(shuō),如果事先GP1,GP0這兩個(gè)管腳處于輸入狀態(tài),這兩個(gè)例句無(wú)效,因?yàn)樵谶@種狀態(tài)下它們是控制不了電平的。

無(wú)論如何,這一會(huì)兒,你就學(xué)會(huì)了兩個(gè)指令,35條我看也沒(méi)啥難的。

下面再加深一下對(duì)寄存器的認(rèn)識(shí):

要把一個(gè)常數(shù)存儲(chǔ)到寄存器,或者說(shuō)寫(xiě)到一個(gè)寄存器中,僅用一條指令是辦不到的,必須通過(guò)一個(gè)特殊的寄存器W,把數(shù)據(jù)倒過(guò)去. 這就應(yīng)該使用到下面兩個(gè)語(yǔ)句:

movlw   02H    指令的意思是把一個(gè)常數(shù)存入特殊寄存器W, 這個(gè)常數(shù)是3,后面的H是表示十六進(jìn)制
    movwf   GPIO  
指令的意思是把特殊寄存器W的數(shù)值存入寄存器,這個(gè)寄存器的名稱是GPIO

這里涉及到兩個(gè)概念,常數(shù)和寄存器:

常數(shù)好說(shuō),比如說(shuō)十進(jìn)制數(shù)35,26。但要注意,在單片機(jī)系統(tǒng)里我們一般不用十進(jìn)制,而使用十六進(jìn)制。有關(guān)數(shù)制轉(zhuǎn)換方面的知識(shí),是計(jì)算機(jī)的基礎(chǔ),必須會(huì)熟練地在二進(jìn)制、十六進(jìn)制、十進(jìn)制之間轉(zhuǎn)換,此處不再羅索。

寄存器也叫單片機(jī)的內(nèi)存,一個(gè)寄存器可以存儲(chǔ)的數(shù)值范圍是0--255,用十六進(jìn)制表示就是0--FFH.用二進(jìn)制表示就是00000000----11111111。“單片機(jī)之路”提醒您:以后要養(yǎng)成習(xí)慣用十六進(jìn)制表示數(shù)。

那么,一個(gè)單片機(jī)里有多少個(gè)這樣的寄存器哩,pic12ce512里面有1024個(gè)這樣的寄存器可以供你使用,為了使用方便生產(chǎn)商已經(jīng)給它們編上了號(hào)碼,第一號(hào)碼是000H,往下依照次序?yàn)?/span> 001H,002H........3FFH.(怎么樣,開(kāi)始用十六進(jìn)制說(shuō)事了吧,如果你不熟悉熟制轉(zhuǎn)換趕緊補(bǔ)課還來(lái)得及。)有了編號(hào)就像我們居住的房間有了房間號(hào)碼,使用就方便的多了.房間號(hào)碼在郵政行業(yè)叫地址,因此我們稱這些號(hào)碼叫做寄存器地址,或稱地址數(shù)。例如:名稱為GPIO的寄存器,它的地址或地址數(shù)是06H。所以我們的兩個(gè)例句完全等同于:

my_name006     movlw  02h      '常數(shù)2進(jìn)入w
                              movwf  06H      'W
的數(shù)進(jìn)入寄存器GPIO

有兩個(gè)寄存器比較特殊,它們沒(méi)有地址,一個(gè)名字叫做W,另一個(gè)叫做TRIS.所以他們兩個(gè)在存儲(chǔ)數(shù)據(jù)的時(shí)候比較快,一個(gè)指令就可以解決問(wèn)題,例如:movlw 03H 一條指令就把常數(shù)3寫(xiě)入到W寄存器了。關(guān)于TRIS寄存器,我們以后用到它再說(shuō)。除了他們兩個(gè)以外的其他所有寄存器,在寫(xiě)入數(shù)據(jù)時(shí)一般都要用兩條指令進(jìn)行。

本文雖然只有兩個(gè)指令,但主要目的是讓大家接觸一下指令,建立寄存器的概念以及他們同硬件部件的聯(lián)系。增強(qiáng)學(xué)習(xí)的信心。能有這些體會(huì),這一節(jié)就算過(guò)關(guān)了。

隨著以后的深入,你會(huì)發(fā)現(xiàn)小小單片機(jī)里面是一個(gè)大世界,興趣也由此而生。
三.
   
PIC系列單片機(jī)入門并不難(2)中講的是兩個(gè)指令如何控制管腳電平的高低。前提是所有管腳已經(jīng)被定義成輸出了(OUT)如果被定義成了輸入,則上次的指令雖然也能運(yùn)行,但運(yùn)行后絲毫不能改變管腳電平高低,因?yàn)榇藭r(shí)管腳是輸入狀態(tài),電平取決于外部輸入,指令無(wú)法改變。

PIC單片機(jī)系列中,改變I/O口的輸入輸出依靠寫(xiě)入寄存器TRIS的值,相應(yīng)位寫(xiě)0,表示對(duì)應(yīng)管腳被定義成了輸出,寫(xiě)1,就是輸入。

現(xiàn)在假如預(yù)把GP1、GP2管腳定義成輸出,其他腳全是輸入。那就應(yīng)該向TRIS寄存器寫(xiě)入二進(jìn)制數(shù) 11111001,換算成十六進(jìn)制就是F9H.

依照以前我們學(xué)到的知識(shí),PIC系列單片機(jī)里,本來(lái)應(yīng)該用下列的語(yǔ)句來(lái)完成我們的設(shè)定:

movlw     0F9H      '常數(shù)進(jìn)W,以字母開(kāi)頭的常數(shù)前面必須加0
movwf    TRISA      '
W內(nèi)的數(shù)復(fù)制到TRIS

實(shí)際上PIC系列的單片機(jī)也都是這么寫(xiě)的,后面加的A,表示第一個(gè)8位的口(有的單片機(jī)不僅一個(gè)口,還有好幾個(gè)8位的I/O口如TRISB、TRISC、TRISD等等).

但是,記住了,PIC12系列的單片機(jī)必須改寫(xiě)成為:
        
        movlw    0F9H      '
常數(shù)進(jìn)W,以字母開(kāi)頭的常數(shù)前面必須加0
        tris     GPIO      '
W內(nèi)的數(shù)復(fù)制到TRIS,以后凡見(jiàn)到這個(gè)指令一律理解成 movwf  TRISA

寫(xiě)法不同,意思是一樣的.這樣你就又學(xué)了一個(gè)指令TRIS,不過(guò)這個(gè)指令的實(shí)質(zhì)還是你曾經(jīng)學(xué)過(guò)的movwf 只是寫(xiě)法不同罷了.PIC12系列里TRIS作為指令, 在其他系列(PIC16\17\18)里把TRIS作為普通寄存器看待.因?yàn)槲覀儸F(xiàn)在講的就是PIC12CE519,所以我們暫時(shí)用tris  GPIO 這個(gè)格式,等以后進(jìn)入PIC16C877 我們?cè)賹?xiě)成 movwf TRISA,至于理解按照后者進(jìn)行.

如果我們要控制GP1、GP2管腳的輸出電平, 其他管腳作為輸入.并且讓GP1輸出低電平,GP2輸出高電平.完整的程序如下:

movlw    0F9H      '常數(shù)進(jìn)W  
                 tris     GPIO       '
W內(nèi)的數(shù)復(fù)制到TRIS GP1  GP2為輸出,其他為輸入
                  '此行無(wú)命令,起到的作用是容易讀懂程序
     movlw    04H       '常數(shù)4的二進(jìn)制是 00000100 ,GP1=0  GP2=1
              movwf    GPIO      'W
內(nèi)的數(shù)進(jìn)GPIO輸出生效,原來(lái)定義成輸入的腳的電平,不會(huì)受該句影響
四.
   
前面已經(jīng)學(xué)會(huì)了三條指令,至此,8位寄存器的概念概念一定要建立起來(lái),程序通過(guò)寫(xiě)入寄存器不同的數(shù)據(jù)控制管腳作為輸入使用還是輸出使用,作為輸出時(shí)是輸出高電平還是低電平。這樣操作的又一個(gè)特點(diǎn)就是每次寫(xiě)入數(shù)據(jù),同時(shí)控制的往往不是一個(gè)管腳,而是好幾個(gè),最多一次可以控制8個(gè)管腳.在單片機(jī)里往往每8個(gè)腳叫做一個(gè)口,如口A、口B,用英文表示就是GPIO、PORTA、PORTB、PORTC 等.

更多的情況是:某個(gè)口內(nèi)的某一個(gè)管腳需要改變電平,其他腳電平不變.例如我們僅需要GPIO口上的GP1這個(gè)管腳的電平拉高,其他管腳電平不發(fā)生變化.這時(shí)候位操作指令為我們提供了方便,假如我們事先已經(jīng)把GP1管腳定義過(guò)輸出了(方法見(jiàn)前面講過(guò)的):

bcf     GPIO,GP1         '注釋:GPIO口上GP1管腳電平拉低,我們行話叫清除。
   bSf     GPIO,GP1         '注釋:GPIO口上GP1管腳電平拉高,我們行話叫置位。

怎么樣,這樣控制某一個(gè)管腳的電平就方便多了,你的編程效率將會(huì)大大提高.

記住PIC所有單片機(jī)所有寄存器都是可以位操作的,這在51的單片機(jī)上是不能完全實(shí)現(xiàn)的.不僅如此,PIC所有單片機(jī)所有管腳的單腿驅(qū)動(dòng)輸出電流可以高達(dá)25mA,所以如果你驅(qū)動(dòng)一個(gè)510mA電流的LED發(fā)光二極管,根本不用加三極管,串個(gè)電阻直接掛在單片機(jī)上就得了,這在51的單片機(jī)上也是不能實(shí)現(xiàn)的,要加驅(qū)動(dòng)三極管或驅(qū)動(dòng)芯片.

怎么樣?學(xué)PIC有好處吧.別急,好處還有。。。。。。

一不小心,已經(jīng)學(xué)會(huì) 5 個(gè)指令了,還有30個(gè),加油啊。

五.
單片機(jī)的大部分指令,或者說(shuō)單片機(jī)所做的大部分工作,多數(shù)在寫(xiě)入或讀出寄存器。關(guān)于寄存器的初步概念我想我們已經(jīng)建立起來(lái)了,它是一個(gè)能夠存儲(chǔ)8位二進(jìn)制數(shù)據(jù)(最大255=0FFH)的單元,每個(gè)單元都有它的編號(hào),我們叫做它的地址或地址編碼.地址編碼也是十六進(jìn)制的.另外寄存器里的數(shù)據(jù)掉電就會(huì)丟失。

寄存器的英文是RAM.

PIC12CE519里面共有48個(gè)寄存器供我們操作使用,它們每一個(gè)都有固定的地址編碼。地址編碼并不是連續(xù)的號(hào)碼,而是分成了兩段:

第一段00H 開(kāi)始, 依次是01H, 02H, 03H ....0AH, 0BH......1FH 結(jié)束計(jì)32個(gè)寄存器
第二段30H 開(kāi)始, 依次是31H, 32H, ......................3FH 結(jié)束   計(jì)16個(gè)寄存器

這種地址不是連續(xù)編號(hào),而是要跳過(guò)一段的做法, 對(duì)于我們新手來(lái)說(shuō)很是不習(xí)慣.為了讓我們?nèi)菀兹腴T, 我們暫時(shí)先不管第二段RAM, 只當(dāng)它不存在,所有程序我們只涉及到第一段連續(xù)的RAM地址.等我們熟練的掌握好了RAM的使用,再涉及第二段地址的RAM, 那時(shí),你就會(huì)理解單片機(jī)設(shè)計(jì)者把它們分成兩段的苦心了.

為了規(guī)范,我們今后一律把RAM的分段, 叫做分頁(yè).第一地址段叫00頁(yè)面,第二地址段叫01頁(yè)面.例如:我們學(xué)過(guò)的I/O口電平控制寄存器GPIO,它的地址編碼是06H,屬于00頁(yè)面.

所有這32+16=48個(gè)寄存器除了在地址上分成了兩個(gè)頁(yè)面以外,又把它們分成兩類:

一類專用寄存器,一類通用寄存器.

所謂專用,就是這個(gè)寄存器的功能已經(jīng)由系統(tǒng)分配好了.例如:地址為06H的名稱就做GPIO寄存器的功能,它的每個(gè)位都對(duì)應(yīng)到一個(gè)I/O腳的電平.另一類是通用寄存器,你可以理解成它的功能系統(tǒng)沒(méi)有事先預(yù)定,而是由你在編程序的時(shí)候隨機(jī)使用.

pic12ce519的專用寄存器有7個(gè),位置在我們第00頁(yè)面的最前面.7個(gè)專用寄存器的地址編碼是:00H,01H, 02H, ----06H,剩下的所有寄存器包括所有第01頁(yè)面,全部都是通用寄存器.

例子:在兩個(gè)通用寄存器09H、0AH內(nèi)寫(xiě)入常數(shù)FCH

movlw     0FCH    '常數(shù)進(jìn)
      movwf     9H      '
復(fù)制W內(nèi)的數(shù)到通用寄存器09H 
      movwf     0AH     '
復(fù)制W內(nèi)的數(shù)到通用寄存器0AH,由于此時(shí)W內(nèi)并沒(méi)有改變,W不用再進(jìn)常數(shù).

00H06H都已經(jīng)起好了名稱,它們是專用寄存器,用處各有不同。以后我們會(huì)逐個(gè)介紹它們.剩下的都是通用寄存器或者叫普通寄存器(General Purpose Registers),意思是一般用途的寄存器。

內(nèi)存圖譜,不要求記下來(lái),但是應(yīng)該有個(gè)大體印象,用的時(shí)候會(huì)察看就可以了。等編程時(shí)間一長(zhǎng),就那么幾個(gè)字節(jié),自然就記住了。

所謂字節(jié)是衡量二進(jìn)制數(shù)據(jù)長(zhǎng)度的一個(gè)單位。一個(gè)寄存器剛好能記住一個(gè)字節(jié)的數(shù)據(jù)。如果你要存儲(chǔ)的數(shù)據(jù)比較大超過(guò)了255,那就要占2個(gè)存儲(chǔ)器甚至更多。描述的時(shí)候通常我們不說(shuō)這個(gè)數(shù)值占了多少個(gè)寄存器,而是說(shuō)這個(gè)數(shù)據(jù)是幾個(gè)字節(jié)的。字節(jié)的英文是byte,一個(gè)二進(jìn)制數(shù)的一位,叫比特,英文bit。1byte包含8bit

六.
下面我們學(xué)習(xí)一條新指令,叫做空操作指令.

nop    '什么事情也不做,但執(zhí)行這個(gè)指令也要消耗掉一點(diǎn)時(shí)間。它沒(méi)有操作數(shù)。
          '
不要理解成程序停了,實(shí)際上程序仍在正常運(yùn)行。執(zhí)行一連串的空操作指令,單片機(jī)
           '
白耗費(fèi)時(shí)間,什么活也不干,往往用于延時(shí)。

如果你需要一個(gè)很短時(shí)間的延時(shí),可以采用一連串的空操作。注意每個(gè)nop也是占一行,例如:

movlw    0F9H      '常數(shù)進(jìn)W  
    tris     GPIO      '
W內(nèi)的數(shù)復(fù)制到TRIS ,GP1  GP2為輸出,其他為輸入
    bsf      GPIO,GP1  '
管腳GP1輸出高電平點(diǎn)亮LED燈(如果你已經(jīng)接上燈的話)
    nop
    nop
    nop
    nop
    nop
    ... .
     bcf      GPIO,GP1  '
管腳GP1輸出低電平關(guān)閉LED
    nop
    nop
    nop
    nop
    ...

運(yùn)行的效果是接在管腳GP1上的LED燈先亮一段時(shí)間,再熄滅一段時(shí)間的閃爍。

 

七.
下面我們學(xué)習(xí)兩個(gè)新指令incfdecf,它們都是對(duì)某一個(gè)寄存器進(jìn)行增1或減1操作,例句中假如我們要操作的寄存器是09H。

movlw    02H   '常數(shù)2進(jìn)入
      movwf    09H   '
w內(nèi)的數(shù)2復(fù)制到09H 這個(gè)寄存器 
                   '
現(xiàn)在09H寄存器內(nèi)存儲(chǔ)的數(shù)是2
      incf     09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)增加1  
                   '
現(xiàn)在09H內(nèi)存儲(chǔ)的數(shù)變成3
      decf     09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)減掉1
                   '
現(xiàn)在09H內(nèi)存儲(chǔ)的數(shù)變成2

movlw    0FFH  '常數(shù)255進(jìn)入
      movwf    09H   '
w 內(nèi)的數(shù)255復(fù)制到09H這個(gè)寄存器 
                   '
現(xiàn)在09H 寄存器內(nèi)存儲(chǔ)的數(shù)是255
      incf     09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)增加1  
                   '
現(xiàn)在09H內(nèi)存儲(chǔ)的數(shù)變成0
      decf     09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù) 減掉1
                   '
現(xiàn)在09H內(nèi)存儲(chǔ)的數(shù)又變成255

如果你事先定義好了地址為09H的這個(gè)寄存器里存儲(chǔ)的數(shù)字大小代表電視機(jī)節(jié)目頻道的話,你會(huì)很喜歡這兩個(gè)指令的。并且當(dāng)節(jié)目頻道到達(dá)最大值255或最小值0的時(shí)候無(wú)需擔(dān)心,寄存器在0時(shí)減1會(huì)得255,255狀態(tài)下增1會(huì)得0。

至于為什么會(huì)這樣,學(xué)過(guò)環(huán)形計(jì)數(shù)器的人不會(huì)感到奇怪的。你要是沒(méi)有學(xué)過(guò)計(jì)數(shù)器電路也不要緊,記住一個(gè)寄存器的最大存儲(chǔ)數(shù)值是255=0FFH就可以了,加減法都會(huì)導(dǎo)致它“進(jìn)位”。

當(dāng)然控制音量時(shí)這個(gè)程序不能使用,因?yàn)樗?/span>0255之間變化,音量忽大忽小怎們行。為解決這個(gè)問(wèn)題,我們必須再學(xué)習(xí)兩條指令incfszdecfsz。

它們與上兩個(gè)功能基本相同,不同的是:寄存器增1或減1操作以后,該指令會(huì)自動(dòng)判定寄存器內(nèi)的結(jié)果是否為零,如果不為零,繼續(xù)正常執(zhí)行該指令后面的語(yǔ)句.但如果結(jié)果為零的話,則程序會(huì)"跳一步".繞過(guò)緊挨著它下面的一條指令,繼續(xù)執(zhí)行更下面的語(yǔ)句,舉例子說(shuō)明。

假定我們操作的寄存器還是09H: 
   
   movlw    0FDH   '
常數(shù)253進(jìn)入
   movwf    09H    '
w 內(nèi)的數(shù)253 復(fù)制到09H 這個(gè)寄存器 
                   '
現(xiàn)在09H 寄存器內(nèi)存儲(chǔ)的數(shù)是253
   incfsz    09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)增加1,結(jié)果變成254結(jié)果不等于0,故程序繼續(xù)執(zhí)行下一指令
   nop             '
該句得到執(zhí)行(因?yàn)樯弦痪浼拇嫫?/span>09H的計(jì)算結(jié)果不等于0  
   incf      09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)增加1,結(jié)果是255
   incfsz    09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù)增加1,結(jié)果變成0  
                   '
因?yàn)榻Y(jié)果等于0,故程序要跳過(guò)下面的一句(不運(yùn)行下面的一句).
   incf      09H      '
由于上一句的存在并結(jié)果為0,該句得不到執(zhí)行,被忽略
   incf      09H      '
程序跳入這一句繼續(xù)運(yùn)行 寄存器09H內(nèi)存儲(chǔ)的數(shù) 增加1
   nop                  '
因此現(xiàn)在 09H寄存器存儲(chǔ)的數(shù)是1
   nop                  '
繼續(xù)運(yùn)行
        .
        .
     
思考題:設(shè)計(jì)一段程序代碼,當(dāng)用戶連續(xù)按下音量減小鍵后,判定音量寄存器09H的存儲(chǔ)音量數(shù)值,
防止該寄存器的值從0 變成255,以免震驚到用戶。
        .
SMALL_SOUND:  nop    '
標(biāo)號(hào)可以任意寫(xiě)的,此前用戶一旦按下音量減,就把程序引導(dǎo)到這一句上來(lái)
              decfsz    09H   '
寄存器09H內(nèi)存儲(chǔ)的數(shù) 1,如果結(jié)果為0 就跳一步  
              goto      OK    '
如果上一句結(jié)果不為0,執(zhí)行該句后,程序去了ok語(yǔ)句 
              movlw     01H   '
跳到這一步說(shuō)明寄存器結(jié)果是0
              movwf     09    '
強(qiáng)行把 09H內(nèi)的數(shù)值寫(xiě)成1,仍然是小音量,這樣音量不會(huì)被因?yàn)?/span> 減小而變成255

OK:        nop     '繼續(xù)運(yùn)行   
      .   .
   
思考題:利用decfsz 指令設(shè)計(jì)一段延時(shí)代碼,使得延時(shí)時(shí)間可以在10個(gè)機(jī)器周期到65535個(gè)機(jī)器周期之間,可以通過(guò)程序任意控制在這個(gè)例子中,設(shè)我們要控制的延時(shí)時(shí)間大約是24086個(gè)及其周期,用16進(jìn)制表是就是 5E16 H. 如果用到通用寄存器,請(qǐng)使用 0AH, 0BH

yanshi:           movlw              5EH             ' 常數(shù)5E進(jìn)W 標(biāo)號(hào)是延時(shí)
                           movwf              0BH             '0B
寄存器數(shù)為5EH
                           movlw              16H              '
常數(shù)16進(jìn)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             '
延時(shí)完畢
        .
      
你現(xiàn)在可以只用這幾個(gè)簡(jiǎn)單句子完成任意時(shí)間的延時(shí)程序了。
八.
  
下面介紹單片機(jī)匯編語(yǔ)言里的一個(gè)概念“子程序”

先打個(gè)比方,如果你做一頓飯,要做湯,炒菜,燉魚(yú),汆丸子,奧,忘了還有炒小螃蟹,期間有一個(gè)動(dòng)作在我看來(lái)不斷的重復(fù),這個(gè)動(dòng)作就是放鹽,放鹽的過(guò)程描述是這樣的:

放鹽:用一把小勺子深入鹽罐
       
舀出氯化鈉適量。
       
把小勺子里的氯化鈉
       
均勻?yàn)⒃阱伬铩?/span>
       
完畢

如果我們把做飯定義為主任務(wù),那么放鹽這個(gè)動(dòng)作就叫做子任務(wù)。

這樣定義的一個(gè)好處就是描述主任務(wù)的時(shí)候比較方便,當(dāng)你用語(yǔ)言文字描述主任務(wù)的時(shí)候,無(wú)論哪一道菜,到了該加鹽的時(shí)候不必細(xì)說(shuō)用一把小勺子深入鹽罐......,因?yàn)楹芏嗖硕加型瑯拥倪@個(gè)過(guò)程,所以,你用 “放鹽” 兩個(gè)字就可以了。但是在你使用 放鹽 這個(gè)詞之前或者之后,你應(yīng)該解釋一下放鹽這個(gè)詞的具體過(guò)程是什么。

我們單片機(jī)的程序也是一樣的,如果你設(shè)計(jì)一個(gè)電視機(jī)的自動(dòng)搜索頻道的程序,程序要求電視機(jī)每搜索成功一個(gè)頻道,它面板上的發(fā)光二極管就眨一次眼睛,也就說(shuō),先熄滅一段時(shí)間然后再點(diǎn)亮。這樣就會(huì)遇到很多這樣的眨眼動(dòng)作,為了簡(jiǎn)化主程序我們可以把眨眼這樣一個(gè)過(guò)程定義為一段子程序,以后每次遇到需要眨眼的時(shí)候就調(diào)用一次子程序就可以了。

子程序的定義是這樣的:
Zhayan: bcf  GPIO,GP1  '
管腳GP1輸出低電平關(guān)閉LED,標(biāo)號(hào)是必須有的,標(biāo)號(hào)就是子程序的名字
        nop
        nop
        nop
        nop
        nop
        ... .
           
        bsf  GPIO,GP1  '
管腳GP1輸出高電平點(diǎn)亮LED
        nop
        nop
        nop
        nop
         ...        
        return    '
這個(gè)命令表示子程序的結(jié)束 是必需的 否則這個(gè)子程序沒(méi)有結(jié)束

這樣,子程序就定義完了,如果想在程序的某個(gè)位置需要led燈熄滅以下(眨眼一次),只需在那個(gè)程序位置調(diào)用一下子程序就可以了。調(diào)用的方法是用 call 命令。

主程序:
     ....               '
這些點(diǎn)點(diǎn)表示主程序里的語(yǔ)句
     ....
     ......
     ......              '
這個(gè)位置搜所成功一個(gè)臺(tái) 需要“眨眼”一次
     call  Zhayan        
     ......              '
繼續(xù)搜索下一個(gè)臺(tái)的命令行
      ......
     ......
     ......
     ......              '
這個(gè)位置搜所成功一個(gè)臺(tái) 需要“眨眼”一次
     call  Zhayan
     ......              '
繼續(xù)搜索下一個(gè)臺(tái)的命令行
      ......
     ......
     ......              '
這個(gè)位置搜所成功一個(gè)臺(tái) 需要“眨眼”一次
     call  Zhayan        
     ......              '
繼續(xù)搜索下一個(gè)臺(tái)的命令行
      ......


疑問(wèn)1  我在一個(gè)主程序里固然可以調(diào)用另一個(gè)子程序,而我在一個(gè)子程序里能不能調(diào)用另一個(gè)子程序?
答:  可以的,這叫子程序嵌套,甚至還可以在另一個(gè)子程序中再繼續(xù)調(diào)用別的子程序。

疑問(wèn) 嗯,那繼續(xù)往下調(diào)用下去,有限制么?
答:有,這叫允許嵌套的層數(shù) 每個(gè)品牌 型號(hào)的單片機(jī)允許的嵌套層數(shù)都是有規(guī)定的 例如pic16f74 允許8
   pic12e519
允許兩層,也就是說(shuō)pic12e519的主程序里可以調(diào)用子程序,子程序里??梢栽僬{(diào)用子程序,到此為止不要再往下調(diào)用了,否則程序報(bào)錯(cuò)或者超出你預(yù)計(jì)的結(jié)果。

疑問(wèn) 在同一層程序空間里,例如在我的某個(gè)子程序之中,調(diào)用另一個(gè)子程序的次數(shù)有限制么?
回答: 沒(méi)有限制,只要你的程序寄存器裝得下你的程序。

疑問(wèn) 我聽(tīng)說(shuō)單片機(jī)在調(diào)用子程序以前,好像需要程序“堆棧”訪問(wèn)什么的,要進(jìn)行一些程序計(jì)數(shù)器的保存保護(hù),以保證子程序返回來(lái)得時(shí)候,程序能夠正確回到原來(lái)位置和環(huán)境。是這樣的么?
答: pic單片機(jī)不用管這些問(wèn)題,它是硬件自動(dòng)完成這些堆棧的事情,我們的指令里不用關(guān)心這些。盡管如此,中檔pic單片機(jī)的例如 pic16等系列,它們的程序存儲(chǔ)器地址是分頁(yè)的,盡量調(diào)用本頁(yè)的子程序,如果子程序不在本頁(yè),而是在另一個(gè)頁(yè)面里存放,你還是要告訴單片機(jī)你的子程序所在的頁(yè)面數(shù)據(jù)的,具體操作指令可以查相關(guān)指令說(shuō)明。我們的pic12c519的程序存儲(chǔ)器,沒(méi)有分頁(yè),不用關(guān)心這事。

九.
學(xué)習(xí)到這里,就已經(jīng)初窺門庭了,下一步還有一個(gè)重要的關(guān)口-------中斷

單片機(jī)的中斷,概念并不難以理解。只是要真正理解運(yùn)用編程處理一些實(shí)際中斷的例子,卻也不是很容易,甚至是單片機(jī)學(xué)習(xí)、入門的攔路虎。要想學(xué)會(huì)實(shí)際的中斷處理編程,也還需要清楚一些程序存儲(chǔ)器,程序結(jié)構(gòu),程序計(jì)數(shù)器,硬件堆棧,現(xiàn)場(chǎng)保護(hù)等這些個(gè)另雜碎概念。因此,我們?cè)趯W(xué)習(xí)中斷以前、以后和學(xué)習(xí)中斷過(guò)程中,都有必要介紹回顧復(fù)習(xí)一些有關(guān)上述關(guān)鍵詞的概念和知識(shí),否則,盡管你學(xué)了中斷,用起來(lái)可還是不能得心應(yīng)手,以至于茫然。

還是用比喻的方法介紹一下中斷的概念:

你的主程序任務(wù)是做一桌可口的飯菜,期間可能要多次調(diào)用子程序“撒鹽”。盡管子程序下邊還有更小的子任務(wù),比如“計(jì)算食鹽的量”等過(guò)程,盡管這些子過(guò)程很復(fù)雜,但他們的出場(chǎng)時(shí)間和順序是可以預(yù)料的,是可以預(yù)先安排的。也就說(shuō)你肯定知道在什么時(shí)候放鹽。

有一類子程序,他的出場(chǎng)時(shí)間是不確定的,突然的,處理他們的時(shí)間刻不容緩,必須趕緊的。我們稱這一類子程序?yàn)橹袛嘧映绦?。也就是我們所說(shuō)的“中斷”。

你正在做菜的過(guò)程中,隔壁鄰居小孩突然敲門說(shuō)他的二大爺在他房間里摔倒了,請(qǐng)你幫忙把二大爺扶起來(lái)。這是急迫的,必須處理的事務(wù)。

你肯定關(guān)掉爐子一溜煙跑出去幫忙,等回來(lái)以后再點(diǎn)著爐子繼續(xù)做菜。

這個(gè)事件的特點(diǎn)就是發(fā)生的時(shí)間你無(wú)法預(yù)先知道,而這個(gè)任務(wù)必須得停下當(dāng)前工作去處理,并且是刻不容緩。從開(kāi)始關(guān)爐子到回來(lái)點(diǎn)著爐子的這段時(shí)間里以及你的救人行為,就叫做“中斷子程序”。
   
在中斷子程序過(guò)程中,你關(guān)爐子的動(dòng)作,叫做“中斷現(xiàn)場(chǎng)保護(hù)”;點(diǎn)著爐子叫做“中斷現(xiàn)場(chǎng)恢復(fù)”;中間走出去扶起隔壁二大爺?shù)交貋?lái)叫做“中斷任務(wù)處理”;小孩子敲門就叫做“中斷請(qǐng)求”。這就是中斷的基本概念。

在單片機(jī)里,中斷的例子也是很多的。我舉一個(gè)你手里的手機(jī)的例子,你的GSM手機(jī)正工作在賦閑,屏幕上也就顯示個(gè)時(shí)間日期中國(guó)電信什么的,表面看沒(méi)有什么。其實(shí)它內(nèi)部的cpu高速運(yùn)行忙碌地工作在諸如聯(lián)絡(luò)無(wú)線網(wǎng)絡(luò),查詢是否有短消息發(fā)來(lái),計(jì)算當(dāng)前信號(hào)強(qiáng)度,時(shí)間等任務(wù)。你突然按下數(shù)字鍵“8”,此時(shí)內(nèi)部cpu必須停下它正在干的工作來(lái)應(yīng)付你,也就是清屏,顯示你按下的數(shù)字8,然后再回到它原來(lái)的任務(wù)接著運(yùn)行。(當(dāng)然,這個(gè)例子不一恰當(dāng),現(xiàn)在有操作系統(tǒng)Windows-ce windows-mobile的手機(jī)的工作機(jī)制遠(yuǎn)沒(méi)有如此的簡(jiǎn)單).

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多