前言

      前面写了几篇关于运动目标检测的文章了:
1、基于FPGA:运动目标检测(VGA显示,原理图+源码+硬件选择)
2、基于FPGA:运动目标检测(LCD显示+串口输出,纯Verilog工程)
3、基于FPGA:运动目标检测(补充仿真结果,可用毕设)

      LCD显示、VGA显示都做完了,这篇文章补充一下包围盒的仿真代码,下载工程可以直接运行仿真。

一、安装器件库

      因为仿真占用逻辑资源比较多,这里需要用的cyclone V的器件库,如果没有的,自己安装(最好是Quartus II 18.0以上)
       18.0器件库链接:https://www.intel.com/content/www/us/en/software-kit/667160/intel-quartus-prime-standard-edition-design-software-version-18-0-for-windows.html
      在这里面就能找到了。其他版本可以自己选。(下载的时候,最好自己用邮箱注册一个英特尔账号)
在这里插入图片描述
在这里插入图片描述

      下载完器件库,把器件库放在quartus的安装目录的bin目录下,然后在win开始页,选择Device Installer,进行安装。
在这里插入图片描述
      选择Bin路径
在这里插入图片描述

      一路nex。
在这里插入图片描述

二、仿真工程操作

1、进入文件列表

在这里插入图片描述

2、找到bounding_box_locate.vt,双击打开文件

在这里插入图片描述

3、修改路径

      在右侧窗口中找到45~47行,修改里面的文件路径,如果不知道怎么修改请看第4条
在这里插入图片描述

4、路径设置

      路径修改主要是确保doc文件夹路径要正确,因为在你的电脑上解压存放的路径和我的路径不一定一样,比如在我电脑上doc路径是:F:\FPGA\FPGA\bounding_box_locate\doc,注意在修改3中的路径时单斜杠要换成双斜杠;
在这里插入图片描述

5、切换回“Hierarchy”,即工程界面

在这里插入图片描述

6、运行仿真

      点击“Tools”–“Run Simulation Tool”–“RTL Simulation”

在这里插入图片描述

7、查看波形

      仿真开始后可以在“Wave”窗口看到波形,仿真完成会自动停止
在这里插入图片描述

重点:调试问题

问题1:
      如果第6步点了之后,出现这个界面,证明你的quartus没有安装modelsim,或者指定modelsim路径。

在这里插入图片描述

      这个时候,需要点击Tools-Options…

在这里插入图片描述

      添加正确真实的ModelSim-Altera安装路径。

在这里插入图片描述
问题2:

Error: (vish-42) Unsupported ModelSim library format for "F:/FPGA/FPGA/bounding_box_locate/par/simulation/modelsim/rtl_work". (Format: 4)

在这里插入图片描述

      这种问题多出现在拷贝别人的工程然后直接打开进行仿真,或者电脑软件重装且Modelsim软件降版之后。
      实际原因为工程中已经有的编译生成的仿真库文件版本比正在使用的仿真软件版本高,导致现在版本的Modelsim无权限去删除旧的库文件以重新生成新的库文件。所以报这个错误。

解决办法:
      手动将当前工程目录(注意,是当前工程目录,不是你的Quartus或者Modelsim软件安装目录,这种低级理解性错误很多人都犯),你当前仿真的是哪个工程,就把这个工程目录下的simulation文件夹删除了,然后重新运行仿真就可以了。

问题3:

#** Error: (vlog-7) Failed to open design unit file "F:/FPGA/FPGA/bounding_box_locate/par/simulation/modelsim/bounding_box_locate.vt" in read mode.

在这里插入图片描述
      因为很乖巧,按问题2我说的方法解决了问题2,所以就出现了问题3🐸
      这个问题,很明显,就是在simulation文件夹下,有bounding_box_locate.vt,然后被你删除了🐸

      到这里应该就没有其他问题了,一些路径过长,路径有空格,中文的,记得不要有。

三、仿真代码

1、仿真顶层文件

//功能:绘制包围盒模块
module bounding_box_top#(
    parameter MAX_NUM    = 8  ,
    parameter GAP_THR    = 60 ,//离散阈值,即任意白点到某个已存在的包围盒距离小于等于GAP_THR则归属于此包围盒
    parameter CW         = 10 , //cordinate width
	parameter BOX_COLOR  = 24'hff_00_00//包围盒默认红色
	)
