1 指針訪問方法
1.1 關鍵詞及解釋
data
:固定指前面0x00-0x7f的128個RAM,可以用acc直接讀寫的,速度最快,生成的代碼也最小。
idata
:固定指前面0x00-0xff的256個RAM,其中前128和data
的128完全相同,只是因爲訪問的方式不同。idata
是用類似C中的指針方式 訪問的。彙編中的語句爲:mox ACC,@Rx
。
xdata
:外部擴展RAM,一般指外部0x0000-0xffff空間,用DPTR訪問。
pdata
:外部擴展RAM的低256個字節,地址出現在A0-A7的上時讀寫,用movx ACC,@Rx
讀寫。這個比較特殊,對於C51來說好象有BUG, 建議少用。
code
:訪問程序存儲器(默認僅限於標準51能夠尋址的64kB空間內),生成的代碼主要通過 MOVC@A+DPTR
實現。
far
:far
是Keil 編譯器爲了支持新出現的8051家族增強型MCU,這些增強型MCU可能擁有大於64KB的存儲器。使用far
可訪問擴展的RAM,使用**const far
可訪問擴展的ROM**。NXP 51MX架構51單片機提供通過通用指針訪問多達8MB的code和xdata存儲空間。Dallas 390架構的51單片機通過24位的DPTR寄存器結合傳統MOVX
、MOVC
指令來訪問擴展的RAM和ROM。
注意:訪問ROM只能讀取不能修改。
1.2 代碼及調試
例:將存儲在RAM (20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
#include "reg52.h"
/************************************************************
Copyright (C), HAUT.
FileName: main.c
Author:JosephCooper Date:2020/6/23
Description:將存儲在RAM (20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
Version:1.0
Function List:
1.void main();
History:none
***********************************************************/
void main()
{
unsigned long idata *pRam;
pRam = 0x20;
*pRam = 0x11223344;//假定RAM中的數據爲0x11223344
*pRam = ((*pRam & 0xFFFFFF00)*2);
while(1);
}
//data內部128B地址空間
//idata全部256B地址空間
//xdata外擴64K地址空間
1.3 51單片機數據在內存中的存儲模式
-
1.大端模式:BigEndian 大端模式第一個字節是最高位字節(按照從低地址到高地址的順序存放數據的高位字節到低位字節),高字節在低地址, 低字節在高地址。
-
2.小端模式:LittleEndian 小端模式第一個字節是最低位字節(按照從低地址到高地址的順序存放數據的低位字節到高位字節),高字節在高地址, 低字節在低地址。
例: 從內存地址爲0x0000開始有以下數據:0x1234abcd
BigEndian
低地址 | 高地址 | ||
---|---|---|---|
0x0000 | 0x0001 | 0x0002 | 0x0003 |
0x12 | 0x34 | 0xab | 0xcd |
LittleEndian
低地址 | 高地址 | ||
---|---|---|---|
0x0000 | 0x0001 | 0x0002 | 0x0003 |
0xcd | 0xab | 0x34 | 0x12 |
- 8051系列MCU中,用C語言進行編程時,數據的存儲模式由編譯器(Compiler)決定,如Keil C51Compiler 4.0版本開始使用“大端存儲模式”,而較早前的編譯器版本中使用的是“小端存儲模式”。
2 絕對地址訪問方法
2.1 絕對宏
使用絕對宏時,需要添加投文件“absacc.h”
,在該文件中定義的絕對宏有CBYTE、XBYTE、PWORD、DBYTE、CWORD、XWORD、PBYTE、DWORD
。
CBYTE
:對程序存儲區(code)的字節地址進行訪問。例如:i=CBYTE[0X000F];表示i指向程序存儲區的地址爲0x000F的存儲單元,地址範圍爲0X0000~0XFFFF。
XBYTE
:對擴展RAM區的字節地址進行訪問。例如:i=XBYTE[0X000F];表示i指向擴展RAM區的地址爲0x000F的存儲單元,地址範圍爲0X0000~0XFFFF。
PBYTE
:對擴展RAM區的字節地址進行訪問。例如:i=PBYTE[0X000F];表示i指向擴展RAM區的地址爲0x000F的存儲單元,地址範圍僅爲一頁(256字節)。
DBYTE
:對內部RAM區的字節地址進行訪問。例如:i=PBYTE[0X000F];表示i指向內部RAM區的地址爲0x000F的存儲單元。
以WORD
表示的是爲字操做,其餘的跟以上相同。
代碼及調試:
例:將存儲在RAM (20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
#include "reg52.h"
#include <absacc.h>
/************************************************************
Copyright (C), HAUT.
FileName: main.c
Author:JosephCooper Date:2020/6/23
Description:將存儲在RAM(20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
Version:1.0
Function List:
1.void main();
History:none
***********************************************************/
void main()
{
unsigned long Res = 0;
unsigned char i = 0,j = 0,k = 0,l = 0;
unsigned long idata *pRam;
pRam = 0x20;
*pRam = 0x11223344;//假定RAM中的數據爲0x11223344
i = DBYTE[0x20];j = DBYTE[0x21];k = DBYTE[0x22];l = DBYTE[0x23];
Res = (((((unsigned long)(i<<8)|j) << 16)|((unsigned long)(k<<8)|l))&0xFFFFFF00) *2;
DBYTE[0x20] = Res >> 24;
DBYTE[0x21] = Res >> 16;
DBYTE[0x22] = Res >> 8;
DBYTE[0x23] = Res;
while(1);
}
//CBYTE用來訪問rom,用到movc指令。
//XBYTE用來訪問擴展ram的,使用movx指令,dptr當指針。
//DBYTE用來絕對訪問片內ram中的數據的。
//PBYTE也用來訪問擴展ram,但只能訪問開始的256字節,即movx指令,R0或R1當指針。
//這幾個宏用於51單片機的絕對地址訪問。上面4個是單字節訪問,對應雙字節訪問用下面4個。
//CWORD、XWORD、DWORD、PWORD
//這些定義在頭文件<absacc.h>中,所以使用時要加入下面語句:
//#include<absacc.h>
2.2 關鍵詞_at_
使用關鍵字“_at_
”不能對絕對變量進行初始化,位變量及函數不能用該關鍵字進行指定。使用方法爲直接在定義的數據後邊加上_at_
,在加上要指向的絕對地址即可。
例如:
unsigned char data i _at_ 0x0F;
表示i指向內部RAM區域地址爲0x0f的單元;
unsigned char xdata i _at_ 0x0F;
表示i指向擴展RAM區域地址爲0x0f的單元;
unsigned char xdata i[10] _at_ 0x0F;
表示數組的起始地址爲擴展RAM區的0x0f單元。
注意:變量必須是全局變量
代碼及調試:
例:將存儲在RAM (20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
#include "reg52.h"
/************************************************************
Copyright (C), HAUT.
FileName: main.c
Author:JosephCooper Date:2020/6/23
Description:將存儲在RAM(20H)(21H)(22H)中的數據乘以2後存入(20H)(21H)(22H)(23H)
Version:1.0
Function List:
1.void main();
History:none
***********************************************************/
unsigned char idata i[3] _at_ 0x20;//必須是全局變量
void main()
{
unsigned long idata *pRam;
unsigned long Res = 0;
pRam = 0x20;
*pRam = 0x11223344;//假定RAM中的數據爲0x11223344
Res = (((((unsigned long)(i[0]<<8)|i[1]) << 16)|((unsigned long)(i[2]<<8)|i[3]))&0xFFFFFF00) *2;
i[0] = Res >> 24;
i[1] = Res >> 16;
i[2] = Res >> 8;
i[3] = Res;
while(1);
}