小弟最近学习开发板上的1602液晶,
写了代码,下载后液晶没显示,只有背光是亮的。
相信很多人都用过1602噻,程序也很普遍,
我贴出代码来大家帮我在你们的开发板上运行下
看看能实现不?
最好能找下问题所在,谢谢各位指点
/*************************************************
//Module: lcd1602
//File Name: lcd1602.v
//Version: 1.0
//Date: 2011.12.5
//Author: wang li
//Code Type: RTL
//Description: LCD1602液晶显示
// clk——时钟输入(1位)
// rst——复位信号输入(1位)
// 输入看模块
**************************************************/
module lcd1602(clk,rst,LCD_E,LCD_RW,LCD_RS,LCD_DATA);
input clk; //时钟信号,50Mhz
input rst; //复位信号,低电平进行复位
output LCD_E; //1602使能引脚,1时读取信息,1->0(下降沿)执行命令
output LCD_RS; //1602数据——H/命令——L 选择端
output LCD_RW; //1602写——L/读——H 选择端
output [7:0] LCD_DATA; //1602数据传输端口
wire LCD_E;
reg [8:0] count;
reg clk_div1; //500个clk的周期,20ns*500=10us
reg clk_div2; //1000个,20us
reg [8:0] count1; //500个clk_div2的周期,10us*200=2000u=5ms
reg clk_buf;
//******************
//-----分频模块-----
//******************
always @(posedge clk or negedge rst)
begin
if(!rst) //rst=0
count<=0;
else
begin
if(count<250) //2500
begin
clk_div1<=0;
count<=count+1'b1;
end
else if(count>=500-1) //5000
count<=0;
else
begin
clk_div1<=1;
count<=count+1'b1;
end
end
end
always @(posedge clk_div1 or negedge rst)
begin
if(!rst)
clk_div2<=0;
else
clk_div2<=~clk_div2;
end
always @(posedge clk_div2 or negedge rst)
begin
if(!rst) //rst=0
count1<=0;
else
begin
if(count1<250) //2500
begin
clk_buf<=0;
count1<=count1+1'b1;
end
else if(count1>=500-1) //5000
count1<=0;
else
begin
clk_buf<=1;
count1<=count1+1'b1;
end
end
end
assign LCD_E=clk_buf;
//**********************
//-----显示控制模块-----
//**********************
reg [3:0] state; //当前状态寄存器 ,10个状态
reg [4:0] address; //地址的位置,0~31
reg [7:0] LCD_DATA;
reg LCD_RW,LCD_RS;
parameter
IDLE = 4'd0, //空闲
SET_FUNCTION = 4'd2, //工作方式设置指令
SWITCH_MODE = 4'd3, //开关控制指令
SET_MODE = 4'd4, //输入方式设置
CLEAR = 4'd5,
SET_DDRAM1 = 4'd6, //设定第一行DDRAM地址指令
WRITE_RAM1 = 4'd7, //向第一行写入的数码
WRITE_RAM2 = 4'd8, //向第2行写入的数码
SHIFT = 4'd9, //设定显示屏或光标移动方向指令
SET_DDRAM2 = 4'd10, //设定第2行DDRAM地址指令
STOP = 4'd11;
reg [127:0] Data_First = "www.endchina.com"; //液晶显示的第一行的数据
reg [127:0] Data_Second = " chick_kid "; //液晶显示的第二行的数据
reg [127:0] Data_First_Buf,
Data_Second_Buf; //液晶显示的数据缓存
//-----状态控制-----
always @(posedge clk_buf or negedge rst)
begin
if(!rst)
begin
state<=IDLE;
address<=5'd0;
LCD_DATA<=8'b0000_0000;
LCD_RS<=0;
LCD_RW<=0;
end
else
begin
case(state)
IDLE: //空闲状态
begin
LCD_DATA<=8'b00000000; //8'bzzzz_zzzz
state<=SET_FUNCTION;
end
SET_FUNCTION: //工作方式设置
begin
LCD_RS<=0;
LCD_RW<=0;
LCD_DATA<=8'b0011_1000; //38h
//第4位DL:0=数据总线为4位;1=数据总线为8位★★★
//第3位N:0=显示1行;1=显示2行★★★
//第2位F:0=5×7点阵/每字符★★★;1=5×10点阵/每字符
state<=SWITCH_MODE;
end
SWITCH_MODE: //显示开关控制指令
begin
LCD_RS<=0;
LCD_RW<=0;
LCD_DATA<=8'b0000_1111; //0Fh
//第2位D:0=显示功能关;1=显示功能开★★★
//第1位C:0=无光标;1=有光标★★★
//第0位B:0=光标闪烁; 1=光标不闪烁★★★
state<=SET_MODE;
end
SET_MODE: //设定显示屏或光标移动方向指令
begin
LCD_RS<=0;
LCD_RW<=0;
LCD_DATA<=8'b0000_0110; //06h
//第1位N:0=读或者写一个字符后,地址指针-1,光标-1
// 1=读或者写一个字符后,地址指针+1,光标+1★★★
//第0位S:0=当写一个字符,整屏显示不移动★★★
// 1=当写一个字符,整屏显示左移(N=1)或者右移(N=0),以得到光标不移动而屏幕移动的效果
state<=CLEAR;
end
CLEAR: //清屏指令
begin
LCD_RS<=0;
LCD_RW<=0;
LCD_DATA<=8'b0000_0001; //指令
state<=SHIFT;
end
SHIFT: //设定显示屏或光标移动方向指令
begin
LCD_RS<=0;
LCD_RW<=0;
LCD_DATA<=8'b0001_0100;
//第3位S/C;第2位R/L
// S/C R/L 设定情况
// 0 0 光标左移1格,且AC值减1
// 0 1 光标右移1格,且AC值加1 ★★★
// 1 0 显示器上字符全部左移一格,但光标不动
// 1 1 显示器上字符全部右移一格,但光标不动
state<=SET_DDRAM1;
end
SET_DDRAM1: //设定第一行DDRAM地址指令
begin
LCD_RS<=0;
LCD_RW<=0;
//-----写入第一行显示起始地址:-----
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 第一行
LCD_DATA<=8'h80+8'd0; //第一行第1个位置
state<=WRITE_RAM1;
Data_First_Buf<=Data_First;
end
WRITE_RAM1: //向第一行写入的数码
begin
if(address<=15) //表示写第一行
begin
LCD_RS<=1;
LCD_RW<=0;
LCD_DATA<=Data_First_Buf[127:120];
Data_First_Buf<=(Data_First_Buf<<8); //左移
address<=address+1'b1;
state<=WRITE_RAM1;
end
else
begin
LCD_RS<=0;
LCD_RW<=0;
state<=SET_DDRAM2;
end
end
SET_DDRAM2: //设定第2行DDRAM地址指令
begin
LCD_RS<=0;
LCD_RW<=0;
//-----写入第2行显示起始地址:-----
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 第二行
LCD_DATA<=8'hC0+8'd0; //第2行第1个位置
state<=WRITE_RAM2;
Data_Second_Buf<=Data_Second;
end
WRITE_RAM2: //向第2行写入的数码
begin
if(address<=31) //表示写第一行
begin
LCD_RS<=1;
LCD_RW<=0;
LCD_DATA<=Data_First_Buf[127:120];
Data_Second_Buf<=(Data_Second_Buf<<8);
address<=address+1'b1;
state<=WRITE_RAM2;
end
else
begin
LCD_RS<=0;
LCD_RW<=0;
address<=5'd0;
state<=STOP;
end
end
STOP: //设定第一行DDRAM地址指令
begin
state<=STOP;
end
default:
state<=CLEAR;
endcase
end
end
endmodule
|