FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示

这篇具有很好参考价值的文章主要介绍了FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系统框图:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

需要用到的模块有:

1,UART_RX(串口接收模块);

2,串口接受的数据存放到RAM模块;

3,RAM IP核;

4,时钟IP核 (TFT显示屏驱动时钟的产生);

5,TFT显示驱动模块;

1,UART_RX(串口接收模块)

具体构建方式及详见(其中的串口接收部分)

FPGA-UART串口https://blog.csdn.net/weixin_46897065/article/details/135586405?spm=1001.2014.3001.5502

2,串口接受的数据存放到RAM模块

串口接受的数据存放到RAM的逻辑时序图如下:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

然后编辑控制器逻辑代码:

module img_rx_wr(
    Clk        ,
    Reset_n    ,
    rx_data    ,
    rx_done    ,
    ram_wren   ,
    ram_eraddr ,
    ram_wrdata ,
    led        
    );
    input                  Clk        ;
    input                  Reset_n    ;
    input        [7:0]     rx_data    ;
    input                  rx_done    ;
    output reg             ram_wren   ;
    output reg  [15:0]     ram_eraddr ;
    output      [15:0]     ram_wrdata ;
    output reg             led        ;
    
    reg[16:0]data_cnt;    //统计串口接收数据个数计数器
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        data_cnt <= 0;
    else if(rx_done)
        data_cnt <= data_cnt + 1'd1;
        

    
    reg [15:0]rx_data_temp; 
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        rx_data_temp <= 1'b0;
    else if(rx_done)
        rx_data_temp <= {rx_data_temp[7:0],rx_data};
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        ram_wren <= 0;
    else if(rx_done && data_cnt[0])
        ram_wren <= 1'd1;
    else
        ram_wren <= 0;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)        
        ram_eraddr <= 0;
    else if (rx_done && data_cnt[0])
        ram_eraddr <= data_cnt[16:1];  // data_cnt/2
    
    
    assign ram_wrdata = rx_data_temp;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        led <= 0;
    else if((rx_done)&&(data_cnt == 131071))
        led <= ~led ;  
endmodule

测试此逻辑代码的正确性:

编写测试文件:

`timescale 1ns / 1ps
module img_rx_wr_tb;
    reg              Clk        ;
    reg              Reset_n    ;
    reg    [7:0]     rx_data    ;
    reg              rx_done    ;
    wire             ram_wren   ;
    wire  [15:0]     ram_eraddr ;
    wire  [15:0]     ram_wrdata ;
    wire             led        ;
    
    img_rx_wr img_rx_wr(
        .Clk       (Clk       ) ,
        .Reset_n   (Reset_n   ) ,
        .rx_data   (rx_data   ) ,
        .rx_done   (rx_done   ) ,
        .ram_wren  (ram_wren  ) ,
        .ram_eraddr(ram_eraddr) ,
        .ram_wrdata(ram_wrdata) ,
        .led       (led       ) 
        );
        
    initial Clk =1;
    always #10 Clk = ~Clk;
    initial begin
        Reset_n = 0;
        rx_data = 0;
        rx_done = 0;
        #201;
        Reset_n = 1;
        #2000;
        rx_data = 8'd255;
        repeat(131072)begin
            rx_done = 1;
            #20;
            rx_done = 0;
            #200;
            rx_data = rx_data - 1;
        end
        #2000000;
        
        repeat(131072)begin
            rx_done = 1;
            #20;
            rx_done = 0;
            #200;
            rx_data = rx_data - 1;
        end
        $stop;
             
    end

    
endmodule

仿真波形如下:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

写入第一个数据时:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

写入最后一个数据时:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

RAM写逻辑已经完成,接下来完成RAM的读逻辑。

3,构建RAM IP核

具体构建方式及其内部参数详见FPGA-学会使用vivado中的存储器资源RAM(IP核)https://blog.csdn.net/weixin_46897065/article/details/136325283?spm=1001.2014.3001.5502

4,TFT显示屏驱动时钟产生

具体构建方式详见:

FPGA-时钟管理单元https://blog.csdn.net/weixin_46897065/article/details/136356331?spm=1001.2014.3001.5502

5,TFT显示驱动模块

具体原理详见

FPGA- RGB_TFT显示屏原理及驱动逻辑https://blog.csdn.net/weixin_46897065/article/details/136401589?spm=1001.2014.3001.5502      以及FPGA-VGA成像原理与时序https://blog.csdn.net/weixin_46897065/article/details/136386813?spm=1001.2014.3001.5502

在以上链接中介绍的TFT显示逻辑其中使用的组合逻辑,为了使得整体得到更好的时序性(RAM得出地址后数据输出是有延迟时,后面使用时为了确保数据一个都不丢,进行时序对齐)将链接中的逻辑代码重新设计,如下:

`include "disp_parameter_cfg.v" 
//800x480
//H_Right_Borde = 0      V_Bottom_Bord   =  8
//H_Front_Porch = 40     V_Front_Porch   =  2
//H_Sync_Time   = 128    V_Sync_Time     =  2
//H_Back_Porch  = 88     V_Back_Porch    =  25
//H_Left_Border = 0      V_Top_Border    =  8
//H_Data_Time   = 800    V_Data_Time     =  480
//H_Total_Time  = 1056   V_Total_Time    =  525

