FPGA一键测距仪之超声波模块篇

这篇具有很好参考价值的文章主要介绍了FPGA一键测距仪之超声波模块篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


系列篇章目录

FPGA一键测距仪之数码管篇
FPGA一键测距仪之[按键+控制+蜂鸣器]篇
FPGA一键测距仪之终篇
第一个FPGA小项目:基于BASYS3的超声波一键测距仪


超声波模块csdn,FPGA学习,fpga开发

前言

本篇会对超声波测距模块进行详细的讲解,包括测距原理、各模块的时序图构思以及代码实现。

所用到的软件工具:

  1. Vivado 2019.1
  2. Modelsim SE-64 10.4
  3. MATLAB R2018a
  4. Excel

一、超声波测距原理

拿特权老师的图来解释一下。如下图所示,超声波测距传感器通过两个TX、RX收发头输出、返回超声波来测距,测距传感器和FPGA之间通过TRIG和ECHO引脚交互波形数据,使得FPGA可以获取传感器测得的距离。
超声波模块csdn,FPGA学习,fpga开发
如上图所示,要想让传感器TX头发送超声波,我们需要在TRIG引脚上输入高电平持续时间大于10us的脉冲信号,TX头就会发送8个的40khz脉冲,并且在第8个脉冲下降沿的位置传感器主动拉高ECHO电平。当40khz脉冲碰到障碍物然后返回,被RX头采集到后,同样在第8个脉冲下降沿的位置拉低ECHO电平,这样一来我们让FPGA采集计数ECHO引脚的高电平时间t。再根据这个t来算出距离s,在室温25摄氏度下音速v为346m/s,高电平时间t代表着声波从TX头到障碍物再到RX头所花费的时间,由初中物理知识可知:2 * s = v * t,代入音速反解s,得到s(单位:米) = 173 * t(单位:秒),可对于FPGA来说处理时间的单位为us更为合适,所以将单位换算一下就可以得到s(单位:毫米) = 0.173 * t(单位:微秒),既然测出了时间,那么距离也就知道了。

二、测距模块框图的构思

下图是我构思的框图,暂时忽略vlg_key(按键)和vlg_ctrl(控制)模块,可以看到构想的超声波测距模块内部的组成,包括vlg_en(分频使能时钟模块)、vlg_trig(超声波触发模块)、vlg_echo(回响接收模块)、vlg_filt(均值滤波模块)、vlg_review(稳定检测模块)和vlg_cal(数学运算模块)这6份子模块文件。
超声波模块csdn,FPGA学习,fpga开发
工作流程大致如下:分频使能时钟模块将100Mhz系统时钟分频为周期1us的使能时钟,使能时钟为超声波触发模块(vlg_trig)和回响信号模块(vlg_echo)提供1us的计数单位;超声波触发模块负责产生触发脉冲驱动硬件传感器工作,回响接收模块处理硬件传感器传回的回响信号,对回响脉冲高电平时间计数;再通过均值滤波模块把采集到的n个回响高电平时间进行滤波,然后分别输出给数学运算模块(vlg_cal)和稳定检测模块(vlg_review),数学运算模块负责将时间转换成距离,稳定检测模块负责检测m个滤波后的回响脉冲高电平时间是否趋于一致,一致即判定数据已稳定,并会输出一个高脉冲。

下图为最后编译出来的原理图文件,符合构思框图,可以实现超声波的测距功能。测距模块外部留有输出给后级模块的引脚(如o_check_posedge、o_s_mm)、方便前级控制模块接入的信号引脚(如i_en)、还有接到硬件超声波传感器的Trig和Echo引脚。
超声波模块csdn,FPGA学习,fpga开发

三、分频使能时钟模块(vlg_en.v)的设计

1. 时序图的构思

时序图如下所示,因为最后输出的时间是以us为单位的,所以我们要让该模块在外部使能信号i_en下产生1us为周期的超声波使能时钟,为内部的vlg_trig和vlg_echo模块提供工作时钟。当i_en信号拉高时寄存器r_divcnt从0开始计数,当i_en拉低后r_divcnt计数值清零不会计数。在i_en为高电平的前提下,由100M/1M = 100可知分频计数范围是0~99,最大值计到99后归0继续计数;在r_divcnt=99后一个时钟周期下将o_clk_en拉高,此时o_clk_en就是我们要的后级的使能时钟。
超声波模块csdn,FPGA学习,fpga开发

