宋桓公

【红色飓风Nano二代测评】教你如何编写带FIFO的LCD接口

0
阅读(4458)

桓公出品,转载请注明出处http://blog.chinaaet.com/songhuangong

 

之前写的一些博客,为这篇博客的诞生,打下了基础。

这篇文章,主要贴出完整的代码。所以想详细的了解所有的步骤,

可能需要复习下我之前的博客。

【技术分享】Verilog打造TFT接口1

介绍了LCD驱动芯片的寄存器,以及时序。

赛 【红色飓风Nano二代测评】FIFO易错点时序分析

介绍了FIFO读写需要注意的地方,以及如何在ISE中添加FIFO IP Core

赛 【红色飓风Nano二代测评】Verilog实现直线插补

介绍了如何用插补绘制任意斜率的直线。

 

   话说FIFO作为模块之间的沟通工具“真真是极好的!”,桓公何处此言呢?

就拿这个LCD接口为例,它自带一个FIFO,FIFO的读部分为自己所用,FIFO

的写部分作为输入引脚,以供其他模块使用

   对于LCD接口而言,只需关注FIFO是否为空,有数据就读取数据画点。

对于外部控制模块而言,只负责产生数据,写入FIFO即可。这就是所谓

的“低耦合,高内聚”吧,呵呵!但是这还不是重点。重点是模块可以

利用这个缓冲区,腾出时间做其他事情。比如说LCD是需要一个初始化

过程的,而且这个过程的时间还不短,但是在初始化的时候,控制模块

可能已经开始产生数据了,而此时LCD还在初始化,无法画点,不过不要

紧,产生的数据被缓存到FIFO中,当LCD初始化完成了之后,就会自动去

读取FIFO中的数据。也就是说控制模块不用傻傻的等待着LCD完成初始化完

成,再去产生数据。(不然的话控制模块肯定还需要接收一个LCD初始

化的完成信号,这样的话耦合度也就上升了)。

    同时这个方法也有需要注意的地方,比如说在LCD初始话的时候,控制

模块产生了10个数据,但是LCD的FIFO大小只有8,那么就会造成2个数据

的丢失。所以,这也需要设计者合理的设置FIFO的大小,以确保FIFO不会

溢出,导致数据的丢失。

先用一张结构图来表明大意:

wps_clip_image-26565

以下程序就是通过按键模块,产生坐标,将坐标点写入FIFO。(之后会介绍用插补产生坐标)

LCD接口检测到FIFO中有数据,就会数据反映到LCD显示屏。

效果图:

按键绘图

代码结构图:

不要看代码文件似乎很多,其实很多是多次重复例化而来。

比如说按键模块,就是将一路按键,重复例化四次,再封装而成的四路按键模块。

这样做的好处就是方便代码的维护,以及拓展。

好了上完整的代码:

1、TOP_Control:总顶层文件,链接TFT_Interface和key_control

module TOP_Control
(
	input CLK,
	input RSTn,
	
	input key_before,
	input key_back,
	input key_left,
	input key_right,
	
	output [3:0]LED,
	
	output TFT_RST,
	output TFT_CS,
	output TFT_RS,
	output TFT_WR,
	output [15:0]TFT_Data
);


wire Full_Sig;
wire Write_Sig;
wire [31:0]FIFO_Write_Data;
key_control		key_control
					(
						//.LED(LED),
						
						.CLK(CLK),
						.RSTn(RSTn),
						
						.key_before(key_before),
						.key_back(key_back),
						.key_left(key_left),
						.key_right(key_right),
						
						//fifo写部分
						.Full_Sig(Full_Sig),
						.Write_Sig(Write_Sig),
						.FIFO_Write_Data(FIFO_Write_Data)
					);

					TFT_Interface		TFT_Interface
					(
						.LED(LED),
						
						.CLK(CLK),
						.RSTn(RSTn),
						
						//fifo写部分
						.Full_Sig(Full_Sig),
						.Write_Sig(Write_Sig),
						.FIFO_Write_Data(FIFO_Write_Data),
						
						.TFT_RST(TFT_RST),
						.TFT_CS(TFT_CS),
						.TFT_RS(TFT_RS),
						.TFT_WR(TFT_WR),
						.TFT_Data(TFT_Data)
					);