module TFT_Ctrl(
    Clk_33M   ,
    Reset_n   ,
    Data_in   ,
    Data_req  ,
    hcount    ,   //行扫描位置(显示图像行扫描地址)
    vcount    ,   //场扫描位置(显示图像场扫描地址)
    TFT_HS    ,   //行同步信号
    TFT_VS    ,   //场同步信号
    TFT_DE   ,   //有效数据输出 
    TFT_CLK   ,   
    TFT_DATA ,     //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]  
    TFT_BL
    );
    input                Clk_33M;
    input                Reset_n;
    input   [15:0]       Data_in;
    output  reg          Data_req;
    output  reg [11:0]   hcount;
    output  reg [11:0]   vcount;
    output               TFT_HS;
    output               TFT_VS;
    output               TFT_DE;
    output               TFT_CLK;
    output  reg [15:0]   TFT_DATA;  //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]  
    output               TFT_BL;
//    parameter  VGA_HS_end = 11'd127  ,
//                hdat_begin = 11'd216  ,
//                hdat_end   = 11'd1016 ,
//                hpixel_end = 11'd1055 ,
//                VGA_VS_end = 11'd1    , 
//                vdat_begin = 11'd35   ,
//                vdat_end   = 11'd515  ,
//                vline_end  = 11'd524  ;
    parameter TFT_HS_end = `H_Sync_Time-1  ;
    parameter hdat_begin = `H_Sync_Time + `H_Back_Porch +`H_Left_Border - 1'b1;
    parameter hdat_end = `H_Total_Time - `H_Right_Border -`H_Front_Porch - 1'b1;
    parameter vdat_begin = `V_Sync_Time + `V_Back_Porch +`V_Top_Border - 1'b1;
    parameter vdat_end = `V_Total_Time - `V_Bottom_Border -`V_Front_Porch - 1'b1;    
    parameter hpixel_end = `H_Total_Time -1 ;
    parameter TFT_VS_end = `V_Sync_Time-1  ;     
    parameter vline_end  = `V_Total_Time -1 ; 
                
    reg [11:0] hcount_r;
    reg [11:0] vcount_r;
    
    always@(posedge Clk_33M or negedge Reset_n)
    if(!Reset_n)
       hcount_r <= 11'd0; 
    else if(hcount_r == hpixel_end )
        hcount_r <= 11'd0;
    else
        hcount_r <= hcount_r + 1'd1;
        
    always@(posedge Clk_33M or negedge Reset_n)
    if(!Reset_n)
       vcount_r <= 11'd0; 
    else if(hcount_r == hpixel_end) 
            if(vcount_r == vline_end )
                vcount_r <= 11'd0;
            else
                vcount_r <= vcount_r + 1'd1;
    else
        vcount_r <= vcount_r;
    
    always@(posedge Clk_33M)
        Data_req <= ((hcount_r >= hdat_begin) && (hcount_r < hdat_end)&&
                         (vcount_r >= vdat_begin) && (vcount_r < vdat_end)) ? 1'b1 : 1'b0; 
    reg [3:0]TFT_DE_r; 
    always@(posedge Clk_33M) begin
        TFT_DE_r[0] <= Data_req;
        TFT_DE_r[3:1] <= TFT_DE_r[2:0];
    end
    
    assign  TFT_DE = TFT_DE_r[2];    
