2015年第十六周lcd

设计思路:

只用LCD进行写操作,写入指令和数据,所以RW一直为0;EN在lcd_clk的上升沿高电平。

这样只需要操作RS信号即可。

写入指令RS为0,写入数据RS为1.

重要之处是:lcd_clk的选择,这里选择的是10KHZ。(这里的主时钟是40MHZ的)

用状态机来写比较方便,其中有2个case语句,一个是对RS的控制和状态的转换,另一个是在对应状态写入数据的选择。

数据在LCD_TOP中,用的是ASCII码,否则要自己去查找手册中相应字符的编码值。如下图


FPGA的LCD1602驱动 - fantasy - 悠然见南山

0x200x7F为标准的ASCII,0xA00xFF为日文字符和希腊文字符,其余的(0x100x1F0x800x9F)没有定义。


====================================================================================================

驱动模块:LCD_drive.v

module LCD_drive(

clk,

rst,

lcd_row1_val,

lcd_row2_val,

lcd_rs,

lcd_rw,

lcd_en,

lcd_data);

input clk;

input rst;

input [127:0] lcd_row1_val;

input  [127:0] lcd_row2_val;

output   lcd_rs;

output   lcd_rw;

output   lcd_en;

output [7:0] lcd_data;

parameter  TIME = 1999;  // 10KHZ

parameter  lcd_initial = 0;

parameter  row1_addr = 5;

parameter  row1       = row1_addr + 1;

parameter  row2_addr = row1 + 16;

parameter  row2       = row2_addr + 1;

reg [11:0] cnt;

reg         lcd_clk;

reg [7:0] lcd_data;

reg [5:0] state;

reg         lcd_rs;

assign lcd_rw = 1'b0;  //LCD一直是写入模式

assign lcd_en = lcd_clk;

//-------------分频---------------

always @ (posedge clk or negedge rst)

begin

if(!rst)

begin

cnt  <= 12'd0;

lcd_clk <= 1'b0;

end

else

begin

if(cnt == TIME)

begin

cnt  <= 12'd0;

lcd_clk <= ~lcd_clk;

end

else

cnt <= cnt + 12'd1;

end

end

//-----------------------------------------------------------------------

always @ (posedge lcd_clk or negedge rst)

begin

if(!rst)

begin

lcd_rs <= 0;

state   <= lcd_initial;

lcd_data <= 8'hxx;

end

else

begin//------------LCD驱动----------------

case(state)

//--初始化--

lcd_initial+0: begin lcd_rs <= 0; state  <= lcd_initial+1; end

lcd_initial+1: begin lcd_rs <= 0; state  <= lcd_initial+2; end

lcd_initial+2: begin lcd_rs <= 0; state  <= lcd_initial+3; end

lcd_initial+3: begin lcd_rs <= 0; state  <= row1_addr; end

//--第一行--

row1_addr: begin lcd_rs <= 0; state  <= row1+0; end

row1+0: begin lcd_rs <= 1; state  <= row1+1; end

row1+1: begin lcd_rs <= 1; state  <= row1+2; end

row1+2: begin lcd_rs <= 1; state  <= row1+3; end

row1+3: begin lcd_rs <= 1; state  <= row1+4; end

row1+4: begin lcd_rs <= 1; state  <= row1+5; end

row1+5: begin lcd_rs <= 1; state  <= row1+6; end

row1+6: begin lcd_rs <= 1; state  <= row1+7; end

row1+7: begin lcd_rs <= 1; state  <= row1+8; end

row1+8: begin lcd_rs <= 1; state  <= row1+9; end

row1+9: begin lcd_rs <= 1; state  <= row1+10; end

row1+10: begin lcd_rs <= 1; state  <= row1+11; end

row1+11: begin lcd_rs <= 1; state  <= row1+12; end

row1+12: begin lcd_rs <= 1; state  <= row1+13; end

row1+13: begin lcd_rs <= 1; state  <= row1+14; end

row1+14: begin lcd_rs <= 1; state  <= row1+15; end

row1+15: begin lcd_rs <= 1; state  <= row2_addr; end

//--第二行--

row2_addr: begin lcd_rs <= 0; state  <= row2+0; end

row2+0: begin lcd_rs <= 1; state  <= row2+1; end

row2+1: begin lcd_rs <= 1; state  <= row2+2; end

row2+2: begin lcd_rs <= 1; state  <= row2+3; end

row2+3: begin lcd_rs <= 1; state  <= row2+4; end

row2+4: begin lcd_rs <= 1; state  <= row2+5; end

row2+5: begin lcd_rs <= 1; state  <= row2+6; end

row2+6: begin lcd_rs <= 1; state  <= row2+7; end

row2+7: begin lcd_rs <= 1; state  <= row2+8; end

row2+8: begin lcd_rs <= 1; state  <= row2+9; end

row2+9: begin lcd_rs <= 1; state  <= row2+10; end

row2+10: begin lcd_rs <= 1; state  <= row2+11; end

