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

本文介绍了如何通过串口将图像数据转换为RGB332格式,并通过FPGA的VGA接口实时显示。详细描述了图像数据处理流程、MATLAB代码示例以及核心模块的Verilog代码,包括注意事项和串口通信的实验方法。
摘要由CSDN通过智能技术生成

目录

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

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分享自己的串口接收GUI可实时观察数据图像-MyScomTest可实时显示数据.rar 做这个软件的想法是这样的 先是阅读了飞哥的串口收发助手程序 其中 在第二版书中的P512页末端提出了一个串口接收数据的要求 即 假设计算机与某硬件设备用串口相连 设备每隔固定时间(我这里是5mS 速度非常快)通过串口给计算机发送数据 这帧数据中包含有 帧头 两字节 0x55 0xAA 数据字节数20 一共每帧22个数据 飞哥提出的是仅用串口的定时器定时读取的方法 并且他说 “经实践证明是可以的” 费劲九牛二虎之力我把它实现了 还是挺艰辛的 程序刚刚完成基本调试 代码也不是特别整齐 我用单片机做上位机发送串口数据 按一帧20个数据并 2个帧起始位  帧发送间歇时间是定时的5mS 为什么要做这个东西呢?因为 这个做法是很有意义的  实时地观察采样数据 我参加的智能车比赛中就意识到 上位机调试 看数据曲线十分重要  否则 不知道参数的变化情况 怎么调试? 大概描述一下这个程序 STM32底层A/D转换采样 通过DMA连接片上USART  定时地发送数据到上位机 其中我对一个通道进行采样 采样十次 即同一个传感器  一共20个数据(STM32是12位的片上AD 参考电压3.3V) 数据传入Matlab的串口中 用矩阵相乘的方法求出平均值 后plot到axes图上   由于是定时器触发的读取数据函数 那么每次读取到的数据有以下几种情况: ||Data, Data,StartByte1,StartByte2,Data,...,StartByte1,StartByte2|| ||Data, Data,StartByte1,StartByte2,Data,...,StartByte1|| ||Data, Data,StartByte1,StartByte2,Data,...,Data||  %这一次定时器定时接收的到的数据末尾的最后一帧的Data不满20个 不够一帧 ||StartByte1,StartByte2,Data,...,Data,Data,StartByte1,StartByte2|| %这次读到的数据末尾只有帧头的2位标志数据 连原始数据全部都得在下一次定时读取中才能读得到 情况比较多 即一帧的数据可能会被中间间断成2次读取!每一次定时读取的时候 就意味着至多会有2帧数据是不完整的! 大家一般的想法大概就是丢失被中断的帧 这样做程序简洁 方便读 但不可避免地会丢失掉一些数据 我在这里耽误了很久 写了很多段程序代码来完整地恢复了这些被打断的数据 (吹毛求疵吧 但我觉得如果在非常严格的数据观察里是有意义的) 程序有时还是有些不知道为什么的BUG 工科人 表达能力不行 分享一个小作品 可能程序写得比较乱 大家看不明白 或运行不了 有需要就问吧    使用方法 我把STM32 工程里的USER文件放进来了 整个工程太大放不下   连接STM32 ADC1 通道15到外设 把USART1接到电脑上 Matlab 打开GUI 'serial_communication2'  ‘打开串口’ OK 看看数据吧 (有时可能会Matlab报错 关闭再重新执行一次GUI 这BUG一直不知道错在哪)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值