为了测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的要求。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
回复【2楼】hujh3116
在扩展外部存储器时经常用,把c/d放在锁存器的输出还可以省一个io口
-----------------------------------------------------------------------
是的,但我的ale没引出来。估计很多业余的新手都是像我这样直接学c,对单片机的硬件结构不是太了解,所以我把分析得到的东西写出来。
-----------------------------------------------------------------------
应该是不能把CD接到ALE上
一周热门 更多>