非常详细的verilog写的LCD1602驱动
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最近在网上找了很多用verilog驱动LCD1602的程序,但基本没有一个是完美运行,很多论坛所谓大神的代码综合时候一样很多缺陷,要知道每一个warning都有可能是导致最终失败的原因。于是乎只能自己下功夫,找到一个稍微靠谱的开发板配套例程,但是分频器模块编的叫一塌糊涂,主时钟分频后继续分频而且组合时序乱用,通过分频模块重新编写后基本无warning完美运行,仿真功能实现并且下载显示成功,后面附上了我的testbench,本人用的软件为ISE12.2,不过个人感觉quartus应该一样跑,下面是代码,需要在1602显示什么字符自己改显示函数就行,希望对大家有帮助。
module lcd1602(clk,rst,LCD_E,LCD_RW,LCD_RS,LCD_D);
input clk,rst;
output LCD_E,LCD_RW,LCD_RS;
output [7:0] LCD_D;
reg LCD_E,LCD_RW,LCD_RS;
reg [7:0] LCD_D;
reg [9:0] state;
reg [5:0] address;
parameter IDLE=10'b0000000000;
parameter CLEAR=10'b0000000001;//清屏
parameter RETURNCURSOR=10'b0000000010;//归home位
parameter SETMODE=10'b0000000111;
//输入方式设置,读写数据后ram地址增/减1;画面动/不动
parameter SWITCHMODE=10'b0000001111;
//显示状态设置,显示开/关;光标开/关;闪烁开/关
parameter SHIFT=10'b0000011100;
//光标画面滚动画面/光标平移一位;左/右平移一位
parameter SETFUNCTION=10'b0000111100;
//工作方式设置1:8/1:4位数据接口;两行/一行显示;5x10/5x7点阵
parameter SETCGRAM=10'b0001000000;//设置CGRAM
parameter SETDDRAM1=10'b0010000001;//设置DDRAM
parameter SETDDRAM2=10'b0010000010;//设置DDRAM
parameter READFLAG=10'b010*******;//读状态
parameter WRITERAM1=10'b1000000001;//写RAM
parameter WRITERAM2=10'b1000000010;//写RAM
parameter READRAM=10'b1100000000;//读RAM
parameter cur_inc =1;
parameter cur_dec =0;
parameter cur_shift =1;
parameter cur_noshift =0;
parameter open_display =1;
parameter open_cur =0;
parameter blank_cur =0;
parameter shift_display=1;
parameter shift_cur =0;
parameter right_shift =1;
parameter left_shift =0;
parameter LCD_Dwidth8 =1;
parameter LCD_Dwidth4 =0;
parameter twoline =1;
parameter oneline =0;
parameter font5x10 =1;
parameter font5x7 =0;
/******************************************************************/ function [7:0] ddram; //写入需要的字符数据
input [5:0] n;
begin
case(n)
0:ddram=8'h48;//H
1:ddram=8'h65;//e
2:ddram=8'h6c;//l
3:ddram=8'h6c;//l
4:ddram=8'h6f;//o
5:ddram=8'h21;//!
6:ddram=8'h21;//!
7:ddram=8'hA0;//space
8:ddram=8'h7E;//->
9:ddram=8'hA0;//space
10:ddram=8'h5A;//Z
11:ddram=8'h52;//R
12:ddram=8'h74;//t
13:ddram=8'h65;//e
14:ddram=8'h63;//c
15:ddram=8'h68;//h
16:ddram=8'h77;//w
17:ddram=8'h77;//w
18:ddram=8'h77;//w
19:ddram=8'h2E;//.
20:ddram=8'h5A;//Z
21:ddram=8'h52;//R
22:ddram=8'hB0;//R
23:ddram=8'h74;//t
24:ddram=8'h65;//e
25:ddram=8'h63;//c
26:ddram=8'h68;//h
27:ddram=8'h2E;//.
28:ddram=8'h6E;//n
29:ddram=8'h65;//e
30:ddram=8'h74;//t
31:ddram=8'hA0;//space
default: ddram=8'hxx;
endcase
end
endfunction
/******************************************************************/ //分频模块
reg [16:0] clkcnt;
reg clkdiv;
always @ (posedge clk)
if(!rst)
clkcnt<=17'b0_0000_0000_0000_0000;
else
begin
if(clkcnt<17'b0_1001_1100_0100_0000) //16'b1001_1100_0100_0000 begin
clkcnt<=clkcnt+1;
clkdiv<=0;
end
else if(clkcnt==17'b1_0011_1000_0111_1111)
clkcnt<=17'b0_0000_0000_0000_0000;
else
begin
clkcnt<=clkcnt+1;
clkdiv<=1;
end
end