TFT_LCD 字符显示

发布时间 2023-08-27 17:53:13作者: jasonlee~

第43章、TFT_LCD 字符显示

【实战】

实验目标:在TFT显示屏中心位置显示金色“野火科技”四个汉字,字符外的背景颜色为黑色。每个汉字大小为56*56,字模点阵为64*64(4个汉字大小 256*64),TFT显示屏显示模式为480*270@60。

【图像数据生成模块(tft_pic)】

本模块的目的是,以TFT时序控制模块传入的图像有效显示区域像素点坐标(pix_x,pix_y)为约束条件,产生图像像素点色彩信息pix_data并回传给TFT时序控制模块。在字符显示区域pi_data赋值为金色,其他区域均为黑色。

第一部分:字符点阵显示区域坐标信号

利用 取模软件 生成了要显示字符的 字模,字模点阵的大小为 256*64 :

(1)确定字符有效显示区域,区域大小与字符点阵大小相同,显示区域的像素点与字模点阵中数据项一一对应,当字模点阵中的数据项数值为“1”时,赋值字符颜色给对应像素点;当字模点阵中的数据项数值为“0”时,赋值点阵背景颜色给对应像素

(2)声明char_x、char_y,两变量组成字符点阵显示区域坐标,在字符点阵有效显示区域内,char_x信号0-255循环计数,char_y信号0-63循环计数 ,根据坐标(char_x,char_y)寻找字符点阵对应的数据项,根据数据项的数值,赋予对应坐标像素点颜色信息。

第二部分:输出图像数据信号

本模块的目的是生成图像像素点色彩信息回传给TFT_LCD时序控制模块,声明像素点色彩信息pix_data信号。在字符点阵显示区域内、字符点阵数据项数值为“1”时, pix_data赋值为字符颜色;其他区域均赋值为背景色。因为pix_data的赋值条件超前图像显示区域一个时钟周期、且采用时序逻辑的赋值方式,pix_data与字符显示有效区域保持同步。

module tft_pic(
    input              tft_clk_9m   ,
    input              tft_rst_n ,
    input      [9:0]   pix_x     ,//表示坐标位置,0-640,需要10位
    input      [9:0]   pix_y     ,
output reg [15:0]  pix_data   //rgb565 共10位

);
//----------------参数定义------------//
//1.定义字符显示区域的顶点坐标
parameter CHAR_VALID_LEFT = 10'd112 ,
CHAR_VALID_RIGHT = 10'd368 ,
CHAR_VALID_TOP = 10'd81 ,
CHAR_VALID_BUTTOM = 10'd145 ;

//2.定义显示颜色
parameter BLACK = 16'h0000 ,
GOLDRN = 16'hFEC0 ;

//----------------字符显示区域坐标 char_x、char_y------------//
//确定char_x、char_y:pix_x、pix_y在vga_ctrl模块由h_cnt、v_cnt确定,表示了 640 范围内的坐标
wire [9:0] char_x ;
wire [9:0] char_y ;
assign char_x = ( ((pix_x >= CHAR_VALID_LEFT) && ( pix_x < CHAR_VALID_RIGHT ))
&& ((pix_y >= CHAR_VALID_TOP) && ( pix_y < CHAR_VALID_BUTTOM )) )? (pix_x - CHAR_VALID_LEFT) : 10'h3ff ,
char_y = ( ((pix_x >= CHAR_VALID_LEFT) && ( pix_x < CHAR_VALID_RIGHT ))
&& ((pix_y >= CHAR_VALID_TOP) && ( pix_y < CHAR_VALID_BUTTOM )) ) ? (pix_y - CHAR_VALID_TOP) : 10'h3ff ;

