基于altera 公司cyclone4代芯片的fpga以及quartusII软件设计一款屏幕显示系统,显示装置可以选择点阵或字符型液晶,最终实现滚动显示、可控制滚动方向、暂停、清屏等功能。
原理图工程文件
仿真工程文件
源代码
仿真截图
低重复率论文,字数:19964
本次系统为基于FPGA的显示控制器设计,实现液晶显示器的左翻滚、右翻滚、暂停、清屏的功能。程序编写对各个功能编写程序。系统具有多功能,通过模块化的方式来进行设计,根据各个功能进行编程,在设计上和仿真上均通过模块化的方式进行,保证设计可以减少调试时间,更可以使功能顺利实现。本次系统由于考虑多方面的因素实现了显示控制器设计,具有一定的推广意义和学习意义。
该控制器可以显示字符、图片两个部分。字符显示功能上通过调用RAM实现,可以通过调用液晶显示器内部的字库来实现字符的调用。功能按键实时控制液晶显示器的状态,同步改变LCD上显示的内容,并且将内部RAM的字符图片数据显示在LCD1602显示器中。
本次毕业设计使用FPGA系列产品开发,并且使用到了当前市面上常用的LCD1602液晶显示器。使用FPGA开发系统可以缩短研发系统的开发时间。并且系统分两个模块按键、与液晶显示模块。模块化的设计可以使其应用在更多FPGA系列产品上。基于FPGA的显示控制器设计是当前热门研究方式,具有人机交互意义并且可以使人们生活出现新的改变。
第一章 绪论 1
1.1 研究背景与意义 1
1.2 课题发展现状 1
1.3 国内外发展情况 1
1.31 国外发展情况 2
1.32 国内发展情况 2
1.4 EDA技术的设计流程 2
第二章 系统设计平台及方案 4
2.1 EDA技术发展 4
2.2 FPGA介绍 6
2.21 FPGA工作原理 6
2.22 FPGA基本特点 7
2.3 Quartus II简编程软件的介绍 8
2.31 Quartus II简介 8
2.32 Quartus II设计流程 8
2.4 编程语言介绍 9
2.5 系统设计方案 10
2.51 系统实现功能描述 10
2.52 系统功能框架 11
第三章 系统硬件设计 13
3.1 FPGA最小系统设计 13
3.11 电源电路 13
3.12 晶振电路 14
3.13 复位电路 15
3.14 EPCS4SI8配置芯片电路 15
3.15 下载接口电路 16
3.2 LCD1602电路设计 16
3.3 按键电路设计 19
3.4 系统总电路设计 19
3.5 系统PCB设计 20
第四章 系统软件设计及仿真 22
4.1 系统软件设计 22
4.12 LCD1602控制模块设计 22
4.13 按键模块软件设计 26
4.14 顶层模块设计 28
4.2 系统仿真验证 29
4.21 仿真流程 29
4.22 仿真结果 31
结 论 35
参考文献 37
致 谢 38
附录 39
外文资料原文 50
译文 53
字数:19964
源代码:
library verilog;
use verilog.vl_types.all;
entity lcd1602 is
port(
clk : in vl_logic;
rst_n : in vl_logic;
key1 : in vl_logic;
key2 : in vl_logic;
key3 : in vl_logic;
key4 : in vl_logic;
lcd_rs : out vl_logic;
lcd_rw : out vl_logic;
lcd_en : out vl_logic;
lcd_data : out vl_logic_vector(7 downto 0)
);
end lcd1602;
library verilog;
use verilog.vl_types.all;
entity key_bounce is
port(
key_in : in vl_logic_vector(3 downto 0);
clk : in vl_logic;
rst_n : in vl_logic;
key1 : out vl_logic;
key2 : out vl_logic;
key3 : out vl_logic;
key4 : out vl_logic
);
end key_bounce;
library verilog;
use verilog.vl_types.all;
entity top is
port(
clk : in vl_logic;
rst_n : in vl_logic;
key_in : in vl_logic_vector(3 downto 0);
lcd_rs : out vl_logic;
lcd_rw : out vl_logic;
lcd_en : out vl_logic;
lcd_data : out vl_logic_vector(7 downto 0)
);
end top;
module lcd1602(
input clk ,
input rst_n ,
input key1 ,//左滚动
input key2 ,//右滚动
input key3 ,//暂停
input key4 ,//清屏
output reg lcd_rs ,//0:命令 1:数据
output lcd_rw ,//0:写 1:读
output reg lcd_en ,//使能
output reg [7:0] lcd_data //8-bit
);
assign lcd_rw = 1'b0 ; //只写
reg [4:0] char_cnt ;
reg [7:0] data_display1 =8'b0 ; //第一行数据
reg [7:0] data_display2 =8'b0 ; //第二行数据
localparam S0 = 4'd0 ;
localparam S1 = 4'd1 ;
localparam S2 = 4'd2 ;
localparam S3 = 4'd3 ;
localparam S4 = 4'd4 ;
localparam S5 = 4'd5 ;
localparam S6 = 4'd6 ;
localparam S7 = 4'd7 ;
localparam S8 = 4'd8 ;
localparam IDLE = 4'd9 ;
localparam LEFT = 4'd10 ;
localparam RIGHT = 4'd11 ;
localparam STOP = 4'd12 ;
localparam CLEAR = 4'd13 ;
//localparam cnt_2ms = 17'd50000 ;
// 2ms 时钟计数
//localparam cnt_15ms = 17'd7 ;
// 16ms延时
//localparam cnt_500ms = 17'd249 ;
// 500ms延时
localparam cnt_2ms = 17'd500 ;
// 缩短仿真计数2ms 时钟
localparam cnt_15ms = 17'd7;
// 缩短仿真计数16ms延时
localparam cnt_500ms = 17'd9 ;
// 缩短仿真计数500ms延时
reg [16:0] cnt_en ;
always @(posedge clk or negedge rst_n)
if (!rst_n)
cnt_en <= 17'd0;
else if (cnt_en==cnt_2ms - 1)
cnt_en <= 17'd0;
else
cnt_en <= cnt_en + 1'b1;
//**************************************************************
reg [1:0] key1_reg ;
//同步key1 ,左滚动
reg [1:0] key2_reg ;
//同步key2 ,右滚动
reg [1:0] key3_reg ;
//同步key3 ,暂停
reg [1:0] key4_reg ;
//同步key4 ,清屏
wire [3:0] key ;
assign key ={key4_reg[1],key3_reg[1],key2_reg[1],key1_reg[1]};
always @(posedge lcd_en or negedge rst_n)
if (!rst_n)begin
key1_reg <= 2'b11;
key2_reg <= 2'b11;
key3_reg <= 2'b11;
key4_reg <= 3'b111;
end
else begin
key1_reg <= {key1_reg[0], key1};
key2_reg <= {key2_reg[0], key2};
key3_reg <= {key3_reg[0], key3};
key4_reg <= {key4_reg[0], key4};
end
//**********************************************
always @(posedge clk or negedge rst_n) //lcd_en为500khz
if (!rst_n)
lcd_en <= 1'b0;
else if (cnt_en==cnt_2ms - 1)
lcd_en <= ~lcd_en;
reg [3:0] state;
reg [31:0] cnt;
always @(posedge lcd_en or negedge rst_n)
begin
if(!rst_n)begin
cnt <= 1'b0;
lcd_rs <= 1'b0;
lcd_data <= 1'b0;
state <= S0;
char_cnt <= 4'd0;
end
else case(state)
S0:begin
lcd_rs <= 1'b0; //15ms延时
if(cnt==cnt_15ms) begin
cnt <= 10'b0;
state <= S1;
end
else begin
cnt <= cnt+1'b1;
state <= state;
end
end
S1:begin
lcd_rs <= 1'b0;
//功能设定,数据8位,显示2行,5x7点阵
lcd_data <= 8'b0011_1000;
state <= S2;
end
S2:begin
lcd_rs <= 1'b0;
/显示开关控制,一直显示,无光标。
lcd_data <= 8'b0000_1100; //8'b0000_1ABC;
A:显示功能;0关1开。
state <= S3; /
/B:光标; 0无1有。
end
//C:光标闪 ; 0闪1不闪。
S3:begin
lcd_rs <= 1'b0;
//清屏,指令码01h
lcd_data <= 8'h01;
state <= S4;
end
S4:begin
lcd_rs <= 1'b0;
//设置模式,写入一个数据,光标右移
lcd_data <= 8'b0000_0101;
//8'b0000_01DS; DS: 00光标左移,10光标右移
state <= S5;
//10显示屏不移动,11显示屏右移
end
S5:begin
lcd_rs <= 1'b0;
//设置第一行地址
lcd_data <= 8'b10000000;
高位
state <= S6;
end
S6:begin
lcd_rs <= 1'b1;
//写入第一行数据
lcd_data <= data_display1;
char_cnt <= char_cnt+1'b1;
if(char_cnt==5'd15)begin
state <= S7;
end
else
state <= state;
end
S7:begin
lcd_rs <= 1'b0;
//设置第二行地址
lcd_data <= 8'b11000000;
state <= S8;
end
S8:begin
lcd_rs <= 1'b1;
//写入第二行数据
lcd_data <= data_display2;
char_cnt <= char_cnt+1'b1;
if(char_cnt==5'd31)begin
state <= IDLE;
char_cnt <= 5'd0;
end
else
state <= S8;
end
****************以上都是初始****************************//
IDLE:begin
lcd_rs <= 1'b0;
cnt <= 0;
lcd_data<= 8'b0;
begin
case(key)
4'b1110:state <= LEFT ;
4'b1101:state <= RIGHT ;
4'b1011:state <= STOP ;
4'b0111:state <= CLEAR ;
default: state <= IDLE;
endcase
end
end
LEFT:begin
lcd_rs <= 1'b0;
begin
case(key)
4'b1110:state <= LEFT ;
4'b1101:state <= RIGHT ;
4'b1011:state <= STOP ;
4'b0111:state <= CLEAR ;
default: state <= LEFT ;
endcase
//左滚动,0.5s移动一次。
end
//设置显示屏或光标移动方向,
begin
if(cnt==1) //8'b0001_AB00; AB: 00光标左移,01光标右移;
lcd_data <= 8'b0001_1000;
//10显示屏左移,11显示屏右移 ;
else
lcd_data <= 8'h0;
end
begin
if(cnt==cnt_500ms)
cnt <= 0;
else
cnt<=cnt+1'b1;
end
end
RIGHT:begin
lcd_rs <= 1'b0;
begin
case(key)
//右滚动,0.5s移动一次。
4'b1110:state <= LEFT ;
//设置显示屏或光标移动方向,
4'b1101:state <= RIGHT ;
//8'b0001_AB00; AB: 00光标左移,01光标右移;
4'b1011:state <= STOP ;
//10显示屏左移,11显示屏右移 ;
4'b0111:state <= CLEAR ;
default: state <= RIGHT;
endcase
end
begin
if(cnt==1)
lcd_data <= 8'b0001_1100;
else
lcd_data <= 8'h0;
end
begin
if(cnt==cnt_500ms)
cnt <= 0;
else
cnt<=cnt+1'b1;
end
end
STOP:begin
//暂停
cnt <= 32'b0;
lcd_data<= 8'b0;
lcd_rs <= 1'b0;
case(key)
4'b1110:state <= LEFT ;
4'b1101:state <= RIGHT ;
4'b1011:state <= STOP ;
4'b0111:state <= CLEAR ;
default: state <= STOP;
endcase
end
CLEAR:begin
//清屏
cnt <= 32'b0;
lcd_rs <= 1'b0;
lcd_data<= 8'h01;
case(key)
4'b1110:state <= LEFT ;
4'b1101:state <= RIGHT ;
4'b1011:state <= STOP ;
4'b0111:state <= CLEAR ;
default: state <= CLEAR;
endcase
end
default:state <= 4'd0;
endcase
end
always @(*) begin
//第一行数据显示“hello chengdu”
case(char_cnt)
5'd0: data_display1 = "h";
5'd1: data_display1 = "e";
5'd2: data_display1 = "l";
5'd3: data_display1 = "l";
5'd4: data_display1 = "o";
5'd5: data_display1 = " ";
5'd6: data_display1 = "c";
5'd7: data_display1 = "h";
5'd8: data_display1 = "e";
5'd9: data_display1 = "n";
5'd10: data_display1 = "g";
5'd11: data_display1 = "d";
5'd12: data_display1 = "u";
5'd13: data_display1 = "-";
5'd14: data_display1 = "-";
5'd15: data_display1 = "-";
//第二行数据显示“---2021-03-15---”
5'd16: data_display2 = "-";
5'd17: data_display2 = "-";
5'd18: data_display2 = "-";
5'd19: data_display2 = "-";
5'd20: data_display2 = "2";
5'd21: data_display2 = "0";
5'd22: data_display2 = "2";
5'd23: data_display2 = "1";
5'd24: data_display2 = "-";
5'd25: data_display2 = "0";
5'd26: data_display2 = "3";
5'd27: data_display2 = "-";
5'd28: data_display2 = "1";
5'd29: data_display2 = "5";
5'd30: data_display2 = "-";
5'd31: data_display2 = "-";
default:begin
data_display1 = "-";
data_display2 = "-";
end
endcase
end
endmodule