天天看點

8051 MCU學習之分析單片機的啟動過程

接觸單片機有幾年的時間了,一直專注于如何在單片機上寫一些應用,對單片機如何啟動的知之甚少,慚愧慚愧。。。今天得空整理了一下,加深了對單片機的認識,如為什麼定義data區裡的變量重新開機的初始值為0。

單片機在開機上電後,會執行startup.A51檔案的指令,我分析了一下某個項目中這個檔案裡的指令,在這裡單片機會做如下幾件事情:

  1. 初始化8051硬體堆棧的大小和堆棧指針;
  2. 初始化中斷向量表,配置設定每個中斷的入口位址和中斷服務函數;
  3. 初始化内部RAM空間,即DATA/IDATA,将内容清零;
  4. 初始化外部RAM空間,即XDATA/PDATA,将内容清零;
  5. 初始化SMALL/COMPACT/LARGE模式下reentrant函數使用的堆棧指針;
  6. 調用main()函數,去執行我們編寫的代碼。

當用keil作為開發環境,建立一個工程時,需要選擇所使用的單片機型号,然後Keil會将相應單片機的startup.A51檔案拷貝到工程目錄下,在編譯時,該檔案會被編譯到最終的目标檔案中。一般情況下,這個檔案是不需要我們做修改的,保持預設狀态即可,是以可能很多人對此檔案不太熟悉。下面是具體的code以及我的個人分析:

$NOMOD51   ;取消對SFR的預定義,由使用者自行定義。

; 以下定義個SFR
sfr CLKSEL  = 
sfr P3 = 
sfr MMU_SEL = 

; 以下初始化IDATA, XDATA和PDATA存儲區
IDATASTART  EQU H     ; the absolute start-address of IDATA memory
IDATALEN    EQU H        ; the length of IDATA memory in bytes.
;
XDATASTART  EQU H  ; the absolute start-address of XDATA memory
XDATALEN    EQU F00H   ; the length of XDATA memory in bytes.
;
PDATASTART  EQU H  ; the absolute start-address of PDATA memory
PDATALEN    EQU H    ; the length of PDATA memory in bytes.

; 定義存儲PLL值的位址。
PLLADDR     EQU 
;

;  當函數是可重入的(用reentrant關鍵字修飾),以下初始化可重入函數所使用的堆棧, 考慮到了三種編譯模式SMALL/COMPACT/LARGE。
;  Stack Space for reentrant functions in the SMALL model.
IBPSTACK    EQU    ; set to  if small reentrant is used.
IBPSTACKTOP EQU FFH+  ; set top of stack to highest location+
;
;  Stack Space for reentrant functions in the LARGE model.  
XBPSTACK    EQU    ; set to  if large reentrant is used.
XBPSTACKTOP EQU FFFFH+; set top of stack to highest location+
;
;  Stack Space for reentrant functions in the COMPACT model.    
PBPSTACK    EQU    ; set to  if compact reentrant is used.
PBPSTACKTOP EQU FFFFH+; set top of stack to highest location+
;
;------------------------------------------------------------------------------
;   初始化PDATA區
;  Page Definition for Using the Compact Model with  KByte xdata RAM
;
;  The following EQU statements define the xdata page used for pdata
;  variables. The EQU PPAGE must conform with the PPAGE control used
;  in the linker invocation.
;
PPAGEENABLE EQU    ; set to  if pdata object are used.
PPAGE       EQU    ; define PPAGE number.
PPAGE_SFR       DATA    A0H
START_GPNVM_CODE EQU    H ; Start of Code
;
;------------------------------------------------------------------------------

; Standard SFR Symbols 
ACC     DATA    H
B       DATA    F0H
SP      DATA    H
DPL     DATA    H
DPH     DATA    H
P2      DATA    A0H

    NAME    ?C_STARTUP  ;定義這段彙編代碼在obj檔案中的名字
; 聲明三個在外部定義的中斷函數, 以便在本子產品中調用
EXTRN CODE (TrqIsr)
EXTRN CODE (uartISR)
EXTRN CODE (FlashInterrupt)

; 聲明段C_C51STARTUP和STACK存儲位置
?C_C51STARTUP   SEGMENT   CODE
?STACK      SEGMENT   IDATA

; 選擇STACK段,并設定STACK的size
        RSEG    ?STACK
        DS  

; 選擇位址(CODE區),并跳轉到(CODE區)的位置      
        CSEG    AT  
        LJMP    

        EXTRN CODE (?C_START)   ;聲明外部段名 C_START,以便在本子產品中調用
        PUBLIC  ?C_STARTUP      ;聲明在本檔案中定義的段C_STARTUP為public的,以供其他子產品調用

; 選擇位址(CODE區),并跳轉到 STARTUP1(CODE區)的位置
        CSEG    AT        