//----------------加载字符数据------------//
//加载字符数据流:字符分辨率为 64*256,则字符取模软件生成的数据流共 64行256列,相应位置为0则表示无颜色表示,不为零则为金色,需要定义多维变量存储
reg [255:0] char [63:0] ;//char变量,数据深度 64个,每个数据位宽 256位
always@(posedge tft_clk_9m or negedge tft_rst_n)begin
char[0] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[1] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[2] <= 256'h0000000000000000000000200000000000000020000000000000000000000000;
char[3] <= 256'h0000000000000000000000380000000000000038000000000000000000000000;
char[4] <= 256'h00000000000000000000007E000000000000003E000000000000000000080000;
char[5] <= 256'h00000000000000000000007C000000000000003C0000000000000000001C0000;
char[6] <= 256'h0000000000000000000000F800000000000000380000000000000000003E0000;
char[7] <= 256'h0000000000000000000000FC000000000000003800018000003FFFFFFFFF0000;
char[8] <= 256'h0000000000000000000001E600000000000000380003C00000100000007F0000;
char[9] <= 256'h0000000000000000000001E200000000000000380007E0000000000000F80000;
char[10] <= 256'h0000000000000000000003C30000000007FFFFFFFFFFF0000000000003E00000;
char[11] <= 256'h0000000000000000000003C180000000000003F9000000000000000007800000;
char[12] <= 256'h000000000000000000000781C0000000000007F900000000000000000E000000;
char[13] <= 256'h000000000000000000000F00E0000000000007B9800000000000000018000000;
char[14] <= 256'h000000000000000000000E007000000000000F38C00000000000000070000000;
char[15] <= 256'h000000000000000000001E003800000000001E386000000000000000C0000000;
char[16] <= 256'h000000000000000000003C003C00000000003C38700000000000001180000000;
char[17] <= 256'h0000000000000000000078001E00000000007838380000000000001A00000000;
char[18] <= 256'h0000000000000000000070200F000000000070381E0000000000001E00000000;
char[19] <= 256'h00000000000000000000E038078000000000E0380F0000000000001F00000000;
char[20] <= 256'h00000000000000000001C03E03E000000003C03807C000000000001C00000000;
char[21] <= 256'h00000000000080000003803C01F800000007803803F000000000001C00008000;
char[22] <= 256'h000000000003C0000007003C00FE0000000F003801FE00000000001C0001C000;
char[23] <= 256'h000000000007E000000E003C007F8000001E003800FFE0000000001C0003E000;
char[24] <= 256'h00000000000FE0000038003C003FF00000380020043FF8000000001C0007F000;
char[25] <= 256'h0FFFFFFFFFFFF0000070003C000FFC0000E000000E0FC0001FFFFFFFFFFFF800;
char[26] <= 256'h040000000000000000C0003C0007C00001C1FFFFFF0780000800001C00000000;
char[27] <= 256'h00000000000000000380003C00018000070000001F8000000000001C00000000;
char[28] <= 256'h00000000000000000E00003C000000001C0000003C0000000000001C00000000;
char[29] <= 256'h00000000000000003800003C0000000000000000700000000000001C00000000;
char[30] <= 256'h00000000000000000000003C0000000000000001C00000000000001C00000000;
char[31] <= 256'h00000000000000000000003C000000000000001B000000000000001C00000000;
char[32] <= 256'h00000000000000000000003C000000000000001E000000000000001C00000000;
char[33] <= 256'h00000000000000000000003C000000000000001F800000000000001C00000000;
char[34] <= 256'h00000000000000000000003C000000000000001E000180000000001C00000000;
char[35] <= 256'h00000000000000000000003C000000000000001C0003C0000000001C00000000;
char[36] <= 256'h00000000000000000000003C000000000000001C0007E0000000001C00000000;
char[37] <= 256'h00000000000000000000003C000000000FFFFFFFFFFFF0000000001C00000000;
char[38] <= 256'h00000000000000000000003C000000000400001C000000000000001C00000000;
char[39] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[40] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[41] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[42] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[43] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[44] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[45] <= 256'h00000000000000000000003C000000000000001C000000000000001C00000000;
char[46] <= 256'h00000000000000000000003C000000000000001C000000000000003C00000000;
char[47] <= 256'h00000000000000000000003C0000000000001E3C0000000000007FFC00000000;
char[48] <= 256'h00000000000000000000003C0000000000000FFC0000000000001FFC00000000;
char[49] <= 256'h00000000000000000000003C00000000000001FC00000000000003F800000000;
char[50] <= 256'h00000000000000000000003C00000000000000F800000000000001F800000000;
char[51] <= 256'h00000000000000000000003C000000000000007000000000000000E000000000;
char[52] <= 256'h000000000000000000000038000000000000002000000000000000C000000000;
char[53] <= 256'h0000000000000000000000200000000000000000000000000000000000000000;
char[54] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[55] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[56] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[57] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[58] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[59] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[60] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[61] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[62] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[63] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
end

