51平臺下初始化文件的引入導致全局變量無法初始化的問題

寫在前面

-----------------

在前段時間的工作中,就遇見過全局變量無法初始化的問題,不過之前是在一些C文件中定義的變量能初始化,而其他C文件中不能初始化,當時將這個問題繞過去了,並沒有去深究...而這一週又出現了這個問題。於是就有了這篇文章

 

這裏不去討論其他情況下全局變量無法初始化的問題,只是針對我所遇見的問題討論....

原因:由於引入庫文件INIT.A51和STARTUP.A51導致的, 這裏之所以要引入這兩個文件,是由我們的應用環境決定的,如果在實際過程中沒有手動引入這兩個文件到工程項目中,則不會出現我這裏提到的類似問題。

 

簡述如下:

mcu復位後 PC=0 先執行STARTUP.A51的相關文件,該文件主要是對IDATA XDATA PDATA清零以及初始化堆棧指針;附上網絡上一篇文章對其的講解之部分關鍵代碼:

 

 

;  STARTUP.A51:  用戶上電初始化程序
;------------------------------------------------------------------------------
;
;  用戶定義需上電初始化的內存空間
;
;  使用以下EQU命令可定義在CPU復位時需用0進行初始化的內存空間
;
;;      
; IDATA 存儲器的空間的絕對起始地址總是0.; 
IDATALEN   EQU  80H   ; 需用0進行初始化的IDATA存儲器空間的字節數
;
XDATASTART   EQU   0H   ; XDATA存儲器空間的絕對起始地址
XDATALEN   EQU   400H   ; 需用0進行初始化的XDATA存儲器的空間字節數.
;
PDATASTART   EQU   0H   ; PDATA存儲器的空間的絕對起始地址
PDATALEN   EQU   0H   ; 需用0進行初始化的PDATA存儲器的空間字節數.
;
;  注意:   IDATA 存儲器的空間在物理上包括了8051單片機的DATA和BIT存儲器空間.
;           聽 說 至少要保證與C51編譯器運行庫有關的存儲器的空間進行0初始化 不知是否
;------------------------------------------------------------------------------
;
;  再入函數模擬初始化
;
;  以下用EQU指令定義了再入函數模擬堆棧指針的初始化
;
;  使用SMALL存儲器模式時再入函數的堆棧空間 .
IBPSTACK   EQU   0   ; 使用SMALL存儲器模式再入函數時將其設置成1.
IBPSTACKTOP   EQU   0FFH+1   ; 將堆棧頂設置爲最高地址+1.
;
;  使用LARGE存儲器模式時再入函數的堆棧空間.;  使用LARGE存儲器模式時再入函數的堆棧空間.  
XBPSTACK   EQU   0   ; 使用LARGE存儲器模式再入函數時將其設置成1.
XBPSTACKTOP   EQU   0FFFFH+1; 將堆棧頂設置爲最高地址+1.
;
; 使用COMPACT存儲器模式時再入函數的堆棧空間.; 使用COMPACT存儲器模式時再入函數的堆棧空間.  
PBPSTACK   EQU   0   ; 使用COMPACT存儲器模式再入函數時將其設置成1.
PBPSTACKTOP   EQU   0FFFFH+1; 將堆棧頂設置爲最高地址+1.
;
;------------------------------------------------------------------------------
;
;  使用COMPACT存儲器模式時64K字節XDATA存儲器空間的分頁定義
;
;  以下用EQU指令定義PDATA類型變量在XDATA存儲器空間的頁地址
;  使用EQU指令定義PFAGE時必須與L51連接定位器PDATA指令的控制參數一致
;
PPAGEENABLE   EQU   0   ; 使用PDATA類型變量時將其設置成1.
PPAGE      EQU   0   ; 定義頁號.
;
;------------------------------------------------------------------------------
.....
.....
.....
;     RSEG   ?STACK      ; 堆棧
;     DS   1
 
.....
.....
..... 
      CSEG   AT   0x0000  ;  定義用戶程序的起始地址
?C_STARTUP:   LJMP   STARTUP1
 
.....
.....
.....
;  設置堆棧的起始地址
      MOV   SP,#?STACK-1   ; 例如 MOV  SP,#4FH;
.....
.....
.....
; 跳轉到ININ.A51的初始化入口?C_START
      LJMP   ?C_START
      END
由代碼可知,在執行完清零操作後,程序將跳轉到?C_START標號處,該程序標號定義在INIT.A51文件中,文件INIT.A51完成全局變量的初始化,其中包含有如下代碼:
 
...
               RSEG    ?C_C51STARTUP
INITEND:        LJMP    MAIN
...
...
...
 
 
 
?C_START:       
                MOV     DPTR,#?C_INITSEG
Loop:
                WATCHDOG
                CLR     A
                MOV     R6,#1
                MOVC    A,@A+DPTR
                JZ      INITEND
                INC     DPTR
                MOV     R7,A
                ANL     A,#3FH
...
...
...
...
 
 
RSEG    ?C_INITSEG
                DB      0
...
...
 
其中#?C_INITSEG爲編譯生成的初始化段,該段保存了需要初始化的變量信息,可以看出上面的代碼是利用該段的信息對相應變量進行初始化,注意其中的'JZ      INITEND'(判斷初始化段的相關位置爲零則結束初始化);而INIT.A51文件的最後位置有'RSEG    ?C_INITSEG';和'DB      0',所以問題的答案就在這裏了!
 
 
問題出在INIT.A51在整個工程文件中的位置,假如在整個工程文件的最開始就編譯INIT.A51,那麼則'?C_INITSEG'第一個字節就是'0',所以接下來的初始化信息都不會被執行,解決辦法就是INIT.A51最後才加入整個工程中,確保在該文件中加入'?C_INITSEG'段中的'0'是加在整個'?C_INITSEG'段的最後一個位置....
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章