前面已经实现了VGA等宽颜色彩条、VGA字符显示,显示的色彩信息都是通过代码生成的,这一篇博客实现显示已存在的图片
1. 实验目的
在等宽彩条背景上,显示存储在ROM中100*100大小的图显示在VGA显示640 * 480 @60最中间位置
ROM其实用的还是FPGA内部的RAM存储资源
2. 代码实现
锁相环IP
生成25MHz
vga控制模块
复用,驱动VGA进行显示
vga图像数据生成模块
要在彩条的基础上添加ROM图像信息,内部添加ROM-IP保存图像信息
rom_pic
需要用matlab将图片转成的.coe文件,再初始化进ROM中
coe_gen.m
clear %清理命令行窗口
clc %清理工作区
% 使用imread函数读取图片,并转化为三维矩阵
image_array = imread('dog_100x100.jpg');
% 使用size函数计算图片矩阵三个维度的大小
% 第一维为图片的高度,第二维为图片的宽度,第三维为图片维度
[height,width,z]=size(image_array); % 100*100*3
red = image_array(:,:,1); % 提取红色分量,数据类型为uint8,图层为第1图层
green = image_array(:,:,2); % 提取绿色分量,数据类型为uint8,图层为第2图层
blue = image_array(:,:,3); % 提取蓝色分量,数据类型为uint8,图层为第3图层
% 这样导出的rgb分量都是8bit
% 使用reshape函数将各个分量重组成一个一维矩阵
%为了避免溢出,将uint8类型的数据扩大为uint32类型
% 100x100是10000个像素点
r = uint32(reshape(red' , 1 ,height*width)); %1维 10000个数据 8bit
g = uint32(reshape(green' , 1 ,height*width));
b = uint32(reshape(blue' , 1 ,height*width));
% 初始化要写入.COE文件中的RGB颜色矩阵
rgb=zeros(1,height*width); % 1维 数据有10000个 ?? 数据大小
% 显示模式的转换
% 将RGB888转换为RGB444
% 红色分量右移4位取出高4位,左移8位作为ROM中RGB数据的第11bit到第8bit
% 绿色分量右移4位取出高4位,左移4位作为ROM中RGB数据的第7bit到第4bit
% 蓝色分量右移4位取出高4位,左移0位作为ROM中RGB数据的第3bit到第0bit
for i = 1:height*width
rgb(i) = bitshift(bitshift(r(i),-4),8)+ bitshift(bitshift(g(i),-4),4)+ bitshift(bitshift(b(i),-4),0);
end
fid = fopen( 'D:\wwww\mine\image.coe', 'w+' ); // 这里的地址需要写成绝对路径 不然有报错
% .mif文件字符串打印
fprintf( fid, 'MEMORY_INITIALIZATION_RADIX=16;\n');
fprintf( fid, 'MEMORY_INITIALIZATION_VECTOR=\n',height*width);
% 写入图片数据
for i = 1:height*width
if i == height*width
fprintf(fid,'%x;\n',rgb(i)); %最后一个数据后面加分号
else
fprintf(fid,'%x,\n',rgb(i));
end
end
fclose( fid ); % 关闭文件指针
运行,生成对应.coe文件,创建ROM-IP,初始化
ROM 12x10005,12bit的像素点数据10000个,多留5个空闲位置,数据深度需要14bit
vga_pic
这个模块内部需要田间ROM-IP部分,对之前的数据生成模块改一下
不勾选输出寄存器选项,第一拍输入有效地址和使能信号,第二拍返回有效数据
在扫描图像数据时,按照下面的顺序扫描像素点到显示屏上,一行一行的弄,所有在每一行的扫描过程中,需要读ROM的时候,需要提前一拍将有效地址和使能信号准备好
module vga_pic (
input wire vga_clk,
input wire sys_rst_n,
input wire [ 9: 0] pix_x,
input wire [ 9: 0] pix_y,
output wire [11: 0] pix_data
);
// 分辨率 也就是坐标信号的最大值
parameter H_VALID = 10'd640,
V_VALID = 10'd480;
// 颜色参数定义
parameter RED = 12'h0_0_F,
ORANGE = 12'h0_A_F,
YELLOW = 12'h0_F_F,
GREEN = 12'h0_F_0,
CYAN = 12'hF_F_0,
BLUE = 12'hF_0_0,
PUPPLE = 12'hF_2_A,
BLACK = 12'h0_0_0,
WHITE = 12'hF_F_F,
GRAY = 12'hB_B_B;
// 图片大小参数定义
parameter H_PIC = 10'd100,
V_PIC = 10'd100;
parameter PIC_SIZE= 14'd10000;
reg [11: 0] data_pix ; // 彩条颜色
reg pic_valid ; // ROM图像有效信号
wire rd_en ; // ROM读使能信号
reg [13: 0] rom_addr ; // ROM读地址
wire [11: 0] pic_data ; // ROM读数据
assign pix_data = (pic_valid == 1'b1) ? real_rgb_data : data_pix;
// rd_en:
// 横向:269 ≤ pix_x < 369 需要提前一拍准备好读ROM使能
// 纵向:190 ≤ pix_x < 290
assign rd_en = ((pix_x >= (((H_VALID - H_PIC) / 2)) - 1'b1)) // pix_x ≥ (((640-100)/2))-1'b1 = 269
&& ((pix_x < (((H_VALID - H_PIC) / 2) + H_PIC) - 1'b1)) // pix_x < (((640-100)/2)+100)-1'b1= 369
&& ((pix_y >= (((V_VALID - V_PIC) / 2)))) // pic_y ≥ (((480-100)/2)) = 190
&& ((pix_y < (((V_VALID - V_PIC) / 2) + V_PIC))); // pix_x < (((480-100)/2)+100) = 290
// pic_valid: 将rd_en打一拍
always @ (posedge vga_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
pic_valid <= 1'b0;
else
pic_valid <= rd_en;
// rom_addr:
always @ (posedge vga_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
rom_addr <= 14'd0;
else if (rom_addr == PIC_SIZE - 1'b1)
rom_addr <= 14'd0;
else if (rd_en)
rom_addr <= rom_addr + 1'b1;
else
rom_addr <= rom_addr;
// data_pix: 彩条颜色信号赋值
always @ (posedge vga_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
data_pix <= BLACK; // 默认显示黑色
else if (pix_x >= 0 && pix_x < (H_VALID / 10) * 1)
data_pix <= RED;
else if (pix_x >= (H_VALID / 10) * 1 && pix_x < (H_VALID / 10) * 2)
data_pix <= ORANGE;
else if (pix_x >= (H_VALID / 10) * 2 && pix_x < (H_VALID / 10) * 3)
data_pix <= YELLOW;
else if (pix_x >= (H_VALID / 10) * 3 && pix_x < (H_VALID / 10) * 4)
data_pix <= GREEN;
else if (pix_x >= (H_VALID / 10) * 4 && pix_x < (H_VALID / 10) * 5)
data_pix <= CYAN;
else if (pix_x >= (H_VALID / 10) * 5 && pix_x < (H_VALID / 10) * 6)
data_pix <= BLUE;
else if (pix_x >= (H_VALID / 10) * 6 && pix_x < (H_VALID / 10) * 7)
data_pix <= PUPPLE;
else if (pix_x >= (H_VALID / 10) * 7 && pix_x < (H_VALID / 10) * 8)
data_pix <= BLACK;
else if (pix_x >= (H_VALID / 10) * 8 && pix_x < (H_VALID / 10) * 9)
data_pix <= WHITE;
else if (pix_x >= (H_VALID / 10) * 9 && pix_x < (H_VALID / 10) * 10)
data_pix <= GRAY;
else
data_pix <= BLACK;
// 经过matlab生成的.coe文件中,一维数组的颜色分量是这样的,需要改变一下顺序,不然下板之后的图片有一点颜色对不上
// 红色分量,第11bit到第8bit
// 绿色分量,第7bit到第4bit
// 蓝色分量,第3bit到第0bit
wire [11: 0] real_rgb_data = {pic_data[3:0], pic_data[7:4], pic_data[11:8]};
rom_pic rom_pic_inst (
.clka (vga_clk ), // input wire clka
.ena (rd_en ), // input wire ena
.addra (rom_addr ), // input wire [13 : 0] addra
.douta (pic_data ) // output wire [11 : 0] douta
);
endmodule
顶层模块
测试验证