//    assign  TFT_DE   =  ((hcount_r >= hdat_begin) && (hcount_r < hdat_end)&&
//                         (vcount_r >= vdat_begin) && (vcount_r < vdat_end)) ? 1'b1 : 1'b0;  
  
    always@(posedge Clk_33M) begin
        hcount <= Data_req ? (hcount_r - hdat_begin) : 10'd0;
        vcount <= Data_req ? (vcount_r - vdat_begin) : vcount;
    end
//    assign  hcount   =   TFT_DE ? (hcount_r - hdat_begin) : 10'd0;  
//    assign  vcount   =   TFT_DE ? (vcount_r - vdat_begin) : 10'd0;  
  
    reg [3:0]TFT_HS_r; 
    always@(posedge Clk_33M) begin
        TFT_HS_r[0] <= (hcount_r > TFT_HS_end)? 1'b1 :1'b0; 
        TFT_HS_r[3:1] <= TFT_HS_r[2:0];
    end  
    assign  TFT_HS = TFT_HS_r[2];      
//    assign  TFT_HS   =  (hcount_r > TFT_HS_end)? 1'b1 :1'b0;

    reg [3:0]TFT_VS_r; 
    always@(posedge Clk_33M) begin
        TFT_VS_r[0] <= (vcount_r > TFT_VS_end)? 1'b1 :1'b0; 
        TFT_VS_r[3:1] <= TFT_VS_r[2:0];
    end  
    assign  TFT_VS  = TFT_VS_r[2];   
//    assign  TFT_VS   =  (vcount_r > TFT_VS_end)? 1'b1 :1'b0; 

    always@(posedge Clk_33M) begin
        TFT_DATA <=  (TFT_DE) ? Data_in : 16'h0000;    
        end
//    assign  TFT_DATA =  (TFT_DE) ? Data_in : 24'h000000;
    assign  TFT_CLK  =  ~Clk_33M;
    assign  TFT_BL = 1;
    
endmodule

6,顶层模块

将以上5个小模块设计好后,根据以下系统框图设计顶层模块。

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

代码如下:

