目录
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