LCD1602液晶显示实验Word文件下载.docx
《LCD1602液晶显示实验Word文件下载.docx》由会员分享,可在线阅读,更多相关《LCD1602液晶显示实验Word文件下载.docx(24页珍藏版)》请在冰点文库上搜索。
![LCD1602液晶显示实验Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/1/5e0eea7e-2853-4385-80dd-ca013b60f27f/5e0eea7e-2853-4385-80dd-ca013b60f27f1.gif)
3
VL
液晶显示偏压
11
D4
4
RS
数据/命令选择
12
D5
5
R/W
读/写选择
13
D6
6
E
使能信号
14
D7
7
D0
15
BLA
背光源正极
8
D1
16
BLK
背光源负极
1.1.31602LCD的指令说明及时序
1602液晶模块内部的控制器共有11条控制指令,如表1-4所示:
表1-4控制命令表
序号
指令
清显示
光标返回
*
置输入模式
I/D
S
显示开/关控制
D
C
B
光标或字符移位
S/C
R/L
置功能
DL
N
F
置字符发生存贮器地址
字符发生存贮器地址
置数据存贮器地址
显示数据存贮器地址
读忙标志或地址
BF
计数器地址
写数到CGRAM或DDRAM)
要写的数据内容
从CGRAM或DDRAM读数
读出的数据内容
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:
1为高电平、0为低电平)读写操作时序如图1-5和1-6所示:
图1-5读操作时序
图1-6写操作时序
1.1.41602LCD的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以,在执行每条指令之前,一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
要显示字符时,要先输入显示字符地址,也就是告诉模块在哪里显示字符,图1-7是1602的内部显示地址。
图1-71602LCD内部显示地址
例如,第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?
这样不行,因为写入显示地址时要求最高位D7恒定为高电平1,所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。
在对液晶模块的初始化中,要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。
每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:
阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”
因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,编程中还可以用字符型常量或变量赋值,如“A”。
1602通过D0~D7的8位数据端传输数据和指令。
1.1.51602LCD的一般初始化(复位)过程
延时15mS
写指令38H(不检测忙信号)
延时5mS
以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:
显示模式设置
写指令08H:
显示关闭
写指令01H:
显示清屏
写指令06H:
显示光标移动设置
写指令0CH:
显示开及光标设置
1.2任务1及其原理
任务1:
更改lcd上显示的字符。
通过更改wire[127:
0]row1_val,wire[127:
0]row2_val的赋值即可,注意保证“”内的字符数包括空格共16位。
1.3任务2及其原理
任务2:
将“LCD1602驱动模块”文件与“LCD1602驱动测试模块”文件合并成为一个verilog文件。
首先,新建一个顶层VerilogHDL文件,将两个文件的输入,内容合并,调试新的模块,然后将管脚连接在一起,从而完成合并。
1.4任务3及其原理
任务3:
实现液晶屏的某一位完成0~9的循环变换,并且设置复位键,在循环过程中按下复位键循环可从0重新开始。
完成本次的实验想法是将“LCD1602驱动测试模块”文件中wire[127:
0]row2_val变量进行改动,将row1_val原本赋予的字符替换为一个变量,设定新的时钟,即循环变换的间隔时间,再通过条件语句控制循环。
使能键的控制原理是通过对循环变换的条件进行操作实现的,即当按键使能时循环开始,反之,则从0开始。
2.实验流程图
0~9循环变换流程图
3.实验程序
3.1任务1程序
程序更改部分:
wire[127:
0]row1_val="
liuwupeng"
;
wire[127:
0]row2_val="
2009081206"
3.2任务2程序
将测试模块中的驱动部分,两个文件的对应命名只留其一,合并两文件,即以下部分
//例化LCD1602驱动
lcd1602_driveu0(
.clk(CLOCK_50M),
.rst_n(Q_KEY),
.row1_val(row1_val),
.row2_val(row2_val),
.lcd_data(LCD1602_DATA),
.lcd_e(LCD1602_E),
.lcd_rs(LCD1602_RS),
.lcd_rw(LCD1602_RW));
完整程序请参见附件:
3.3任务3程序
改动模块:
LCD1602驱动测试模块,加重处为修改、添加部分
modulelcd1602_test(
inputCLOCK_50M,//板载时钟25MHz
inputQ_KEY,//板载按键RST
output[7:
0]LCD1602_DATA,//LCD1602数据总线
outputLCD1602_E,//LCD1602使能
outputLCD1602_RS,//LCD1602指令数据选择
outputLCD1602_RW,//LCD1602读写选择
outputSEL0,//LCD1602读写选择
outputSEL1,//LCD1602读写选择
outputSEL2//LCD1602读写选择
inputkey,//使能控制键
);
reg[127:
0]row1_val;
//将原本的wire型改为reg型,保证其可变
"
//将第二行赋值都是空格,实验时显示为空
reg[7:
0]a;
//a变化控制reg[127:
0]row1_val
reg[3:
0]i;
reg[25:
0]cnt;
//分频用
regen;
//使能控制
assignSEL0=1'
b0;
assignSEL1=1'
assignSEL2=1'
b1;
always@(posedgeCLOCK_50M,negedgeQ_KEY)
if(!
Q_KEY)cnt<
=0;
elsecnt<
=cnt+1'
wirelcd_clk=cnt[25];
//分频模块
always@(a)
begin
row1_val[7:
0]<
=a;
end//将a赋给row1_val[7:
0]的低8位
always@(negedgekey)
if(en==0)en<
=1;
else
en<
=0;
end//使能控制模块,下降沿有效
always@(posedgelcd_clk)
if(en)
if(i<
=8)
a=a+1;
i=i+1;
end
i=0;
a=8'
h30;
else
//通过条件控制语句实现0~9的循环变换
//例化LCD1602驱动
.rst_n(Q_KEY),
//LCD1602InputValue
.row2_val(row2_val),
//LCD1602Interface
.lcd_rw(LCD1602_RW)
endmodule
4.管脚分配
4.1任务2管教分配
4.2任务3管教分配
5.实验结果
5.1任务1实验结果
修改程序后,液晶屏第一行显示"
,第二行显示"
。
5.2任务2实验结果
文件合并后,显示内容仍与原始程序相同。
5.3任务3实验结果
液晶屏第一行最后一位可实现0~9的循环变换,拨动复位键,计数从0重新开始。
6.实验心得
通过本次实验,我了解了LCD-1602的构成及使用方法,能够通过编程显示字符。
在完成课堂任务“实现某一位0~9循环变换”时,起初由于没有掌握LCD的工作原理,出现了问题,即0~9快速变化,无法控制其速度,经过对程序及实验原理的研究,最后完成了任务。
FPGA实验是锻炼编程能力、逻辑思维能力的一门很好的课程,我现在所欠缺的便是缜密的思维及查错的能力,还望在以后实验中提高。
通过这次实验,学到了很多东西,体会到了自己实现一个程序功能的小小喜悦,也认识到了自己只是FPGA道路上的新手,还有很多未知的知识需要学习。
真正学习的历程需要在课下多下功夫,希望通过这学期的学习自己能熟练掌握一些编程的技术,培养良好的思维模式。
附件:
modulehebing(
inputclk,//50MHz时钟
inputrst_n,//复位信号
input[127:
0]row1_val,//第一行字符
0]row2_val,//第二行字符
outputSEL2,//LCD1602读写选择
outputreg[7:
0]lcd_data,//数据总线
outputlcd_e,//使能信号
outputreglcd_rs,//指令、数据选择
outputlcd_rw//读、写选择
//0~(8*16-1)=128
//16bits->
0123456789ABCDEF<
-
//+++++++++++++++++++++++++++++++++++++
//分频模块开始
reg[15:
//计数子
always@(posedgeclk,negedgerst_n)
rst_n)
cnt<
//500Khz~1MHz皆可
wirelcd_clk=cnt[15];
//(2^15/50M)=1.31ms
//-------------------------------------
//分频模块结束
//LCD1602驱动模块开始
//格雷码编码:
共40个状态
parameterIDLE=8'
h00;
//写指令,初始化
parameterDISP_SET=8'
h01;
//显示模式设置
parameterDISP_OFF=8'
h03;
//显示关闭
parameterCLR_SCR=8'
h02;
//显示清屏
parameterCURSOR_SET1=8'
h06;
//显示光标移动设置
parameterCURSOR_SET2=8'
h07;
//显示开及光标设置
//显示第一行
parameterROW1_ADDR=8'
h05;
//写第1行起始地址
parameterROW1_0=8'
h04;
parameterROW1_1=8'
h0C;
parameterROW1_2=8'
h0D;
parameterROW1_3=8'
h0F;
parameterROW1_4=8'
h0E;
parameterROW1_5=8'
h0A;
parameterROW1_6=8'
h0B;
parameterROW1_7=8'
h09;
parameterROW1_8=8'
h08;
parameterROW1_9=8'
h18;
parameterROW1_A=8'
h19;
parameterROW1_B=8'
h1B;
parameterROW1_C=8'
h1A;
parameterROW1_D=8'
h1E;
parameterROW1_E=8'
h1F;
parameterROW1_F=8'
h1D;
//显示第二行
parameterROW2_ADDR=8'
h1C;
//写第2行起始地址
parameterROW2_0=8'
h14;
parameterROW2_1=8'
h15;
parameterROW2_2=8'
h17;
parameterROW2_3=8'
h16;
parameterROW2_4=8'
h12;
parameterROW2_5=8'
h13;
parameterROW2_6=8'
h11;
parameterROW2_7=8'
h10;
parameterROW2_8=8'
parameterROW2_9=8'
h31;
parameterROW2_A=8'
h33;
parameterROW2_B=8'
h32;
parameterROW2_C=8'
h36;
parameterROW2_D=8'
h37;
parameterROW2_E=8'
h35;
parameterROW2_F=8'
h34;
reg[5:
0]current_state,next_state;
//现态、次态
//FSM:
always1
always@(posedgelcd_clk,negedgerst_n)
if(!
rst_n)current_state<
=IDLE;
elsecurrent_state<
=next_state;
always2
always
begin
case(current_state)
IDLE:
next_state=DISP_SET;
//写指令,初始化
DISP_SET:
next_state=DISP_OFF;
DISP_OFF:
next_state=CLR_SCR;
CLR_SCR:
next_state=CURSOR_SET1;
CURSOR_SET1:
next_state=CURSOR_SET2;
CURSOR_SET2:
next_state=ROW1_ADDR;
//显示第一行
ROW1_ADDR:
next_state=ROW1_0;
ROW1_0:
next_state=ROW1_1;
ROW1_1:
next_state=ROW1_2;
ROW1_2:
next_state=ROW1_3;
ROW1_3:
next_state=ROW1_4;
ROW1_4:
next_state=ROW1_5;
ROW1_5:
next_state=ROW1_6;
ROW1_6:
next_state=ROW1_7;
ROW1_7:
next_state=ROW1_8;
ROW1_8:
next_state=ROW1_9;
ROW1_9:
next_state=ROW1_A;
ROW1_A:
next_state=ROW1_B;
ROW1_B:
next_state=ROW1_C;
ROW1_C:
next_state=ROW1_D;
ROW1_D:
next_state=ROW1_E;
ROW1_E:
next_state=ROW1_F;
ROW1_F:
next_state=ROW2_ADDR;
//显示第二行
ROW2_ADDR:
next_state=ROW2_0;
ROW2_0:
next_state=ROW2_1;
ROW2_1:
next_state=ROW2_2;
ROW2_2:
next_state=ROW2_3;
ROW2_3:
next_state=ROW2_4;
ROW2_4:
next_state=ROW2_5;
ROW2_5:
next_state=ROW2_6;
ROW2_6:
next_state=ROW2_7;
ROW2_7:
next_state=ROW2_8;
ROW2_8:
next_state=ROW2_9;
ROW2_9:
next_state=ROW2_A;
ROW2_A:
next_state=ROW2_B;
ROW2_B:
next_state=ROW2_C;
ROW2_C:
next_state=ROW2_D;
ROW2_D:
next_state=ROW2_E;
ROW2_E:
next_state=ROW2_F;
ROW2_F:
//
default:
next_state=IDLE;
endcase
end
always3
rst_n)
begin
lcd_rs<
lcd_data<
=8'
hxx;
//写lcd_rs
case(next_state)
//写数据,显示第一行
=1;
//写数据,显示第二行
lcd