endmodule

2、TFT_Interface:LCD顶层文件

module TFT_Interface
(
	output [3:0]LED,
	
	input CLK,
	input RSTn,
	
	//fifo写部分
	output Full_Sig,
	input Write_Sig,
	input [31:0]FIFO_Write_Data,
	
	output TFT_RST,
	output TFT_CS,
	output TFT_RS,
	output TFT_WR,
	output [15:0]TFT_Data
);

	parameter WHITE = 16'hFFFF;
	parameter BLACK = 16'h0000;
	parameter GREY = 16'hF7DE;
	parameter BLUE = 16'h001F;
	parameter BLUE2 = 16'h051F;
	parameter RED = 16'hF800;
	parameter MAGENTA = 16'hF81F;
	parameter GREEN = 16'h07E0;
	parameter CYAN = 16'h7FFF;
	parameter YELLOW = 16'hFFE0;
	
	
	reg Init_Start;
	wire Init_Done;
	wire [18:0]Init_oData;
	TFT_Init 	TFT_Init
					(
						.CLK(CLK),
						.RSTn(RSTn),
						.Start_Sig(Init_Start),
						.Done(Init_Done),
						.oData(Init_oData) //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
					);
	
	reg Clear_Start;
	wire Clear_Done;
	wire [18:0]Clear_oData;	
	TFT_Clear	TFT_Clear
					(
						.CLK(CLK),
						.RSTn(RSTn),
						.Start_Sig(Clear_Start),
						.Done(Clear_Done),
						
						.Color(BLACK),

						.oData(Clear_oData)
					);
					
	
	reg Point_Start;
	wire Point_Done;
	wire [18:0]Point_oData;
	reg [15:0]X_Pos = 16'd0;
	reg [15:0]Y_Pos = 16'd0;
	TFT_DrawPoint	TFT_DrawPoint
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.Start_Sig(Point_Start),
					.Done(Point_Done),
					
					.X_Pos(X_Pos),
					.Y_Pos(Y_Pos),
					.Color(RED),

					.oData(Point_oData)			//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
				);	
			
	//-------------------------FIFO例化部分-----------------------------------
	//fifo读部分
	wire Empty_Sig;
	reg Read_Sig = 1'b0;
	wire [31:0]FIFO_Read_Data;
	
	//宽度为32,深度为512~~
	fifo		PosFIFO
				(
					.clk(CLK),
					.din(FIFO_Write_Data), // Bus [31 : 0] 
					.wr_en(Write_Sig),
					.rd_en(Read_Sig),
					.dout(FIFO_Read_Data), // Bus [31 : 0] 
					.full(Full_Sig),
					.empty(Empty_Sig)
				);		
		
//--------------------------------TFT总体控制---------------------------------------
	reg [2:0]i;
	always @(posedge CLK or negedge RSTn)
		if(!RSTn)
		begin 
			i <= 3'd0;
			Init_Start <= 1'b0;
			Clear_Start <= 1'b0;
			Point_Start <= 1'b0;
		end
		else
			case(i)
				0://Initialization
				begin
					if(Init_Done)begin Init_Start <= 1'b0; i <= i + 1'b1; end
					else begin Init_Start <= 1'b1; end
				end
				1://Clear the screen
				begin
					if(Clear_Done)begin Clear_Start <= 1'b0; i <= i + 1'b1; end
					else begin Clear_Start <= 1'b1; end
				end
				//-----------------fifo读部分-----------------------
				2://FIFO read
				begin
					if(!Empty_Sig)begin Read_Sig <= 1'b1; i <= i + 1'b1;end
					else begin Read_Sig <= 1'b0; i <= i; end
				end
				3:
				begin
					Read_Sig <= 1'b0;
					i <= i + 1'b1;
				end
				4://赋值将要绘制的点
				begin
					X_Pos <= FIFO_Read_Data[31:16];	
					Y_Pos <= FIFO_Read_Data[15:0];	
					i <= i + 1'b1;
				end
				5://draw
				begin
					if(Point_Done)begin Point_Start <= 1'b0; i <= 3'd2; end
					else begin Point_Start <= 1'b1; end
				end
				default:
				begin
					i <= 3'd0;
					Init_Start <= 1'b0;
					Clear_Start <= 1'b0;
					Point_Start <= 1'b0;
				end
			endcase
			
			assign LED = i;

