实验目标:
sobel算法,处理100X100灰度图像:野火logo
边缘检测:
边缘检测,针对的是灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的是标识数字图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为不相关的信息,大幅度减少了数据量,便于图像的传输和处理。
什么是sobel算法:
算出来的Gxy与一个数据T比较大小,大于T则b2像素点赋值为黑色,小于赋值白色。
我踩得坑:
vga_pic模块,调用的时候由于图片大小需要更改,当初写vga_pic模块的时候,没有把代码中的一些数,用parameter表示,在修改的时候很麻烦。所以以后写代码的时候,大于2的参数一定要重新定义一下,代码写的应该更具复用性。
代码复用性也是代码质量的体现。
经验总结:
想要沉浸式写代码,就要清清楚楚的画好时序图。在写代码之前就应该想清楚用到的每个信号的时序图应该是什么样的。
fpga开发一大部分时间花在整体(顶层)设计上,一部分时间花在如何把想法转换为Verilog语言,一部分时间花在仿真调试上。
我认为最重要的就是整体设计,以及画好时序图。或者有流程图或者相关的辅助你把想法转换为代码的图。
模块框图:
时序图:
特别大
代码:
就放sobel算法部分,和顶层。
module sobel(
input wire clk_50 ,
input wire sys_rst_n ,
input wire [7:0] pi_data ,
input wire pi_flag ,
output reg po_flag ,
output reg [7:0] po_data
);
// parameter
parameter MAX_LINE = 8'd100 ,
MAX_COL = 8'd100 ,
THR = 8'b0000_1100 ,
BLACK = 8'b0000_0000 ,
WHITE = 8'b1111_1111 ;
// reg signal define
reg [7:0] cnt_line ;
reg [7:0] cnt_col ;
reg wrreq1 ;
reg [7:0] dataf1_in ;
reg rdreq ;
reg wrreq2 ;
reg [7:0] dataf2_in ;
reg [7:0] pi_data_reg1;
reg [7:0] cnt_read ; // 对从FIFO中读出的数据个数计数。
reg dataRegFlag ;
reg [7:0] fifo1_reg ;
reg [7:0] fifo2_reg ;
reg [7:0] pi_data_reg2;
reg [7:0] pi_data_reg3; // 用来保存pi_data以进行sobel运算。不是单纯的对pi_data_reg2打拍。
reg flag_abc ;
reg [7:0] a3 ;
reg [7:0] b3 ;
reg [7:0] c3 ;
reg [7:0] a2 ;
reg [7:0] b2 ;
reg [7:0] c2 ;
reg [7:0] a1 ;
reg [7:0] b1 ;
reg [7:0] c1 ;
reg arithmetic ; // 进行sobel算法的标志。
reg [8:0] gx ; // 因为有符号位,所以运算过后要多加一位。
reg [8:0] gy ; // 因为有符号位,所以运算过后要多加一位。
reg flag_gxy ;
reg [8:0] gxy ;
reg answer_flag ;
// wire signal define
wire rdreq_w ;
wire wrreq1_w ;
wire [7:0] dataf1_in_w ;
wire [7:0] dataf1_out ;
wire [9:0] usedw_f1 ;
wire full_f1 ;
wire empty_f1 ;
wire wrreq2_w ;
wire [7:0] dataf2_in_w ;
wire [7:0] dataf2_out ;
wire [9:0] usedw_f2 ;
wire full_f2 ;
wire empty_f2 ;
/*********************************************************************/
// reg [7:0] cnt_line ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_line <= 8'd0 ;
else if(pi_flag && cnt_col == MAX_COL - 1 && cnt_line == MAX_LINE - 1)
cnt_line <= 8'd0 ;
else if(pi_flag && cnt_col == MAX_COL - 1)
cnt_line <= cnt_line + 1'b1 ;
else
cnt_line <= cnt_line ;
end
// reg [7:0] cnt_col ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_col <= 8'd0 ;
else if(pi_flag && cnt_col == MAX_COL - 1)
cnt_col <= 8'd0 ;
else if(pi_flag)
cnt_col <= cnt_col + 1'b1 ;
else
cnt_col <= cnt_col ;
end
// reg wrreq1 ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
wrreq1 <= 1'b0 ;
else if(cnt_line == 0)
wrreq1 <= pi_flag ;
else if(((cnt_line == 2) && (cnt_col != 0))
|| ((cnt_line) > 2 && (cnt_line < MAX_LINE - 1))
|| ((cnt_line == MAX_LINE - 1) && (cnt_col == 0)))
wrreq1 <= wrreq2 ;
else
wrreq1 <= 1'b0 ;
end
// reg [7:0] dataf1_in ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
dataf1_in <= 8'd0 ;
else if(cnt_line == 0)
dataf1_in <= pi_data ;
else if(((cnt_line == 2) && (cnt_col != 0))
|| ((cnt_line) > 2 && (cnt_line < MAX_LINE - 1))
|| ((cnt_line == MAX_LINE - 1) && (cnt_col == 0)))
dataf1_in <= dataf2_out ;
else
dataf1_in <= dataf1_in ;
end
// reg rdreq ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
rdreq <= 1'b0 ;
else if(cnt_line >= 2)
rdreq <= pi_flag ;
else
rdreq <= 1'b0 ;
end
// reg wrreq2 ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
wrreq2 <= 1'b0 ;
else if(cnt_line == 1)
wrreq2 <= pi_flag ;
else if((cnt_line >= 2 && cnt_line <= (MAX_LINE - 1))
|| (cnt_line == (MAX_LINE - 1) && (cnt_col == 0)) )
wrreq2 <= rdreq ;
else
wrreq2 <= 1'b0 ;
end
// reg [7:0] dataf2_in ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
dataf2_in <= 8'd0 ;
else if(cnt_line == 1)
dataf2_in <= pi_data ;
else if((cnt_line >= 2 && cnt_line <= (MAX_LINE - 1))
|| (cnt_line == (MAX_LINE - 1) && (cnt_col == 0)) )
dataf2_in <= pi_data_reg1 ;
else
dataf2_in <= dataf2_in ;
end
// reg [7:0] pi_data_reg1;
// reg [7:0] pi_data_reg2;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n) begin
pi_data_reg1 <= 8'd0 ;
pi_data_reg2 <= 8'd0 ;
end else begin
pi_data_reg1 <= pi_data ;
pi_data_reg2 <= pi_data_reg1 ;
end
end
// reg [7:0] cnt_read ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_read <= 8'd0 ;
else if(rdreq && cnt_read == MAX_COL - 1)
cnt_read <= 8'd0 ;
else if(rdreq)
cnt_read <= cnt_read + 1'b1 ;
else
cnt_read <= cnt_read ;
end
// reg dataRegFlag ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
dataRegFlag <= 1'b0 ;
else
dataRegFlag <= rdreq ;
end
// reg [7:0] fifo1_reg ;
// reg [7:0] fifo2_reg ;
// reg [7:0] pi_data_reg3;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n) begin
fifo1_reg <= 8'd0 ;
fifo2_reg <= 8'd0 ;
pi_data_reg3 <= 8'd0 ;
end else begin
if(dataRegFlag) begin
fifo1_reg <= dataf1_out ;
fifo2_reg <= dataf2_out ;
pi_data_reg3 <= pi_data_reg2 ;
end else begin
fifo1_reg <= fifo1_reg ;
fifo2_reg <= fifo2_reg ;
pi_data_reg3 <= pi_data_reg3 ;
end
end
end
// reg flag_abc ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
flag_abc <= 1'b0 ;
else
flag_abc <= dataRegFlag ;
end
// reg [7:0] a3 ;
// reg [7:0] b3 ;
// reg [7:0] c3 ;
// reg [7:0] a2 ;
// reg [7:0] b2 ;
// reg [7:0] c2 ;
// reg [7:0] a1 ;
// reg [7:0] b1 ;
// reg [7:0] c1 ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n) begin
a3 <= 8'd0 ;
b3 <= 8'd0 ;
c3 <= 8'd0 ;
a2 <= 8'd0 ;
b2 <= 8'd0 ;
c2 <= 8'd0 ;
a1 <= 8'd0 ;
b1 <= 8'd0 ;
c1 <= 8'd0 ;
end else begin
if(flag_abc) begin
a3 <= fifo1_reg ;
b3 <= fifo2_reg ;
c3 <= pi_data_reg3 ;
a2 <= a3 ;
b2 <= b3 ;
c2 <= c3 ;
a1 <= a2 ;
b1 <= b2 ;
c1 <= c2 ;
end else begin
a3 <= a3 ;
b3 <= b3 ;
c3 <= c3 ;
a2 <= a2 ;
b2 <= b2 ;
c2 <= c2 ;
a1 <= a1 ;
b1 <= b1 ;
c1 <= c1 ;
end
end
end
// reg arithmetic ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
arithmetic <= 1'b0 ;
else if(cnt_col != 1 && cnt_col != 2)
arithmetic <= flag_abc ;
else
arithmetic <= 1'b0 ;
end
// reg [8:0] gx ;
// reg [8:0] gy ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n) begin
gx <= 9'd0 ;
gy <= 9'd0 ;
end else begin
if(arithmetic) begin
gx <= (a3-a1)+((b3-b1) << 1)+(c3-c1) ; // 向左移动1bit相当于扩大二倍。
gy <= (a1-c1)+((a2-c2) << 1)+(a3-c3) ; // 向左移动1bit相当于扩大二倍。
end else begin
gx <= gx ;
gy <= gy ;
end
end
end
// reg flag_gxy ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
flag_gxy <= 1'b0 ;
else
flag_gxy <= arithmetic ;
end
// reg [8:0] gxy ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
gxy <= 8'd0 ;
else if(flag_gxy) begin
case ({gx[8],gy[8]})
2'b00 : gxy <= gx[7:0] + gy[7:0] ;
2'b01 : gxy <= gx[7:0] + ~gy[7:0] + 1'b1 ;
2'b10 : gxy <= ~gx[7:0] + gy[7:0] + 1'b1 ;
2'b11 : gxy <= ~gx[7:0] + ~gy[7:0] + 2'd2 ;
default: gxy <= gxy ;
endcase
end // gxy <= {1'b0,gx[7:0]} + {1'b0,gy[7:0]} ; // 取其绝对值相加。也就是说最高位应该为0.
end
// reg answer_flag ;
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
answer_flag <= 1'b0 ;
else
answer_flag <= flag_gxy ;
end
// output signal
// reg po_flag
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
po_flag <= 1'b0 ;
else if(answer_flag)
po_flag <= 1'b1 ;
else
po_flag <= 1'b0 ;
end
// reg [7:0] po_data
always @(posedge clk_50 or negedge sys_rst_n) begin
if(~sys_rst_n)
po_data <= 8'd0 ;
else if(answer_flag && (gxy > THR))
po_data <= BLACK ;
else if(answer_flag && (gxy <= THR))
po_data <= WHITE ;
else
po_data <= po_data ;
end
/*************************************************************/
// 例化
assign dataf1_in_w = dataf1_in ;
assign dataf2_in_w = dataf2_in ;
assign rdreq_w = rdreq ;
assign wrreq1_w = wrreq1 ;
assign wrreq2_w = wrreq2 ;
fifo fifo_f1(
.clock ( clk_50 ) ,
.data ( dataf1_in_w ) ,
.rdreq ( rdreq_w ) ,
.wrreq ( wrreq1_w ) ,
.empty ( empty_f1 ) ,
.full ( full_f1 ) ,
.q ( dataf1_out ) ,
.usedw ( usedw_f1 )
);
fifo fifo_f2(
.clock ( clk_50 ) ,
.data ( dataf2_in_w ) ,
.rdreq ( rdreq_w ) ,
.wrreq ( wrreq2_w ) ,
.empty ( empty_f2 ) ,
.full ( full_f2 ) ,
.q ( dataf2_out ) ,
.usedw ( usedw_f2 )
);
endmodule
module top(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output wire hsync ,
output wire vsync ,
output wire [7:0] rgb ,
output wire tx
);
// 例化间连线
wire clk_50 ;
wire clk_25 ;
wire rst_n ;
wire po_flag_rx ;
wire [7:0] po_data_rx ;
wire po_flag_so ;
wire [7:0] po_data_so ;
pll pll_50_25(
.sys_rst_n ( sys_rst_n ) ,
.areset ( ~sys_rst_n ) ,
.inclk0 ( sys_clk ) ,
.c0 ( clk_50 ) ,
.c1 ( clk_25 ) ,
.locked ( rst_n )
);
uart_rx uart_rx_inst(
.sys_clk ( clk_50 ) ,
.sys_rst_n ( rst_n ) ,
.rx ( rx ) ,
.po_flag ( po_flag_rx ) ,
.po_data ( po_data_rx )
);
sobel sobel_inst(
.clk_50 ( clk_50 ) ,
.sys_rst_n ( rst_n ) ,
.pi_data ( po_data_rx ) ,
.pi_flag ( po_flag_rx ) ,
.po_flag ( po_flag_so ) ,
.po_data ( po_data_so )
);
uart_tx uart_tx_inst(
.sys_clk ( clk_50 ) ,
.sys_rst_n ( rst_n ) ,
.pi_flag ( po_flag_so ) ,
.pi_data ( po_data_so ) ,
.tx ( tx )
);
vga vga_inst(
.clk_25 ( clk_25 ) ,
.clk_50 ( clk_50 ) ,
.rst_n ( rst_n ) ,
.pi_data ( po_data_so ) ,
.pi_flag ( po_flag_so ) ,
.hsync ( hsync ) ,
.vsync ( vsync ) ,
.rgb ( rgb )
);
endmodule
仿真图忘记截屏了。