2.代码实现

/*
	模块功能:产生周期1us的使能脉冲
*/

`timescale 1ns/1ps

module vlg_en #(
	parameter SYS_CLK_STEP = 10  //系统时钟100MHz,一周期10ns
	)
(
	input i_clk,
	input i_rst,
	input i_en,
	output reg o_clk_en
    );

/*****************1us计数器****************/
localparam DIV_CNT_MAX = 1000/SYS_CLK_STEP;
reg [7:0] r_divcnt;

always @(posedge i_clk)
	if(i_rst)	r_divcnt <= 'b0;
	else if(i_en)
	 begin
		if(r_divcnt < (DIV_CNT_MAX-1))	r_divcnt <= r_divcnt + 1'b1;
		else	r_divcnt <= 'b0;
	 end
	else	r_divcnt <= 'b0;
/*****************************************/

/**************产生使能脉冲**************/
always @(posedge i_clk)
	if(i_rst)	o_clk_en <= 1'b0;
	else if(r_divcnt == (DIV_CNT_MAX-1))	o_clk_en <= 1'b1;
	else	o_clk_en <= 1'b0;
/**************************************/
	
endmodule

四、超声波触发模块(vlg_trig.v)的设计

1.时序图的构思

如下图所示,寄存器r_trig_cnt在1us使能时钟i_clk_en下进行计数。为了让o_trig信号产生周期100ms、高电平为10us的脉冲,需要计算一下r_trig_cnt的计数最大值,由100ms/1us = 100,000可得,计数最大值为99,999,即r_trig_cnt计数到99,999后清零再次计数,在计数值为1~11时将o_trig拉高,即可产生我们要求的触发脉冲o_trig。
超声波模块csdn,FPGA学习,fpga开发

2.代码实现

/*
	模块功能:产生100ms为周期、高电平持续10us的脉冲
*/

`timescale 1ns/1ps

module vlg_trig (
	input i_clk,
	input i_rst,
	input i_clk_en,
	output reg o_trig
    );

	
localparam TRIG_CNT_MAX = 100_000;
localparam TRIG_CNT_10US = 10;
reg [31:0] r_trig_cnt;

/*******************100ms计数******************/	
always @(posedge i_clk)
	if(i_rst)	r_trig_cnt <= 'b0;
	else if(i_clk_en)
	 begin
		if(r_trig_cnt < (TRIG_CNT_MAX-1))	r_trig_cnt <= r_trig_cnt + 1'b1;
		else	r_trig_cnt <= 'b0;
	 end
	else ;
/*********************************************/

/****************产生10us的高脉冲***************/
always @(posedge i_clk)
	if(i_rst)	o_trig <= 1'b0;
	else if((r_trig_cnt > 0)&&(r_trig_cnt <= TRIG_CNT_10US))	o_trig <= 1'b1;
	else	o_trig <= 1'b0;
/*********************************************/
	

endmodule

五、回响接收模块(vlg_echo.v)的设计

1.时序图的构思

如下图所示,在vld_echo模块的设计中,i_echo接收传感器返回的回响脉冲,由于原始的回响脉冲有可能异步于时钟,所以先对回响脉冲进行上升沿/下降沿的边沿检测,利用边沿检测后的r_pos_echo和r_neg_echo来让回响脉冲和时钟边沿同步,同步成r_cnt_en再对它进行高电平时间计数,即在r_cnt_en为1的前提下根据使能时钟1us的周期进行计数,当r_cnt_en = 0后清零停止计数。在r_neg_echo产生高脉冲后(即表示i_echo回响信号产生下降沿跳变),我们让计数寄存器r_echo_cnt计到的数n锁存到o_t_us中,并输出到后级模块;在锁存的同时,还会产生一个o_echo_en脉冲信号,用作给后级提供回响脉冲个数的信号。
超声波模块csdn,FPGA学习,fpga开发

2.代码实现

/*
	模块功能:测量echo引脚返回的高脉冲时间
*/