//----------------图形样式输出 pix_data------------//
//pix_data:根据char_x、char_y确定图像显示的样式
// reg [15:0] pix_data ;
always@(posedge tft_clk_9m or negedge tft_rst_n)begin
if(!tft_rst_n)
pix_data <= BLACK ;
else if( ((pix_x >= CHAR_VALID_LEFT) && ( pix_x < CHAR_VALID_RIGHT ))
&& ((pix_y >= CHAR_VALID_TOP) && ( pix_y < CHAR_VALID_BUTTOM )) //表明在图片显示区域内
&& (char[char_y][10'd255 - char_x]) ) //char_x范围为[0-255] ,[char_y][10'd255 - char_x]:表示了字符坐标位置,
pix_data <= GOLDRN ; //char[char_y][10'd255 - char_x]:表明像素点上是否为0 , 不为0则赋值金色
else
pix_data <= BLACK ;
end

endmodule

【时钟生成模块】

module clk_gen(
    input   sys_clk     ,
    input   sys_rst_n   ,
    output  tft_clk_9m  ,
    output  locked  
);

clk_9 clk_9_inst01 (
.inclk0 ( sys_clk ),
.areset ( sys_rst_n ),
.c0 ( tft_clk_9m ),
.locked ( locked )
);

endmodule

 

【时序控制模块】

module tft_ctrl(
    input         tft_clk_9m , 
    input         tft_rst_n  ,
    input  [15:0] pix_data   ,//pix_data即显示图像的信息,rgb565模式共16位
output        hsync      ,
output        vsync      ,
output [8:0]  pix_x      ,//480*272,9位足够
output [8:0]  pix_y      ,
output [15:0] rgb_tft    ,//rgb565模式,共16位
output        tft_bl     ,
output        tft_de     ,
output        tft_clk    

);
/----------------------------tft扫描参数定义----------------------------------/
//定义行、场信号节点参数:同步、后沿、有效数据、前沿、总周期 (相较于vga、hdmi无边框)
parameter H_SYNC = 10'd41 , //行同步
H_BACK = 10'd2 , //行时序后沿
H_VALID = 10'd480 , //行有效数据
H_FRONT = 10'd2 , //行时序前沿
H_TOTAL = 10'd525 ; //行扫描周期,一个周期525个像素点
parameter V_SYNC = 10'd10 , //场同步
V_BACK = 10'd2 , //场时序后沿
V_VALID = 10'd272 , //场有效数据
V_FRONT = 10'd2 , //场时序前沿
V_TOTAL = 10'd286 ; //场扫描周期,一个周期286

/----------------------------行场计数器:h_cnt、v_cnt----------------------------------/
//行、场计数器(h_cnt、v_cnt):用来生成行、场扫描信号,行计数器h_cnt,计数(0-799),共10位
reg [9:0] h_cnt ;
always@(posedge tft_clk_9m or negedge tft_rst_n)begin
if(!tft_rst_n)
h_cnt <= 10'b0 ;
else if(h_cnt == H_TOTAL-1'b1)
h_cnt <= 10'b0 ;
else
h_cnt <= h_cnt + 10'b1 ;
end
reg [9:0] v_cnt ;
always@(posedge tft_clk_9m or negedge tft_rst_n)begin
if(!tft_rst_n)
v_cnt <= 10'b0 ;
else if((v_cnt == V_TOTAL-1'b1) && (h_cnt == H_TOTAL - 1'b1))//计数到整幅图片的最后一个像素
v_cnt <= 10'b0 ;
else if(h_cnt==H_TOTAL - 1'b1)//每当行计数满则向下一行
v_cnt <= v_cnt + 10'b1 ;
else
v_cnt <= v_cnt ;
end

/----------------------------1、行场同步信号(hsync、vsync):由计数器确定行、场同步信号hsync、vsync----------------------/
//行、场同步信号(hsync、vsync):只有行、场同步信号为高,其余皆为低 ,表明行场扫描信号的过程/进程
wire hysnc ;
wire vysnc ;
//assign hsync = (cnt_h <= H_SYNC - 1'd1) ? 1'b1 : 1'b0 ;
assign hsync = (h_cnt >= 0) && (h_cnt < 41) ;
assign vsync = (v_cnt >= 0) && (v_cnt < 10) ;

/----------------------------2、区域有效标志信号(rgb_valid):计数器确定,680480,底边的大小----------------------------------*/
wire rgb_valid ;
assign rgb_valid = (((h_cnt >= H_SYNC + H_BACK )&&(h_cnt < H_SYNC + H_BACK + H_VALID)) //43-523
&&((v_cnt >= V_SYNC + V_BACK )&&(v_cnt < V_SYNC + V_BACK + V_VALID)));//12-284

/---------------------------3、色彩请求信号(pix_data_req):计数器确定,在行扫描信号上超前pic_valid信号一个时钟---------------/
wire pix_data_req ;
assign pix_data_req = (((h_cnt >= H_SYNC + H_BACK - 1'b1 )&&(h_cnt < H_SYNC + H_BACK + H_VALID - 1'b1))
&&((v_cnt >= V_SYNC + V_BACK )&&(v_cnt < V_SYNC + V_BACK + V_VALID)));

/-----------------------------4、像素点坐标:请求信号和计数器确定,坐标即距有效显示区域边界的值-----------------------------/
assign pix_x = (pix_data_req == 1'b1)?(h_cnt - H_SYNC - H_BACK -1'b1):9'd511 ;//行场计数器的值计算出相应像素点的坐标位置
assign pix_y = (pix_data_req == 1'b1)?(v_cnt - V_SYNC - V_BACK ) :9'd511 ;//最大值511

/-----------------------------5、输出pic_rgb:将vga_pic模块生成的图形样式(pix_data)赋值给pic_rgb,并显示-----------------------------/
assign rgb_tft = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;

//tft_clk,tft_de,tft_bl:TFT像素时钟、数据使能、背光信号
assign tft_clk = tft_clk_9m ;
assign tft_de = rgb_valid ;
assign tft_bl = tft_rst_n ;

endmodule

 

【顶层模块】

module top_tft_colorbar(
    input         sys_clk   ,
    input         sys_rst_n ,
output        hsync     ,
output        vsync     ,
output [15:0] rgb       ,
output        tft_bl    ,
output        tft_clk   ,
output        tft_de       

);

// wire tft_clk   ;
wire        locked    ;
wire [8:0]  pix_x     ; 
wire [8:0]  pix_y     ; 
wire [15:0] pix_data  ; 
wire        tft_rst_n ;

assign tft_rst_n = (sys_rst_n && locked);

//25MHZ时钟生成模块
clk_gen clk_gen_inst01(
. sys_clk (sys_clk ) ,
. sys_rst_n (~sys_rst_n ) ,

. c0         (tft_clk_9m  ) ,
. locked     (locked      ) 

);

//图像样式确定模块
tft_pic tft_pic_inst01(
. tft_clk_9m (tft_clk_9m ) ,
. tft_rst_n (tft_rst_n ) ,
. pix_x (pix_x ) ,
. pix_y (pix_y ) ,

. pix_data      (pix_data   )

);

//vga时序控制模块,输出像素点坐标,并根据图像样式输出行场信号
tft_ctrl tft_ctrl_inst01(
. tft_clk_9m ( tft_clk_9m) ,
. tft_rst_n ( tft_rst_n ) ,
. pix_data ( pix_data ) ,//pix_data即显示图像的信息,rgb565模式共16位

. hsync      ( hsync     )  ,
. vsync      ( vsync     )  ,
. pix_x      ( pix_x     )  ,//480*272,9位足够
. pix_y      ( pix_y     )  ,
. rgb_tft    ( rgb       )  ,//rgb565模式,共16位
. tft_bl     ( tft_bl    )  ,
. tft_de     ( tft_de    )  ,
. tft_clk    ( tft_clk   )

);

endmodule

 

`timescale 1ns/1ns
module tb_top_tft_char();
    reg         sys_clk   ;
    reg         sys_rst_n ;
wire        hsync     ;
wire        vsync     ;
wire [15:0] rgb       ;
wire        tft_bl    ;
wire        tft_clk   ;
wire        tft_de    ;

top_tft_char top_tft_char_inst01(
. sys_clk ( sys_clk ) ,
. sys_rst_n ( sys_rst_n) ,

. hsync     ( hsync    ) ,
. vsync     ( vsync    ) ,
. rgb       ( rgb      ) ,
. tft_bl    ( tft_bl   ) ,
. tft_clk   ( tft_clk  ) ,
. tft_de    ( tft_de   )    

);

initial begin
sys_clk = 1'b1 ;
sys_rst_n = 1'b0 ;
#200
sys_rst_n = 1'b1 ;
end

always #10 sys_clk = ~sys_clk ;

endmodule