`timescale 1ns / 1ps
module UART_RAM_TFT(
    Clk, 
    Reset_n,
    uart_rx,
    TFT_RGB,   //TFT数据输出
    TFT_HS,   // TFT行同步信号
    TFT_VS,   //TFT场同步信号
    TFT_DE,   //TFT数据有效信号
    TFT_CLK,
    TFT_BL,   //TFT背光
    led
    );
    input  Clk; 
    input  Reset_n;
    input  uart_rx;
    output [15:0]TFT_RGB;
    output TFT_HS;
    output TFT_VS;
    output TFT_DE;
    output TFT_CLK;
    output TFT_BL;
    output led;
    
//    assign TFT_BL = 1;
    
    reg     [15:0]   ram_rdaddr ;
    wire    [15:0]   ram_rdata  ;
    wire    [7:0]    rx_data    ;
    wire             rx_done    ;
    wire             ram_wren   ;
    wire  [15:0]     ram_eraddr ;
    wire  [15:0]     ram_wrdata ;
    wire             led        ;   
    wire             clk_TFT    ;
//    wire             locked     ;
    
    MMCM MMCM
        (
        // Clock out ports
        .clk_out1(clk_TFT),     // output clk_out1
        // Status and control signals
        .reset(!Reset_n), // input reset
        // Clock in ports
        .clk_in1(Clk));  
  
        
    img_rx_wr img_rx_wr(
        .Clk       (Clk       ) ,
        .Reset_n   (Reset_n   ) ,
        .rx_data   (rx_data   ) ,
        .rx_done   (rx_done   ) ,
        .ram_wren  (ram_wren  ) ,
        .ram_eraddr(ram_eraddr) ,
        .ram_wrdata(ram_wrdata) ,
        .led       (led       ) 
        );
        
    uart_byte_rx uart_byte_rx(
        .Clk     (Clk    )    ,
        .Reset_n (Reset_n)    ,
        .uart_rx (uart_rx)    ,
        .Baud_Set(2      )    ,
        .Data    (rx_data)    ,
        .Rx_done (rx_done)
        ); 

    RAM RAM (
          .clka(Clk),    // input wire clka
          .ena(1),      // input wire ena
          .wea(ram_wren),      // input wire [0 : 0] wea
          .addra(ram_eraddr),  // input wire [15 : 0] addra
          .dina(ram_wrdata),    // input wire [15 : 0] dina
          .clkb(clk_TFT),    // input wire clkb
          .enb(1),      // input wire enb
          .addrb(ram_rdaddr),  // input wire [15 : 0] addrb
          .doutb(ram_rdata )  // output wire [15 : 0] doutb
        ); 


    wire ram_data_en;
    wire Data_req;
    //RAM中存储的数据时256*256的像素矩阵
    always@(posedge clk_TFT or negedge Reset_n)
    if(!Reset_n)
        ram_rdaddr <= 0;
    else if(ram_data_en)
        ram_rdaddr <= ram_rdaddr + 1'd1;
        
    wire [11:0]h_count,v_count;
    wire [15:0]dis_data;
    assign ram_data_en = Data_req && (h_count >= 272 && h_count < 528) && (v_count >= 112 && v_count < 368);
    assign dis_data = ram_data_en ? ram_rdata: 0;
    TFT_Ctrl TFT_Ctrl(
        .Clk_33M (clk_TFT)  ,
        .Reset_n (Reset_n)  ,
        .Data_in (dis_data)  ,
        .Data_req(Data_req)  ,
        .hcount  (h_count)  ,   //行扫描位置(显示图像行扫描地址)
        .vcount  (v_count)  ,   //场扫描位置(显示图像场扫描地址)
        .TFT_HS  (TFT_HS  )  ,   //行同步信号
        .TFT_VS  (TFT_VS  )  ,   //场同步信号
        .TFT_DE  (TFT_DE  ) ,   //有效数据输出 
        .TFT_CLK (TFT_CLK )  ,   
        .TFT_DATA(TFT_RGB) ,     //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]  
        .TFT_BL  (TFT_BL  )
        );      
endmodule

为了仿真验证逻辑代码的准确性,我们可以在RAM中提前写入一张256*256大小的图片数据,如下图:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

然后编写测试代码,验证逻辑的正确性:

测试代码如下:

`timescale 1ns / 1ps
module UART_RAM_TFT_TB();
    reg   Clk; 
    reg   Reset_n;
    reg   uart_rx;
    wire [15:0]TFT_RGB;
    wire TFT_HS;
    wire TFT_VS;
    wire TFT_DE;
    wire TFT_CLK;
    wire TFT_BL;
    wire led;

    UART_RAM_TFT UART_RAM_TFT(
        .Clk    (Clk    ) , 
        .Reset_n(Reset_n) ,
        .uart_rx(uart_rx) ,
        .TFT_RGB(TFT_RGB) ,   //TFT数据输出
        .TFT_HS (TFT_HS ) ,   // TFT行同步信号
        .TFT_VS (TFT_VS ) ,   //TFT场同步信号
        .TFT_DE (TFT_DE ) ,   //TFT数据有效信号
        .TFT_CLK(TFT_CLK) ,
        .TFT_BL (TFT_BL ) ,   //TFT背光
        .led    (led    )
        );   
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #2000;
        #20000000;
        $stop;
    end
endmodule

仿真波形如下:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

TFT显示屏开始接收的数据波形图:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发TFT显示屏最后接收的数据波形图:

FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示,fpga开发

7,总结

在本博客中实现了串口接收图像写入RAM并读出在TFT显示屏上显示的这样一个实验。这个实验中使用的时FPGA中片内RAM,所以只能显示一个256*256大小的图片。如果能够将存储器的容量扩大,比如DDR4存储器,那这个时候就可以用串口传输一整幅图像,就可以将完整图片显示在整个显示屏上去。再其次把串口接收到的数据改为摄像头采集到的实时的数据流,那就可以做一个摄像采集头图像,存储,实时显示的应用。再者,对采集到的图像数据。进行一定的各种滤波算法,检测算法等等,就可以实现图像处理功能。文章来源地址https://www.toymoban.com/news/detail-841539.html

