直接存储器访问把存储器地址编码在要读写存储器的指令中。使用直接存储器存取我们可以访问存储器类型中DATA和BIT中的变量。对于251来说,还有EDATA存储器类型可以使用直接寻址访问。
间接存储器访问使用要读写存储器的指令中的一个寄存器中的内容。使用间接寻址操作数,可以访问x51中所有类型的存储空间。
下面的例子示出了怎样访问一个x51系统的不同存储器类型。
DATA
DATA中的存储器地址可以使用两种寻址方式:直接和间接存储器访问。x51的特殊功能寄存器(SFR)具有在DATA空间中0x80之上的地址。SFR只可采用直接存储器寻址。在x51微处理器中不支持对SRF的间接寻址。
适用于所有8051版本的例子
| ?DT?myvar | SEGMENT | DATA | ; 定义一个DATA类型的段 |
| RSEG | ?DT?myvar | ||
| VALUE: | DS | 1 | ; 在DATA空间保留一个字节(BYTE) |
| IO_PORT2 | DATA | 0A0H | ; 特殊功能寄存器 |
| VALUE2 | DATA | 20H | ; 绝对存储器地址 |
| 罗亩的笔记 | |||
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | A, IO_PORT2 | ; 对DATA直接寻址 | |
| ADD | A, VALUE | ||
| MOV | VALUE2, A | ||
| MOV | R1, #VALUE | ; 将VALUE的地址装入R1 | |
| ADD | A, @R1 | ; 对VALUE间接寻址 |
罗亩按:这些例程的格式,很值得我们学习,其程序的可读性、条理性非常好。“?DT?”代表DATA类型的段,“?PR?”代表程序代码段。
BIT
BIT类型的存储器地址使用8051的位寻址指令寻址。位于可位寻址存储器地址的特殊功能寄存器(SFR)也可以使用位指令寻址。位可寻址的SFR地址是:80H,88H,90H,98H,0A0H,0A8H,0B0H,0B8H,0C0H,0C8H,0D0H,0D8H,0E0H,0E8H,0F0H和0F8H。
适用于所有8051版本的例子
| ?BI?mybits | SEGMENT | BIT | ; 定义一个BIT类型的段 |
| RSEG | ?BI?mybits | ||
| FLAG: | DBIT | 1 | ; 在BIT空间保留一位 |
| P1 | DATA | 90H | ; 8051 SFR端口1 |
| GREEN_LED | BIT | P1.2 | ; 在I/O端口1.2上的绿色LED |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| SETB | GREEN_LED | ; P1.2 = 1 | |
| JB | FLAG, is_on | ; 对DATA直接寻址 | |
| SETB | FLAG | ||
| CLR | ACC.5 | ; 复位寄存器A中的位5 | |
| …… | |||
| is_on: | CLR | FLAG | |
| CLR | GREEN_LED | ; P1.2 = 0 |
EBIT(仅适用于英特尔/爱特梅尔WM251)
251提供了EBIT存储类型,作为扩展的位可寻址空间,寻址时使用扩展的位指令。251中所有的特殊功能寄存器(SFR)都可以使用扩展的位指令寻址。
英特尔/爱特梅尔WM251的例子
| ?EB?mybits | SEGMENT | EBIT | ; 定义一个EBIT类型的段 |
| RSEG | ?EB?mybits | ||
| FLAG: | DBIT | 1 | ; 在BIT空间保留一位 |
| CMOD | DATA | 0D9H | ; PCA计数器模式 |
| CPS0 | BIT | CMOD.1 | ; CPS0位 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| JB | FLAG, is_on | ; 直接对DATA寻址 | |
| SETB | FLAG | ||
| …… | |||
| is_on: | CLR | FLAG | |
| CLR | CPS0 | ; CMOD.1 = 0 |
在该空间中的变量通过寄存器R0和R1存取。
适用于所有8051版本的例子
| ?ID?myvars | SEGMENT | IDATA | ; 定义一个IDATA类型的段 |
| RSEG | ?EB?mybits | ; 罗亩按:此处疑为 “RSEG ?ID?myvars” | |
| BUFFER: | DS | 100 | ; 保留100字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | R0, #BUFFER | ; 把地址装载到R0中 | |
| MOV | A, @R0 | ; 读存储器地址缓冲器所指地址的内容 | |
| INC | R0 | ; R0中的存储器地址加1 | |
| MOV | @R0, A | ; 写存储器地址BUFFER+1 |
在菲利浦80C51MX中,EDATA存储器可以通过EPTR或通用指针PR0和PR1访问。通用指针可以访问16MB地址空间中的任意地址。
适用于菲利浦80C51MX的例子
| ?ED?my_seg | SEGMENT | EDATA | ; 定义一个EDATA类型的段 |
| RSEG | ?ED?my_seg | ||
| STRING: | DS | 100 | ; 保留100个字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | R1, #BYTE0 STRING | ; 把STRING的地址装入PR0 | |
| MOV | R2, #BYTE1 STRING | ||
| MOV | R3, #BYTE2 STRING | ||
| MOV | A, @PR0 | ; 把STRING中的第一个字节装入A |
适用于英特尔/爱特梅尔的WM251的例子
| ?ED?my_seg | SEGMENT | EDATA | ; 定义一个EDATA类型的段 |
| RSEG | ?ED?my_seg | ||
| STRING: | DS | 100 | 保留100个字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | R11, STRING+2 | ; 装载位于STRING[2]中的字符 | |
| MOV | WR4, #STRING | ; 装载STRING的地址 | |
| MOV | R6, @WR4 | ; 间接寻址 | |
| MOV | @WR4+2, R6 | ; 使用常量偏移访问 |
XDATA存储器类型可以通过寄存器DPTR使用指令MOVX访问。单页XDATA存储空间也可以通过R0,R1访问。在C编译器级,该内存类型叫做pdata,段前缀使用?PD?。该pdata页的高地址典型地用P2寄存器设置。但在新型8051微处理器中,也有专用的特殊功能寄存器用于定义XDATA页地址。
适用于所有8051微处理器的例子
| ?XD?my_seg | SEGMENT | XDATA | ; 定义一个XDATA类型的段 |
| RSEG | ?ED?my_seg | ||
| XBUFFER: | DS | 100 | ; 保留100个字节 |
| ?PD?myvars | SEGMENT | XDATA INPAGE | ; 定义一个页的XDATA段 |
| RSEG | ?PD?myvars | ||
| VAR1: | DS | 1 | ; 保留一个字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | P2, #HIGH ?PD?myvars | ; 装载页地址寄存器 | |
| …… | |||
| MOV | DPTR, #XBUFFER | ; 装载地址 | |
| MOVX | A, @DPTR | ; 通过DPTR访问 | |
| MOV | R1, #VAR1 | ; 装载地址 | |
| MOVX | @R1, A | ; 通过R0或R1访问 |
CODE和CONST存储器可以使用DPTR寄存器通过指令MOVC访问。存储类型CONST不适用于A51和BL51。
适用于所有8051微处理器的例子
| ?CO?my_seg | SEGMENT | CODE | ; 定义一个CODE类型的段 |
| RSEG | ?CO?my_seg | ||
| TABLE: | DB | 1, 2, 4, 8, 0x10 | ; 一个常量表 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | DPTR, #TABLE | ; 装载表的地址 | |
| MOV | A, #3 | ; 把偏移量装入表中 | |
| MOVC | A, @A+DPTR | ; 通过MOVC指令访问 |
HDATA和HCONST存储器仅可以通过菲利浦80C51MX和251架构的CPU指令访问。在传统8051器件上,可以使用存储器堆模拟HDATA和HCONST存储器。HDATA和HCONST存储器类型不适用于A51和BL51。
在菲利浦80C51MX中,HDATA和HCONST存储器可以通过EPTR或通用指针(全局指针)PR0和PR1访问。通用指针可以访问16MB存储器空间中的任意地址。
适用于80C51MX的例子
| ?HD?my_seg | SEGMENT | HDATA | ; 定义一个HDATA类型的段 |
| RSEG | ?HD?my_seg | ||
| ARRAY: | DS | 100 | ; 保留100字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprog | ||
| MOV | R1, #BYTE0 ARRAY | ; 把ARRAY的地址装载到PR0中 | |
| MOV | R2, #BYTE1 ARRAY | ||
| MOV | R3, #BYTE2 ARRAY | ||
| MOV | A, @PR0 | ; 把ARRAY的第一个字节装载到A中 |
适用于英特尔/爱特梅尔WM251的例子
| ?HD?my_seg | SEGMENT | HDATA | ; 定义一个HDATA类型的段 |
| RSEG | ?HD?my_seg | ||
| ARRAY: | DS | 100 | ; 保留100个字节 |
| ?PR?myprog | SEGMENT | CODE | ; 为程序代码定义一个段 |
| RSEG | ?PR?myprgog | ||
| MOV | WR8, #WORD2 ARRAY | ; 装载ARRAY的地址到DR8中 | |
| MOV | WR10, #WORD0 ARRAY | ||
| MOV | R4, @DR8 | ; 间接寻址 | |
| MOV | @DR8+50H, R4 | ; 使用常量偏移访问 |