【红色飓风Nano二代测评】教你如何编写带FIFO的LCD接口
0赞桓公出品,转载请注明出处http://blog.chinaaet.com/songhuangong
之前写的一些博客,为这篇博客的诞生,打下了基础。
这篇文章,主要贴出完整的代码。所以想详细的了解所有的步骤,
可能需要复习下我之前的博客。
介绍了LCD驱动芯片的寄存器,以及时序。
介绍了FIFO读写需要注意的地方,以及如何在ISE中添加FIFO IP Core
介绍了如何用插补绘制任意斜率的直线。
话说FIFO作为模块之间的沟通工具“真真是极好的!”,桓公何处此言呢?
就拿这个LCD接口为例,它自带一个FIFO,FIFO的读部分为自己所用,FIFO
的写部分作为输入引脚,以供其他模块使用。
对于LCD接口而言,只需关注FIFO是否为空,有数据就读取数据画点。
对于外部控制模块而言,只负责产生数据,写入FIFO即可。这就是所谓
的“低耦合,高内聚”吧,呵呵!但是这还不是重点。重点是模块可以
利用这个缓冲区,腾出时间做其他事情。比如说LCD是需要一个初始化
过程的,而且这个过程的时间还不短,但是在初始化的时候,控制模块
可能已经开始产生数据了,而此时LCD还在初始化,无法画点,不过不要
紧,产生的数据被缓存到FIFO中,当LCD初始化完成了之后,就会自动去
读取FIFO中的数据。也就是说控制模块不用傻傻的等待着LCD完成初始化完
成,再去产生数据。(不然的话控制模块肯定还需要接收一个LCD初始
化的完成信号,这样的话耦合度也就上升了)。
同时这个方法也有需要注意的地方,比如说在LCD初始话的时候,控制
模块产生了10个数据,但是LCD的FIFO大小只有8,那么就会造成2个数据
的丢失。所以,这也需要设计者合理的设置FIFO的大小,以确保FIFO不会
溢出,导致数据的丢失。
先用一张结构图来表明大意:
以下程序就是通过按键模块,产生坐标,将坐标点写入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] SS14、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 endmodule5、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 endmodule6、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 endmodule7、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}; endmodule8、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 endmodule9、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) ); endmodule10、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