(
	input         clk    ,
	input         rst_n  ,
    //原始图像
	input         i_vsync,
	input         i_hsync,
	input         i_clken,
	input [23:0]  i_data ,//
    //目标检测并二值化后图像
    input         i_vsync_bin,
    input         i_hsync_bin,
    input         i_clken_bin,
    input [0:0]   i_data_bin ,//
	 //目标数量
	 output [$clog2(MAX_NUM)-1:0] obj_num,
    //原始图像添加包围盒后的图像
	output        o_vsync,
	output        o_hsync,
	output        o_clken,
	output [23:0] o_data  //
);
wire       post1_frame_vsync;
wire       post1_frame_href ;
wire       post1_frame_clken;
wire [7:0] post1_frame_data ;

wire [CW*MAX_NUM-1:0] x_min;
wire [CW*MAX_NUM-1:0] x_max;
wire [CW*MAX_NUM-1:0] y_min;
wire [CW*MAX_NUM-1:0] y_max;
multy_locate#(
    .MAX_NUM(MAX_NUM),//支持的最大目标数量
    .GAP_THR(GAP_THR),//离散阈值,即任意白点到某个已存在的包围盒距离小于等于GAP_THR则归属于此包围盒
    .CW     (CW     )//cordinate width
    )u_multy_locate_0
(
    .clk    (clk        ) ,
    .rst_n  (rst_n      ) ,
    .i_vsync(i_vsync_bin) ,
    .i_hsync(i_hsync_bin) ,
    .i_clken(i_clken_bin) ,
    .i_data (i_data_bin ) ,//binary data
    .obj_num(obj_num    ) ,//检测到的目标个数
    .x_min  (x_min      ) ,//目标的包围盒坐标
    .x_max  (x_max      ) ,//目标的包围盒坐标
    .y_min  (y_min      ) ,//目标的包围盒坐标
    .y_max  (y_max      ) //目标的包围盒坐标
);
// bounding_box_locate #(
//     .MAX_NUM    (MAX_NUM )  ,
//     .GAP_THR    (GAP_THR)  ,//离散阈值,即任意白点到某个已存在的包围盒距离小于等于GAP_THR则归属于此包围盒
//     .CW         (CW)   //cordinate width
// )u_bounding_box_locate_0
// (
//     .clk  (clk),
//     .rst_n(rst_n),
//     .i_vsync(i_vsync_bin),
//     .i_hsync(i_hsync_bin),
//     .i_clken(i_clken_bin),
//     .i_data (i_data_bin ),//binary data
//     .o_valid(),
//     .x_min(x_min),
//     .x_max(x_max),
//     .y_min(y_min),
//     .y_max(y_max)
// );
wire [MAX_NUM-1:0] i_vsync_w;
wire [MAX_NUM-1:0] i_hsync_w;
wire [MAX_NUM-1:0] i_clken_w;
wire [23:0]        i_data_w[MAX_NUM-1:0];
wire [MAX_NUM-1:0] o_vsync_w;
wire [MAX_NUM-1:0] o_hsync_w;
wire [MAX_NUM-1:0] o_clken_w;
wire [23:0]        o_data_w[MAX_NUM-1:0];
//使用generate语句循环例化多个bounding_box_draw模块,每个bounding_box_draw模块画一个包围盒,同时产生一个时钟的数据延迟
generate
genvar m;
for(m=0;m<MAX_NUM;m=m+1)begin:u_drw
    if(m==0)begin:u_drw_0
        bounding_box_draw#(
            .BOX_COLOR  ( BOX_COLOR ),//包围盒默认红色
            .CW         ( CW           ) //cordinate width
            ) u_bounding_box_draw_0
        (
            .clk    (clk  ),
            .rst_n  (rst_n),
            .i_vsync(i_vsync) ,
            .i_hsync(i_hsync) ,
            .i_clken(i_clken) ,
            .i_data (i_data ) ,
            .x_min  (x_min[(m+1)*CW-1-:CW]),
            .x_max  (x_max[(m+1)*CW-1-:CW]),
            .y_min  (y_min[(m+1)*CW-1-:CW]),
            .y_max  (y_max[(m+1)*CW-1-:CW]),
            .o_vsync(o_vsync_w[m]),
            .o_hsync(o_hsync_w[m]),
            .o_clken(o_clken_w[m]),
            .o_data (o_data_w[m]) //binary data
        );
    end
    else begin:u_drw_m
        bounding_box_draw#(
            .BOX_COLOR  ( BOX_COLOR ),//包围盒默认红色
            .CW         ( CW           ) //cordinate width
            ) u_bounding_box_draw_0
        (
            .clk    (clk  ),
            .rst_n  (rst_n),
            .i_vsync(o_vsync_w[m-1]),
            .i_hsync(o_hsync_w[m-1]),
            .i_clken(o_clken_w[m-1]),
            .i_data (o_data_w[m-1] ),
            .x_min  (x_min[(m+1)*CW-1-:CW]),
            .x_max  (x_max[(m+1)*CW-1-:CW]),
            .y_min  (y_min[(m+1)*CW-1-:CW]),
            .y_max  (y_max[(m+1)*CW-1-:CW]),
            .o_vsync(o_vsync_w[m]),
            .o_hsync(o_hsync_w[m]),
            .o_clken(o_clken_w[m]),
            .o_data (o_data_w[m] ) //binary data
        );
    end
