2基于fpga实现5.0英寸的TFT显示屏的控制

实战描述:通过按键来切换TFT屏上的八种不同的颜色。

LCD的显示与VGA的显示时序基本一致。不过他们与fpga的引脚不一样,并且相对VGA,LCD与fpga多连接一个引脚,tft_de。VGA时序:

一行或一场(又称一帧)有四部分:低电平同步脉冲、显示后沿、有效数据、显示前沿。800*480是有效数据的区域。

行同步:

场同步:

 输入数据的行时序参数:这个红框是正点原子的。这里参考了部分数据,选择的低电平同步脉冲、显示后沿、有效数据、显示前沿分别是1、46、846、210。

输入数据的场时序参数:这个红框是正点原子的。这里参考了部分数据,选择的低电平同步脉冲、显示后沿、有效数据、显示前沿分别是1、24、504、20。

当MODE引脚拉高时,选择DE同步模式,此时行场同步信号VS和HS必须为高电平;当MODE引脚拉低时,选择HV同步模式,此时数据使能信号DE必须为低电平。

使用的是5.0英寸显示屏:800*480。这个分辨率表示屏幕有480行,800列,即屏幕有480条水平线,每一条水平线上有800个像素点。显示屏输入数据的时序图(DE模式):

RGB格式即一个像素由R、G、B三基色构成,例如 RGB565 格式的像素排列为R[4:0]、G[5:0]、B[4:0],RGB三个分量的数值不同,最后合成的像素颜色则不同。

代码实现从左向右、从上向下扫描,如果计数值在有效数据的矩阵区域,那么rgb的数值就会传送过来。第一行的TFT行扫描计数器计算到有效数据区域,数据就会装进这一行中就不会动,然后TFT行扫描计数器扫描第二行,计算到有效数据区域,数据也会装到这一行中,以此类推在人眼没有反应过来时,所有行都已经装入这个数据,然后屏幕就会显示这个颜色:

扫描完这里算一帧。

具体代码实现:

LCD屏幕与fpga芯片的连接有六个引脚:

output tft_vclk                    //采样时钟

output tft_blank                //背光控制信号

output tft_hs                   //行同步信号

output tft_vs                   //场同步信号

output tft_de                   //数据使能

output [15:0]tft_rgb        //RGB565颜色数据

其中采样时钟是33.3M,设置成33M也可以。背光控制信号让他一直为高电平。由时序图可以看出行同步信号和场同步信号需要经过同步之后才拉高。后面还有一小节拉低不管他,就让他们一直拉高。数据使能之后才把电平传输给LCD屏幕。


 顶层模块tft.v

module tft(
input sys_clk,
input sys_rst_n,
input key,
output [15:0]tft_rgb,
output tft_hs,
output tft_vs,
output tft_blank,
output tft_de,
output tft_vclk
);

reg [2:0]key_cnt;
wire clk_33M;
wire [15:0]rgb;

