【51拓展】KeilC51訪問RAM、ROM指定地址內存的兩種方法(指針訪問+絕對地址訪問)

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寄存器結合傳統MOVXMOVC指令來訪問擴展的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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章