色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 教你學(xué)單片機(jī) 2:用機(jī)器的視角思考

          教你學(xué)單片機(jī) 2:用機(jī)器的視角思考

          作者: 時(shí)間:2016-11-25 來源:網(wǎng)絡(luò) 收藏
          你準(zhǔn)備寫第一個(gè)單片機(jī)程序了,在此之前我假設(shè)你已經(jīng)會(huì)使用編譯器,也會(huì)下載程序了。
          P.S. 因?yàn)檫@些工作確實(shí)很簡(jiǎn)單,在網(wǎng)上找份教程看看就會(huì)了。
          一般剛開始學(xué)一種單片機(jī)的時(shí)候,寫的第一個(gè)程序都是“點(diǎn)亮第一個(gè)LED”。這個(gè)程序很經(jīng)典,它代表你已經(jīng)成功學(xué)會(huì)操控單片機(jī)的IO端口,學(xué)51單片機(jī)亦是如此。代碼如下(我使用ATMEL 公司的AT89S52):
          #include
          sbit LED = P1^0 ;
          void Delay(unsigned int t)
          {
          unsigned int i,j ;
          for(i=t;i>0;i--)
          for(j=100;j>0;j--);
          }
          void main(void)
          {
          LED = 1 ;
          while(1)
          {
          Delay(500);
          LED=~LED;
          }
          }
          單片機(jī)會(huì)從main函數(shù)開始執(zhí)行,所以我們把思緒拉到main函數(shù)。
          一開始用了“LED = 1 ;”,初始化IO端口,讓它設(shè)定在某個(gè)狀態(tài)。接下來使用一個(gè)while大循環(huán)語句,調(diào)用Delay函數(shù),時(shí)間一到就把LED取反,再回到循環(huán),周而復(fù)始。在高級(jí)語言里面看起來這個(gè)過程貌似很簡(jiǎn)單,小學(xué)生都會(huì)理解了。但是你知道把它翻譯成機(jī)器碼之后是什么樣的嗎?在這里我不想把產(chǎn)生的匯編代碼貼出來,免得你難以接受。不過我可以把執(zhí)行過程詳細(xì)地講給你聽。
          首先,所有的CPU,它們?cè)趫?zhí)行指令的時(shí)候都是從程序段的0地址(也就是程序最開始的地方)開始的,而且CPU永遠(yuǎn)只做兩件事情,一是從程序區(qū)里取出指令,二是執(zhí)行這條指令,然后再回去取指令。。
          這樣說很簡(jiǎn)單嘛,把main函數(shù)的代碼從程序區(qū)的0地址開始一條條存放不就行了嗎。其實(shí)不是這樣的,一般0地址里存放的都不會(huì)是main函數(shù)的真實(shí)代碼,它會(huì)放一條跳轉(zhuǎn)指令(就是一條指令后面跟一個(gè)地址,告訴CPU要跳到那個(gè)地方去工作),這條指令跟著的是main函數(shù)的入口地址,把單片機(jī)指到main函數(shù)真正的地址去執(zhí)行。為什么要這樣做?看下面的圖:


          程序存儲(chǔ)區(qū)的固定前面幾個(gè)地址是要用來存放中斷服務(wù)程序的地址的(中斷?后面會(huì)講,先不管),稱之為“中斷向量”。程序在執(zhí)行過程中遇到中斷的時(shí)候,它就會(huì)根據(jù)中斷信號(hào)的類型跳回到這些固定的地址,再由這些地址里面存儲(chǔ)的指令指引,跳轉(zhuǎn)到中斷服務(wù)程序真正開始的地方去執(zhí)行。所以,最開始的一系列地址是不能存放另的東西的,不然程序會(huì)亂掉。如果你把main函數(shù)定義在這里,沒遇到中斷之前當(dāng)然可以正常運(yùn)行,但如果你在程序中使用了中斷,后果就不堪設(shè)想了??偠灾琺ain不是放在最開始的地方的!
          那它放在哪里?理論上只要避開了中斷向量地址的沖突,你可以放在任何地方,你用C語言編寫的時(shí)候編譯器會(huì)自動(dòng)處理這個(gè)問題,不用你操心,如果以后你要用匯編寫了,你就必須自己定義main函數(shù)的地址了。
          好了,那我們就進(jìn)入main函數(shù)里面看看吧。
          根據(jù)這段代碼,你覺得第一句應(yīng)該執(zhí)行的語句應(yīng)該是“LED = 1 ;”,然后是while循環(huán)。。BLA..BLA..
          錯(cuò)了,進(jìn)入main函數(shù)之后首先要做的事情是初始化相關(guān)寄存器。因?yàn)樾酒瑒傞_始工作的時(shí)候,寄存器都處于一種未知的狀態(tài),你必須首先賦給它一個(gè)初值才行,在這個(gè)main函數(shù)中沒有使用變量,所以可以不用初始化內(nèi)存區(qū),但至少CPU必須初始化一個(gè)很重要的寄存器:SP堆棧指針。關(guān)于這家伙以后再講,總之就是先初始化。
          初始化完畢之后才開始執(zhí)行你的真正的代碼,先讓LED設(shè)置為1,然后進(jìn)入一個(gè)循環(huán)結(jié)構(gòu),調(diào)用延時(shí)函數(shù)Delay,等待它執(zhí)行完畢之后再回來把LED取反,然后返回繼續(xù)周而復(fù)始地執(zhí)行。
          等等,有一個(gè)很重要的問題:?jiǎn)纹瑱C(jī)是怎么延時(shí)的?在延時(shí)的時(shí)間里它都在干什么?
          我們知道,單片機(jī)的一個(gè)主要性能就是執(zhí)行速度,也就是一秒鐘能執(zhí)行多少條指令,一般速度越快代表性能越好,比如51單片機(jī)如果你在外面給它接上一個(gè)12M Hz的晶振,它的CPU就會(huì)以一百萬條/秒的速度工作,即是說它執(zhí)行一條指令要花費(fèi)一百萬分之一秒的時(shí)候即一微秒(是不是覺得很快?其實(shí)以現(xiàn)在的標(biāo)準(zhǔn)來說已經(jīng)算很慢了,慢得像烏龜)。按照這個(gè)道理,如果我們想要讓單片機(jī)延時(shí),比如延時(shí)1ms,我們可以讓CPU空轉(zhuǎn)1000次,因?yàn)镃PU空轉(zhuǎn)一次也需要一條指令的時(shí)間。讓它轉(zhuǎn)上1000次之后結(jié)束,那么就相當(dāng)于它延遲了1ms,延時(shí)函數(shù)就是這樣寫出來的,工作原理如果下圖:

          這就是Delay函數(shù)的作用,但是這樣的延時(shí)不能做到很精確,因?yàn)樵谶@段時(shí)間里CPU要執(zhí)行判斷、賦值等等一系列指令,在C語言寫的代碼里面你不能準(zhǔn)確預(yù)測(cè)到編譯器會(huì)把你這段代碼轉(zhuǎn)換為怎么樣的匯編指令,所以你也就無法計(jì)算出精確的變量值,只能在一個(gè)大概的范圍里面選取。雖然C語言寫起程序來很方便,但同時(shí)它的缺點(diǎn)也顯現(xiàn)在這里:無法控制編譯器寫出精確的延遲函數(shù),在有些對(duì)時(shí)間要求很高的場(chǎng)合里C語言無法勝任,只能用匯編來寫;同時(shí)用C語言寫出的程序產(chǎn)生的機(jī)器碼一般都比用匯編寫的要多,即不夠精簡(jiǎn),效率不高,在有些單片機(jī)里面程序存儲(chǔ)容量不高的話就比較麻煩,不過現(xiàn)在的單片機(jī)程序存儲(chǔ)容量普遍都比較高了。這樣說來用C語言來寫一些對(duì)時(shí)間性要求不高的程序是很有優(yōu)勢(shì)的,開發(fā)周期比匯編要高得多。


          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