欣欣学习网,老工程师带你学习单片机技术,欢迎来坐坐。
首  页 | 学习NIOSII | 学习C51 | 学习CPLD | 51+CPLD实验板 | | | MY-RTOS

 实验板首页
 安装QuartusII软件
 安装USB-Blaster驱动
 安装CH340C驱动
 安装Keil uVision软件
 运行Hello World例程
 新建Keil uVision工程
 在Flash中运行程序
 恢复CPLD中的出厂逻辑
 安装调试代理程序
 硬件架构分析
 实现LCD驱动接口
 实现数码管驱动接口
 实现4x2键盘接口
 使用ADC采集拟量
 使用EEPROM保存数据
 使用UART通信
 红外遥控信号解码
 用作USB转232/485
 相关软件与文档


实现LCD接口


实验板上集成有1602A型LCD显示屏。该显示屏由EPM7128S来管理,需要通过在EMP728S实现的接口逻辑连接到89C52上,以便软件可以对其操作。

1602A型LCD显示屏的接口如图(1)所示,该接口属于典型的Motorola总线接口。其信号分为两部分,一部分是控制信号,另一部分是数据信号。控制信号由RS、RW、E组成,全部是单向传输的输入信号。其中RS是数据/指令选择信号,高电平时接口进行数据读写,低电平时接口接收指令。RW信号用于区分读/写操作,当RW为高电平时进行读操作,当RW为低电平时进行写操作。E信号是使能信,在读操作时,在E信号的高电平阶段,数由LCD送到数据总线上;在写操作时,数据总线上的数据数据在E信号的下降沿锁存到LCD的寄存器中。数据总由DB0-DB7组成,是双向传输的信号,用于传输读写操作的数据。该接口没有地址信号,控制信号中的使能信号E兼作地址信号的职责。

图(1)图(2)

由于51单片机诞生于Intel,所以其总线是Intel标准总线。因此,要把1602A挂在51单片机的总线上,就需要做一些逻辑上的变换。

图(3)

图(3)所示,是一个典型的应用实例。在这个电路中读和写使用地址信号A1进行区分。也就是,地址0x8000和地址0x8001是只能写操作,而地址0x8002和0x8003只能读操作。地址线A0用于区分指令还是数据,所以0x8000和0x8002是指令寄存器地址,而0x8001和0x8003是数据寄存器地址。整个接口的选通由A15实现,只有当A15为"1"时,写信号和读信号才可以传送到LCD的E端子,触发读写操作。

这个电路在低主频时可以很好的工作,但在高主频时会有问题。因为LCD的接口的速度不高,在高主频时会跟不上单片机总线的节拍。为了在高主频下使LCD接口匹配单片机总线的速度,可以在单片机总线上挂接两个端口,再由端口与LCD交换数据。

图(4)

如图(4)所示,可以由74377、74373、74244组成双向接口来驱动LCD。控制信号由74377产生,输数据先锁存在74373中再由74373传输给LCD,输入数据通过74244读回。由于读写时序由软件产生,避免了LCD与单片机总线速度不匹配的问题。

图(5)所示为EPM7128S的出厂逻辑设计中的LCD接口的输出部分。由74377产生LCDRS、LCDRW、LCDE这三个控制信号,分别输出给LCD的RS、RW、E管脚,其中LCDRW信号在输出给LCD的同时,也送给74373的输出使端子OE。在74373中锁存的是待输出的数据,若LCDRW为低电平则74373输出数据信号给LCD。74377的使能信号由CS2和A0的反向信号相"或"产生,对应的地址为0x8041。送给74373的WR信号由CS2和A0通过"或非"门控制,所以对应的地址为0x8040。

图(5)

LCD接口的输入通路如图(6)所示。数据在RD信号有效时,由CS2信号选通后经由两级多路选择器,再通过74244传送到单片机的数据总线上。可以用过地址0x8040读取这一数据。

图(6)

LCD接口的输入通路如图(6)所示。数据在RD信号有效时,由CS2信号选通后经由两级多路选择器,再通过74244传送到单片机的数据总线上。可以用过地址0x8040读取这一数据。

向1602A型LCD写命令字的示例代码如下:

void LCDWriteCmd(unsigned char Cmd)
{
  unsigned char RdData;
  
  do
  {
    XBYTE[CAddr] = 0x02;      // CAddr = 0x8041,74377地址,
                              // 写0x02则 LCDRS = 0,LCDRW = 1, LCDE = 0。
                              // 先置LCDRW = 1为了使74373在LCD输出之前转为高阻输出
    XBYTE[CAddr] = 0x06;      // 向74377写0x06,使LCDRS = 1,LCDRW=1,LCDE = 0。
                              // 发命令给LCD,让其送出状态字
    RdData = XBYTE[DAddr];    // DAddr = 0x8040,74244的地址,读回LCD送出的状态字
  }while((RdData&0x80) != 0); // 判断BF位是不为"1",不为"1"则控制器空闲,
                              // 可发送命令给LCD  
  XBYTE[CAddr] = 0x00;        // 写74377,使LCDRS = 0,LCDRW = 0,LCDE = 0
                              // LCDRS = 0,代表写入LCD的是命令字
  XBYTE[CAddr] = 0x04;        // 写74377,使LCDE = 1
  XBYTE[DAddr] = Cmd;         // DAddr = 0x8040,是74373的写地址。将命令字写入74373
  XBYTE[CAddr] = 0x00;        // 写74377,使LCDE = 0,产生一个下降沿,
                              // 将74373中的命令字写入LCD
}
          

