LCD1602液晶显示
LCD1602液晶显示实验报告
一、实验目的
(1)了解LCD1602的基本原理,掌握其基本的工作
。
(2)学习用Verilog HDL语言编写LCD1602的控制指令程序,能够在液晶屏上显示出正确的符号。
(3)能够自行改写程序,并实现符号的动态显示。
二、实验设备与器件
Quartus II 软件、EP2C8Q208C8实验箱
三、实验
设计
1.实验可实现的功能
可以实现在LCD1602液晶屏第一行左侧第一位的位置循环显示0~9,并且可以用一个拨码开关BM8实现显示的复位功能。
2.LCD1602基本知识
LCD1602液晶能够同时显示16x02即32个字符,模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,在单片机编程中还可以用字符型常量或变量赋值,如“A”。1602通过D0~D7的8位数据端传输数据和指令。
3.系统工作原理
系统的状态转换
如图3.1.1所示。通过状态流程图可以看到, LCD1602液晶屏的状态是不断更新的,依次完成液晶的初始化和0~9的动态显示过程,并且过程可由开关控制。
1
开始
IDLE
DISP_SET 显示模式
设置
DISP_OFF 显示关闭
CLR_SCR 显示清屏
CUTSOR_SET1显示
光标移动设置
CURSOR_SET2显示
开关及光标设置
ROW1_ADDR 写第一
行起始地址
ROW1_0字符显示位
置不移动
数字0~9依次显示
拨码复位?
结束Y
N
图3.1.1 状态流程图
4.程序设计
module LCD1602(
input clk, // 50MHz 时钟
input rst_n, //开关信号
output reg [7:0] lcd_data, // 数据总线
output lcd_e, // 使能信号
output reg lcd_rs, // 指令、数据选择
output lcd_rw, // 读、写选择
output SEL0, // LCD1602读写选择
output SEL1, // LCD1602读写选择
output SEL2 // LCD1602读写选择
);
reg [127:120] row1_val; // 第一行字符
reg [23:0] cnt,cnt1;
assign SEL0 = 1'b0;
assign SEL1 = 1'b0;
assign SEL2 = 1'b1;
always @ (posedge clk, negedge rst_n)
if (!rst_n)
cnt <= 0;
else
cnt <= cnt + 1'b1;
wire lcd_clk = cnt[23]; // (2^23 / 50M)=0.168s always@(posedge lcd_clk)
if(cnt1>=24'd2)
begin
reg lcd_clk1;
lcd_clk1=1;
cnt1=0;
end
else
begin
cnt1=cnt1+1; //cnt1对lcd_clk二分频
lcd_clk1=0;
end
always@(posedge lcd_clk1)
begin
row1_val<=8'h30;//设初值
case(row1_val) //数字0~9循环显示8'h30: row1_val<=8'h31;
8'h31: row1_val<=8'h32;
8'h32: row1_val<=8'h33;
8'h33: row1_val<=8'h34;
8'h34: row1_val<=8'h35;
8'h35: row1_val<=8'h36;
8'h36: row1_val<=8'h37;
8'h37: row1_val<=8'h38;
8'h38: row1_val<=8'h39;
8'h39: row1_val<=8'h30;
default: row1_val<=8'h30;
endcase
end
parameter IDLE = 8'h00;
parameter DISP_SET = 8'h01; // 显示模式设置parameter DISP_OFF = 8'h03; // 显示关闭parameter CLR_SCR = 8'h02; // 显示清屏parameter CURSOR_SET1 = 8'h06; // 显示光标移动设置parameter CURSOR_SET2 = 8'h07; // 显示开及光标设置parameter ROW1_ADDR = 8'h05; // 写第1行起始地址parameter ROW1_0 = 8'h04;
reg [5:0] current_state, next_state; // 现态、次态
always @ (posedge lcd_clk, negedge rst_n)
if(!rst_n) current_state <= IDLE;
else current_state <= next_state;//在时钟信号作用期间,次态重复
的赋给现态
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_ADDR;
default : next_state = IDLE ;
endcase
end
always @ (posedge lcd_clk, negedge rst_n)
begin
if(!rst_n)
begin
lcd_rs <= 0;
lcd_data <= 8'hxx;
end
else
begin
case(next_state)
IDLE : lcd_rs <= 0;
DISP_SET : lcd_rs <= 0;
DISP_OFF : lcd_rs <= 0;
CLR_SCR : lcd_rs <= 0;
CURSOR_SET1 : lcd_rs <= 0;
CURSOR_SET2 : lcd_rs <= 0;
ROW1_ADDR : lcd_rs <= 0;
ROW1_0 : lcd_rs <= 1;
endcase
case(next_state)
IDLE : lcd_data <= 8'hxx;
DISP_SET : lcd_data <= 8'h38;
DISP_OFF : lcd_data <= 8'h08;
CLR_SCR : lcd_data <= 8'h01;
CURSOR_SET1 : lcd_data <= 8'h04;
CURSOR_SET2 : lcd_data <= 8'h0C;
ROW1_ADDR : lcd_data <= 8'h80;
ROW1_0 : lcd_data <= row1_val[127:120];
endcase
end
end
assign lcd_e = lcd_clk; // 数据在时钟高电平被锁存
assign lcd_rw = 1'b0; // 只写
endmodule
5.下载电路及引脚分配设计
设计中用实验箱自带的50MHz时钟信号作为输入端,用sel0、sel1、sel2三个使能端选通LCD1602液晶屏,EP2C8Q208C8就会工作在给液晶下命令的状态,使得点阵正常工作,如图3.5.1所示。
图3.5.1 输入输出端口电路
引脚分配设计如图3.5.2所示。
图3.5.2 引脚分配
继续阅读