串口传图
使用串口通信协议传输一张图像到SDRAM存储后VGA协议显示到屏幕。
工程设计
图片生成 使用小梅哥资源中的Picture2Hex软件生成任意分辨率的图片(我这里选择640*480)。
matlab将得到合适分辨率的照片使用matlab软件分析为文本便于串口发送(图片中每一个像素点都有具体的数值)。这里有两种方法:
1 将图片转为RGB332 使用野火提供视频资源基于RS232的VGA显示中的matlab代码,一个像素点为8位数据使用串口发送。
clc; %清理命令行窗口
clear all; %清理工作区
RGB=imread('0003.bmp'); %使用imred函数读取图片数据
[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('picture3.txt','w+');
for i=1:ROW*COL
fprintf(fidc,'%02x',imgdata(i));
end
fclose(fidc);
2 将图片转为RGB565 使用串口传图中的matlab代码,一个像素点为16位数据。串口一次发送8位,使用此代码发送一个像素点的信息需要发送两次。由于工程中VGA模块输入端口为16位故采用此方法。
clear all;
RGB24 = imread('0001.bmp'); %读取图片文件
fid = fopen('rgb565_1.txt','w+'); %打开文件
[ROW,COL,N] = size(RGB24); %获得图片尺寸[高度,长度,维度]
for i = 1:ROW
for j = 1:COL
RG = bitand(RGB24(i,j,1),248) + bitshift(RGB24(i,j,2),-5); %{R[7:3],3'd0} + {5'd0,G[7:5]}
G = bitand(RGB24(i,j,2),28); %{3'd0,G[4:2],2'd0}
GB = bitshift( G,3) + bitshift(RGB24(i,j,3),-3); %{G[4:2],5'd0} + {3'd0,B[7:3]}
fprintf(fid,'%02x %02x ',RG,GB);%将字符打印到txt文件中
end
end
工程整体图
工程源码
注: 由于串口传输8位数据,故将SDRAM中读缓存IP输入端口设置为8位。
顶层源码
module UART_DISP(
input wire Rx ,
input wire Clk ,
input wire Rst_n ,
//VGA显示端口
output wire [15:0] Rgb ,
output wire Hsync ,
output wire Vsync ,
output wire Clk_vga ,
output wire Disp_DE ,
//与SDRAM硬件端口
inout wire [15:0] Sdram_dq ,
output wire Sdram_cke ,
output wire Sdram_cs_n ,
output wire Sdram_cas_n ,
output wire Sdram_ras_n ,
output wire Sdram_we_n ,
output wire [1:0] Sdram_ba ,
output wire [12:0] Sdram_addr ,
output wire [1:0] Sdram_dqm ,
output wire Sdram_clk ,
output wire Led
);
parameter baud_set = 3'd4; //波特率设置,115200bps
parameter img_h = 640; //图片宽度 //640
parameter img_v = 480; //图片高度 //480
parameter img_data_byte = img_h*img_v;
wire wr_en ; //写SDRAM数据使能信号
reg [31:0] byte_cnt ; //计数8位串口发送次数计数器
reg disp_state ; //显示状态使能信号
wire sys_rst_n ;
wire locked ;
wire clk_50M ;
wire clk_100M ;
wire clk_100M_shit ;
wire clk_40M ;
wire [7:0] data_out_rx ; //8位串口输出数据
wire pix_reg ; //读SDRAM读缓存请求信号
wire vga_begin ; //SDRAM端读FIFO清零使能信号
wire [15:0] pix_data ; //16位像素数据
reg rd_en ; //读SDRAM读FIFO使能信号
wire sdram_rd_en ; //读SDRAM读缓存请求信号
assign sdram_rd_en = (disp_state) ? pix_reg:1'b0 ;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
rd_en <= 1'b0;
else
if(disp_state && vga_begin)
rd_en <= 1'b1;
else
rd_en <= rd_en;
assign Led = rd_en;
assign sys_rst_n = Rst_n && locked ;
//计数串口发送的次数
always @(posedge Clk or negedge sys_rst_n)
if(!sys_rst_n)
byte_cnt <= 1'b0 ;
else
if(wr_en)
begin
if( byte_cnt < (img_data_byte<<1))
byte_cnt <= byte_cnt + 32'b1 ;
else
byte_cnt <= (img_data_byte<<1) ;
end
else
byte_cnt <= byte_cnt ;
//串口发送图片尺寸一半变为可读取状态
always @(posedge Clk or negedge sys_rst_n)
if(!sys_rst_n)
disp_state <= 1'b0 ;
else
if(byte_cnt == (img_data_byte<<1))
disp_state <= 1'b1 ;
else
disp_state <= 1'b0 ;
UART_RX UART_RX_inst( //串口接收模块
.Clk ( clk_50M ) ,
.Rst_n ( sys_rst_n ) ,
.Rs232_rx ( Rx ) ,
.Bps_set ( baud_set ) ,
.Data_out ( data_out_rx ) ,
.Done_rx ( wr_en )
);
CLK_STRAT CLK_STRAT_inst(
.areset ( !Rst_n ),
.inclk0 ( Clk ),
.c0 ( clk_50M ), //50M
.c1 ( clk_100M ), //100M
.c2 ( clk_100M_shit ), //100M位移信号
.c3 ( clk_40M ), //25M
.locked ( locked )
);
SDRAM_TOP SDRAM_TOP_inst(
.Clk ( clk_100M ),
.Rst_n ( sys_rst_n ),
.Clk_out ( clk_100M_shit ), //输入相位偏移时钟
// 写FIFO
.Wr_fifo_wr_clk ( clk_50M ),
.Wr_fifo_wr_req ( wr_en ),
.Wr_fifo_wr_data ( data_out_rx ), //写入写FIFO中的数据
.Sdram_wr_b_addr ( 24'b0 ),
.Sdram_wr_e_addr ( img_data_byte ),
.Wr_burst_len ( 10'd512 ), //max512
.Wr_rst ( ~sys_rst_n ), //写复位信号
// 读FIFO
.Rd_fifo_rd_clk ( clk_40M ),
.Rd_fifo_rd_req ( sdram_rd_en ),
.Sdram_rd_b_addr ( 24'b0 ),
.Sdram_rd_e_addr ( img_data_byte ),
.Rd_burst_len ( 10'd512 ), //读突发长度
.Rd_rst ( ~sys_rst_n ), //读复位信号
.Rd_value ( rd_en ),
.Rd_fifo_rd_data ( pix_data ), //读FIFO中读出的数据
.Rd_fifo_num ( ), //读FIFO中存在的数据个数
// 与SDRAM的硬件接口
.Sdram_clk ( Sdram_clk ),
.Sdram_cke ( Sdram_cke ),
.Sdram_cs_n ( Sdram_cs_n ),
.Sdram_cas_n ( Sdram_cas_n ),
.Sdram_ras_n ( Sdram_ras_n ),
.Sdram_we_n ( Sdram_we_n ),
.Sdram_ba ( Sdram_ba ),
.Sdram_addr ( Sdram_addr ),
.Sdram_dq ( Sdram_dq ), // SDRAM 数据总线
.Sdram_dqm ( Sdram_dqm )
);
VGA_CTRL
// #(
// .H_SYNC (11'd128) ,
// .H_BACK (11'd88) ,
// .H_LEFT (11'd0) ,
// .H_ABLE (11'd800) ,
// .H_RIGHT (11'd0) ,
// .H_PRONT (11'd40) ,
// .H_TORAL (11'd1056) ,
// .V_SYNC (11'd4) ,
// .V_BACK (11'd23) ,
// .V_LEFT (11'd0) ,
// .V_ABLE (11'd600) ,
// .V_RIGHT (11'd0) ,
// .V_PRONT (11'd1) ,
// .V_TORAL (11'd628)
// )
VGA_CTRL_inst(
.Clk ( clk_40M ) ,
.Rst_n ( sys_rst_n ) ,
.Pix_data ( {pix_data[7:0],pix_data[15:8]} ) ,
.Rgb ( Rgb ) ,
.Hsync ( Hsync ) ,
.Vsync ( Vsync ) ,
.Pix_x ( ) ,
.Pix_y ( ) ,
.Clk_vga ( Clk_vga ) ,
.Disp_DE ( Disp_DE ) , //VGA 场消隐信号
.Vga_begin ( vga_begin ) , //SDRAM读FIFO缓存清零信号 高电平有效
.Pix_reg ( pix_reg ) //每个像素点显示16位信息请求信号
);
endmodule
顶层仿真源码
`timescale 1ns/1ns
`define CLOCK 20
module UART_DISP_tb();
defparam UART_DISP_inst.VGA_CTRL_inst.H_SYNC = 11'd96 , //行同步周期
UART_DISP_inst.VGA_CTRL_inst.H_BACK = 11'd40 , //行后沿周期
UART_DISP_inst.VGA_CTRL_inst.H_LEFT = 11'd8 , //行左边框周期
UART_DISP_inst.VGA_CTRL_inst.H_ABLE = 11'd640 , //行有效图像周期数
UART_DISP_inst.VGA_CTRL_inst.H_RIGHT = 11'd8 , //行右边框
UART_DISP_inst.VGA_CTRL_inst.H_PRONT = 11'd8 , //行前沿
UART_DISP_inst.VGA_CTRL_inst.H_TORAL = 11'd800 , //行总扫描周期
UART_DISP_inst.VGA_CTRL_inst.V_SYNC = 11'd2 , //列同步周期
UART_DISP_inst.VGA_CTRL_inst.V_BACK = 11'd25 , //列后沿周期
UART_DISP_inst.VGA_CTRL_inst.V_LEFT = 11'd8 , //列左边框周期
UART_DISP_inst.VGA_CTRL_inst.V_ABLE = 11'd480 , //列有效图像周期数
UART_DISP_inst.VGA_CTRL_inst.V_RIGHT = 11'd8 , //列右边框
UART_DISP_inst.VGA_CTRL_inst.V_PRONT = 11'd2 , //列前沿
UART_DISP_inst.VGA_CTRL_inst.V_TORAL = 11'd525 ; //列总扫描周期
reg Clk ;
reg Rst_n ;
reg con_en ;
reg [7:0] data_in ;
wire rs232_tx ;
wire done_tx ;
//VGA显示端口
wire [15:0] rgb ;
wire hsync ;
wire vsync ;
wire clk_vga ;
wire disp_DE ;
//与SDRAM硬件端口
wire [15:0] sdram_dq ;
wire sdram_cke ;
wire sdram_cs_n ;
wire sdram_cas_n ;
wire sdram_ras_n ;
wire sdram_we_n ;
wire [1:0] sdram_ba ;
wire [12:0] sdram_addr ;
wire [1:0] sdram_dqm ;
wire sdram_clk ;
reg [7:0] randone ;
initial Clk = 1;
always #(`CLOCK/2) Clk = ~ Clk;
UART_TX UART_TX_inst(
.Clk (Clk ) ,
.Rst_n (Rst_n ) ,
.Bps_set (3'd4) ,
.Con_en (con_en ) ,
.Data_in (data_in ) ,
.Rs232_tx (rs232_tx ) ,
.Done_tx (done_tx ) ,
.Uart_state ()
);
UART_DISP #( .img_h(10),
.img_v(5)
)
UART_DISP_inst(
.Rx (rs232_tx) ,
.Clk (Clk ) ,
.Rst_n (Rst_n ) ,
//VGA显示端口
.Rgb (rgb ) ,
.Hsync (hsync ) ,
.Vsync (vsync ) ,
.Clk_vga (clk_vga ) ,
.Disp_DE (disp_DE ) ,
//与SDRAM硬件端口
.Sdram_dq (sdram_dq ) ,
.Sdram_cke (sdram_cke ) ,
.Sdram_cs_n (sdram_cs_n ) ,
.Sdram_cas_n (sdram_cas_n) ,
.Sdram_ras_n (sdram_ras_n) ,
.Sdram_we_n (sdram_we_n ) ,
.Sdram_ba (sdram_ba ) ,
.Sdram_addr (sdram_addr ) ,
.Sdram_dqm (sdram_dqm ) ,
.Sdram_clk (sdram_clk )
);
sdram_model_plus sdram_model_plus_inst(
.Dq (sdram_dq ),
.Addr (sdram_addr ),
.Ba (sdram_ba ),
.Clk (sdram_clk ),
.Cke (sdram_cke ),
.Cs_n (sdram_cs_n ),
.Ras_n (sdram_ras_n ),
.Cas_n (sdram_cas_n ),
.We_n (sdram_we_n ),
.Dqm (2'b0 ),
.Debug (1'b1 )
);
//发送8位字节数据任务
task send_bit_data;
begin
@(posedge done_tx);
#(`CLOCK*2) ;
con_en = 1 ;
#(`CLOCK) ;
con_en = 0 ;
end
endtask
initial
begin
randone = {$random} % 60 ; //通过位并接操作产生一个值在0到59之间的数。
Rst_n = 0;
#(`CLOCK*5+1);
con_en = 0 ;
Rst_n = 1;
#(`CLOCK*5);
data_in = 1'b0 ;
#(`CLOCK*50);
con_en = 1 ;
#(`CLOCK) ;
con_en = 0 ;
repeat(230) //输出串口次数像素尺寸的两倍
begin
data_in = data_in + randone;
send_bit_data;
end
#(`CLOCK*500+1);
$stop ;
end
endmodule
顶层仿真结果
在VGA协议扫描一帧后串口图像传输完成,扫描下一帧时产生VGA_begin信号,读SDRAM信号Rd_value使能有效。