`timescale 1ns/1ps

module vlg_echo (
	input i_clk,
	input i_rst,
	input i_echo,
	input i_clk_en,
	output reg [15:0] o_t_us,
	output reg o_echo_en
    );

reg [1:0] r_echo;
wire w_pos_echo,w_neg_echo;
reg r_cnt_en;
reg [15:0] r_cnt_echo;

/******************获取边沿检测信号*****************/
always @(posedge i_clk)
	if(i_rst)	r_echo <= 'b0;
	else	r_echo <= {r_echo[0],i_echo};

assign w_pos_echo = r_echo[0] & ~r_echo[1];
assign w_neg_echo = ~r_echo[0] & r_echo[1];
/*************************************************/

/*****************产生计数使能信号*****************/
always @(posedge i_clk)
	if(i_rst)	r_cnt_en <= 1'b0;
	else if(w_pos_echo)	r_cnt_en <= 1'b1;
	else if(w_neg_echo)	r_cnt_en <= 1'b0;
	else;
/************************************************/

/***************对使能信号高脉冲进行计数**************/
always @(posedge i_clk)
	if(i_rst)	r_cnt_echo <= 'b0;
	else if(r_cnt_en)
	 begin
		if(i_clk_en)	r_cnt_echo <= r_cnt_echo + 1'b1;
		else;
	 end
	else	r_cnt_echo <= 'b0;
/**************************************************/

/*****************对计数值锁存输出****************/
always @(posedge i_clk)
	if(i_rst)	o_t_us <= 'b0;
	else if(w_neg_echo)	o_t_us <= r_cnt_echo;
/***********************************************/

/****************使能信号有效输出*****************/
always @(posedge i_clk)
	if(i_rst)	o_echo_en <= 1'b0; 
	else	o_echo_en <= w_neg_echo;
/***********************************************/

	
endmodule

六、数学运算模块(vlg_cal.v)的设计

1.代码实现

vlg_cal模块用于解决s = 0.173 * t的转换问题,首先得清楚FPGA是不能做浮点运算的,我们就需要通过手段把浮点运算变成定点数据的运算。在这里我们先将s = 0.173 * t左右两边同时乘上4096,得到4096 *s= 709 * t,再除4096,这里很有讲究,因为4096 = 2^12,所以x除以4096就相当于x在二进制下右移12位,即此时s = (709 * t) >> 12,当然这里右移的12位也可以改成其他的位数,对应着不同的算术精度,这里就不再讨论了。
接着我们需要处理709 * t的问题,可以直接在时钟周期下直接相乘,也可以使用乘法器IP核,这里面有不同方案的对比取舍,具体可以看特权同学的视频:不同Multiplier设计的性能比对,从8:34开始
因为我的Modelsim仿真工具版本较低,导致配置乘法器IP核时出现意想不到的报错,所以我选择了直接相乘的方案,这也是合理的,同样能在FPGA内部被综合成乘法器。

/*
	模块功能:乘法器
*/

`timescale 1ns/1ps

module vlg_cal (
	input i_clk,
	input i_rst,
	input  [15:0] i_t_us,
	output [15:0] o_s_mm
    );

/*************s=0.173*t变成整数乘法的过程***********/
//	s*4096 = 0.173*4096*t 
//	=>	s*4096 = 709*t
//	=> 	s = 709*t / 4096
//	=>	s = 709*t >> 12
/************************************************/
localparam	MUL_N = 10'd709;
reg [25:0] w_mult_result;

always @(posedge i_clk)
	if(i_rst)	w_mult_result <= 'b0;
	else 	w_mult_result <= MUL_N * i_t_us;

/***********乘法器IP例化,实现709*t的功能***********/
/*
mult_gen_0 your_instance_name (
  .CLK(i_clk),  	// input wire CLK
  .A(MUL_N),    	// input wire [9 : 0] A
  .B(i_t_us),   	// input wire [15 : 0] B
  .P(w_mult_result) // output wire [25 : 0] P
);
/*************************************************/