//--------------------------------TFT引脚驱动选择器--------------------------------
			reg rTFT_CS = 1'b0;
			reg rTFT_RS = 1'b0;
			reg rTFT_WR = 1'b0;
			reg [15:0]rTFT_Data = 16'd0;
			
			always @(*)
				case(i)
					0://TFT初始化过程
					begin
						rTFT_CS = Init_oData[18];
						rTFT_RS = Init_oData[17];
						rTFT_WR = Init_oData[16];
						rTFT_Data = Init_oData[15:0];
					end	
					1://TFT清屏过程
					begin
						rTFT_CS = Clear_oData[18];
						rTFT_RS = Clear_oData[17];
						rTFT_WR = Clear_oData[16];
						rTFT_Data = Clear_oData[15:0];
					end
					5://TFT打点过程 
					begin
						rTFT_CS = Point_oData[18];
						rTFT_RS = Point_oData[17];
						rTFT_WR = Point_oData[16];
						rTFT_Data = Point_oData[15:0];
					end
					default:
					begin
						rTFT_CS = 1'bz;
						rTFT_RS = 1'bz;
						rTFT_WR = 1'bz;
						rTFT_Data = 16'bzzzz_zzzz_zzzz_zzzz;
					end
				endcase 
					

			assign TFT_CS = rTFT_CS;
			assign TFT_RS = rTFT_RS;
			assign TFT_WR = rTFT_WR;
			assign TFT_Data = rTFT_Data;
			assign	TFT_RST = 1'b1;
			
endmodule

3、TFT_Init:LCD初始化模块

