本帖最后由 wakayi 于 2024-12-10 14:25 编辑
两个操作指令 MOVX,MOVC,如果用我们用汇编写外扩RAM、ROM,就是用这两个操作指令,当出现这两个操作指令的时候,单片机的相关引脚就会产生对应的时序,这样我们把相关外扩器件与之相连的时候,就不用去管时序的问题了。
MOVX A,@DPTR //读外扩ram,产生读时序,由WR/p3.6产生
MOVX @DPTR,A //写外扩ram,产生写时序,由RD/p3.7产生
MOVC A,@DPTR //读外扩rom,产生读时序,由PSEN产生
我这里这介绍RAM的读写。当我们发出一条MOVX指令的时候,先发出16位地址,产生控制时序,然后在写(读)数据,这个时候,我们低8位地址总线就与数据总线冲突了(因为都是用的P0口),使用如果我们要时候低8位地址去限定的时候,就可以就一个锁存器,来锁存低8位地址(这个时候要用到锁存信号引脚ALE),再比如我们外围器件不多的时候,或者外扩ram不超过2^8=256B的时候,完全可以不管低8位。
然后就是我们读写控制线都有效时序都是由高到低,当数据读写完后,在变为高电平,你们要注意自己控制的外围器件的时序,看要不要加非门处理一下读写时序,比如控制LCD1602的时候。
我们大致了解了这个控制过程(想详细了解的建议去看书,单片机原理),我们在开发的过程中很少用汇编写项目,下面我们就来看看C语言的写法。
首先我们来看一看下面的关键字:
code 以MOVC @A+DPTR 读取的程序内存
data 可以直接存取的内部数据存储器
idata 以 MOV@Rn 存取的内部数据存储器
bdata 可以位寻址(BitAddressable)的内部存储器
xdata 以MOVX @DPTR 存取的外部数据存储器
pdata 以MOVX @Rn 存取的外部数据存储器
我们一般都只用到 xdata,我们在头文件<absacc.h>中可以看到这样一个定义
#define XBYTE ((unsigned char voalite xdata*)0)
这样一个宏定义,这个宏定义我按我自己的理解去演示一遍,
当我们用XBYTE[0X1000]=1;
想当于 MOV @DPTR,1000H
MOV A,#1
MOVX @DPTR,A
把1写到外部ram地址位0x1000中,如果是 i=XBYTE[0X1000];这就是读了,意思是差不多的。
这个地址0x1000,就是通过地址总线发出去的,P0发送0x00也就是低8位,P2发送0x10也就是高8位,发送地址后,控制线发出对应的控制时序,ALE发送锁存,WR发出一个下降沿,这个时候在通过数据总线P0发送1出去。WR在复位到高电平。这就是大概流程。
当我们不是外扩ram的时候 XBYTE[]中的地址应该怎么去填呢,我们来举的DAC0832的例子,借用的别人的图
我们0832是在片选CS为低的时候,给WR低电平就可以工作了。
上图我们可以明显体会到用外扩ram这种编程方法的便利,以及节省很多资源了(用i/o直接操作的话,不加额外的器件,连接两个DAC起码要16个引脚)。
当我们想让dac0832(1)工作,但片2不工作,就要让P2.7=0,P2.6=0,P2.5=1。是不是这样的。
所以我们片1的地址高3位就出来了,其余的地址都影响不到它,所以我们称为地址无关位,我们任意填什么都可以,为了方便,我就填0。那么片1的地址 是不是就是XBYTE[0X2000] (001 0 0000 0000 0000),是不是就是这样的,
同理片2的就为 XBYTE[0X8000] (100 0 0000 0000 0000) 。 |