assign o_s_mm = {2'b00,w_mult_result[25:12]};

endmodule

七、不加滤波模块的仿真

1.超声波模块例化程序

`timescale 1ns/1ps

module vlg_ultrawave(
	input i_clk,
	input i_rst,
	input i_en,
	input i_echo,
	output o_trig,
	output [15:0] o_s_mm
    );

localparam SYS_CLK_STEP = 10;
wire w_clk_en;
wire [15:0] w_t_us;
wire [15:0] w_t_filt_us;
wire w_echo_en;

/**********使能时钟产生模块**********/
vlg_en #(
	.SYS_CLK_STEP(SYS_CLK_STEP)

	)		
uut_vlg_en(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_en(i_en),
	.o_clk_en(w_clk_en)
    );	
/***********************************/

/***********产生触发信号o_trig驱动超声波模块工作*********/
vlg_trig    uut_vlg_trig(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_clk_en(w_clk_en),
	.o_trig(o_trig)
	);
/****************************************************/

/**********超声波模块回响信号i_echo引脚高电平时间测量**********/
vlg_echo    uut_vlg_echo(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo(i_echo),
	.i_clk_en(w_clk_en),
	.o_t_us(w_t_us)
	//.o_echo_en(w_echo_en)
	);
/**********************************************************/

/**********将回响信号高电平时间(us)通过公式转换成距离(mm)**********/
vlg_cal		uut_vlg_cal(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_t_us(w_t_us),
	.o_s_mm(o_s_mm)
	);
/*************************************************************/

endmodule

2.仿真代码

在这份仿真文件中,我们例化了vlg_ultrawave模块,在i_en拉高的时候随机产生不同高电平时长的i_echo信号做测试,i_en拉高的4.8秒内可以产生48个随机的距离数据。

`timescale 1ns/1ps

module testbench_top();
	

//参数定义

`define CLK_PERIORD		10		//时钟周期设置为10ns(100MHz)	


//接口申明
	
reg clk;
reg rst;
reg i_en;
reg i_echo;
wire o_trig;
wire [15:0] o_s_mm;

	
//对被测试的设计进行例化
vlg_ultrawave		uut_vlg_ultrawave(
	.i_clk(clk),
	.i_rst(rst),
	.i_en(i_en),
	.i_echo(i_echo),
	.o_trig(o_trig),
	.o_s_mm(o_s_mm)
	);


//复位和时钟产生

	//时钟和复位初始化、复位产生
initial begin
	clk <= 0;
	rst <= 1;
	#1000;
	rst <= 0;
end
	
	//时钟产生
always #(`CLK_PERIORD/2) clk = ~clk;	


//测试激励产生

initial begin
	i_echo = 0;
	@(negedge rst);	//等待复位完成
	
	@(posedge clk);

	repeat(100_000) begin
		@(posedge clk);
		i_en = 0;
	end
	i_en = 1;
	#4_000_000_000;	
	i_en = 1;
	#800_000_000;
	
	i_en = 0;
	#300_000_000;
	
	$stop;
end

integer tricnt = 0;
integer dly_time;
integer target_distance;

always @(posedge o_trig)
 begin 
	tricnt = tricnt + 1;
	#5000;
	i_echo = 1;
	//dly_time = dly_time + 58;
	dly_time = 11+{$random}%26000; //11<t<26011	
	target_distance = function_t2s(dly_time);
	$display("Test %0d:\tdistance of testbench = %0dmm",tricnt,target_distance);
	#(dly_time*1000);
	i_echo = 0;
 end
 
initial begin
	#1;
	$monitor("o_s_mm = %0dmm",o_s_mm);
end 
 
//函数实现运算s=t*0.173
function real function_t2s;
	input real t;
	begin
		function_t2s = 0.173*t;
	end


endfunction
 
endmodule

3.波形分析

由下图我们看到,每当i_echo脉冲高电平结束的下降沿到来后输出的距离数据得到一次更新,target_distance为测试程序设定的距离值,o_s_mm是我们通过捕获i_echo计数、转换后的距离值,可见下图中这两个值基本符合+/-3mm的误差范围。
超声波模块csdn,FPGA学习,fpga开发

八、均值滤波模块(vlg_filt.v)的设计

1.代码实现

在vlg_filt模块的设计中,我们要实现最近测量的16个回响脉冲高电平时间取均值滤波,也就是对16个数据取平均值。先根据vlg_echo模块输出的i_echo_en脉冲来判断是否有数据,有数据的情况下移位锁存16个回响脉冲高电平时间,然后对16个数据求和取均值,取均值时将数据之和右移4位,表示除以16,最终输出这个o_t_filt_us信号给后级模块。

