发布论文 | 上传资料 | 发布供求 | 发布求职 | 发布项目 | 加入收藏 | RSS
您当前的位置:首页 > 文章中心 > EDA 设计 > ASIC/CPLD/FPGA/IC

FPGA字符型LCD模块控制

时间:2008-08-12 07:10:11  来源:  作者: 点击:17

字符型LCD模块价格便宜且便于和单片机或者FPGA连接。下面是一个1X16的字符型LCD模块。
 
为了控制LCD模块,一共需要11个引脚,其中包括8根数据线和3跟控制信号。这3个控制信号分别为:

  • E:使能信号或者说是LCD片选信号,高有效
  • R/W:读/写信号,0:写,1:读
  • RS:寄存器选择,0:选择命令寄存器,1:选择数据寄存器

大多数的字符型LCD模块都是基于HD44780或者兼容芯片的,从这里可以得到更为详细的资料。

7位设计
下面用我们FPGA板来驱动这个LCD模块,下面是硬件连接框图。
 
Pluto板从PC机的串行口接收数据,完成串并转换后发送到LCD模块。串并转换模块的设计与串行接口项目中的一样,所以这里只需要将其实例化即可。

module LCDmodule(clk, RxD, LCD_RS, LCD_RW, LCD_E, LCD_DataBus);
input clk, RxD;
output LCD_RS, LCD_RW, LCD_E;
output [7:0] LCD_DataBus;

wire RxD_data_ready;
wire [7:0] RxD_data;
async_receiver deserialer(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data)); 

每次从串行口接收到1个字节的数据,RxD_data_ready变为有效,且持续一个时钟周期。

PC机通过串行口,以8位的模式发送数据,所以理论上我们需要从PC机接收9位数据才能驱动8位数据和LCD模块的RS线。现在,我们使用接收到的数据的最高位(bit 7)来驱动"RS",并且只发送7位数据到数据总线上。

assign LCD_RS = RxD_data[7];
assign LCD_DataBus = {1'b0, RxD_data[6:0]}; ? // 只发送7位数据到数据到LCD模块, 最高位补0以凑足8位

assign LCD_RW = 0; 

因为我们不需要从LCD模块读取数据,所以R/W引脚直接连接到地。

下一个问题是"E"的有效信号需要持续220nS,这对与使用25MHz(每周期40nS)时钟信号的FPGA来说是比较长的时间了。所以"E"至少需要连续驱动5.5个时钟周期,这里我们驱动其7个时钟周期。
reg [2:0] count;
always @(posedge clk) if(RxD_data_ready | (count!=0)) count <= count + 1; 

"E"信号由寄存器产生以避免毛刺。

reg LCD_E;
always @(posedge clk) LCD_E <= (count!=0); 

产生的波形如下所示 :
 
完整的HDL代码在这里下载。

软件
我们需要初始化LCD模块并向其发送一些数据,使之显示出来。
 
下面是初始化LCD模块并在其上显示"hello"的C语言代码。

void main()
{
OpenComm();

// 初始化LCD模块
WriteCommByte(0x38); // 设置成8位模式
WriteCommByte(0x0F); // 显示光标
WriteCommByte(0x01); // 清屏,此操作将需要1.64ms,所以延时
Sleep(2);

// 显示 "hello"
WriteCommByte('h' + 0x80);
WriteCommByte('e' + 0x80);
WriteCommByte('l' + 0x80);
WriteCommByte('l' + 0x80);
WriteCommByte('o' + 0x80);

CloseComm();

完整的代码在这里下载。

点击这里查看更多的关于HD44780的指令集。

8位设计
前面的设计的主要弊端在于我们实际上只使用了7位数据总线,从而导致LCD模块的"设置 DD RAM 地址"的命令不能执行。

一个比较简单的解决办法是使用“标志字符”。这里我选择0x00,因为他没有被HD44780的命令使用。(具体从这里查看)

新的协议如下所示 :

  • 发送命令字节之前,先发送该“标志字符”。
  • 发送数据字节时,直接发送,不需要在其前增加“标志字符”。

新的C语言代码如下所示:

void main()
{
OpenComm();

// 初始化
WriteCommByte(0x00); WriteCommByte(0x38); // 设置成8位模式
WriteCommByte(0x00); WriteCommByte(0x0F); // 显示光标
WriteCommByte(0x00); WriteCommByte(0x01); // 清屏,此操作将需要1.64ms,所以延时
Sleep(2);

WriteCommByte('h');
WriteCommByte('e');
WriteCommByte('l');
WriteCommByte('l');
WriteCommByte('o');

WriteCommByte(0x00); WriteCommByte(0xC0); // 继续显示下半部分
WriteCommByte('e');
WriteCommByte('v');
WriteCommByte('e');
WriteCommByte('r');
WriteCommByte('y');
WriteCommByte('o');
WriteCommByte('n');
WriteCommByte('e');

CloseComm();

新的HDL代码如下所示:

module LCDmodule(clk, RxD, LCD_RS, LCD_RW, LCD_E, LCD_DataBus);
input clk, RxD;
output LCD_RS, LCD_RW, LCD_E;
output [7:0] LCD_DataBus;

wire RxD_data_ready;
wire [7:0] RxD_data;
async_receiver deserialer(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));

assign LCD_RW = 0;
assign LCD_DataBus = RxD_data;

wire Received_Escape = RxD_data_ready & (RxD_data==0);
wire Received_Data = RxD_data_ready & (RxD_data!=0);

reg [2:0] count;
always @(posedge clk) if(Received_Data | (count!=0)) count <= count + 1;

// LCD_E 有效6个时钟周期, 所以输入25MHz的时钟时, 结果为 6x40ns=240ns
reg LCD_E;
always @(posedge clk)
if(LCD_E==0)
LCD_E <= Received_Data;
else
LCD_E <= (count!=6);

reg LCD_instruction;
always @(posedge clk)
if(LCD_instruction==0)
LCD_instruction <= Received_Escape;
else
LCD_instruction <= (count!=7);

assign LCD_RS = ~LCD_instruction;

endmodule 

HD44780的数据手册中表示“E”变低后,“RS”需要继续有效10个纳秒。在这里你需要记得:"E"只驱动了6个时钟周期,并且 "LCD_instruction" 标志在第七个时钟后复位,留了25ns的时间余量。
 
下面该轮到您们去实践了。

来顶一下
近回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
推荐资讯
音乐程序的设计原理之单片机
音乐程序的设计原理之
FPGA的可编程全数字锁相环路实现
FPGA的可编程全数字锁
什么是模拟电路?
什么是模拟电路?
挪威发明蛇形消防机器人
挪威发明蛇形消防机器
相关文章
栏目更新
栏目热门