end
endgenerate
assign o_vsync = o_vsync_w[MAX_NUM-1];
assign o_hsync = o_hsync_w[MAX_NUM-1];
assign o_clken = o_clken_w[MAX_NUM-1];
assign o_data  = o_data_w[MAX_NUM-1] ;
endmodule 

2、绘制包围盒模块

//功能:绘制包围盒模块
module bounding_box_draw#(
	parameter BOX_COLOR  = 24'hff_00_00,//包围盒默认红色
	parameter CW         = 12  //cordinate width
	)
(
	input       clk    ,
	input       rst_n  ,
	input       i_vsync,
	input       i_hsync,
	input       i_clken,
	input [23:0]i_data ,//binary data
	input [CW-1:0] x_min,x_max,y_min,y_max,
	output reg       o_vsync,
	output reg       o_hsync,
	output reg       o_clken,
	output reg [23:0]o_data  //binary data
);
reg [CW-1:0] x_cnt,y_cnt;//当前输入的像素坐标
reg i_vsync_r,i_hsync_r,i_vsync_neg_r;
wire i_vsync_neg,i_hsync_neg;
assign i_vsync_neg = ~i_vsync && i_vsync_r;//vsyn下降沿检测
assign i_hsync_neg = ~i_hsync && i_hsync_r;//hsyn下降沿检测
//产生i_vsync_r、i_hsync_r逻辑
always@(posedge clk or negedge rst_n)
if(~rst_n)
    begin
    i_vsync_r <= 1'b0;
    i_hsync_r <= 1'b0;
    end
else
    begin
	i_vsync_r <= i_vsync;
	i_hsync_r <= i_hsync;
	end
//产生x_cnt,y_cnt逻辑
always @(posedge clk or negedge rst_n) 
if(~rst_n) //复位,包围盒坐标全部清零,坐标全零的包围盒视为不存在
    begin
    x_cnt   <= 'd0;
    y_cnt   <= 'd0;
    end 
else if(i_vsync_neg)
    begin
    x_cnt   <= 'd0;//每帧结束清空坐标计数器
    y_cnt   <= 'd0;//每帧结束清空坐标计数器 
    end
else
    begin	 
    //坐标计数器计数
    x_cnt <= i_hsync_neg?'d0:(i_clken?x_cnt+1'b1:x_cnt);//hsyn下降沿清零,i_clken高电平时自增1
    y_cnt <= i_hsync_neg?y_cnt+1'b1:y_cnt;//hsyn下降沿自增1		
	end
//包围盒着色 
always@(posedge clk or negedge rst_n)
begin
if(~rst_n) //复位
    begin
    o_vsync <= 1'b0;
    o_hsync <= 1'b0;
    o_clken <= 1'b0;
    o_data  <= 'd0;		
    end	
else 
    begin
	o_vsync <= i_vsync; 
    o_hsync <= i_hsync; 
    o_clken <= i_clken; 
    if( (( (x_cnt+2'd3 >= x_min && x_cnt <= x_min) || (x_cnt <= x_max+2'd3 && x_cnt >= x_max)) && y_cnt+2'd3 >= y_min && y_cnt <= y_max+2'd3) || 
    	(( (y_cnt+2'd3 >= y_min && y_cnt <= y_min) || (y_cnt <= y_max+2'd3 && y_cnt >= y_max)) && x_cnt+2'd3 >= x_min && x_cnt <= x_max+2'd3) 
      )    o_data <= BOX_COLOR;
    else   o_data <= i_data;
    end
end
endmodule 

四、工程获取

1、直接点击下载:
基于FPGA:运动目标包围盒仿真(Quartus+modelsim)
注:如果点击无效,证明资源还在审核。

2、私信我或添加邮箱获取

Logo

苏州本地的技术开发者社区,在这里可以交流本地的好吃好玩的,可以交流技术,可以交流招聘等等,没啥限制。

更多推荐