/*
	模块功能:对最近测量的16个回响脉冲高电平时间求均值滤波
*/

`timescale 1ns/1ps

module vlg_filt (
	input i_clk,
	input i_rst,
	input i_echo_en,
	input  [15:0] i_t_us,
	output [15:0] o_t_filt_us
    );

/*****************锁存16个回响脉冲高电平时间数据****************/
reg [15:0] r_record_us[15:0];
integer i;

always @(posedge i_clk)
	if(i_rst)	
	 begin
		for(i=0;i<16;i=i+1)
		 begin
			r_record_us[i] <= 'b0;
		 end
	 end
	else if(i_echo_en)
	 begin
		r_record_us[0] <= i_t_us;
		for(i=0;i<15;i=i+1)
		 begin
			r_record_us[i+1] <= r_record_us[i];
		 end
		 
	 end
/************************************************************/

/*********************16个数据求和取均值*********************/
reg [19:0] r_record_sum_us;
	
always @(posedge i_clk)
	if(i_rst)	r_record_sum_us <= 'b0;
	else	r_record_sum_us <= r_record_us[0] + r_record_us[1] + r_record_us[2] + r_record_us[3] + r_record_us[4] + r_record_us[5] + r_record_us[6] + r_record_us[7] + r_record_us[8] + r_record_us[9] + r_record_us[10] + r_record_us[11] + r_record_us[12] + r_record_us[13] + r_record_us[14] + r_record_us[15];

assign o_t_filt_us = r_record_sum_us[19:4];  //右移4位,表示除以16
/**********************************************************/
	
endmodule

2.仿真分析

带有均值滤波功能的模块例化程序如下所示。

`timescale 1ns/1ps

module vlg_ultrawave(
	input i_clk,
	input i_rst,
	input i_en,
	input i_echo,
	output o_trig,
	output [15:0] o_s_mm
	//output o_check_posedge
    );

localparam SYS_CLK_STEP = 10;
wire w_clk_en;
wire [15:0] w_t_us;
wire [15:0] w_t_filt_us;
wire w_echo_en;

/**********使能时钟产生模块**********/
vlg_en #(
	.SYS_CLK_STEP(SYS_CLK_STEP)

	)		
uut_vlg_en(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_en(i_en),
	.o_clk_en(w_clk_en)
    );	
/***********************************/

/***********产生触发信号o_trig驱动超声波模块工作*********/
vlg_trig    uut_vlg_trig(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_clk_en(w_clk_en),
	.o_trig(o_trig)
	);
/****************************************************/

/**********超声波模块回响信号i_echo引脚高电平时间测量**********/
vlg_echo    uut_vlg_echo(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo(i_echo),
	.i_clk_en(w_clk_en),
	.o_t_us(w_t_us),
	.o_echo_en(w_echo_en)
	);
/**********************************************************/

/****************均值滤波后的回响信号高电平时间****************/

vlg_filt	uut_vlg_filt(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo_en(w_echo_en),
	.i_t_us(w_t_us),
	.o_t_filt_us(w_t_filt_us)
	);
/**********************************************************/

/**********将回响信号高电平时间(us)通过公式转换成距离(mm)**********/
vlg_cal		uut_vlg_cal(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_t_us(w_t_filt_us),
	.o_s_mm(o_s_mm)
	);
/*************************************************************/
	
endmodule

仿真测试程序任和不带有滤波模块的相同,会随机产生48个echo回响脉冲来让超声波测距模块采集时间测量距离。
下面我从48个距离数据中去除了前15个,从第16个到第48个的距离数据(以毫米为单位,滤波前和滤波后都有)被记录在Excel表格中,如下图所示。
超声波模块csdn,FPGA学习,fpga开发
下面写一段Matlab代码来把这些数据画成一张曲线图,代码如下所示:

test_array = xlsread('D:\test.xls','sheet1');
x = test_array(1,:);
y1 = test_array(2,:);
y2 = test_array(3,:);

plot(x,y1,'g',x,y2,'b','LineWidth',2);
xlabel("数据个数/个");
ylabel("测量距离/mm");

