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