?C_STARTUP: LJMP    STARTUP1

; 以下是中斷向量表,配置設定每個中斷的位址和對應的中斷服務函數。
        CSEG AT START_GPNVM_CODE+BH        ; IT timer 
;       gpnvmVectorEtuCnt:
        LJMP TrqIsr
        RETI                    
;       LJMP    InterruptRoutineVectorEtuCnt

        CSEG AT START_GPNVM_CODE+H        ; MMU COB or DOB or OVD
;       gpnvmVectorFault:
        LJMP uartISR            
        RETI

        CSEG AT START_GPNVM_CODE+H        ; MMU COB or DOB or OVD
;       gpnvmVectorFault:
        LJMP FlashInterrupt         
        RETI

; 選擇C_C51STARTUP段所在位址       
        RSEG    ?C_C51STARTUP
STARTUP1:
        MOV MMU_SEL,#01H    ; 初始化SFR: MMU_SEL
        MOV P3,#05H         ; 初始化SFR: P3

;初始化單片機的時鐘頻率
        MOV DPTR,#PLLADDR
        MOVX A,@DPTR
        ANL A, #0C0H
        MOV CLKSEL, A

; 初始化 IRAM ( - )
IF IDATALEN <> 
        MOV R0,#IDATALEN - 1
;        MOV R1,#IDATASTART
        CLR A
IDATALOOP:  MOV @R0,A
;        INC R1
        DJNZ    R0,IDATALOOP
ENDIF
; 初始化 XRAM
IF XDATALEN <> 
        MOV DPTR,#XDATASTART
        MOV R7,#LOW (XDATALEN)
  IF (LOW (XDATALEN)) <> 
        MOV R6,#(HIGH (XDATALEN)) +1
  ELSE
        MOV R6,#HIGH (XDATALEN)
  ENDIF
        CLR A
XDATALOOP:  MOVX    @DPTR,A
        INC DPTR
        DJNZ    R7,XDATALOOP
        DJNZ    R6,XDATALOOP
ENDIF

; 初始化PDATA
IF PPAGEENABLE <> 
        MOV P2,#PPAGE
ENDIF

IF PDATALEN <> 
        MOV R0,#PDATASTART
        MOV R7,#LOW (PDATALEN)
        CLR A
PDATALOOP:  MOVX    @R0,A
        INC R0
        DJNZ    R7,PDATALOOP
ENDIF

; 初始化reentrant函數使用的堆棧指針(SMALL/COMPACT/LARGE)
IF IBPSTACK <> 
EXTRN DATA (?C_IBP)

        MOV ?C_IBP,#LOW IBPSTACKTOP
ENDIF

IF XBPSTACK <> 
EXTRN DATA (?C_XBP)

        MOV ?C_XBP,#HIGH XBPSTACKTOP
        MOV ?C_XBP+,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 
EXTRN DATA (?C_PBP)
        MOV ?C_PBP,#LOW PBPSTACKTOP
ENDIF

        MOV SP,#?STACK-1        ;初始化堆棧指針,指向棧底

; 聲明外部定義的函數B_SWITCH0,并調用之
EXTRN CODE (?B_SWITCH0)
        CALL    ?B_SWITCH0      ; init bank mechanism to code bank 

        LJMP    ?C_START    ;調用main()函數

END
           

這個是編譯輸出檔案.lst中的部分代碼在code區的配置設定情況,結合彙編代碼,我們可以知道在code區某個位置存放的是什麼指令。

H   H   H   ---    OFFS..   CODE           ?CO?STTF06?       ;此處存放的代碼為 LJMP  x0200
H   AH   H   ---    ---      **GAP**
BH   EH   H   ---    OFFS..   CODE           ?CO?STTF06?       ;此處存放的代碼為 LJMP TrqIsr
FH   H   H   ---    ---      **GAP**
H   H   H   ---    OFFS..   CODE           ?CO?STTF06?       ;此處存放的代碼為 LJMP uartISR
H   H   CH   ---    ---      **GAP**
H   H   H   ---    OFFS..   CODE           ?CO?STTF06?       ;此處存放的代碼為 LJMP FlashInterrupt
H   FFH   D9H   ---    ---      **GAP**
H   H   H   ---    OFFS..   CODE           ?CO?STTF06?       ;此處存放的代碼為 LJMP  STARTUP1
H   H   H   BYTE   UNIT     CODE           ?C?LIB_CODE
EAH   A0H   B7H   BYTE   UNIT     CODE           ?C_C51STARTUP      ;此處存放的代碼為 段?C_C51STARTUP的内容,對單片機的硬體做初始化
           

下面是描述startup.A51的流程圖,作為這次學習的總結。

8051 MCU學習之分析單片機的啟動過程

繼續閱讀