在读本文之前,请先阅读 LCD1602 的 datasheet(百度到处都是) ,熟悉有关的11条指令集。

LCD1602的11个指令集链接 http://www.cnblogs.com/aslmer/p/5801363.html(这是我总结的11条指令集,中英文结合)


1、LCD1602基础知识

(2)LCD1602操作流程


2、代码:

module lcd_1602_driver(
clk ,
rst_n ,
lcd_en ,
lcd_rw , //因为只执行写操作,所以永远为0.
lcd_rs ,
lcd_data );
input clk ;
input rst_n ; output lcd_en ;
output lcd_rw ;
output lcd_rs ;
output [:] lcd_data;
wire clk ;
wire rst_n ;
wire lcd_en ;
wire lcd_rw;
reg [:] lcd_data;
reg lcd_rs ;
reg [:] c_state ;
reg [:] n_state ;
wire [:] row_1;
wire [:] row_2;
assign row_1 ="i am liu xiao yi" ; //第一行显示的内容
assign row_2 ="happy everyday !"; //第二行显示的内容
//----------------------------------------------------------------------
//initialize
//first step is waitng more than 20 ms. 数据手册要求的,目的是等待系统上电稳定。
parameter TIME_20MS = 1000_000 ; //20000000/20=1000_000
//parameter TIME_15MS = 9'h100 ; //just for test
parameter TIME_500HZ= 100_000 ; //
//parameter TIME_500HZ= 4'hf; //just for test
//use gray code
parameter IDLE= 'h00 ; //因为此状态机一共有40个状态,所以这里用了格雷码,一次只有1位发生改变。00 01 03 02
parameter SET_FUNCTION= 'h01 ;
parameter DISP_OFF= 'h03 ;
parameter DISP_CLEAR= 'h02 ;
parameter ENTRY_MODE= 'h06 ;
parameter DISP_ON = 'h07 ;
parameter ROW1_ADDR= 'h05 ;
parameter ROW1_0= 'h04 ;
parameter ROW1_1= 'h0C ;
parameter ROW1_2= 'h0D ;
parameter ROW1_3= 'h0F ;
parameter ROW1_4= 'h0E ;
parameter ROW1_5= 'h0A ;
parameter ROW1_6= 'h0B ;
parameter ROW1_7= 'h09 ;
parameter ROW1_8= 'h08 ;
parameter ROW1_9= 'h18 ;
parameter ROW1_A= 'h19 ;
parameter ROW1_B= 'h1B ;
parameter ROW1_C= 'h1A ;
parameter ROW1_D= 'h1E ;
parameter ROW1_E= 'h1F ;
parameter ROW1_F= 'h1D ; parameter ROW2_ADDR= 'h1C ;
parameter ROW2_0= 'h14 ;
parameter ROW2_1= 'h15 ;
parameter ROW2_2= 'h17 ;
parameter ROW2_3= 'h16 ;
parameter ROW2_4= 'h12 ;
parameter ROW2_5= 'h13 ;
parameter ROW2_6= 'h11 ;
parameter ROW2_7= 'h10 ;
parameter ROW2_8= 'h30 ;
parameter ROW2_9= 'h31 ;
parameter ROW2_A= 'h33 ;
parameter ROW2_B= 'h32 ;
parameter ROW2_C= 'h36 ;
parameter ROW2_D= 'h37 ;
parameter ROW2_E= 'h35 ;
parameter ROW2_F= 'h34 ; //20ms的计数器,即初始化第一步
reg [:] cnt_20ms ;
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
cnt_20ms<=;
end
else if(cnt_20ms == TIME_20MS -)begin
cnt_20ms<=cnt_20ms;
end
else
cnt_20ms<=cnt_20ms + ;
end
wire delay_done = (cnt_20ms==TIME_20MS-)? 'b1 : 1'b0 ;
//----------------------------------------------------------------------
//500ns 这里是分频,因为LCD1602的工作频率是500HZ,而FPGA是50Mhz,所以要分频
reg [:] cnt_500hz;
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
cnt_500hz <= ;
end
else if(delay_done==)begin
if(cnt_500hz== TIME_500HZ - )
cnt_500hz<=;
else
cnt_500hz<=cnt_500hz + ;
end
else
cnt_500hz<=;
end assign lcd_en = (cnt_500hz>(TIME_500HZ-)/)? 'b0 : 1'b1; //下降沿
assign write_flag = (cnt_500hz==TIME_500HZ - ) ? 'b1 : 1'b0 ; //set_function ,display off ,display clear ,entry mode set
//----------------------------------------------------------------------状态机
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
c_state <= IDLE ;
end
else if(write_flag==) begin
c_state<= n_state ;
end
else
c_state<=c_state ;
end always @(*)begin
case (c_state)
IDLE: n_state = SET_FUNCTION ;
SET_FUNCTION: n_state = DISP_OFF ;
DISP_OFF: n_state = DISP_CLEAR ;
DISP_CLEAR: n_state = ENTRY_MODE ;
ENTRY_MODE: n_state = DISP_ON ;
DISP_ON : n_state = ROW1_ADDR ;
ROW1_ADDR: n_state = ROW1_0 ;
ROW1_0: n_state = ROW1_1 ;
ROW1_1: n_state = ROW1_2 ;
ROW1_2: n_state = ROW1_3 ;
ROW1_3: n_state = ROW1_4 ;
ROW1_4: n_state = ROW1_5 ;
ROW1_5: n_state = ROW1_6 ;
ROW1_6: n_state = ROW1_7 ;
ROW1_7: n_state = ROW1_8 ;
ROW1_8: n_state = ROW1_9 ;
ROW1_9: n_state = ROW1_A ;
ROW1_A: n_state = ROW1_B ;
ROW1_B: n_state = ROW1_C ;
ROW1_C: n_state = ROW1_D ;
ROW1_D: n_state = ROW1_E ;
ROW1_E: n_state = ROW1_F ;
ROW1_F: n_state = ROW2_ADDR ; ROW2_ADDR: n_state = ROW2_0 ;
ROW2_0: n_state = ROW2_1 ;
ROW2_1: n_state = ROW2_2 ;
ROW2_2: n_state = ROW2_3 ;
ROW2_3: n_state = ROW2_4 ;
ROW2_4: n_state = ROW2_5 ;
ROW2_5: n_state = ROW2_6 ;
ROW2_6: n_state = ROW2_7 ;
ROW2_7: n_state = ROW2_8 ;
ROW2_8: n_state = ROW2_9 ;
ROW2_9: n_state = ROW2_A ;
ROW2_A: n_state = ROW2_B ;
ROW2_B: n_state = ROW2_C ;
ROW2_C: n_state = ROW2_D ;
ROW2_D: n_state = ROW2_E ;
ROW2_E: n_state = ROW2_F ;
ROW2_F: n_state = ROW1_ADDR ;
default: n_state = n_state ;
endcase
end assign lcd_rw = ;
always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
lcd_rs <= ; //order or data 0: order 1:data
end
else if(write_flag == )begin
if((n_state==SET_FUNCTION)||(n_state==DISP_OFF)||
(n_state==DISP_CLEAR)||(n_state==ENTRY_MODE)||
(n_state==DISP_ON ) ||(n_state==ROW1_ADDR)||
(n_state==ROW2_ADDR))begin
lcd_rs<= ;
end
else begin
lcd_rs<= ;
end
end
else begin
lcd_rs<=lcd_rs;
end
end always @(posedge clk or negedge rst_n)begin
if(rst_n=='b0)begin
lcd_data<= ;
end
else if(write_flag)begin
case(n_state) IDLE: lcd_data <= 'hxx;
SET_FUNCTION: lcd_data <= 'h38; //2*16 5*8 8位数据
DISP_OFF: lcd_data <= 'h08;
DISP_CLEAR: lcd_data <= 'h01;
ENTRY_MODE: lcd_data <= 'h06;
DISP_ON : lcd_data <= 'h0c; //显示功能开,没有光标,且不闪烁,
ROW1_ADDR: lcd_data <= 'h80; //00+80
ROW1_0: lcd_data <= row_1 [:];
ROW1_1: lcd_data <= row_1 [:];
ROW1_2: lcd_data <= row_1 [:];
ROW1_3: lcd_data <= row_1 [: ];
ROW1_4: lcd_data <= row_1 [ : ];
ROW1_5: lcd_data <= row_1 [ : ];
ROW1_6: lcd_data <= row_1 [ : ];
ROW1_7: lcd_data <= row_1 [ : ];
ROW1_8: lcd_data <= row_1 [ : ];
ROW1_9: lcd_data <= row_1 [ : ];
ROW1_A: lcd_data <= row_1 [ : ];
ROW1_B: lcd_data <= row_1 [ : ];
ROW1_C: lcd_data <= row_1 [ : ];
ROW1_D: lcd_data <= row_1 [ : ];
ROW1_E: lcd_data <= row_1 [ : ];
ROW1_F: lcd_data <= row_1 [ : ]; ROW2_ADDR: lcd_data <= 'hc0; //40+80
ROW2_0: lcd_data <= row_2 [:];
ROW2_1: lcd_data <= row_2 [:];
ROW2_2: lcd_data <= row_2 [:];
ROW2_3: lcd_data <= row_2 [: ];
ROW2_4: lcd_data <= row_2 [ : ];
ROW2_5: lcd_data <= row_2 [ : ];
ROW2_6: lcd_data <= row_2 [ : ];
ROW2_7: lcd_data <= row_2 [ : ];
ROW2_8: lcd_data <= row_2 [ : ];
ROW2_9: lcd_data <= row_2 [ : ];
ROW2_A: lcd_data <= row_2 [ : ];
ROW2_B: lcd_data <= row_2 [ : ];
ROW2_C: lcd_data <= row_2 [ : ];
ROW2_D: lcd_data <= row_2 [ : ];
ROW2_E: lcd_data <= row_2 [ : ];
ROW2_F: lcd_data <= row_2 [ : ];
endcase
end
else
lcd_data<=lcd_data ;
end endmodule

3、testbench

`timescale  ns/ ns

module lcd1602_tb();

//时钟和复位
reg clk ;
reg rst_n; wire lcd_en ;
wire lcd_rs ;
wire lcd_rw ;
wire [:] lcd_data;
//时钟周期,单位为ns,可在此修改时钟周期。
parameter CYCLE = ; //复位时间,此时表示复位3个时钟周期的时间。
parameter RST_TIME = ; //待测试的模块例化
lcd_1602_driver u1_lcd_1602_driver(
.clk (clk ),
.rst_n (rst_n ),
.lcd_en (lcd_en ),
.lcd_rw (lcd_rw ),
.lcd_rs (lcd_rs ),
.lcd_data(lcd_data) ); //生成本地时钟50M
initial begin
clk = ;
forever
#(CYCLE/)
clk=~clk;
end //产生复位信号
initial begin
rst_n = ;
#;
rst_n = ;
#(CYCLE*RST_TIME);
rst_n = ;
end endmodule

4、modesim 仿真


5、结果展示及总结

易错之处:1、忽略了lcd1602的正常工作频率

2、显示地址需要加80

3、这篇文章只是lcd1602的基本显示,下一目标就是要自定义汉字,会用到CGRAM的相关知识,详情请见下篇文章,链接如下

 http://www.cnblogs.com/aslmer/p/5819868.html,欢迎提问并给出宝贵意见

 
转载请注明出处:http://www.cnblogs.com/aslmer/p/5819422.html

verilog写的LCD1602 显示的更多相关文章

  1. 是否有必要学习使用纯Verilog写一个SDRAM控制器

    在做这个SDRAM控制器之前,博主有一个疑问,对于学生来说,是否有必要学习用纯Verilog写一个SDRAM控制器?因为目前X家和A家都有了DDR IP Core,对于要实现一个应用可以直接调用IP ...

  2. 实现 AD 采样,使用 LCD1602 显示 AD 数值

    实现 AD 采样,使用 LCD1602 显示 AD 数值 写在前面 单片机内集成的A/D转换,一般都有相应的特殊功能寄存器来设置A/D的使能标志,参考电压,转换频率,通道选择,A/D输入口的属性(模拟 ...

  3. LCD1602显示中文汉字

    小子在西藏 2011-11-25编写 特别说明笔者是上面的作者,感谢那些原意分享知识的人.时隔5年我又看到了笔者当年写的东西,我想这期间还有许许多多的人 今天写在博客上,愿更多后来者可以学习. LCD ...

  4. 51单片机—LCD1602显示模块

    文章目录 - 什么是LCD1602 - 如何操作LCD1602 - 上代码 - 什么是LCD1602 LCD:Liquid Crystal Display-液晶显示器,简称LCD,其主要显示原理是以电 ...

  5. 3.5.基于STC89C52+MC20的短信远程控制开关LCD1602显示

    需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...

  6. 树莓派的演奏音符3 -- LCD1602显示文章

    LCD1602它是低-cost输出装置.它具有体积小.简单的操作.低功耗优势.因此,在一些DIY 用它来输出关于产品的一些信息. 昨日在使用,尽管平局网上资源,但仍存在一些问题,确处理. 一.LCD1 ...

  7. Verilog写一个对数计算模块Log2(x)

    网上一个能用的也没有,自己写一个把. 1.计算原理:  整数部分 网上找到了一个c语言的计算方法如下: int flog2(float x) { return ((unsigned&)x> ...

  8. 写一个TimeUI显示的函数,上代码

    public void FreshDateTime() { string strWeek = string.Empty; #region 格式化星期 switch (DateTime.Now.DayO ...

  9. [FPGA]浅谈LCD1602字符型液晶显示器(Verilog)

    目录 概述 LCD1602 LCD1602是什么? LCD1602的管脚 RS_数据/命令选择 E_使能 D0-D7 LCD1602有个DDRAM LCD1602还有个CGROM 指令集 清屏 进入模 ...

随机推荐

  1. 【虚拟机-网关】如何在使用应用程序网关和 Nginx 的环境下实现强制 HTTPS 跳转

    背景介绍 大家在使用 Nginx 部署网站时,实现 HTTP 到 HTTPS 的强制跳转是非常容易的事情,一般可以使用rewrite 命令或者使用返回自定义 301 页面的方法对 HTTP 请求进行 ...

  2. AD 域复制FRS 迁移到DFSR

    假设您尝试将在先前版本的Windows Server上运行的某个Active Directory域控制器(DC)升级到Windows Server 2019. 您可能会看到以下错误: “副本验证失败. ...

  3. Kail安装后的配置

    安装完Kail系统后进行简单的几项配置可以让使用更方便 VMware安装Kail系统这里就不介绍了,大家可以参考这个博客:http://www.cnblogs.com/xuanhun/p/568831 ...

  4. 在广州学习PHP零基础可以学习吗?

    PHP现今作为互联网运用很广泛的编程语言,市场需求量也越来越高,而PHP开发工程师的薪资也是一路水涨船高,更多的人看到了PHP的发展前景,纷纷都想投入到PHP的开发大军中来,那么对于很多转行或者零基础 ...

  5. CPP-基础:extern"C"

    简介:extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的:其次,被它修饰的目标是“C”的.让我们来详细解读这两重含义. 含义: 1.被e ...

  6. 11.使用while和for循环分别打印字符串s=’asdfer’中每个元素

    1).for循环 s = 'asdfer' for i in s: print(i) 2).while循环 s = 'asdfer' while 1: print(s[index]) index += ...

  7. Python——流程控制语句

    if语句 条件进行判断,满足,则执行里面 的内容:不满足,则执行if循环下面的语句 基本语法: if 判断条件: 满足后执行语句 1 如果:女人的年龄>30岁,那么:叫阿姨 age_of_gir ...

  8. Nodejs:npm run build之后,dist\index.html页面在火狐中可以正常显示登录页面并登录成功,在Chrome中可以正常显示登录页面,登录失败

    问题描述:Nodejs:npm run build之后,dist\index.html页面在火狐中可以正常显示登录页面并登录成功,在Chrome中可以正常显示登录页面,登录失败 解决方法:将打包后的d ...

  9. Template 基础篇-函数模板(待看

    Template 基础篇-函数模板 Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分. Template ...

  10. vector总结(更新中。。。)

    vector中这两个属性很容易弄混淆. size是当前vector容器真实占用的大小,也就是容器当前拥有多少个容器. capacity是指在发生realloc前能允许的最大元素数,即预分配的内存空间. ...