向1602A型LCD写显示字符的示例代码如下:

void LCDWriteData(unsigned char WrData)
{
  unsigned char RdData;
  
  do
  {
    XBYTE[CAddr] = 0x02;      // CAddr = 0x8041,74377地址,
                              // 写0x02则 LCDRS = 0,LCDRW = 1, LCDE = 0。
                              // 先置LCDRW = 1为了使74373在LCD输出之前转为高阻输出
    XBYTE[CAddr] = 0x06;      // 向74377写0x06,使LCDRS = 1,LCDRW=1,LCDE = 0。
                              // 发命令给LCD,让其送出状态字
    RdData = XBYTE[DAddr];    //  DAddr = 0x8040,74244的地址,读回LCD送出的状态字
  }while((RdData&0x80) != 0); // 判断BF位是不为"1",不为"1"则控制器空闲,
                              // 可发送命令给LCD 
  XBYTE[CAddr] = 0x01;        // 写74377,使LCDRS = 1,LCDRW = 0,LCDE = 0
                              // LCDRS = 1,表示写入LCD的是显示字符
  XBYTE[CAddr] = 0x05;        // 写74377,使LCDE = 1
  XBYTE[DAddr] = WrData;      // DAddr = 0x8040,是74373的写地址。将命令字写入74373
  XBYTE[CAddr] = 0x01;        // 写74377,使LCDE = 0,产生一个下降沿,
                              // 将74373中的字符写入LCD
}
          

对1602A型LCD初始化示例代码如下:

/* 设置显示模式,两行,8位数据传输 */
LCDWriteCmd(LCD_CMD_DATA|LCD_CMD_DT_8BIT|LCD_CMD_DT_2LINE); 
/* 清屏                              */
LCDWriteCmd(LCD_CMD_CLR);
/* 打开显示,打开光标,光标闪烁    */
LCDWriteCmd(LCD_CMD_SWITCH|LCD_CMD_SW_DISPLAY|LCD_CMD_SW_BAR|LCD_CMD_SW_FLASH);
/* 光标自动进移                     */
LCDWriteCmd(LCD_CMD_MODE|LCD_CMD_MD_INC);
/* 光标回到屏幕起点                 */
LCDWriteCmd(LCD_CMD_HOME);
/* 光标右移一个字符                 */
LCDWriteCmd(LCD_CMD_SHIFT|LCD_CMD_SH_BAR|LCD_CMD_SH_RT);
          

完整的LCD范例程序,可参见:Hello World 程序

附:1602A型LCD指令集

1.

清屏指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 0000001

功能:清除屏幕上的所有字符

2.

HOME指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 000001-

功能:光标回到左上角

3.

输入方式设置指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 00001MS

功能:设置光标、画面移动方式

M = 1: 数据读、写后光标位置前进

M = 0:数据读、写后光标位置后退

S = 1:数据读、写后画面平移

S = 0:数据读、写后画面不动

4.

显示开关设置指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 0001DCB

功能:显示开关控制

D = 1: 显示开

D = 0:显示关

C = 1:光标开

C = 0:光标关

B = 1:闪烁开

B = 0:闪烁关

5.

光标、画面位移指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 001SCRL--

功能:光标、画面移动控制

SC = 1: 画面平移一个字符

SC = 0:光标平移一个字符

RL = 1:右移

RL = 0:左移

6.

接口设置指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 01DLN---

功能:接口设置

DL = 1: 8位数据接口

DL = 0:4位数据接口

N = 1:两行显示

N = 0:一行显示

7.

CG RAM 地址设置指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 0 1A5A4A3A2A1A0

功能:设置CG RAM地址

8.

DD RAM 地址设置指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 0 1 A6A5A4A3A2A1A0

功能:设置DD RAM地址

9.

读控制器状态指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
0 1BFA6A5A4A3A2A1A0

功能:读状态字

BF = 1: 控制器忙

BF = 0:控制器空闲

A6 - A0:最近一次地址设置的值

10.

写数据指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
1 0 D7 D6D5D4D3D2D1D0

功能:写数据到显存中

11.

读数据指令:

RSRWDB7DB6DB5DB4DB3DB2DB1DB0
1 1 D7 D6D5D4D3D2D1D0

功能:从显存中读数据




管理员信箱: stonewayqi@hotmail.com

欣 欣 学 习 网

粤ICP备2023138008号