row2+11: begin lcd_rs <= 1; state  <= row2+12; end

row2+12: begin lcd_rs <= 1; state  <= row2+13; end

row2+13: begin lcd_rs <= 1; state  <= row2+14; end

row2+14: begin lcd_rs <= 1; state  <= row2+15; end

row2+15: begin lcd_rs <= 1; state  <= row1_addr; end

default: begin lcd_rs <= 1'bx; state  <= lcd_initial; end

endcase

//------------字符显示----------------

case(state)

//--初始化--

lcd_initial+0: lcd_data <= 8'h38;  //设置初始工作状态:数据8bit,显示2行,字符为5x7点阵

lcd_initial+1: lcd_data <= 8'h0C;  //开显示,字符无闪烁,光标闪烁

lcd_initial+2: lcd_data <= 8'h01;  //清屏

lcd_initial+3: lcd_data <= 8'h06;  //写入数据光标左移

//--第一行--

row1_addr: lcd_data <= 8'h80;     //第一行写入地址

row1+0: lcd_data <= lcd_row1_val[127:120];

row1+1: lcd_data <= lcd_row1_val[119:112];

row1+2: lcd_data <= lcd_row1_val[111:104];

row1+3: lcd_data <= lcd_row1_val[103: 96];

row1+4: lcd_data <= lcd_row1_val[ 95: 88];

row1+5: lcd_data <= lcd_row1_val[ 87: 80];

row1+6: lcd_data <= lcd_row1_val[ 79: 72];

row1+7: lcd_data <= lcd_row1_val[ 71: 64];

row1+8: lcd_data <= lcd_row1_val[ 63: 56];

row1+9: lcd_data <= lcd_row1_val[ 55: 48];

row1+10: lcd_data <= lcd_row1_val[ 47: 40];

row1+11: lcd_data <= lcd_row1_val[ 39: 32];

row1+12: lcd_data <= lcd_row1_val[ 31: 24];

row1+13: lcd_data <= lcd_row1_val[ 23: 16];

row1+14: lcd_data <= lcd_row1_val[ 15:  8];

row1+15: lcd_data <= lcd_row1_val[  7:  0];

//--第二行--

row2_addr: lcd_data <= 8'h80 + 8'h40;//第二行写入地址

row2+0: lcd_data <= lcd_row2_val[127:120];

row2+1: lcd_data <= lcd_row2_val[119:112];

row2+2: lcd_data <= lcd_row2_val[111:104];

row2+3: lcd_data <= lcd_row2_val[103: 96];

row2+4: lcd_data <= lcd_row2_val[ 95: 88];

row2+5: lcd_data <= lcd_row2_val[ 87: 80];

row2+6: lcd_data <= lcd_row2_val[ 79: 72];

row2+7: lcd_data <= lcd_row2_val[ 71: 64];

row2+8: lcd_data <= lcd_row2_val[ 63: 56];

row2+9: lcd_data <= lcd_row2_val[ 55: 48];

row2+10: lcd_data <= lcd_row2_val[ 47: 40];

row2+11: lcd_data <= lcd_row2_val[ 39: 32];

row2+12: lcd_data <= lcd_row2_val[ 31: 24];

row2+13: lcd_data <= lcd_row2_val[ 23: 16];

row2+14: lcd_data <= lcd_row2_val[ 15:  8];

row2+15: lcd_data <= lcd_row2_val[  7:  0];

default: lcd_data <= 8'hxx;

endcase

end

end

endmodule

=============================================================================================

测试顶层:LCD_TOP.v

module LCD_TOP(

clk_40m_i,

rst,

lcd_rs,

lcd_rw,

lcd_e,

lcd_data);

input clk_40m_i;

input rst;

output lcd_rs;

output lcd_rw;

output lcd_e;

output [7:0] lcd_data;

//0123456789abcdef//

wire [127:0] row1 = {"abcdefgh12345678"};

wire  [127:0] row2 = {"         fantasy          "};

LCD_drive u1 (

.clk(clk_40m_i),

.rst(rst),

.lcd_row1_val(row1),

.lcd_row2_val(row2),

.lcd_rs(lcd_rs),

.lcd_rw(lcd_rw),

.lcd_en(lcd_e),

.lcd_data(lcd_data));

endmodule

modelsim测试文件: LCD_tb.v

`timescale    1ns / 1ps

module LCD_tb;

reg   clk_40m_i;

reg   rst;

wire   lcd_rs;

wire   lcd_rw;

wire   lcd_e;

wire   [7:0] lcd_data;

LCD_TOP i1(

.clk_40m_i(clk_40m_i),

.rst(rst),

.lcd_rs(lcd_rs),

.lcd_rw(lcd_rw),

.lcd_e(lcd_e),

.lcd_data(lcd_data));

initial

begin

clk_40m_i = 0;

rst       = 0;

#100 rst     = 1;

end

always #20 clk_40m_i = ~clk_40m_i;

endmodule

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值