Text LCD module

文本LCD模块便宜且易于使用微控制器或FPGA进行接口。

这是一个1行x 16个字符的模块:

要控制LCD模块,您需要11个IO引脚来驱动8位数据总线和3个控制信号。3个控制信号是:

E:启用或“ LCD选择”。高活跃。 读/写:读/写。0写入,1读取。 RS:寄存器选择,0表示命令字节,1表示数据字节。 大多数LCD模块都基于HD44780芯片或兼容的。查看Wikipedia以获取更多信息。

7位设计 让我们从FPGA板驱动LCD模块。 这是我们设计的框图:

Pluto从PC串行端口接收数据,对其进行反序列化,然后将其发送到LCD模块。解串器与串行接口项目中的模块相同,因此此处仅对其进行实例化。

LCD 模块模块(clk,RxD,LCDRS,LCDRW,LCDE,LCDDataBus); 输入 clk,RxD; 输出 LCDRS,LCDRW,LCDE; 输出 [7:0] LCDDataBus;

连线 RxDdataready; 线 [7:0] RxDdata; asyncreceiver解串器(.clk(clk)、. RxD(RxD)、. RxDdataready(RxDdataready)、. RxDdata(RxDdata)); 每当串行端口提供一个字节时,“ RxDdataready”将在一个时钟周期内处于活动状态。

PC通过串口以8位模式向我们发送数据。理想情况下,我们需要从PC接收9位,以便我们可以驱动8位数据总线和LCD模块的“ RS”线。现在,让我们使用接收到的数据的MSB(第7位)来驱动“ RS”,并将仅7位发送到数据总线。

分配 LCDRS = RxDdata [7]; 分配 LCDDataBus = {1'b0,RxDdata [6:0]}; 仅发送7位到模块,在前面加一个'0'使8位 分配 LCD_RW = 0; 我们从不读取LCD模块,因此R / W线接地。 最后一个麻烦是“ E”信号需要长时间激活,即220ns。从FPGA的角度来看,这很长,因为我使用的是25MHz时钟(周期为40ns)。因此,“ E”至少需要驱动5.5个时钟。在这里,我们使用一个计数器对时钟进行计数,将其驱动7个时钟。 reg [2:0]计数;如果(RxDdataready |(count!= 0))count ⇐ count + 1; 总是 @(posege clk) “ E”信号是通过寄存器创建的,因此可以保证无干扰。 reg LCDE; 总是 @(posedge CLK)LCDE ⇐(计数!= 0); 波形如下所示: HDL设计在这里。 该软件 我们初始化LCD并发送一些要显示的数据。 这是初始化LCD模块并显示“ hello”的C代码。 void main() { OpenComm(); 初始化LCD模块

WriteCommByte(0x38); // 8位模式下的“功能集”
WriteCommByte(0x0F); //光标打开时“ Display ON”
WriteCommByte(0x01); //“ Clear Display”,最多可能需要1.64ms,因此延迟
Sleep(2);
//显示“你好”
WriteCommByte('h'+ 0x80);
WriteCommByte('e'+ 0x80);
WriteCommByte('l'+ 0x80);
WriteCommByte('l'+ 0x80);
WriteCommByte('o'+ 0x80);
CloseComm();

} 完整的代码在这里。

要获取有关HD44780指令集的更多信息,请在此处检查。

8位设计 主要缺点是较早的设计是我们仅向LCD数据总线发送7位。这是一个问题,因为无法再使用LCD模块的设置DD RAM地址命令。

一种简单的解决方法是使用转义符。我们选择了字符0x00。

新协议如下:

要发送命令字节,请在其前面加上0x00。 要发送数据字节,只需发送它,不需要前缀。 新的C代码是:

void main() {

OpenComm();
//初始化LCD模块
WriteCommByte(0x00); WriteCommByte(0x38); // 8位模式下的“功能集”
WriteCommByte(0x00); WriteCommByte(0x0F); //光标打开时“显示打开”
WriteCommByte(0x00); WriteCommByte(0x01); //“ Clear Display”,最多可能需要1.64ms,因此延迟
Sleep(2);
WriteCommByte('h');
WriteCommByte('e');
WriteCommByte('l');
WriteCommByte('l');
WriteCommByte('o');
WriteCommByte(0x00); WriteCommByte(0xC0); //进入LCD
WriteCommByte('e')的后半部分;
WriteCommByte('v');
WriteCommByte('e');
WriteCommByte('r');
WriteCommByte('y');
WriteCommByte('o');
WriteCommByte('n');
WriteCommByte('e');
CloseComm();

} 新的HDL代码如下所示:

LCD 模块模块(clk,RxD,LCDRS,LCDRW,LCDE,LCDDataBus); 输入 clk,RxD; 输出 LCDRS,LCDRW,LCDE; 输出 [7:0] LCDDataBus;

连线 RxDdataready; 线 [7:0] RxDdata; asyncreceiver deserialer(.clk(clk)、. RxD(RxD)、. RxDdataready(RxDdataready)、. RxDdata(RxDdata));

分配 LCDRW = 0; 分配 LCDDataBus = RxD_data;

电线 ReceivedEscape = RxDdataready&(RxDdata == 0); 电线 ReceivedData = RxDdataready&(RxDdata!= 0);

reg [2:0]计数; 总是 @(posege clk)如果(Received_Data |(count!= 0))count ⇐ count + 1;

激活LCDE为6个时钟,所以在25MHz的,这是6x40ns = 240ns REG LCDE; 总是 @(posedge CLK) 如果(LCDE == 0) LCDE ⇐ ReceivedData; 否则 LCDE ⇐(count!= 6); reg LCDinstruction; 总是 @(posedge CLK) 如果(LCDinstruction == 0) LCDinstruction ⇐ ReceivedEscape; 否则 LCD_instruction ⇐(count!= 7); 分配 LCDRS =〜LCDinstruction; 终端模块 HD44780规范显示,“ E”变低后,“ RS”必须在10ns内有效。因此,您会注意到这里“ E”仅被驱动6个时钟,并且“ LCD_instruction”标志仅在时钟7之后被复位,以提供25ns的空间。 那就是所有人!轮到您尝试了。