开发工具:Quartus II 9.1;

仿真软件:Questa Sim 10.0c;

硬件平台:Terasic DE2-115(EP2C35F672C6);

外设:hd44780控制器lcd1602;

3个工程文件:"lcd1602_cgram_controller.v" + "lcd1602_cgram_driver.v" + "lcd1602_cgram_driver_tsb.v";

设计思路:

  底层直接操作lcd1602的模块为"*_controller.v"文件,三段式状态机,完成初始化液晶工作模式(无光标、5X8、2行...)、在CGRAM写入自定义的8个字符(源文件里条形图,可用于音频FFT波形图显示),完成CGRAM写数据之后进入通用的显示状态,每次显示完一个字符产生的ack信号;

  "_driver.v"完成循环调用显示8个自定义字符;

  "_driver_tsb.v"完成仿真时的驱动(原本是和"_driver.v"在同一个文件,为了方便后续综合,分开了);

注意事项:

  系统工作频率为50MHz,lcd操作的指令、数据周期为2ms(1ms下也能用);

  CYCLONEII的芯片上电未复位之前的寄存器是0,因此程序下载到板子上的时候液晶是不显示的,没有复位引脚的需要自行设计软件复位;

  lcd_on,lcd_blon为DE2-115板子特有设计;

源码1...

 `timescale  ns /  ps
//`define SIM
`define SYS_CLK 50_000_000
//achieve lcd1602 cgram display
//author wuyuehang1990
//version 0.1
module lcd1602_cgram_controller(
sys_clk,
sys_rst_n,
sys_dat_i,
sys_addr_i,
lcd_ack_o,
lcd_en,
lcd_rw,
lcd_rs,
lcd_bus,
lcd_on,
lcd_blon
); input sys_clk;
input sys_rst_n;
input [:] sys_dat_i;//CGRAM ONLY DISP 8 DIFFERENT FONTS//00~07
input [:] sys_addr_i;//DDRAM ADDR
output reg lcd_ack_o;
//lcd interface
output lcd_en;
output lcd_rw;
output reg lcd_rs;
output reg [:] lcd_bus;
//spec io
output lcd_on;
output lcd_blon; `ifdef SIM
parameter ST_WIDTH = ;
parameter CLR = "CLR.....";
parameter FUNC = "FUNC....";
parameter ONOFF = "ON/OFF..";
parameter ENTRY = "ENTRY...";
parameter SETCGRAM = "SETCGRAM";
parameter WRCGRAM = "WR_CGRAM";
parameter SETDDRAM = "SETDDRAM";
parameter WRDDRAM = "WR_DDRAM";
parameter ACK = "ACK.....";
`else
`define FSM
parameter ST_WIDTH = `FSM;
parameter CLR = `FSM'b0_0000_0001;//01
parameter FUNC = `FSM'b0_0000_0010;//38(8BUS-2LINE) 37(8BUS-1LINE)
parameter ONOFF = `FSM'b0_0000_0100;//0C(ON-SHINE)
parameter ENTRY = `FSM'b0_0000_1000;//06(DISP_FIXED-CURSOR_SHIFT)
parameter SETCGRAM = `FSM'b0_0001_0000;
parameter WRCGRAM = `FSM'b0_0010_0000;
parameter SETDDRAM = `FSM'b0_0100_0000;
parameter WRDDRAM = `FSM'b0_1000_0000;
parameter ACK = `FSM'b1_0000_0000; `endif //generate 1KHz(1ms)
reg [:] cnt_1KHz=;
reg clk_1KHz=;
reg pulse1ms=; always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
cnt_1KHz <= ;
end
else if(cnt_1KHz > 'd99999) begin
cnt_1KHz <= ;
end
else begin
cnt_1KHz <= cnt_1KHz + 'd1;
end
end always @ (posedge sys_clk) begin
if(cnt_1KHz < 'd49999) begin
clk_1KHz <= 'd1;
end
else begin
clk_1KHz <= 'd0;
end
end always @ (posedge sys_clk) begin
if(cnt_1KHz == 'd99999) pulse1ms <= 1'd1;
else pulse1ms <= 'd0;
end //generate lcd_en,lcd_rw;
assign lcd_en = clk_1KHz;
assign lcd_rw = 'b0;
//generate spec io
assign lcd_on = 'b1;
assign lcd_blon = 'b1; //FSM
reg [:] cnt64=;//count 64 hex char
reg [ST_WIDTH-:] c_st = FUNC;
reg [ST_WIDTH-:] n_st = FUNC;
//fsm-1
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) c_st <= FUNC;
else c_st <= n_st;
end //fsm-2
always @ (*) begin
n_st = FUNC;
case(c_st)
FUNC:begin
n_st = (pulse1ms == 'b1)?ONOFF:FUNC;
end
ONOFF:begin
n_st = (pulse1ms == 'b1)?ENTRY:ONOFF;
end
ENTRY:begin
n_st = (pulse1ms == 'b1)?CLR:ENTRY;
end
CLR:begin
n_st = (pulse1ms == 'b1)?SETCGRAM:CLR;
end
SETCGRAM:begin
n_st = (pulse1ms == 'b1)?WRCGRAM:SETCGRAM;
end
WRCGRAM:begin
if((pulse1ms == 'b1) && (cnt64 == 6'd63))
n_st = SETDDRAM;
else if(pulse1ms == 'b1)
n_st = SETCGRAM;
else
n_st = WRCGRAM;
end
SETDDRAM:begin
n_st = (pulse1ms == 'b1)?WRDDRAM:SETDDRAM;
end
WRDDRAM:begin
n_st = (pulse1ms == 'b1)?ACK:WRDDRAM;
end
ACK:begin
n_st = SETDDRAM;
end
default:begin
n_st = FUNC;
end
endcase
end //FSM-3
//generate lcd_bus lcd_rs and lcd_ack always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) begin
lcd_ack_o <= ;
lcd_rs <= ;
lcd_bus <= 'h38;
cnt64 <= ;
end
else begin
case(n_st)
FUNC:begin
lcd_rs <= ;
lcd_ack_o <= ;
lcd_bus <= 'h38;//3c(2-line-5*10)//38(2-line-5*8)
cnt64 <= 'd63;
end
ONOFF:begin
lcd_rs <= ;
lcd_ack_o <= ;
lcd_bus <= 'h0d;//no cursor
cnt64 <= 'd63;
end
ENTRY:begin
lcd_rs <= ;
lcd_ack_o <= ;
lcd_bus <= 'h06;
cnt64 <= 'd63;
end
CLR:begin
lcd_rs <= ;
lcd_ack_o <= ;
lcd_bus <= 'h01;
cnt64 <= 'd63;
end
SETCGRAM:begin
lcd_ack_o <= ;
lcd_rs <= ;
cnt64 <= (pulse1ms == 'b1)?cnt64 + 1'd1:cnt64;
lcd_bus <= {'b01,cnt64};
end
WRCGRAM:begin
lcd_ack_o <= ;
lcd_rs <= ;
cnt64 <= cnt64;
/*
case(cnt64)
6'd0,6'd1,6'd2,6'd3,6'd4,6'd5,6'd6,6'd7:lcd_bus <= 8'h00;//empty
6'd8,6'd9,6'd10,6'd11,6'd12,6'd13:lcd_bus <= 8'h00;
6'd14:lcd_bus <= 8'h1f;
6'd15:lcd_bus <= 8'h00;//1step
6'd16,6'd17,6'd18,6'd19,6'd20:lcd_bus <= 8'h00;
6'd21,6'd22:lcd_bus <= 8'h1f;
6'd23:lcd_bus <= 8'h00;//2step
6'd24,6'd25,6'd26,6'd27:lcd_bus <= 8'h00;
6'd28,6'd29,6'd30:lcd_bus <= 8'h1f;
6'd31:lcd_bus <= 8'h00;//3step
6'd32,6'd33,6'd34:lcd_bus <= 8'h00;
6'd35,6'd36,6'd37,6'd38:lcd_bus <= 8'h1f;
6'd39:lcd_bus <= 8'h00;//4step
6'd40,6'd41:lcd_bus <= 8'h00;
6'd42,6'd43,6'd44,6'd45,6'd46:lcd_bus <= 8'h1f;
6'd47:lcd_bus <= 8'h00;//5step
6'd48:lcd_bus <= 8'h00;
6'd49,6'd50,6'd51,6'd52,6'd53,6'd54:lcd_bus <= 8'h1f;
6'd55:lcd_bus <= 8'h00;//6step
6'd56,6'd57,6'd58,6'd59,6'd60,6'd61,6'd62:lcd_bus <= 8'h1f;
6'd63:lcd_bus <= 8'h00;//7step
endcase
*/
case(cnt64)
'd0,6'd1,'d2,6'd3,'d4,6'd5,'d6:lcd_bus <= 8'h00;
'd7:lcd_bus <= 8'h1f;//s1
'd8,6'd9,'d10,6'd11,'d12,6'd13:lcd_bus <= 'h00;
'd14:lcd_bus <= 8'h1f;
'd15:lcd_bus <= 8'h1f;//s2
'd16,6'd17,'d18,6'd19,'d20:lcd_bus <= 8'h00;
'd21,6'd22:lcd_bus <= 'h1f;
'd23:lcd_bus <= 8'h1f;//s3
'd24,6'd25,'d26,6'd27:lcd_bus <= 'h00;
'd28,6'd29,'d30:lcd_bus <= 8'h1f;
'd31:lcd_bus <= 8'h1f;//4step
'd32,6'd33,'d34:lcd_bus <= 8'h00;
'd35,6'd36,'d37,6'd38:lcd_bus <= 'h1f;
'd39:lcd_bus <= 8'h1f;//5step
'd40,6'd41:lcd_bus <= 'h00;
'd42,6'd43,'d44,6'd45,'d46:lcd_bus <= 8'h1f;
'd47:lcd_bus <= 8'h1f;//6step
'd48:lcd_bus <= 8'h00;
'd49,6'd50,'d51,6'd52,'d53,6'd54:lcd_bus <= 'h1f;
'd55:lcd_bus <= 8'h1f;//7step
'd56,6'd57,'d58,6'd59,'d60,6'd61,'d62:lcd_bus <= 8'h1f;
'd63:lcd_bus <= 8'h1f;//8step
endcase
end
SETDDRAM:begin
lcd_ack_o <= ;
lcd_rs <= ;
lcd_bus <= sys_addr_i;
cnt64 <= cnt64;
end
WRDDRAM:begin
lcd_ack_o <= ;
lcd_rs <= ;
cnt64 <= cnt64;
lcd_bus <= sys_dat_i;
end
ACK:begin
lcd_ack_o <= ;
lcd_rs <= ;
lcd_bus <= lcd_bus;
cnt64 <= cnt64;
end
default:begin
lcd_ack_o <= ;
lcd_rs <= ;
lcd_bus <= 'h38;
cnt64 <= cnt64;
end
endcase
end
end endmodule

源码2...

 `timescale  ns /  ps
module lcd1602_cgram_driver(
sys_clk,
sys_rst_n,
lcd_en,
lcd_rw,
lcd_rs,
lcd_bus,
lcd_on,
lcd_blon
);
input sys_clk;
input sys_rst_n;
output lcd_rs;
output lcd_rw;
output lcd_en;
output lcd_on;
output lcd_blon;
output [:] lcd_bus; reg [:] sys_dat_i=;
reg [:] sys_addr_i=;
wire lcd_ack_o; always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
sys_dat_i <= ;
sys_addr_i <= 'h80;
end
else if(lcd_ack_o == 'b1) begin
if(sys_dat_i == 'd7) begin
sys_dat_i <= ;
sys_addr_i <= 'h80;
end
else begin
sys_dat_i <= sys_dat_i + 'd1;
sys_addr_i <= sys_addr_i + 'd1;
end
end
else begin
sys_dat_i <= sys_dat_i;
sys_addr_i <= sys_addr_i;
end
end lcd1602_cgram_controller hal(
.sys_clk( sys_clk ),
.sys_rst_n( sys_rst_n ),
.sys_dat_i( sys_dat_i ),
.sys_addr_i( sys_addr_i ),
.lcd_ack_o( lcd_ack_o ),
.lcd_en( lcd_en ),
.lcd_rw( lcd_rw ),
.lcd_rs( lcd_rs ),
.lcd_bus( lcd_bus ),
.lcd_on( lcd_on ),
.lcd_blon( lcd_blon )
); endmodule

源码3...

`timescale  ns /  ps
module lcd1602_cgram_driver_tsb();
reg sys_clk;
reg sys_rst_n; initial begin
sys_clk=;
sys_rst_n=;
# sys_rst_n=;
end always begin
# sys_clk=~sys_clk;
end wire lcd_rw;
wire lcd_rs;
wire lcd_en;
wire [:] lcd_bus;
wire lcd_on;
wire lcd_blon; lcd1602_cgram_driver api(
.sys_clk( sys_clk ),
.sys_rst_n( sys_rst_n ),
.lcd_en( lcd_en ),
.lcd_rw( lcd_rw ),
.lcd_rs( lcd_rs ),
.lcd_bus( lcd_bus ),
.lcd_on( lcd_on ),
.lcd_blon( lcd_blon )
); endmodule

LCD1602写自定义字符的Verilog源码的更多相关文章

  1. Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析

    这是关于RecyclerView的第二篇,说的是如何自定义Item动画,但是请注意,本文不包含动画的具体实现方法,只是告诉大家如何去自定义动画,如何去参考源代码. 我们知道,RecyclerView默 ...

  2. Jquery+Ajax+asp.net+sqlserver-编写的通用邮件管理(源码)

    开始 邮件管理通常用在各个内部系统中,为了方便快捷的使用现有的代码开发一个邮件管理系统而诞生的. 准备条件 这是我的设计表结构,大家一看就懂了   --邮件接收表CREATE TABLE [dbo]. ...

  3. spring security 之自定义表单登录源码跟踪

    ​ 上一节我们跟踪了security的默认登录页的源码,可以参考这里:https://www.cnblogs.com/process-h/p/15522267.html 这节我们来看看如何自定义单表认 ...

  4. 实现简单的手写涂鸦板(demo源码)

    在一些软件系统中,需要用到手写涂鸦的功能,然后可以将涂鸦的结果保存为图片,并可以将"真迹"通过网络发送给对方.这种手写涂鸦功能是如何实现的了?最直接的,我们可以使用Windows提 ...

  5. 自定义TableViewCell 的方式实现自定义TableView(带源码)

    转载于:http://www.cnblogs.com/macroxu-1982/archive/2012/08/30/2664121.html 实现的效果 实现过程 Step One 创建 自定义Ta ...

  6. [原创]分享本人自己PY写的BOOST编译程序(源码)

    本程序WINDOWS专用,只做抛砖引玉,希望诸位按照各自需求自行修改,主要目的是为了让诸位编译时可以省一些组合指令的时间,只需要修改几个参数即可自动编译. 支持64位编译模式. 改进版本:http:/ ...

  7. 一个基于jQuery写的弹窗效果(附源码)

    最近项目中频繁遇到需要弹出窗口的功能,一直使用浏览器默认的Alert和Confirm弹窗,感觉视觉效果不是那么好,而从网上下载的话又找不到合适的,找到的话有些也是十分臃肿,有时候感觉学习配置的功夫自己 ...

  8. client-go客户端自定义开发Kubernetes及源码分析

    介绍 client-go 是一种能够与 Kubernetes 集群通信的客户端,通过它可以对 Kubernetes 集群中各资源类型进行 CRUD 操作,它有三大 client 类,分别为:Clien ...

  9. 十四.自定义yum仓库、源码编译安装

    pc7:192.168.4.7 1.自定义yum仓库1.1 源码仓库下:/root/tools/other]# createrepo .]# ls ntfs-3g-2014.2.15-6.el6.x8 ...

随机推荐

  1. 4、android BroadcastReceiver详细用法

    BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播. 在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这 ...

  2. UVA 10801 Dij最短路(改模板)

    题意:有n个电梯,目的地是第K层(起点是第0层),给出每个电梯的速度,以及每个电梯能到达的层数,如果中途需要换电梯的话,时间需要+60,求到达目的地的最短时间: 思路:Dij求最短路.如果是另一条路比 ...

  3. SVN 文件解锁

    之前一直一个人用svn,后来团队扩编,同事使用svn下载项目后.我却无法提交了,出现以下错误: locked in another working copy No lock on path (Stat ...

  4. 移动互联网实战--wifi定位和架构

    前言: 非常幸运, 接触过一个与定位服务有些关联的项目. 虽不清楚定位服务内部的实现机制, 但对定位的几种方式也有较清晰的了解. 定位不在局限于GPS, 基站这种需要硬件支持的, 基于wifi的方式更 ...

  5. lnmp 在nginx中配置相应的错误页面error_page

    1. 创建自己的404.html页面 2.更改nginx.conf在http定义区域加入: fastcgi_intercept_errors on; 3.更改nginx.conf(或单独网站配置文件, ...

  6. 强大的wget

    转载自:http://www.cnblogs.com/lidp/archive/2010/03/02/1696447.html 需要下载某个目录下面的所有文件.命令如下 wget -c -r -np ...

  7. ATMEL处理器自带USB CDC的Win7驱动问题

    [背景] 很久以前使用ATMEL的处理器开发了一款设备,通过处理器本身的功能,借助USB在PC端虚拟一个串口出来,实现和上位机软件的通信,和基本的参数设置和数据读取功能. 这个功能就是ATMEL官网上 ...

  8. ajax中返回json数据有"

    1.将“转义为\" string table=sb.ToString(); table.Replace("\"","\\\"");

  9. Android之旅---广播(BroadCast)

    什么是广播 在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制.我们拿广播电台来做个比方.我们平常使用收音机收音是这样的:许许多多不同的广播电台通过特定的频率来发送他们 ...

  10. [Spring MVC] - Annotation验证

    使用Spring MVC的Annotation验证可以直接对view model的简单数据验证,注意,这里是简单的,如果model的数据验证需要有一些比较复杂的业务逻辑性在里头,只是使用annotat ...