RS232的VGA图像显示(FPGA学习笔记)

目录

1.介绍

2.将图片转为数据

2.模块框图与波形图

3.核心模块代码

4.注意事项

5.实验效果


1.介绍

通过串口发送图像数据到FPGA内部,然后再用VGA显示出来,只需要通过串口发送不同的图像数据,便可以显示不同的图片,这样的显示方式可以显示更大的图片,并且图片可以实时更新

但是图像数据是不能用串口直接进行收发的,需要处理成像素信息,然后再由串口收发

串口数据帧中有8bit有效数据,需要将原来的8字节数据转成RGB332格式,再由串口进行发送,一次发送一个像素点信息

处理流程如下图所示:

其中,ram的作用是跨时域处理,并起缓存作用

2.将图片转为数据

使用matlab图片转换为RGB332格式,matlab代码如下:

RGB=imread('logo_2.png');     %使用imread函数读取图片数据
[ROW,COL,D]=size(RGB);      %图片行,列,维度
R=RGB(:,:,1);               %提取图片中的红色分量
G=RGB(:,:,2);               %提取图片中的绿色分量
B=RGB(:,:,3);               %提取图片中的蓝色分量
imgdata=zeros(1,ROW*COL);   %定义一个初值为0的数组,存储转换后的图片数据
%转换为RGB332格式
for r=1:ROW
	for c=1:COL
       imgdata((r-1)*COL+c)=bitand(R(r,c),224)+bitshift(bitand(G(r,c),224),-3)+bitshift(bitand(B(r,c),192),-6);
	end
end
%打开或生成txt文件,将格式转换完成的数据写入txt文件
fidc=fopen('data_logo2.txt','w+');
for i =1:ROW*COL
        fprintf(fidc,'%02x ',imgdata(i));
end
fclose(fidc);

2.模块框图与波形图

3.核心模块代码

module  vga_pic
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_clk     ,   //输入RAM写时钟,频率50MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [7:0]   pi_data     ,   //输入RAM写数据
    input   wire            pi_flag     ,   //输入RAM写使能
    input   wire    [9:0]   pix_x       ,   //输入有效显示区域像素点X轴坐标
    input   wire    [9:0]   pix_y       ,   //输入有效显示区域像素点Y轴坐标

    output  wire    [7:0]   pix_data_out    //输出VGA显示图像数据
);


//parameter define
parameter   H_VALID =   10'd640     ,   //行有效数据
            V_VALID =   10'd480     ;   //场有效数据

parameter   H_PIC   =   10'd100     ,   //图片长度
            W_PIC   =   10'd100     ,   //图片宽度
            PIC_SIZE=   14'd10000   ;   //图片像素个数

parameter   RED     =   8'b1110_0000,   //红色
            GREEN   =   8'b0001_1100,   //绿色
            BLUE    =   8'b0000_0011,   //蓝色
            BLACK   =   8'b0000_0000,   //黑色
            WHITE   =   8'b1111_1111;   //白色

//wire  define
wire            rd_en       ;   //ROM读使能
wire    [7:0]   pic_data    ;   //自ROM读出的图片数据

//reg   define
reg     [13:0]  wr_addr     ;   //ram写地址
reg     [13:0]  rd_addr     ;   //ram读地址
reg             pic_valid   ;   //图片数据有效信号
reg     [7:0]   pix_data    ;   //背景色彩信息


//wr_addr:ram写地址
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_addr <=  14'd0;
    else    if((wr_addr == (PIC_SIZE - 1'b1)) && (pi_flag == 1'b1))
        wr_addr <=  14'd0;
    else    if(pi_flag == 1'b1)
        wr_addr <=  wr_addr + 1'b1;

//rd_addr:ram读地址
always@(posedge vga_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_addr <=  14'd0;
    else    if(rd_addr == (PIC_SIZE - 1'b1))
        rd_addr <=  14'd0;
    else    if(rd_en == 1'b1)
        rd_addr <=  rd_addr + 1'b1;
    else
        rd_addr <=  rd_addr;

//rd_en:ROM读使能
assign  rd_en = (((pix_x >= (((H_VALID - H_PIC)/2) - 1'b1))
                && (pix_x < (((H_VALID - H_PIC)/2) + H_PIC - 1'b1))) 
                &&((pix_y >= ((V_VALID - W_PIC)/2))
                && ((pix_y < (((V_VALID - W_PIC)/2) + W_PIC)))));

//pic_valid:图片数据有效信号
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pic_valid   <=  1'b1;
    else
        pic_valid   <=  rd_en;

//pix_data_out:输出VGA显示图像数据
assign  pix_data_out = (pic_valid == 1'b1) ? pic_data : pix_data;

//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <=  8'd0;
    else    if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
        pix_data    <=  WHITE;
    else    if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
        pix_data    <=  WHITE;
    else
        pix_data    <=  BLACK;


//-------------ram_pic_inst-------------
ram_pic ram_pic_inst
(
    .inclock    (sys_clk    ),    //输入RAM写时钟,50MHz,1bit
    .wren       (pi_flag    ),    //输入RAM写使能,1bit
    .wraddress  (wr_addr    ),    //输入RAM写地址,15bit
    .data       (pi_data    ),    //输入写入RAM的图片数据,8bit
    .outclock   (vga_clk    ),    //输入RAM读时钟,25MHz,1bit
    .rdaddress  (rd_addr    ),    //输入RAM读地址,15bit

    .q          (pic_data   )     //输出读取RAM的图片数据,8bit
);

endmodule

4.注意事项

1.PLL-IP核设计中要注意,本次用于生成25Mhz源50MHz时钟信号,不可再使用,若需使用50MHz时钟信号,只能用IP核多生成一个的50MHz的时钟信号

2.复位信号要与look进行与操作后使用

3.本次我们的图像像素为100x100,总共有10000个,因为数据总共要传输0-9999

4.本次实验仿真中,涉及对串口的仿真,需要使用task函数,注意学习task函数的用法

//rx_byte
task    rx_byte();
    integer j;
    for(j=0;j<10000;j=j+1)
        rx_bit(data_mem[j]);
endtask

//rx_bit
task    rx_bit(input[7:0] data);  //data是data_mem[j]的值。
    integer i;
        for(i=0;i<10;i=i+1)
        begin
            case(i)
                0:  rx  <=  1'b0   ;    //起始位
                1:  rx  <=  data[0];
                2:  rx  <=  data[1];
                3:  rx  <=  data[2];
                4:  rx  <=  data[3];
                5:  rx  <=  data[4];
                6:  rx  <=  data[5];
                7:  rx  <=  data[6];
                8:  rx  <=  data[7];    //上面8个发送的是数据位
                9:  rx  <=  1'b1   ;    //停止位
            endcase
            #1040;                      //一个波特时间=sys_clk周期*波特计数器
        end
endtas

5.实验效果

在串口助手上发送图片数据,显示屏上即可显示图形


参考文章《基于RS232的VGA图像显示》 

原文链接:https://blog.csdn.net/Bunny9__/article/details/120119813

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值