module TFT_Init
(
	input CLK,
	input RSTn,
	input Start_Sig,
	output reg Done,
	output [18:0]oData //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);


reg [31:0]Write_reg_data; 
reg Reg_Start;
wire Reg_Done;
Write_Reg 	Write_Reg
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.Start_Sig(Reg_Start),
					.Done(Reg_Done),
					//--
					.Write_reg_data(Write_reg_data),	//{16'reg,16'COM}
					.oData(oData)							//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
				);

	
	reg [5:0]i;
	always @(posedge CLK or negedge RSTn)
		if(!RSTn)
		begin 
			i <= 6'd0;
			Done <= 1'b0;
			Write_reg_data <= 32'h0;
			Reg_Start <= 1'b0;
		end
		else if(Start_Sig) 
			case(i)
				0://打开晶振
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h0,16'h1}; end
				end
				1://电源控制1 ;0xA8A4
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3,16'hA8A4}; end
				end
				2://电源控制2 
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hC,16'h0}; end
				end
				3://电源控制3
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hD,16'h080C}; end
				end
				4://电源控制4 
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hE,16'h2B00}; end
				end
				5://电源控制5 
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h1E,16'hB0}; end
				end
				6://控制液晶的扫描模式(这个设置比较讲究,可查看日记)
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h1,16'h2B3F}; end
				end
				7://液晶驱动AC控制
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h2,16'h600}; end
				end
				8://睡眠控制
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h10,16'h0}; end
				end
				9://设置为竖屏         //定义数据格式  16位色
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h11,16'h6070}; end
				end
				10://共享寄存器1
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h5,16'h0}; end
				end
				11://共享寄存器2
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h6,16'h0}; end
				end
				12://水平玄关,设置每行有效像素的数目。每行有效像素数等于到XL[7:0]+1
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h16,16'hEF1C}; end
				end
				13://垂直玄关
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h17,16'h3}; end
				end
				14://显示控制    0x0233
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h7,16'h233}; end
				end
				15://帧周期控制,??
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hB,16'h0}; end
				end
				16://栅极扫描开始地址
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hF,16'h0}; end
				end
				17://垂直卷轴控制 1
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h41,16'h0}; end
				end
				18://垂直卷轴控制 2
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h42,16'h0}; end
				end
				19://第一个局部显示的起始位置 SS1[8:0]
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h48,16'h0}; end
				end
				20://第一个局部显示的结束位置SE1[8:0]  SS1<SE1<13EF
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h49,16'h13F}; end
				end
				21://第二个局部显示的起始位置
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4A,16'h0}; end
				end
				22://第二个局部显示的结束位置
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4B,16'h0}; end
				end
				23://水平RAM地址;水平RAM的起始-结束地址位置 (00~EF)
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h44,16'hEF00}; end
				end
				24://垂直RAM起始地址
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h45,16'h0}; end
				end
				25://垂直RAM结束地址
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h46,16'h13F}; end
				end
				26://伽马控制1
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h30,16'h0707}; end
				end
				27://伽马控制2
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h31,16'h0204}; end
				end
				28://伽马控制3
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h32,16'h0204}; end
				end
				29://伽马控制4
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h33,16'h0502}; end
				end
				30://伽马控制5
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h34,16'h0507}; end
				end
				31://伽马控制6
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h35,16'h0204}; end
				end
				32://伽马控制7
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h36,16'h0204}; end
				end
				33://伽马控制8
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h37,16'h0502}; end
				end
				34://伽马控制9
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3A,16'h0302}; end
				end
				35://伽马控制10
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3B,16'h0302}; end
				end
				36://RAM write data mask (1)
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h23,16'h0}; end
				end
				37://RAM write data mask (2)
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h24,16'h0}; end
				end
				38://帧频率 510K
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h25,16'h8000}; end
				end
				39://行首址0,设置GDDRAM Y的计数地址
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4F,16'h0}; end
				end
				40://列首址0,设置GDDRAM X的计数地址 
				begin
					if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
					else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4E,16'h0}; end
				end
				41://
				begin
					Done <= 1'b1;
					i <= i + 1'b1;
				end
				42://
				begin
					Done <= 1'b0;
					i <= 6'd0;
				end
				default:
				begin
					i <= 6'd0;
					Done <= 1'b0;
					Write_reg_data <= 32'hffff_ffff;;
					Reg_Start <= 1'b0;
				end
			endcase

endmodule

4、Write_Reg:LCD写寄存器模块

module Write_Reg
(
	input CLK,
	input RSTn,
	input Start_Sig,
	output reg Done,
	//--
	input [31:0]Write_reg_data,//{16'reg,16'COM}
	output [18:0]oData			//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);

	parameter RS_Com = 1'b0;
	parameter RS_Data = 1'b1;



	reg [16:0]Write_Data;
	reg Write_Start;
	wire Write_Done;
	TFT_Write TFT_Write
					(
						.CLK(CLK),
						//.RSTn(RSTn),
						.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
						.Start_Sig(Write_Start),
						.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
						.Done(Write_Done)
					);

	reg [1:0]i;
	always @(posedge CLK or negedge RSTn)
		if(!RSTn)
		begin 
			i <= 2'd0;
			Write_Start <= 1'b0;
			Write_Data <= 17'd0;
			Done <= 1'b0;
		end
		else if(Start_Sig)
			case(i)
				0://写寄存器地址
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, Write_reg_data[31:16] }; end
				end
				1://写命令
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Write_reg_data[15:0] }; end
				end
				2:
				begin
					Done <= 1'b1;
					i <= i + 1'b1;
				end
				3:
				begin
					Done <= 1'b0;
					i <= 2'd0;
				end
			endcase


endmodule

5、TFT_Clear:LCD清屏模块

