一、环境
quartussii
二、说明
菜鸟一个,代码写的不完美,只是验证学习。
RAM的IP配置:
ram的IP核配置问题,记得把输出寄存器q去掉,直接提取,不然会有两个clk的延时才能读取到数据,造成写时序必须延时两个clk,然后会出现写地址和读地址相同的情况,此时写不进去数据。
三、原理
网上有很多不解释。
四、逻辑
1.初始化RAM,即对RAM清零
2.数据输入,缓存2个CLK
3.相邻数判断 计数器增
4.写入ram(先读取对应地址的原来的数,然后和3的计数器相加)
5.结束判断,就是对输入有效信号vsync缓存两个clk
前一个作为读地址判断标志,后一个作为写数据判断标志
五、代码
`timescale 1ns / 1ps
/*
****日期:2021.2.9
**** ram的IP核配置问题,记得把输出寄存器q去掉,直接提取,不然会有两个clk的延时才能读取到数据,
****造成写时序必须延时两个clk,然后会出现写地址和读地址相同的情况,此时写不进去数据。
****
*/
module histogram(
input clk,
input rst,
input [7:0] data_in,
output[15:0] q,
input vsync //图像有效
);
//DPram
wire [15:0] ram_rd_data_b; //B端口读数据
wire [7:0] address_aw; //A地址
wire [7:0] address_bw; //B地址
wire [15:0] ram_wr_data_a; //A写数据
reg [8:0] w_cnt; //写控制计数器
reg [8:0] r_cnt; //写控制计数器
reg tflag; //清零标志
reg [7:0] buf0; //第一拍数据
reg [7:0] buf1; //第二拍数据
//写计数器,初始化RAM清零操作
always @(posedge clk or negedge rst)begin
if(!rst)begin
tflag<=1'b0;
w_cnt<=1'd0;
end
else if(w_cnt==9'd256) begin
tflag<=1'b1;
end
else if(w_cnt<9'd256)
w_cnt<=w_cnt+1'd1;
else
w_cnt<=w_cnt;
end
//
reg vsync1,vsync2;
//一幅图像结束,读RAM计数器
always @(posedge clk or negedge rst)begin
if(!rst)begin
r_cnt<=1'd0;
end
else if(tflag&(~vsync2)) begin
r_cnt<=r_cnt+1'd1;
end
else if(r_cnt<8'd256)
r_cnt<=r_cnt+1'd1;
else
r_cnt<=r_cnt;
end
//提取数值模块
always @(posedge clk)begin
if(vsync)begin
buf0<=data_in;
buf1<=buf0;
end
else begin
buf1<=8'hx;
buf0<=8'hx;
end
vsync1<=vsync; //vsync打两拍,作为结束信号
vsync2<=vsync1;
end
//读取本像素值
// 相邻数不等的时候才写入地址,否则为8'hx,同时在输入完成一副图片之后,最后一个数据作为读地址,读取当前地址原本的数
assign address_bw=(vsync)?(buf0==data_in)? 8'hx:buf0:(vsync1)?buf0:r_cnt;
//写数据
reg [15:0] cnt;
reg [7:0] address_a;
assign address_aw=address_a;
//写地址缓存一个CLK的读地址
always@(posedge clk)begin
if(tflag)
address_a<=address_bw; //写地址就是前一个clk的读地址
else
address_a<=w_cnt;
end
//相邻数不等的时候才写入数据,否则数据为8'hx,且在输入完一副图片后,把最后统计结果写入最后的灰度级
assign ram_wr_data_a=(vsync)?(tflag)?(buf1!=buf0)?(cnt+ram_rd_data_b):8'hx:0:(vsync2)?(cnt+ram_rd_data_b+1'd1):8'hx;
//相邻数判断,计数
always @(posedge clk or negedge rst)begin
if(!rst)
cnt<=1'd2;
else if(vsync) begin
if(buf1==buf0) begin
cnt<=cnt+1'd1;
end
else begin
cnt<=1'd1;
end
end
else
;
end
ram ram(
.clock(clk),
.data(ram_wr_data_a),
.rdaddress(address_bw),
.rden(1'b1),
.wraddress(address_aw),
.wren(1'b1),
.q(ram_rd_data_b)
);
endmodule
六、附录上测试文件(modelsim)
`timescale 1ns / 1ns
module dptb();
reg clk;
reg rst;
reg [7:0] data_in;
wire [7:0] q;
reg rden_b; //B???
reg wren_a ; //A???
reg vsync; //??????
integer iBmpFileId,iOutFileId,iIndex=0,iCode;
reg [7:0] rBmpData [0:800000];
reg [31:0] rBmpCom;
reg rClk;
reg [7:0] rData;
integer iBmpWidth,iBmpHight,iDataStartIndex,iBmpSize;
initial begin
iBmpFileId = $fopen("C:\\Users\\admin\\Desktop\\flrn\\img\\bmp\\07.bmp","rb+");
iOutFileId = $fopen("C:\\Users\\admin\\Desktop\\flrn\\img\\bmp\\output_file.bmp","wb+");
iCode = $fread(rBmpData,iBmpFileId);
iBmpWidth = {rBmpData[21],rBmpData[20],rBmpData[19],rBmpData[18]};
iBmpHight = {rBmpData[25],rBmpData[24],rBmpData[23],rBmpData[22]};
iDataStartIndex = {rBmpData[13],rBmpData[12],rBmpData[11],rBmpData[10]};
iBmpSize = {rBmpData[5],rBmpData[4],rBmpData[3],rBmpData[2]};
$fclose(iBmpFileId);
for (iIndex = 0; iIndex < iBmpSize; iIndex = iIndex + 4) begin
rBmpCom = {rBmpData[iIndex+3],rBmpData[iIndex+2],rBmpData[iIndex+1],rBmpData[iIndex]};
$fwrite(iOutFileId,"%u",rBmpCom);
end // for
$fclose(iOutFileId);
end
integer cnt;
initial
begin
cnt=0;
clk=0;
rst=0;
rden_b=0;
wren_a=0;
#10
rst=1;
rden_b=1;
wren_a=1;
iIndex = 1078; //????31881
vsync=0;
end
always #10 clk=~clk;
always @(posedge clk)begin
cnt=cnt+1;
if(cnt>256)begin
data_in <= rBmpData[iIndex];
iIndex<=iIndex+1;
end
end
always @(posedge clk)begin
if(iIndex>31877) //31878结束一副图片
vsync<=1'b0;
else
vsync<=1'b1;
end
histogram u1(
.clk(clk),
.rst(rst),
.data_in(data_in),
.q(q),
.vsync(vsync)
);
endmodule
附录测试用图片
附录最后结果
OPENCV的直方图统计数据