一种24064与51接口的深入研究(利用引脚第二功能)

2020-01-27 11:23发布

为了测24060的硬件功能,在网上找了个现成程序进行测试,发现程序的接口定义很特别,分析一下,果然很有看头,程序重点部位如下:

//                    CA24064
//***************************************************************************
//*  Create by :Ssmart   2004/12/01       KeilC V7.0                           *
//***************************************************************************
//连线表:  CPU=89C52                                                        *
//C/D=P2.0           /CE=P2.7            FS=P3.5         /WR=/WR   /RD=/RD  *
//FOSC=12MHz         D0-D7=P0.0-P0.7     /RSET=/(CPU RSET)            *
//***************************************************************************
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>

#define uint  unsigned int
#define uchar unsigned char
#define Graphic            1
#define TXT            0
#define LcmLengthDots            240
#define LcmWidthDots            64

char xdata LcmDataPort _at_ 0x0000;
char xdata LcmCmdPort  _at_ 0x0100;
sbit FS = P3^5;
sbit Key= P3^4;


连线表倒是说得很清楚,可是通常的接口定义这里只有见到两个

sbit FS = P3^5;
sbit Key= P3^4;

其他的哪去了?既然没有用代码指定,那就是利用CPU的某种自动功能了,没错,这里利用C51读取外部数据RAM时,P0(数据输入输出、地址总线低8位输出)和P2的地址总线输出和P3的第二功能(WD、RD)


预备知识:

1.先分析下面两行代码,看看它做了什么

char xdata LcmDataPort _at_ 0x0000;
char xdata LcmCmdPort  _at_ 0x0100;


xdata存储类型标识符指外部数据区64K字节内的任何地址,为什么要把变量指定为外部数据区?

_at_用来把变量定位一个绝对的存储地址,用法如下
type [memory_space] variable_name _at_ constant
这里
memory_space 变量的存储空间如果在声明中没有则使用缺省的存储空间缺
省的存储空间参考94页的存储模式
type 变量类型
variable_name 变量名
constant 定位变量的地址
_at_后面的绝对地址必须在可用的实际存储空间内Cx51 编译器检查无效的地址标
识符

这两行代码就是定义了两个char型的数据LcmDataPort和LcmCmdPort,它们被指定为保存在外部数据区内的变量,地址分别为0x0000和0x0100,注意它们都是16位地址。

从字面意思看LcmDataPort的意思是数据端口,LcmCmdPort是命令端口


2.P0 P2 数据、地址总线功能和P3口的替代功能

P0可进行数据输入输出和16位地址总线的低8位输出,P2为可进行16位地址总线的高8位输出,P3口的WR和RD是重点,我们详细讲它,P3比 P2在结构上多了一个与非门,与非门的另一个输入替代输出功能信号,在对外部数据RAM进行操作时,CPU会自动安排P3.6(WR )P3.7(RD)的时序,换句话说就是RD和WR信号由CPU自动产生,不需要使用软件模拟。


DPTR是数据指针,主要用来保存16位地址,当执行MOVX时,CPU会自动安排WR和RD电平的高低,具体可以看51的时序图。在读外部RAM 时,MOVX     A,@DPTR,把DPTR地址的数据(读PO口得到)放入累加器中,这时候WR为高,RD为低(低电平有效),反之,写外部RAM时MOVX     @DPTR,A,把累加器A中的值写到指定地址(写P0口),这时候WR为低,RD为高。

特别说明一下,这个过程在KEIL的DUBUG里是看不到的。


下面开始分析代码:

我写了几行C测试代码,来看看与汇编的对照

   262:          i=LcmDataPort;
C:0x07C3    900000   MOV      DPTR,#C_STARTUP(0x0000)
C:0x07C6    E0       MOVX     A,@DPTR
C:0x07C7    F508     MOV      0x08,A
   263:          LcmDataPort=0x00;
C:0x07C9    E4       CLR      A
C:0x07CA    F0       MOVX     @DPTR,A
     264:          LcmCmdPort=0x0f;
C:0x07CB    900200   MOV      DPTR,#LcmCmdPort(0x0100)
C:0x07CE    740F     MOV      A,#0x0F
C:0x07D0    F0       MOVX     @DPTR,A


我们分析前两条就够了:

262行代码:LcmDataPort前面我们分析过了,它被指定为保存在外部数据区内的变量,地址为0x0000,先用MOV把要访问的地址0x0000送入DPTR,然后用MOVX把DPRT指定地址内的数据送入累加器A。这期间RD自动变为低电平,T6963的RD也是低电平有效,且与MCU的RD连接,这样就自动实现了对LCD读写的操作,省去单独指定IO脚用软件操作。

264行代码:先把0x0100送入DPTR,再把要写的值0x0f送入A,最后用MOVX把A中的值写到DPTR指定的地址中。这期间是WR自动变为低电平,相应的T6963C的WR也变为低电平,对应写操作。

263行和264行代码一样,为什么转成的汇编不一样呢?这就是编译器的优化啦,263行我们写的值是0x00,反正最终送到ACC的值是0,直接把它CLR不是更省事?看啊,分析代码是非常有趣而且能学到东西的事情。

注意:对外部RAM操作时,总是先向P0和P2送地址,保持一段时间,然后再通过P0读或写数据


这样特别的接口定义方式仅仅是为了省C里的几句代码?当然好处不止这些,别忘了T6963还有个C/D,命令/数据选择,LcmDataPort和 LcmCmdPort只是指定的地址不一样,怎么在操作这两个变量的同时实现对C/D的操作的呢?秘密就在它们外部地址的值上:0x0000,0x0100.

T6963C的CD接到了P2.0上,高电平对应命令,低电平对应数据。对外部RAM操作时,总是先向P0和P2送地址,保持一段时间,然后再通过P0读或写数据,那么LcmDataPort送的是0x0000,P0和P2都是0x00,P2.0是低电平,刚好对应DATA;LcmCmdPort送的是0x0000,P0都是0x00,P2是0x01,P2.0是高电平,刚好对应COMMAND。这就实现了对CD的自动设置。

这两个地址还是有意取的值,根本不存在这两个地址,更别说有个鬼的外部RAM,这里只是利用了51操作外部RAM时的特性。前面提到KEIL的手册里说_at_后面的绝对地址必须在可用的实际存储空间内Cx51 编译器检查无效的地址标识符,看来不守规据有时也能成大事。


我们再稍微深入一点,想想这两个地址还能取哪些值,在CD所接引脚确定的情况下,只要符合以下两条要求的地址都行:

1.LcmDataPort对应的“地址”不能影响CD对应引脚,相应位必须为0

2.LcmCmdPort对应的“地址”在CD所接引脚的对应的位必须为1


再往深考虑,WR RD值是自动设置的,那保持时间够不够6963用?前面还说了先送地址再读写数据,那地址保持时间够不够用?查51的DATASHEET,WR和RD脉宽最小值TRLRH TWLWH均为1675ns,再查T6963C的DATASHEET,WR和RD的要求脉宽的最小值是60ns,完全完全足够。P0和P2的地址保持时间也满足T6963C的要求。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。