module TFT_Clear
(
	input CLK,
	input RSTn,
	input Start_Sig,
	output reg Done,
	
	input [15:0]Color,

	output [18:0]oData
);
	
	parameter RS_Com = 1'b0;
	parameter RS_Data = 1'b1;


	reg [16:0]Write_Data;
	reg Write_Start;
	wire Write_Done;
	
	TFT_Write TFT_Write
						(
							.CLK(CLK),
						//	.RSTn(RSTn),
							.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
							.Start_Sig(Write_Start),
							.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
							.Done(Write_Done)
						);

	reg [3:0]i;
	reg [16:0]C0;
	always @(posedge CLK or negedge RSTn)
		if(!RSTn)
		begin
			i <= 4'd0;
			Done <= 1'b0;
			Write_Data <= 17'h0;
			C0 <= 17'd0;
		end
		else if(Start_Sig)
			case(i)
				0://确定点的X坐标的寄存器
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4E}; end
				end
				1://确定X的坐标
				begin
				if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, 16'h0 }; end
				end
				2://确定点的Y坐标的寄存器
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4F}; end
				end
				3://确定Y的坐标
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, 16'h0 }; end
				end
				4://prepare to write to the LCD RAM
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h22}; end
				end
				5://确定点的颜色
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Color}; end
				end
				6://循环~~76800 = 240*320
				begin
					if(C0 == 17'd76800) begin C0 <= 17'd0; i <= i + 1'b1; end
					else begin C0 <= C0 + 1'b1; i <= i - 1'b1;end
				end
				7:
				begin
					Done <= 1'b1;
					i <= i + 1'b1;
				end
				8:
				begin
					Done <= 1'b0;
					i <= 4'd0;
				end
				default:
				begin
					i <= 4'd0;
					Done <= 1'b0;
					Write_Data <= 17'h1ffff;;
					C0 <= 17'd0;
				end
			endcase
			
			
endmodule

6、TFT_DrawPoint:LCD画点模块

module TFT_DrawPoint
(
	input CLK,
	input RSTn,
	input Start_Sig,
	output reg Done,
	
	input [15:0]X_Pos,
	input [15:0]Y_Pos,
	input [15:0]Color,

	output [18:0]oData			//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
//	parameter X_Pos = 16'd55;
//	parameter Y_Pos = 16'd55;
	
	
	parameter RS_Com = 1'b0;
	parameter RS_Data = 1'b1;

	reg [16:0]Write_Data;
	reg Write_Start;
	wire Write_Done;
	
	TFT_Write TFT_Write
						(
							.CLK(CLK),
							.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
							.Start_Sig(Write_Start),
							.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
							.Done(Write_Done)
						);

	reg [2:0]i;
	always @(posedge CLK or negedge RSTn)
		if(!RSTn)
		begin
			i <= 3'd0;
			Write_Data <= 17'h0;
			Done <= 1'b0;
		end
		else if(Start_Sig)
			case(i)
				0://确定点的X坐标的寄存器
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4E}; end
				end
				1://确定X的坐标
				begin
				if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, X_Pos }; end
				end
				2://确定点的Y坐标的寄存器
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4F}; end
				end
				3://确定Y的坐标
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Y_Pos }; end
				end
				4://prepare to write to the LCD RAM
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h22}; end
				end
				5://确定点的颜色
				begin
					if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
					else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Color }; end
				end
				6:
				begin
					Done <= 1'b1;
					i <= i + 1'b1;
				end
				7:
				begin
					Write_Data <= 17'h1ffff;//为了消除警告,其实不加也不影响结果~~
					Done <= 1'b0;
					i <= 3'd0;
				end
			endcase




endmodule

7、TFT_Write:LCD写时序模块

module TFT_Write
(
	input CLK,
	input [16:0]iData,//{1'TFT_RS,16'TFT_Data}
	input Start_Sig,
	output [18:0]oData,//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
	output reg Done
);

	reg CS;					//驱动TFT片选
	reg WR;					//驱动TFT写信号
	reg [15:0]Data;		//驱动TFT数据总线
	reg [2:0]i;
	always @(posedge CLK)
		if(Start_Sig)
				case(i)
					0:
					begin
						CS <= 1'b0;
						WR <= 1'b0;
						i <= i + 1'b1;
					end
					1:
					begin
						Data <= iData[15:0];
						i <= i + 1'b1;
					end
					2://延时20ns,拉底CS 60ns,CS的读周期,最小是100ns
					begin
						i <= i + 1'b1;
					end
					3,4,5://保证CS拉高60ns,这样读的CS周期就大于100ns了~
					begin
						CS <= 1'b1;
						WR <= 1'b1;			//WR的上升沿数据锁存
						i <= i + 1'b1;
					end
					6:
					begin
						Done <= 1'b1;
						i <= i + 1'b1;
					end
					7:
					begin
						Done <= 1'b0;
						i <= 3'd0;
					end
				endcase

		assign oData = {CS,iData[16],WR,Data};

