單片機_指針讀取內容解析

STC單片機自帶內部參考電壓,單片機生產時內部已經做校準,可分別在ram和rom中讀取,

(1)rom中讀取

在rom中讀取的時候,需要在下載時候勾選下載軟件中的 在程序區的結束處添加重要測試參數,如下圖所示:

勾選下載後,BandGap電壓以mV爲單位可以讀取。

BGV = (int code *)0xeff7;  ROM容量大小不同,地址不同如// STC8A8K60S4A10 是0xeff7

code 是指程序存儲(rom)地址

 

(2)ram中讀取

而在ram中不需要勾選(在程序區的結束處添加重要測試參數),放在在idata區域,讀取時候用如下程序①(官方例程):

#include "reg51.h"
int	*BGV;
unsigned char  hi;
unsigned char  Low;
void main()
{
	BGV = (int idata *)0xef;
	
	Low =(*BGV);
	hi = (*BGV) >> 8;
	
}

 

疑問1:指針類型爲何設置爲int?是否可以設置爲unsigned int?

????

疑問2:0xef是一個地址,爲何可以讀取高地址和低地址的數據?

在debug session 中觀察彙編代碼

     6: void main() 
     7: { 
     8:         BGV = (int idata *)0xef; 
     9:          
C:0x002E    7B00     MOV      R3,#0x00
C:0x0030    7A00     MOV      R2,#0x00
C:0x0032    79EF     MOV      R1,#0xEF
C:0x0034    8B0A     MOV      BGV(0x0A),R3
C:0x0036    8A0B     MOV      0x0B,R2
C:0x0038    890C     MOV      0x0C,R1
    10:         Low =(*BGV); 
C:0x003A    120003   LCALL    C?ILDPTR(C:0003)
C:0x003D    AEF0     MOV      R6,B(0xF0)
C:0x003F    F508     MOV      Low(0x08),A
    11:         hi = (*BGV) >> 8; 
    12:          
    13:          
C:0x0041    EE       MOV      A,R6
C:0x0042    FF       MOV      R7,A
C:0x0043    8F09     MOV      hi(0x09),R7

如上調用了函數ILDPTR,ILDPTR彙編的代碼如下

                 C?ILDPTR:
C:0x0003    BB010A   CJNE     R3,#0x01,C:0010
C:0x0006    8982     MOV      DPL(0x82),R1
C:0x0008    8A83     MOV      DPH(0x83),R2
C:0x000A    E0       MOVX     A,@DPTR
C:0x000B    F5F0     MOV      B(0xF0),A
C:0x000D    A3       INC      DPTR
C:0x000E    E0       MOVX     A,@DPTR
C:0x000F    22       RET      
C:0x0010    5006     JNC      C:0018
C:0x0012    87F0     MOV      B(0xF0),@R1
C:0x0014    09       INC      R1
C:0x0015    E7       MOV      A,@R1
C:0x0016    19       DEC      R1
C:0x0017    22       RET      
C:0x0018    BBFE07   CJNE     R3,#0xFE,C:0022
C:0x001B    E3       MOVX     A,@R1
C:0x001C    F5F0     MOV      B(0xF0),A
C:0x001E    09       INC      R1
C:0x001F    E3       MOVX     A,@R1
C:0x0020    19       DEC      R1
C:0x0021    22       RET      
C:0x0022    8982     MOV      DPL(0x82),R1
C:0x0024    8A83     MOV      DPH(0x83),R2
C:0x0026    E4       CLR      A
C:0x0027    93       MOVC     A,@A+DPTR
C:0x0028    F5F0     MOV      B(0xF0),A
C:0x002A    7401     MOV      A,#0x01
C:0x002C    93       MOVC     A,@A+DPTR
C:0x002D    22       RET      

此程序功能是:
(1)R3的值等於0x01時,執行如下程序:

C:0x0006    8982     MOV      DPL(0x82),R1
C:0x0008    8A83     MOV      DPH(0x83),R2
C:0x000A    E0       MOVX     A,@DPTR
C:0x000B    F5F0     MOV      B(0xF0),A
C:0x000D    A3       INC      DPTR
C:0x000E    E0       MOVX     A,@DPTR
C:0x000F    22       RET      

程序功能:讀取擴展RAM內的數據並賦值給A,尋址範圍0~65535。當數組用xdata定義時如

BGV = (int idata *)0xef;

會跳轉到此處。
(2)R3的值小於0x01即等於0x00時,執行如下程序:

C:0x0010    5006     JNC      C:0018
C:0x0012    87F0     MOV      B(0xF0),@R1
C:0x0014    09       INC      R1
C:0x0015    E7       MOV      A,@R1
C:0x0016    19       DEC      R1
C:0x0017    22       RET    

CJNZ操作會影響CY,所以JNC (進位位爲0則跳轉)

 CJNE     R3,#0x01,C:0010

上述操作 CJNE     R3,#0x01,C:0010 會影響PSW中的借位位,當R3小於#0x01時,CY置1,否則置0.


程序功能:讀取單片機內部256字節RAM內的數據並賦值給A,尋址範圍0~255。當數組用data或idata定義時,會跳轉到此處。如執行BGV = (int idata *)0xef;語句時,即跳轉到自處,讀取內部RAM地址內的數據。   
(3)R3的值不等於0x00或0x01時,通過JNC指令跳轉到C:0x0018處,開始與0xFE做比較。R3的值等於0xFE時,執行如下程序:

C:0x0018    BBFE07   CJNE     R3,#0xFE,C:0022
C:0x001B    E3       MOVX     A,@R1
C:0x001C    F5F0     MOV      B(0xF0),A
C:0x001E    09       INC      R1
C:0x001F    E3       MOVX     A,@R1
C:0x0020    19       DEC      R1
C:0x0021    22       RET 

程序功能:讀取單片機片外RAM內的數據並低位賦值給B,高位賦值給A,尋址範圍0~255。當數組用pdata定義時,會跳轉到此處。通常8051單片機不使用pdata定義變量或數組。
(4)R3的值不等於0xFE時,即R3的值等於0xFF時,跳轉到C:0x0022處執行如下程序:

C:0x0022    8982     MOV      DPL(0x82),R1
C:0x0024    8A83     MOV      DPH(0x83),R2
C:0x0026    E4       CLR      A
C:0x0027    93       MOVC     A,@A+DPTR
C:0x0028    F5F0     MOV      B(0xF0),A
C:0x002A    7401     MOV      A,#0x01
C:0x002C    93       MOVC     A,@A+DPTR
C:0x002D    22       RET      

程序功能:讀取單片機內部ROM內的數據並低位賦值給B,高位賦值給A,尋址範圍0~65535。當數組用code定義時,如 BGV = (int code *)0xef;
由此可見,子函數“C?ILDPTR”的作用是,根據數據所在存儲空間,用不同的尋址方式讀取某地址下的數據。R3用於確定尋址方式,R3的值與對應的尋址方式對應關係爲:
1、R3值等於0x00時,片內RAM間接尋址;此時數據用data,idata定義。
2、R3值等於0x01時,片外RAM(擴展RAM)間接尋址;此時數據用xdata定義。
3、R3值等於0xFE時,片外RAM(擴展RAM)低246字節間接尋址;此時數據用pdata定義
4、R3值等於0xFF時,從存儲存儲器(ROM)進行變址尋址;此時數據用code定義

在Keil C-51編譯環境下,指針變量,不管長度是單字節或是雙字節,指針變量所佔字節數爲3字節,R3表示所在存儲空間R1和R2表示地址

綜上所述,Keil C-51編譯環境下,指針是一個佔3字節的特殊變量,編譯器編譯程序時,自動生成判斷尋址方式的子函數,並根據根據目標數據所在的物理存儲區不同,爲指針首字節賦值,根據賦值的不同,進行不同方式的尋址;指針的後2字節,用於存放引用的地址。

回到程序①,使用的是BGV = (int idata *)0xef;  使用的是idata 所以會執行

C:0x0010    5006     JNC      C:0018
C:0x0012    87F0     MOV      B(0xF0),@R1
C:0x0014    09       INC      R1
C:0x0015    E7       MOV      A,@R1
C:0x0016    19       DEC      R1
C:0x0017    22       RET    

程序功能:R1存地址0xEF,MOV      B(0xF0),@R1操作後,給R1地址加一變爲0xF0,所以疑問二可以讀取高低倆個地址。

附錄

(1)C?CLDPTR 是操作char指針會調用,與ILDPTR(int 指針)彙編原理類似,不做討論

如定義 char *BGV1;讀取內容可得如下代碼

                 C?CLDPTR:
C:0x00AF    BB0106   CJNE     R3,#0x01,C:00B8
C:0x00B2    8982     MOV      DPL(0x82),R1
C:0x00B4    8A83     MOV      DPH(0x83),R2
C:0x00B6    E0       MOVX     A,@DPTR
C:0x00B7    22       RET      
C:0x00B8    5002     JNC      C:00BC
C:0x00BA    E7       MOV      A,@R1
C:0x00BB    22       RET      
C:0x00BC    BBFE02   CJNE     R3,#0xFE,C:00C1
C:0x00BF    E3       MOVX     A,@R1
C:0x00C0    22       RET      
C:0x00C1    8982     MOV      DPL(0x82),R1
C:0x00C3    8A83     MOV      DPH(0x83),R2
C:0x00C5    E4       CLR      A
C:0x00C6    93       MOVC     A,@A+DPTR
C:0x00C7    22       RET      

(2)在keil的memory中D:0x0F 表示在ram中的數據,C:0x0F表示在code中的數據

(如單片機內部ram中高128字節,直接尋址是SFRS(特殊功能寄存器),間接尋址是內部數據區,二者物理上是分開的)

  C:代碼存儲空間

  D:直接尋址片內存儲空間

  I :間接尋址片內存儲空間

  X:擴展的外部RAM空間

(3)for(;;a++,b++) for語句可以加N個++

(4)unsigned char code tab2[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

tab2中的數據時不能修改的,因爲是處於code區域,程序運行過程是不容許改變的。

 

參考文章

http://www.51hei.com/bbs/dpj-39912-1.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章