新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 教你學單片機 2:用機器的視角思考

        教你學單片機 2:用機器的視角思考

        作者: 時間:2016-11-25 來源:網絡 收藏
        你準備寫第一個單片機程序了,在此之前我假設你已經會使用編譯器,也會下載程序了。
        P.S. 因為這些工作確實很簡單,在網上找份教程看看就會了。
        一般剛開始學一種單片機的時候,寫的第一個程序都是“點亮第一個LED”。這個程序很經典,它代表你已經成功學會操控單片機的IO端口,學51單片機亦是如此。代碼如下(我使用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;
        }
        }
        單片機會從main函數開始執行,所以我們把思緒拉到main函數。
        一開始用了“LED = 1 ;”,初始化IO端口,讓它設定在某個狀態。接下來使用一個while大循環語句,調用Delay函數,時間一到就把LED取反,再回到循環,周而復始。在高級語言里面看起來這個過程貌似很簡單,小學生都會理解了。但是你知道把它翻譯成機器碼之后是什么樣的嗎?在這里我不想把產生的匯編代碼貼出來,免得你難以接受。不過我可以把執行過程詳細地講給你聽。
        首先,所有的CPU,它們在執行指令的時候都是從程序段的0地址(也就是程序最開始的地方)開始的,而且CPU永遠只做兩件事情,一是從程序區里取出指令,二是執行這條指令,然后再回去取指令。。
        這樣說很簡單嘛,把main函數的代碼從程序區的0地址開始一條條存放不就行了嗎。其實不是這樣的,一般0地址里存放的都不會是main函數的真實代碼,它會放一條跳轉指令(就是一條指令后面跟一個地址,告訴CPU要跳到那個地方去工作),這條指令跟著的是main函數的入口地址,把單片機指到main函數真正的地址去執行。為什么要這樣做?看下面的圖:


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

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


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 泰安市| 隆回县| 松滋市| 屯昌县| 普兰店市| 酉阳| 吉安县| 道孚县| 吐鲁番市| 南宫市| 海阳市| 泽普县| 巴马| 裕民县| 若尔盖县| 磐石市| 涞水县| 双柏县| 昆明市| 河北区| 得荣县| 兴义市| 竹溪县| 瓦房店市| 延长县| 巢湖市| 乌鲁木齐市| 芒康县| 东山县| 广安市| 东丰县| 衡山县| 富裕县| 成武县| 阜平县| 彰武县| 扶沟县| 舟曲县| 尉犁县| 和静县| 徐水县|