这样有下图,图中绿色线条为未滤波的测量数据,蓝色为滤波后的数据。
超声波模块csdn,FPGA学习,fpga开发
由上图可见,观察这33个因测量随机产生的距离而得到的滤波以及未滤波的数据,我们可以发现:未滤波的数据表现的和随机数据一样不稳定,滤波后的数据整体变化幅度明显减弱,相对未滤波的更加平滑;数值总体上处于未滤波数据的中间位置。我们还可以发现,蓝色曲线的变化趋势类似于绿色曲线,并且蓝色曲线有点滞后于绿色曲线,以上这些对比可以体会到均值滤波的效果。

九、稳定检测模块(vlg_review.v)的设计

1.代码实现

在vlg_review模块中,我们设计的功能是检测滤波后的时间数据是否稳定,这里锁存4个时间数据,同样是根据vlg_echo模块输出的i_echo_en脉冲来判断是否有数据,有数据就锁存,然后判断4个数据是否非0且相等,是的话拉高r_checkstable,否则保持r_checkstable低电平。然后再对r_checkstable进行上升沿检测,产生上升沿脉冲信号o_check_posedge,此信号输出到外部,反馈给vlg_ctrl模块从而达到关闭超声波测距模块的作用。

/*
	模块功能:检测滤波后的时间数据是否稳定
*/

`timescale 1ns/1ps

module vlg_review (
	input i_clk,
	input i_rst,
	input i_echo_en,
	input [15:0] i_t_filt_us,
	output o_check_posedge
    );

/***************锁存4个滤波后的时间数据****************/	
reg [15:0] r_record_filt_us[3:0];
integer i;

always @(posedge i_clk)
	if(i_rst)	
	 begin
		for(i=0;i<4;i=i+1)
		 begin
			r_record_filt_us[i] <= 'b0;
		 end
	 end
	else if(i_echo_en)
	 begin
		r_record_filt_us[0] <= i_t_filt_us;
		for(i=0;i<3;i=i+1)
		 begin
			r_record_filt_us[i+1] <= r_record_filt_us[i];
		 end
		 
	 end
	 else; 
/**************************************************/

/**************判断4个数据是否非0且相等**************/
reg r_checkstable;
reg [1:0] r_check_pulse;
	
always @(posedge i_clk)
	if(i_rst)	r_checkstable <= 1'b0;
	else if((r_record_filt_us[0]!='b0)&&(r_record_filt_us[1]!='b0)&&(r_record_filt_us[2]!='b0)&&(r_record_filt_us[3]!='b0))
	 begin
		if((r_record_filt_us[0]==r_record_filt_us[1])&&(r_record_filt_us[1]==r_record_filt_us[2])&&(r_record_filt_us[2]==r_record_filt_us[3]))	r_checkstable <= 1'b1;		//4个数据相等则将r_checkstable拉高
		else	r_checkstable <= 1'b0;		//4个数据不相等则将r_checkstable拉低
	 end
	else	r_checkstable <= 1'b0;
/**************************************************/

/****************边沿检测,取r_checkstable的上升沿跳变信号做输出**************/
always @(posedge i_clk)
	if(i_rst)	r_check_pulse <= 2'b00;
	else	r_check_pulse <= {r_check_pulse[0],r_checkstable};
	
assign o_check_posedge = r_check_pulse[0] & ~r_check_pulse[1];
/************************************************************************/
	
endmodule

十、超声波模块(vlg_ultrawave.v)的测试

1.模块例化代码

`timescale 1ns/1ps

module vlg_ultrawave(
	input i_clk,
	input i_rst,
	input i_en,
	input i_echo,
	output o_trig,
	output [15:0] o_s_mm,
	output o_check_posedge
    );

localparam SYS_CLK_STEP = 10;
wire w_clk_en;
wire [15:0] w_t_us;
wire [15:0] w_t_filt_us;
wire w_echo_en;

/**********使能时钟产生模块**********/
vlg_en #(
	.SYS_CLK_STEP(SYS_CLK_STEP)

	)		
uut_vlg_en(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_en(i_en),
	.o_clk_en(w_clk_en)
    );	
/***********************************/

/***********产生触发信号o_trig驱动超声波模块工作*********/
vlg_trig    uut_vlg_trig(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_clk_en(w_clk_en),
	.o_trig(o_trig)
	);
/****************************************************/