到了这里,关于FPGA-串口接收图像写入RAM并读出在TFT显示屏上显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ESP8266+TFT显示屏(ST7789 240*240)

    ❤ 操作系统: windows 10 x64 ❤ IDE: Arduino1.8.15 ❤ 运行库1: TFT_eSPI ❤ 运行库2: ESP8266 ❤ 开发板硬件: ESP8266-CH340  ,  ST7789-240*240-TFT显示屏 ESP8266 ST7789 备注 G GND 3V VCC D5 SCL D7 SDA D4 RES D3 DC 3-1 安装库# 打开Arduino,进入: 工具 --   管理库... ,搜索: TFT_eSPI ,选择版本,点击安

    2024年02月06日
    浏览(51)
  • FPGA实现串口的任意字节数接收

    目录 1、概述 2、串口接收驱动 3、任意字节接收的实现方法 4、仿真

    2024年02月09日
    浏览(34)
  • FPGA接收串口数据并通过LCD1602显示

    一、前言 在学习《FPGA设计与Verilog HDL实现》第九章内容Verilog驱动常用I/O外设时,书中有一个驱动LCD1602的例程,但其是通过状态机显示固定的几个字符。本着动手实践的原则,决定利用手头的硬件实现FPGA接收串口数据并在LCD1602上显示,下面记录项目开始的过程。因为刚接触

    2024年02月06日
    浏览(42)
  • arduino-esp32:基于TFT-eSPI库实现触摸显示屏

    在arduino的IDE上已经搭建好了ESP32环境的话,写写小应用的话还是很简单的,毕竟有这么多优秀的库。 之前用自己买的TFT屏试了一下TFT-eSPI库的驱动效果,显示效果挺好的,但是触摸一直没用上。最近有空了弄了一下。 我的屏幕是2.2寸/2.4/2.8/3.2/3.5/4.0寸TFT触摸彩色SPI串口液晶屏

    2023年04月09日
    浏览(39)
  • FPGA串口接收解帧、并逐帧发送有效数据——1

    工程实现的功能:FPGA串口接收到串口调试助手发来的数据,将其数据解帧。判断到正确的帧头和帧尾之后,将有效数据存入rx_data中;另一方面发送端将有效数据逐帧发送出去。 参考:正点原子官方FPGA串口通信实验 模块构成: 在原子哥的基础上改的代码。 添加了接收状态机

    2024年02月05日
    浏览(37)
  • FPGA串口接收解帧、并逐帧发送有效数据-2

    工程实现的功能:FPGA串口接收到串口调试助手发来的数据,将其数据解帧。判断到正确的帧头和帧尾之后,将有效数据存入rx_data中;另一方面发送端将有效数据逐帧发送出去。 参考:正点原子官方FPGA串口通信实验 模块构成: 在原子哥的基础上改的代码。 添加了接收状态机

    2024年02月05日
    浏览(35)
  • FPGA_数码管显示UART串口接收的数据

          实验目标 :通过电脑调试助手向FPGA的UART串口接收模块发送数据,然后数据可以稳定显示 在数码管上。       实验目的 : 练习UART串口模块和数码管的使用。之前已经有文章详细讲解了串口和数码管的开发,故这里直接提供设计思路供大家参考。 (串口文章链接)ht

    2024年02月13日
    浏览(46)
  • Matlab上位机——串口收发、接收转为图像实时显示、图像放大缩小等功能

    原例程代码可以进行串口接收发送,加载与存储数据 本人在例程代码的基础上添加了共三个功能 1.加载文件数据,三通道同时显示波形 2.放大缩小 3.均值滤波 4.将接收到的数据以固定位数转换为实时波形 布局 加载文件数据后(excel的csv格式) 滤波效果 实时波形采集当时忘了

    2024年02月02日
    浏览(44)
  • FPGA图像处理之Shift-RAM Core 生成卷积模板(官方手册原理分析)

    一、引言         当我们进行图像处理算法时,进行均值滤波、中值滤波等相关的计算操作时, 其中的核心部分应该就是矩阵运算了, 需要生成图像像素矩阵,在 C 语言中,我们可以直接用数组表示,但是在使用 FPGA 进行图像处理时, verilog 却无法实现这样的操作。 那

    2023年04月10日
    浏览(32)
  • 一起玩儿物联网人工智能小车(ESP32)——59. 基于TFT_eSPI库的1.3寸SPI彩色显示屏的使用(ST7789)

    摘要:本文是TFT液晶屏的基本知识和TFT_eSPI库的简单介绍 在前边已经介绍过0.96寸OLED显示屏的使用方法,那是一个单色屏,显示效果很是一般,因此,本篇来介绍彩色TFT(Thin Film Transistor:薄膜晶体管)显示屏的使用方法。 TFT屏幕和OLED屏幕是两种不同的显示器件。TFT屏幕和

    2024年02月21日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包