53.综合实验:UART接收图像、写入RAM、通过TFT显示

        (1)设计定义:UART_RX模块接收数据,通过写入逻辑写入RAM存储器中,然后通过读取逻辑,从RAM中读出数据,发送给TFT显示屏。

        (2)FPGA逻辑资源有限,因此设置128 * 128 像素点图片输出,首先使用画图工具制造合适的像素图片,保存为24位位图。

         (3)Verilog代码编写:

  • 串口数据接收模块:
    module UART_RX(clk,reset_n,uart_rxd,rx_done,rx_data);
    
    	input clk;
    	input reset_n;
    	input uart_rxd;
    	
    	output reg rx_done;
    	output reg [7:0]rx_data;
    	
    	reg dff0_uart_rxd;
    	reg dff1_uart_rxd;
    	reg last_dff1_uart_rxd;
    	
    	wire nedge;
    	wire w_rx_done;
    	
    	reg [29:0]baud_cnt;
    	reg [3:0]bit_cnt;
    	reg en_baud_cnt;
    	reg [7:0]r_rx_data;
    
    	
    	parameter f_system = 50_000_000;
    	parameter Baud = 115200;				
    	parameter MCNT = f_system/Baud;
    	
    //为解决亚稳态问题,加入两个寄存器,使外部输入的异步信号uart_rx与时钟信号clk同步。
    //同步化处理
    	always@(posedge clk)
    		begin
    			dff0_uart_rxd <= uart_rxd;
    			dff1_uart_rxd <= dff0_uart_rxd;
    		end
    		
    //下降沿设计	
    	always@(posedge clk)
    		last_dff1_uart_rxd <= dff1_uart_rxd;
    		
    	assign nedge = last_dff1_uart_rxd && (!dff1_uart_rxd);
    		
    //波特计数器模块设计
    	always@(posedge clk or negedge reset_n)
    		if(!reset_n)
    			baud_cnt <= 30'd0;
    		else if(en_baud_cnt)begin
    			if(baud_cnt == MCNT - 1)
    				baud_cnt <= 30'd0;
    			else 
    				baud_cnt <= baud_cnt + 30'd1;
    		end
    		else 
    			baud_cnt <= 30'd0;
    			
    //位设计
    	always@(posedge clk or negedge reset_n)
    		if(!reset_n)
    			bit_cnt <= 4'd0;
    		else if(w_rx_done)
    			bit_cnt <= 4'd0;
    		else if(baud_cnt == MCNT - 1)
    			bit_cnt <= bit_cnt + 4'd1;
    		else 
    			bit_cnt <= bit_cnt;
    		
    
    //en_baud_cnt使能信号的设计
    	always@(posedge clk or negedge reset_n)
    		if(!reset_n)
    			en_baud_cnt <= 0;
    		else if(nedge)
    			en_baud_cnt <= 1;
    		else if((baud_cnt == MCNT/2)&&(bit_cnt == 0)&& (dff1_uart_rxd))
    			en_baud_cnt <= 0;
    		else if(w_rx_done)
    			en_baud_cnt <= 0;
    		else	
    			en_baud_cnt <= en_baud_cnt;
    
    //接收主代码设计
    	always@(posedge clk or negedge reset_n)
    		if(!reset_n)
    			r_rx_data <= 8'd0;
    		else if(baud_cnt == MCNT/2)begin
    			case(bit_cnt)
    				4'd1:r_rx_data[0] <= dff1_uart_rxd;
    				4'd2:r_rx_data[1] <= dff1_uart_rxd;
    				4'd3:r_rx_data[2] <= dff1_uart_rxd;
    				4'd4:r_rx_data[3] <= dff1_uart_rxd;
    				4'd5:r_rx_data[4] <= dff1_uart_rxd;
    				4'd6:r_rx_data[5] <= dff1_uart_rxd;
    				4'd7:r_rx_data[6] <= dff1_uart_rxd;
    				4'd8:r_rx_data[7] <= dff1_uart_rxd;
    				default: r_rx_data <= r_rx_data;
    			endcase
    		end
    		else 
    			r_rx_data <= r_rx_data;
    	
    	always@(posedge clk)
    		if(w_rx_done)
    			rx_data <= r_rx_data;
    		else 
    			rx_data <= rx_data;
    		
    //w_rx_done 和 rx_done信号的设计
    	assign w_rx_done = (baud_cnt == MCNT/2)&&(bit_cnt == 9);
    	
    	always@(posedge clk)
    		rx_done <= w_rx_done;
    	
    endmodule
    
  • ram读写逻辑控制模块:
    module ram_ctrl(
        input                   clk         ,
        input                   reset_n     ,
        input                   clk_33M     ,
        input       [7:0]       rx_data     ,
        input                   rx_done     ,
        input       [9:0]       hang        ,
        input       [9:0]       lie         ,
        
        output reg              ram_wren    ,
        output reg  [13:0]      rdaddress   ,
        output reg  [13:0]      ram_wraddr  ,    
        output      [15:0]      ram_w_data  ,
    	 output 						 img_display
    );
    
    //128*128*2 = 32768    需要一个十五位的寄存器去计数
        reg         [14:0]      done_cnt        ;
        reg         [15:0]      temp_wrdata     ;
    
    /* ---------------------------------------------------写逻辑部分------------------------------------------------*/
    
    //串口传输完成计数器
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            done_cnt <= 15'd0;
        else if(rx_done)
            done_cnt <= done_cnt + 15'd1;
        else    
            done_cnt <= done_cnt;
            
    //ram写入数据寄存器
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            temp_wrdata <= 16'd0;
        else if(rx_done)
            temp_wrdata <= {temp_wrdata[7:0],rx_data};
        else 
            temp_wrdata <= temp_wrdata;
            
    assign ram_w_data = temp_wrdata ;
    
    //ram写使能设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            ram_wren <= 1'd0;
        else if(done_cnt[0] && rx_done)
            ram_wren <= 1'd1;
        else 
            ram_wren <= 1'd0;
            
    //ram写地址设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            ram_wraddr <= 14'd0;
        else if(done_cnt[0] && rx_done)
            ram_wraddr <= done_cnt[14:1];
        else 
            ram_wraddr <= ram_wraddr;
            
    /* ---------------------------------------------------读逻辑部分------------------------------------------------*/
    
    //tft读出有效区域设计
    assign img_display = (hang >= 337) && (hang < 465) && (lie >= 177) && (lie < 305)   ;
    
    //ram读地址设计
    always@(posedge clk_33M or negedge reset_n)
        if(!reset_n)
            rdaddress <= 14'd0;
        else if(img_display)   
            rdaddress <= rdaddress + 14'd1;
        else 
            rdaddress <= rdaddress;     
            
    endmodule 
    
  • 顶层模块:
    module tft_img_top(
    	input 					clk		,
    	input						reset_n	,
    	input						uart_rxd	,
    	
    	output					hsync		,
    	output					vsync		,
    	output	[15:0]		rgb_tft 	,
    	output               tft_bl  	,
       output               tft_clk 	,
    	output               tft_DE  
    
    );
    
    	wire					rx_done 		;
    	wire		[7:0]		rx_data		;
    	wire					clk_33M		;
    	wire					locked		;
    	wire		[9:0]		hang			;
    	wire		[9:0]		lie			;
    	wire					ram_wren		;
    	wire		[13:0]	rdaddress	;
    	wire		[13:0]	ram_wraddr	;
    	wire		[15:0]	data_tft		;
    	wire		[15:0]	ram_w_data	;
    	wire		[15:0]	q				;
    	wire		[15:0]	data_in		;
    	wire					img_display	;
    	
    
    UART_RX	UART_RX_INST(
    	.clk				(clk			),
    	.reset_n			(locked		),
    	.uart_rxd		(uart_rxd	),
    	.rx_done			(rx_done		),
    	.rx_data			(rx_data		)
    );
    
    pll_33M	pll_33M_inst (
    	.areset 	( ~reset_n 	),
    	.inclk0 	( clk 		),
    	.c0 		( clk_33M 	),
    	.locked 	( locked 	)
    );
    
    ram_ctrl		ram_ctrl_inst(
        .clk         ( clk			),
        .reset_n     ( locked		),
        .clk_33M     ( clk_33M		),
        .rx_data     ( rx_data		),
        .rx_done     ( rx_done		),
        .hang        ( hang			),
        .lie         ( lie			),
        
        .ram_wren    (ram_wren		),
        .rdaddress   (rdaddress	),
        .ram_wraddr  (ram_wraddr	),    
        .ram_w_data  (ram_w_data	),
    	 .img_display (img_display )
    );
    
    myram			myram_inst (
    	.data 		( ram_w_data 	),
    	.rdaddress 	( rdaddress 	),
    	.rdclock 	( clk_33M 		),
    	.wraddress 	( ram_wraddr   ),
    	.wrclock 	( clk 			),
    	.wren 		( ram_wren		),
    	.q 			( q 				)
    );
    
    
    assign data_in = (img_display) ? q : 16'd0	;
    
    tft_ctrl		tft_ctrl_inst(
        .clk_33M         (clk_33M		),
        .reset_n         (locked		),
        .data_in         (data_in		),
                        
        .hang            (hang			),
        .lie             (lie			),
        .hsync           (hsync		),
        .vsync           (vsync		),
        .rgb_tft         (rgb_tft 	),
        .tft_bl          (tft_bl  	),
        .tft_clk         (tft_clk 	),
        .tft_DE          (tft_DE		)  
        
    );
    
    endmodule
    

        (4)引脚绑定:

(5)实验现象:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值