wire key_flag;
wire key_value;
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
key_cnt<=3'd0;
else if(key_flag && (!key_value))
key_cnt<=key_cnt+3'd1;
else if(key_cnt>3'd7)
key_cnt<=3'd0;
else
key_cnt<=key_cnt;
end

key_filter u_key_filter(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.key_flag (key_flag),
.key_value (key_value)
);

pll u_pll(
.inclk0 (sys_clk),
.areset (!sys_rst_n), //这里注意是复位的取反,不然产生不了33M时钟驱动不了tft屏
.c0 (clk_33M)
);

rgb_gen u_rgb_gen(
.clk_33M (clk_33M),
.sys_rst_n (sys_rst_n),
.key_cnt (key_cnt),
.rgb (rgb)
);

tft_drive u_tft_drive(
.clk_33M (clk_33M),
.sys_rst_n (sys_rst_n),
.data_in (rgb),
.tft_rgb (tft_rgb),
.tft_hs (tft_hs),
.tft_vs (tft_vs),
.tft_blank (tft_blank),
.tft_de (tft_de),
.tft_vclk (tft_vclk)
);
endmodule

驱动tft屏幕的模块tft_drive.v

module tft_drive(
input clk_33M,
input sys_rst_n,
input [15:0]data_in,//准备好显示的颜色
output [15:0]tft_rgb,//输出颜色
output tft_hs,//行同步信号
output tft_vs,//场同步信号
output tft_blank,
output tft_de,
output tft_vclk
);

assign tft_blank=1'b1; //RGB LCD显示模块背光控制信号,也有写成tft_blank=sys_rst_n;
assign tft_vclk=clk_33M;

parameter
TFT_HS_end=12'd1,
hdat_begin=12'd46,
hdat_end=12'd846,
hpixel_end=12'd1056,
TFT_VS_end=12'd1,
vdat_begin=12'd24,
vdat_end=12'd504,
vline_end=12'd524;

reg [11:0]h_cnt;
reg [11:0]v_cnt;

assign tft_hs=(h_cnt>TFT_HS_end)?1'b1:1'b0;
assign tft_vs=(v_cnt>TFT_VS_end)?1'b1:1'b0;

always @(posedge clk_33M or negedge sys_rst_n)begin
if(!sys_rst_n)
h_cnt<=12'd0;
else if(h_cnt == hpixel_end)
h_cnt<=12'd0;
else
h_cnt<=h_cnt+1'b1;
end

always @(posedge clk_33M or negedge sys_rst_n)begin
if(!sys_rst_n)
v_cnt<=12'd0;
else if(h_cnt == hpixel_end)begin
if(v_cnt == vline_end)
v_cnt<=12'd0;
else
v_cnt<=v_cnt+1'b1;
end
end

wire lcd_en;
assign tft_de=lcd_en;
assign lcd_en=((h_cnt >= hdat_begin) && (h_cnt < hdat_end) && (v_cnt >= vdat_begin) && (v_cnt < vdat_end))?1'b1:1'b0;

assign tft_rgb=(lcd_en)?data_in:16'd0;
endmodule

产生颜色的模块rgb_gen.v

module rgb_gen(
input clk_33M,
input sys_rst_n,
input [2:0]key_cnt,  //这里如果没有位宽[2:0]那么key_cnt默认是0和1的变化,导致不能case到其他颜色
output reg[15:0]rgb
);

always @(posedge clk_33M or negedge sys_rst_n)begin
if(!sys_rst_n)
rgb<=16'd0;
else begin
case(key_cnt)
3'd0:rgb <= 16'hf800;//red
3'd1:rgb <= 16'h07e0;//green
3'd2:rgb <= 16'h001f;//blue
3'd3:rgb <= 16'hf81f;//purple紫色
3'd4:rgb <= 16'hffe0;//yellow
3'd5:rgb <= 16'h07ff;//cyan青色
3'd6:rgb <= 16'hfc00;//orange
3'd7:rgb <= 16'hffff;//white
endcase
end
end

endmodule 

按键切换key_filter.v

module key_filter(
input sys_clk,
input sys_rst_n,
input key,
output reg key_flag,
output reg key_value
);

reg key_reg;
reg [19:0]delay_cnt;

always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
key_reg<=1'b1;
delay_cnt<=20'd0;
end
else begin
key_reg<=key;
if(key_reg != key)
delay_cnt<=20'd1000_000;
else if(key_reg == key)begin
if(delay_cnt > 20'd0)
delay_cnt<=delay_cnt-1'b1;
else
delay_cnt<=delay_cnt;
end
end
end

always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
key_value<=1'b1;
key_flag<=1'b0;
end
else begin
if(delay_cnt == 20'd1)begin
key_flag<=1'b1;
key_value<=key;
end
else begin
key_flag<=1'b0;
key_value<=key_value;
end
end
end

endmodule 
原文地址:https://www.cnblogs.com/FPGAer/p/13905023.html