endmodule

8、key_control:按键控制顶层模块

module key_control
(
	input CLK,
	input RSTn,

	input key_before,
	input key_back,
	input key_left,
	input key_right,
	
	//output reg[3:0]LED,
	//output [3:0]LED,
	
	//fifo写部分
	input Full_Sig,
	output reg Write_Sig,
	output reg [31:0]FIFO_Write_Data
);

	reg [15:0]X_Pos = 16'd0;
	reg [15:0]Y_Pos = 16'd0;


			wire before_down;
			wire before_up;
			wire back_down;
			wire back_up;
			wire left_down;
			wire left_up;
			wire right_down;
			wire right_up;
			Key	key
						(
							.CLK(CLK),
							.RSTn(RSTn),
							
							.key_before(key_before),
							.key_back(key_back),
							.key_left(key_left),
							.key_right(key_right),
							
							.before_down(before_down),
							.before_up(before_up),

							.back_down(back_down),
							.back_up(back_up),

							.left_down(left_down),
							.left_up(left_up),

							.right_down(right_down),
							.right_up(right_up)
						);
						
//-------------------------KEY按键绘图部分------------------------

//------------------------向FIFO中写数据-------------------------
	
		reg [3:0]i;
		reg [15:0]Xpos;
		reg [15:0]Ypos;
		reg [15:0]Ytemp = 16'd0;
		reg [19:0]C0 = 20'd0;
		always @(posedge CLK or negedge RSTn)
			if(!RSTn)
			begin 
				Write_Sig <= 1'b0;
				FIFO_Write_Data <= 32'd0;
				Xpos <= 16'd0;
				Ypos <= 16'd0;
				i <= 4'd0; 
			end
			else 
				case(i)
					0://start point
					begin
						Xpos <= 16'd55;
						Ypos <= 16'd55;
						i <= i + 1'b1;
					end
					1://TFT坐标系转换,(将原点定在竖屏的左下角)
					begin
						Ytemp <= 16'd319 - Ypos;
						i <= i + 1'b1;
					end
					2://write a start point
					begin
						if(!Full_Sig)
						begin
							Write_Sig <= 1'b1; 
							FIFO_Write_Data <= {Xpos,Ytemp}; 
							//FIFO_Write_Data <= {Xpos,Ypos}; 
							i <= i + 1'b1;
						end
						else
						begin
							Write_Sig <= 1'b0; 
							FIFO_Write_Data <= FIFO_Write_Data; 
							i <= i;
						end
					end
					3:
					begin
						Write_Sig<= 1'b0;
						i <= i + 1'b1;
					end
					4://choose//判断按键是否按下
					begin
						if(before_down) i <= 4'd5;
						else if(back_down) i <= 4'd6;
						else if(left_down) i <= 4'd7;
						else if(right_down) i <= 4'd8;
					end
					5://前进
					begin
						if(before_up)
						begin
							i <= 4'd4;
							Write_Sig <= 1'b0; 
							C0 <= 20'd0;
						end
						else
						begin
							if(C0 == 20'hf_ffff)
							begin
								C0 <= 20'd0;
								Write_Sig <= 1'b1; 
								Ypos <= Ypos + 1'b1;
								FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)}; 
								i <= i;
							end
							else
							begin 
								C0 <= C0 + 1'b1;
							end
						end
					end
					6://后退
					begin
						if(back_up)
						begin
							i <= 4'd4;
							Write_Sig <= 1'b0; 
							C0 <= 20'd0;
						end
						begin
							if(C0 == 20'hf_ffff)
							begin
								C0 <= 20'd0;
								Write_Sig <= 1'b1; 
								Ypos <= Ypos - 1'b1;
								FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)}; 
								i <= i;
							end
							else
							begin 
								C0 <= C0 + 1'b1;
							end
						end
					end
					7://左转
					begin
						if(left_up)
						begin
							i <= 4'd4;
							Write_Sig <= 1'b0; 
							C0 <= 20'd0;
						end
						begin
							if(C0 == 20'hf_ffff)
							begin
								C0 <= 20'd0;
								Write_Sig <= 1'b1; 
								Xpos <= Xpos - 1'b1;
								FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)}; 
								i <= i;
							end
							else
							begin 
								C0 <= C0 + 1'b1;
							end
						end
					end
					8://右转
					begin
						if(right_up)
						begin
							i <= 4'd4;
							Write_Sig <= 1'b0; 
							C0 <= 20'd0;
						end
						begin
							if(C0 == 20'hf_ffff)
							begin
								C0 <= 20'd0;
								Write_Sig <= 1'b1; 
								Xpos <= Xpos + 1'b1;
								FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)}; 
								i <= i;
							end
							else
							begin 
								C0 <= C0 + 1'b1;
							end
						end
					end
					default
					begin
						Write_Sig <= 1'b0;
						FIFO_Write_Data <= 32'd0;
						Xpos <= 16'd0;
						Ypos <= 16'd0;
						i <= 4'd0; 
					end
				endcase