/**********超声波模块回响信号i_echo引脚高电平时间测量**********/
vlg_echo    uut_vlg_echo(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo(i_echo),
	.i_clk_en(w_clk_en),
	.o_t_us(w_t_us),
	.o_echo_en(w_echo_en)
	);
/**********************************************************/

/****************均值滤波后的回响信号高电平时间****************/

vlg_filt	uut_vlg_filt(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo_en(w_echo_en),
	.i_t_us(w_t_us),
	.o_t_filt_us(w_t_filt_us)
	);
/**********************************************************/

/**********将回响信号高电平时间(us)通过公式转换成距离(mm)**********/
vlg_cal		uut_vlg_cal(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_t_us(w_t_filt_us),
	.o_s_mm(o_s_mm)
	);
/*************************************************************/

/**************检测滤波后的高电平时间数据是否稳定****************/
vlg_review	uut_vlg_review(
	.i_clk(i_clk),
	.i_rst(i_rst),
	.i_echo_en(w_echo_en),
	.i_t_filt_us(w_t_filt_us),
	.o_check_posedge(o_check_posedge)
	);
/*************************************************************/
	
endmodule

2.仿真程序

在仿真程序中,我们产生一个高电平时间线性增大的i_echo回响信号,当dly_time增大到348us时,也就是理想测得的距离为348*0.173 = 60mm后我们让i_echo高电平时间不变,来观察接入超声波测距模块后各个输出的情况。

`timescale 1ns/1ps

module testbench_top();
	

//参数定义

`define CLK_PERIORD		10		//时钟周期设置为10ns(100MHz)	


//接口申明
	
reg clk;
reg rst;
reg i_en;
reg i_echo;
wire o_trig;
wire [15:0] o_s_mm;
wire o_check;

	
//对被测试的设计进行例化
vlg_ultrawave		uut_vlg_ultrawave(
	.i_clk(clk),
	.i_rst(rst),
	.i_en(i_en),
	.i_echo(i_echo),
	.o_trig(o_trig),
	.o_s_mm(o_s_mm),
	.o_check_posedge(o_check)
	);

//复位和时钟产生

	//时钟和复位初始化、复位产生
initial begin
	clk <= 0;
	rst <= 1;
	#1000;
	rst <= 0;
end
	
	//时钟产生
always #(`CLK_PERIORD/2) clk = ~clk;	


//测试激励产生

initial begin
	i_echo = 0;
	@(negedge rst);	//等待复位完成
	
	@(posedge clk);

	repeat(100_000) begin
		@(posedge clk);
		i_en = 0;
	end
	i_en = 1;
	#4_000_000_000;	
	
	i_en = 0;
	#300_000_000;
	
	$stop;
end

integer tricnt = 0;
integer dly_time = 0;
integer target_distance;

always @(posedge o_trig)
 begin 
	tricnt = tricnt + 1;
	#5000;
	i_echo = 1;
	if(dly_time==348)	dly_time = 348;
	else	
	 begin 
		dly_time = dly_time + 58;
	 end
	//dly_time = 11+{$random}%26000; //11<t<26011	
	target_distance = function_t2s(dly_time);
	$display("Test %0d:\tdistance of testbench = %0dmm",tricnt,target_distance);
	#(dly_time*1000);
	i_echo = 0;
 end
 
initial begin
	#1;
	$monitor("o_s_mm = %0dmm",o_s_mm);
end 
 
//函数实现运算s=t*0.173
function real function_t2s;
	input real t;
	begin
		function_t2s = 0.173*t;
	end


endfunction
 
endmodule

3.波形分析

由下图可见,当target_distance增大到60后不变,因为经过滤波器,所以输出信号o_s_mm会比target_distance慢16拍才会到达60,到了60后由于被检测模块检测到4拍的数据相同,所以判断4拍后数据稳定,o_check随即产生一个高脉冲信号输出,见下图黄圈所示,可见之前的vlg_review模块设计符合要求。其余的信号如o_trig也是输出正常的,由此可知我们的vlg_ultrawave模块设计成功!
超声波模块csdn,FPGA学习,fpga开发


总结

