实验任务:
通过串口助手把 200 行 x200 列数据传入 FPGA,对应三行三列的九个数进行 sobel 算法,把结果通过 vga 来显示,用两种颜色来区分是否是边界点。
Sobel 算法:
1、把图像每三行三列的数据分别乘上算子中对应位置的值再相加。然后进行如 下运算,得到相应方向(x 和 y)的 Dx 和 Dy。
Dx=(a3-a1)+(b3-b1)*2+c3-c1;
Dy=(a1-c1)+(a2-c2)*2+a3-c3;
2、对上面求得的 Dx 和 Dy 做平方和的平方根,再取近似值 Dx 和 Dy 的绝对值的 和得到 Dxy:
3、如果 Dxy 的值大于一个阈值,表示该点为边界点,就让 VGA 显示一个白点, 否则显示黑点。
4、把计算的结果通过 vga 显示,显示器会把是边界点的以白色像素显示,不是 边界点的以黑色像素点显示,于是得到了一幅图像的轮廓。
框图解析:
a、gen_clk 模块为二分频模块,产生的 25Mhz 的时钟传给后面的所有模块,这样 相当于整个系统都是共用了一个时钟。
b、uart_rx 模块负责接收上位机传递过来的 40000 个数据,拼接的同时传给 sobel_ctrl 进行数据的缓存和运算,注意 uart_rx 模块的时钟变了,如果是采用波 特率为 9600 的话,此模块里面的波特计数器需要减半。
c、sobel_ctrl 模块实现数据的缓存和 sobel 算法的运算,结果传给 vga 模块。
d、vga 模块里面调用了一个 ram 存储器,用来存储 198x198 个数据(除去两行两 列),vga 模块负责 ram 的读写,让 ram 里面写的数据位 sobel_ctrl 模块处理好的 数据,读出来的数据需要给 rgb 进行显示的。
顶层模块设计
顶层模块示意图:
顶层模块代码实现:
module sobel_top(
input wire clk,
input wire rst_n,
input wire rx,
output wire [7:0] rgb,
output wire hsync,
output wire vsync
);
wire [7:0] po_data;
wire po_flag;
wire [7:0] rgb1;
wire po_flag1;
wire [7:0] doutb;
wire rd_flag;
uart_rx uart_rx_inst(
.clk(clk2),
.rst_n(rst_n),
.rx(rx),
.po_data(po_data),
.po_flag(po_flag)
);
fifo_ctrl fifo_ctrl_inst(
.clk(clk2),
.rst_n(rst_n),
.rx_data(po_data),
.pi_flag(po_flag),
.rgb(rgb1),
.po_flag(po_flag1)
);
ram_ctrl ram_ctrl_inst(
.clk(clk2),
.rst_n(rst_n),
.wr_en(po_flag1),
.pi_data(rgb1),
.doutb(doutb),
.rd_flag(rd_flag)
);
vga vga_inst(
.clk2(clk2),
.rst_n(rst_n),
.doutb(doutb),
.rd_flag(rd_flag),
.hsync(hsync),
.vsync(vsync),
.rgb(rgb)
);
clk_wiz_0 clk_wiz_0_inst
(
// Clock out ports
.clk_out1(clk2), // output clk_out1
// Clock in ports
.clk_in1(clk));
endmodule
接收模块设计
接收模块示意图:
接收模块波形图:
接收模块代码实现:
module uart_rx(
input wire clk,
input wire rst_n,
input wire rx,
output reg [7:0] po_data,
output reg po_flag
);
reg rx1;
reg rx2;
reg rx2_reg;
reg rx_flag;
reg bit_flag;
reg [3:0] bit_cnt;
reg [12:0] baud_cnt;
always @(posedge clk) begin
rx1<=rx;
rx2<=rx1;
rx2_reg<=rx2;
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
baud_cnt<='d0;
end
else if(baud_cnt=='d2603) begin
baud_cnt<='d0;
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
baud_cnt<='d0;
end
else if (rx_flag==1'b1) begin
baud_cnt<=baud_cnt+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_flag<=1'b0;
end
else if (baud_cnt=='d1301) begin
bit_flag<=1'b1;
end
else begin
bit_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_cnt<='d0;
end
else if(bit_cnt=='d8) begin
bit_cnt<='d0;
end
else if (bit_flag==1'b1) begin
bit_cnt<=bit_cnt+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rx_flag<=1'b0;
end
else if (rx2_reg==1'b1 && rx2==1'b0) begin
rx_flag<=1'b1;
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
rx_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
po_data<='d0;
end
else if (bit_flag==1'b1 && bit_cnt>=1'b1) begin
po_data<={rx2,po_data[7:1]};
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
po_flag<=1'b0;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
po_flag<=1'b1;
end
else begin
po_flag<=1'b0;
end
end
endmodule
sobel控制模块设计
sobel控制模块示意图:
sobel控制模块波形图:
sobel控制模块代码实现:
module fifo_ctrl(
input wire clk,
input wire rst_n,
input wire [7:0] rx_data,
input wire pi_flag,
output reg [7:0] rgb,
output reg po_flag
);
reg [6:0] cnt_col;
reg [6:0] cnt_row;
reg wr_en1;
reg wr_en2;
reg wr_en1_pre1;
reg wr_en1_pre2;
reg [7:0] data_in1;
reg [7:0] data_in2;
reg rd_en;
reg flag_shift;
reg flag_d;
reg flag_d_pre;
wire full1,empty1,full2,empty2;
wire [7:0] dout1;
reg [7:0] dout1_t;
reg [7:0] dout1_tt;
wire [7:0] dout2;
reg [7:0] dout2_t;
reg [7:0] dout2_tt;
reg [7:0] rx_data_t;
reg [7:0] rx_data_tt;
reg [7:0] dx;
reg [7:0] dy;
reg flag_abs;
reg [7:0] abs_dx;
reg [7:0] abs_dy;
reg flag_dxy;
reg [7:0] dxy;
reg flag_rgb;
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
cnt_col<='d0;
end
else if(cnt_col=='d199) begin
cnt_col<='d0;
end
else if (pi_flag==1'b1) begin
cnt_col<=cnt_col+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
cnt_row<='d0;
end
else if (pi_flag==1'b1 && cnt_col=='d199 && cnt_row=='d199) begin
cnt_row<='d0;
end
else if(pi_flag==1'b1 && cnt_col=='d199) begin
cnt_row<=cnt_row+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
wr_en1<=1'b0;
end
else if (cnt_row=='d0 && pi_flag==1'b1) begin
wr_en1<=1'b1;
end
else if(wr_en1_pre1==1'b1) begin
wr_en1<=1'b1;
end
else begin
wr_en1<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
wr_en1_pre1<=1'b0;
end
else if (wr_en1_pre2==1'b1) begin
wr_en1_pre1<=1'b1;
end
else begin
wr_en1_pre1<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
wr_en1_pre2<=1'b0;
end
else if (cnt_row>='d2 && cnt_row<='d84 && pi_flag==1'b1) begin
wr_en1_pre2<=1'b1;
end
else begin
wr_en1_pre2<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
wr_en2<=1'b0;
end
else if (cnt_row>='d1 && cnt_row<='d84 && pi_flag==1'b1) begin
wr_en2<=1'b1;
end
else begin
wr_en2<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
data_in1<='d0;
end
else if (cnt_row=='d0 && pi_flag==1'b1) begin
data_in1<=rx_data;
end
else if(wr_en1_pre1==1'b1) begin
data_in1<=dout2;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
data_in2<='d0;
end
else if (cnt_row>='d1 && cnt_row<='d84 && wr_en2==1'b1) begin
data_in2<=rx_data;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rd_en<=1'b0;
end
else if (cnt_row>='d2 && cnt_row<='d85 && pi_flag==1'b1) begin
rd_en<=1'b1;
end
else begin
rd_en<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_shift<=1'b0;
end
else if (rd_en==1'b1) begin
flag_shift<=1'b1;
end
else begin
flag_shift<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_d_pre<=1'b0;
end
else if (cnt_row>='d2 && cnt_col>='d2) begin
flag_d_pre<=pi_flag;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_d<=1'b0;
end
else begin
flag_d<=flag_d_pre;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
dout1_t<='d0;
dout1_tt<='d0;
dout2_t<='d0;
dout2_tt<='d0;
rx_data_t<='d0;
rx_data_tt<='d0;
end
else if (flag_shift==1'b1) begin
dout1_t<=dout1;
dout1_tt<=dout1_t;
dout2_t<=dout2;
dout2_tt<=dout2_t;
rx_data_t<=rx_data;
rx_data_tt<=rx_data_t;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_abs<=1'b0;
end
else begin
flag_abs<=flag_d;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_dxy<=1'b0;
end
else begin
flag_dxy<=flag_abs;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
flag_rgb<=1'b0;
end
else begin
flag_rgb<=flag_dxy;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
dx<='d0;
end
else if (flag_d==1'b1) begin
dx<=dout1_tt-dout1+(dout2_tt-dout2)*2+rx_data_tt-rx_data;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
dy<='d0;
end
else if (flag_d==1'b1) begin
dy<=dout1-rx_data+(dout1_t-rx_data_t)*2+dout1_tt-rx_data_tt;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
abs_dx<='d0;
end
else if (flag_abs==1'b1 && dx[7]==1'b1) begin
abs_dx<=~dx+1'b1;
end
else if(flag_abs==1'b1 && dx[7]==1'b0) begin
abs_dx<=dx;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
abs_dy<='d0;
end
else if (flag_abs==1'b1 && dy[7]==1'b1) begin
abs_dy<=~dy+1'b1;
end
else if(flag_abs==1'b1 && dy[7]==1'b0) begin
abs_dy<=dy;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
dxy<='d0;
end
else if (flag_dxy==1'b1) begin
dxy<=abs_dx+abs_dy;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rgb<='d0;
end
else if (flag_rgb==1'b1 && dxy>10) begin
rgb<=8'hff;
end
else if(flag_rgb==1'b1 && dxy<=10) begin
rgb<=8'h00;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
po_flag<=1'b0;
end
else if (flag_rgb==1'b1) begin
po_flag<=1'b1;
end
else begin
po_flag<=1'b0;
end
end
fifo_generator_0 fifo_generator_0_inst1 (
.clk(clk), // input wire clk
.din(data_in1), // input wire [7 : 0] din
.wr_en(wr_en1), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(dout1), // output wire [7 : 0] dout
.full(full1), // output wire full
.empty(empty1) // output wire empty
);
fifo_generator_0 fifo_generator_0_inst2 (
.clk(clk), // input wire clk
.din(data_in2), // input wire [7 : 0] din
.wr_en(wr_en2), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(dout2), // output wire [7 : 0] dout
.full(full2), // output wire full
.empty(empty2) // output wire empty
);
endmodule
ram模块设计
ram模块示意图:
ram模块波形图:
ram模块代码实现:
module ram_ctrl(
input wire clk,
input wire rst_n,
input wire wr_en,
input wire [7:0] pi_data,
output wire [7:0] doutb,
output reg rd_flag
);
reg [15:0] wr_addr;
reg [15:0] rd_addr;
reg rd_en;
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rd_flag<=1'b0;
end
else if (wr_addr=='d39999) begin
rd_flag<=1'b1;
end
else begin
rd_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rd_en<=1'b0;
end
else if (rd_addr=='d39999) begin
rd_en<=1'b0;
end
else if(rd_flag==1'b1) begin
rd_en<=1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
wr_addr<='d0;
end
else if(wr_en==1'b1 && wr_addr=='d39999) begin
wr_addr<='d0;
end
else if (wr_en==1'b1) begin
wr_addr<=wr_addr+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
rd_addr<='d0;
end
else if(rd_addr=='d39999 && rd_en==1'b1) begin
rd_addr<='d0;
end
else if (rd_en==1'b1) begin
rd_addr<=rd_addr+1'b1;
end
end
ram_8x40000 ram_8x40000_inst (
.clka(clk), // input wire clka
.wea(wr_en), // input wire [0 : 0] wea
.addra(wr_addr), // input wire [15 : 0] addra
.dina(pi_data), // input wire [7 : 0] dina
.clkb(clk), // input wire clkb
.enb(rd_en), // input wire enb
.addrb(rd_addr), // input wire [15 : 0] addrb
.doutb(doutb) // output wire [7 : 0] doutb
);
endmodule
vga模块设计
vga模块示意图:
vga模块波形图:
vga模块代码实现:
module vga(
input wire clk2,
input wire rst_n,
input wire [7:0] doutb,
input wire rd_flag,
output reg hsync,
output reg vsync,
output reg [7:0] rgb
);
reg [9:0] cnt_h;
reg [9:0] cnt_v;
reg cnt_flag;
reg rd_flag_r;
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
rd_flag_r<=1'b0;
end
else begin
rd_flag_r<=rd_flag;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
cnt_flag<=1'b0;
end
else if(rd_flag_r==1'b1) begin
cnt_flag<=1'b1;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
cnt_h<='d0;
end
else if (cnt_h=='d799) begin
cnt_h<='d0;
end
else if(cnt_flag==1'b1) begin
cnt_h<=cnt_h+1'b1;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
cnt_v<='d0;
end
else if (cnt_v=='d524 && cnt_h=='d799) begin
cnt_v<='d0;
end
else if(cnt_h=='d799) begin
cnt_v<=cnt_v+1'b1;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
hsync<=1'b1;
end
else if (cnt_h=='d95) begin
hsync<=1'b0;
end
else if(cnt_h=='d799) begin
hsync<=1'b1;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
vsync<=1'b1;
end
else if (cnt_v=='d1 && cnt_h=='d799) begin
vsync<=1'b0;
end
else if(cnt_v=='d524 && cnt_h=='d799) begin
vsync<=1'b1;
end
end
always @(posedge clk2 or posedge rst_n) begin
if (!rst_n) begin
rgb<='d0;
end
else begin
rgb<=doutb;
end
end
endmodule