endmodule

9、Key:4路按键封装模块

module Key
(
	input CLK,
	input RSTn,
	
	input key_before,
	input key_back,
	input key_left,
	input key_right,
	
	output before_down,
	output before_up,

	output back_down,
	output back_up,

	output left_down,
	output left_up,

	output right_down,
	output right_up
);
	 

key_moudle	key_before_moudle
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.keypin(key_before),
					
					.key_down(before_down),
					.key_up(before_up)
				);

key_moudle	key_back_moudle
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.keypin(key_back),
					
					.key_down(back_down),
					.key_up(back_up)
				);

key_moudle	key_left_moudle
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.keypin(key_left),
					
					.key_down(left_down),
					.key_up(left_up)
				);
				
key_moudle	key_right_moudle
				(
					.CLK(CLK),
					.RSTn(RSTn),
					.keypin(key_right),
					
					.key_down(right_down),
					.key_up(right_up)
				);
				

endmodule

10、key_moudle:一路按键检测模块

module key_moudle
(
	input CLK,
	input RSTn,
	input keypin,
	
	output key_down,
	output key_up
);

	reg key_rst;
	always @( posedge CLK or negedge RSTn )
	begin
		if( !RSTn ) key_rst <= 1'b1;
		else key_rst <= keypin; 
	end
	
	reg key_rst_r;
	always @( posedge CLK or negedge RSTn )
	begin
		if( !RSTn ) key_rst_r <= 1'b1;
		else key_rst_r <= key_rst; 
	end

	wire key_an = key_rst_r & (~key_rst); 

	//------------------------------------------
	reg[19:0] cnt;
	always @( posedge CLK or negedge RSTn )
	begin
		if( !RSTn ) cnt <= 20'd0;
		else if(key_an) cnt <= 20'd0;//一旦key_an有抖动的情况cnt都会重新计数
		else cnt <= cnt + 1'b1;
	end
	//------------------------------------------

	reg low_sw;
	always @( posedge CLK or negedge RSTn )
	begin
		if( !RSTn ) low_sw <= 1'b1;
		else if( cnt == 20'hfffff ) low_sw <= keypin;//稳定之后的key值
	end

	reg low_sw_r;
	always @( posedge CLK or negedge RSTn )
	begin
	if( !RSTn ) low_sw_r <= 1'b1;
	else low_sw_r <= low_sw;
	end

	assign key_down = low_sw_r & (~low_sw); 
	assign key_up = (~low_sw_r) & low_sw; 

endmodule


技术讨论欢迎加群~~电子技术协会   362584474