本篇详细讲解了FPGA一键测距仪小项目中超声波测距模块的具体实现,从测距原理、各模块的时序图构思以及代码实现都记录了一遍,实现的仿真效果也都和预期差不多,总的来说还是学到了不少关于FPGA自顶向下模块化的设计的方法。
下一篇:FPGA一键测距仪之数码管篇文章来源地址https://www.toymoban.com/news/detail-787810.html

到了这里,关于FPGA一键测距仪之超声波模块篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于FPGA的超声波测距——UART串口输出

    环境: 1、Quartus18.0 2、vscode 3、板子型号:EP4CE10F17C8 4、超声波模块:HC_SR04 要求: 使用 EP4CE10F17C8开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到串口助手上。 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发

    2024年02月14日
    浏览(45)
  • 基于FPGA的超声波测距——数码管显示

    环境: 1、Quartus18.1 2、vscode 3、板子型号:EP4CE6F17C8N 4、超声波模块:HC_SR04 要求: 使用 EP4CE6F17C8开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到开发板上的数码管上 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超

    2024年02月06日
    浏览(40)
  • 基于MAX-10 FPGA 超声波测距模块HC_SR04

    HC-SR04是一种基于超声波的测距模块。该模块向前15度内发送超声波并接收回响,通过发出超声波到收到回响的这个时间间隔计算前方的障碍物距离,可以用来给智能小车做障碍物监测。可提供2cm- 400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接

    2024年02月07日
    浏览(49)
  • 【嵌入式系统应用开发】FPGA——基于HC-SR04超声波测距

    硬件 DE2-115 HC-SR04超声波传感器 软件 Quartus 18.1 使用DE2-115开发板驱动HC-SR04模块,并将所测得数据显示到开发板上的数码管。 HC-SR04 超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为 HC-SR04 外观,

    2024年02月08日
    浏览(62)
  • 超声波测距系统

      具有测距、温度补充、实时时钟、记忆、阈值警报、串口数据发送等等功能,通过LCD1602显示,按键进行相关操作。   LCD1602显示共有五个界面,按键一用于切换显示界面。   此界面测距为连续测距模式,LCD1602不间断刷新测量距离和温度,一旦测量距离小于设置的阈

    2024年02月03日
    浏览(41)
  • 超声波测距仿真

    萌新第一次写博客,有格式不正确的地方还请大家见谅。 用HCSR04超声波传感器测量距离,测量范围0~170cm,精确到小数点后一位。 用LCD1602或者数码管显示测量到的距离。 当距离大于120cm时,绿色LED灯亮; (1)当距离在50-120cm之间,蜂鸣器间断发声“滴 滴 滴 ”提示,黄色LED灯亮

    2024年02月05日
    浏览(42)
  • 全志ARM-超声波测距

    超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离 1.测距原理: 给Trig端口至少10us的高电平发送声波,Echo信号,由低电平跳转到高电平,开始发送波;Echo,由高电平跳转回低电平,表示波回来了

    2024年04月28日
    浏览(34)
  • Verilog 实现超声波测距

    教学视频: https://www.bilibili.com/video/BV1Ve411x75W?p=33spm_id_from=pageDrivervd_source=19ae31dff4056e52d2729a4ca212602b 参考资料:STM32的超声波测距程序_超声波测距stm32程序_VaderZhang的博客-CSDN博客 推荐一波自己的文章:STM32蓝牙控制循迹避障小车源代码——3.舵机、超声波测距模块_stem32超声波舵

    2024年02月11日
    浏览(37)
  • 基于STM32的超声波测距

    一、HC-SR04模块介绍 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可高达3mm;模块包括超声波发射器、接收器、与控制电路。 模块的基本工作原理为: (1)采用 IO口 TRIG触发测距,给最少 10us的高电平信呈。 (2)模块自动发送 8个 40khz的方波,自动检测是

    2024年02月13日
    浏览(47)
  • 输入捕获模块的使用–超声波测距

    @(MSP432P401R) 输入捕获的配置 基本默认即可 输入捕获的API的使用 参数 Capture_Mode即捕获模式,经实际测试,MSP432P401R只能使用前三种模式 Capture_CallBackFxn即回调函数 Capture_PeriodUnits即捕获周期单位 函数表 全局配置,在ti_drivers_config.c文件中生成 功能函数 文档链接:file:///D:/MSP%

    2024年02月15日
    浏览(81)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包