基于FPGA的超声波测距

前言

本篇博客主要是实现使用 DE2-115 开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到开发板上的数码管上。

一、实验设备

DE2-E115 FPGA开发板 + Quartus + HC_SR04超声波检测模块

二、实验原理

1、超声波原理

HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为HC-SR04外观,其基本工作原理为给予此超声波测距模块触发信号后模块发射超声波,当超声波投射到物体而反射回来时,模块输出回响信号,以触发信号和回响信号间的时间差,来判定物体的距离。

HC-SR04超声波测距模块实物图:
在这里插入图片描述
在这里插入图片描述

2、超声波测距模块时序图

在这里插入图片描述
以上时序图表明你只需要提供一个10uS 以上脉冲触发信号,该模块内部将发出8个40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。

三、系统结构设计

在这里插入图片描述

四、代码实现

module 	HC_SR04_TOP(
	input  			clk		,
	input   		rstn	,
	input   		echo	, // 距离信号
 
	output   		trig	, // 触发测距信号
	output 	[6:0]	hex1	, // -共阳极,低电平有效
	output  [6:0]	hex2	, // -
    output  [6:0]	hex3	, // -
    output  [6:0]	hex4	, //连接符
    output  [6:0]	hex5	, //cm -
    output  [6:0]	hex6	, //cm -
    output  [6:0]	hex7	, //cm -
    output  [6:0]	hex8	  //熄
);
 
	wire	[18:00]		data_o		;
	wire 				clk_us		;
 
	seg_driver u_seg_driver(
		.clk		(clk	),
		.rstn		(rstn	),
		.data_in	(data_o	), //待显示数据
		.hex1		(hex1	), // -共阳极,低电平有效
		.hex2		(hex2	), // -
		.hex3		(hex3	), // -
		.hex4		(hex4	), //连接符
		.hex5		(hex5	), //cm - 
		.hex6		(hex6	), //cm - 
		.hex7		(hex7	), //cm - 
		.hex8		(hex8	)  //熄灭
	);
 
	clk_div	u_clk_div(
		.clk		(clk	),
		.rstn		(rstn	),
		.clk_us		(clk_us )
	);
	trig_driver	u_trig_driver(
		.clk_us		(clk_us	),
		.rstn		(rstn	),
		.trig		(trig	)
	);
 
	echo_driver	u_echo_driver(
		.clk		(clk	),
		.clk_us		(clk_us	),
		.rstn		(rstn	),
		.echo		(echo	),
		.data_o		(data_o	)
		);
 
endmodule
module 	trig_driver(
	input  wire			clk_us	,
	input  wire 		rstn	,
		   
	output wire  		trig	  //触发测距信号
);

	parameter CYCLE_MAX = 19'd29_9999;

	reg		[18:00]	cnt		;

// 10毫秒持续电平输出
	
	always @(posedge clk_us or negedge rstn) begin
		if(!rstn) begin
			cnt <= 19'd0;
		end
		else if(cnt == CYCLE_MAX) begin
			cnt <= 19'd0;
		end
		else begin
			cnt <= cnt + 19'd1;
		end
	end
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 
module 	echo_driver(
	input  wire 		clk		,
	input  wire			clk_us	,
	input  wire 		rstn	,
		   
	input  wire 		echo	,
	output wire [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);

	parameter T_MAX = 16'd5_9999;//510cm 对应计数值

	reg				r1_echo,r2_echo; //边沿检测	
	wire			echo_pos,echo_neg; //
	
	reg		[15:00]	cnt		; 
	
	reg		[18:00]	data_r	;
	
	//如果使用clk_us 检测边沿,延时2us,差值过大
	always @(posedge clk or negedge rstn)begin  
		if(!rstn)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end
	
	assign echo_pos = r1_echo & ~r2_echo;
	assign echo_neg = ~r1_echo & r2_echo;
	
	always @(posedge clk_us or negedge rstn) begin
		if(!rstn) begin
			cnt <= 16'd0;
		end
		else if(echo) begin
			if(cnt == T_MAX) begin
				cnt <= 16'd0;
			end
			else begin
				cnt <= cnt + 16'd1;
			end
		end
		else begin
			cnt <= 16'd0;
		end
	end
	
	always @(posedge clk or negedge rstn)begin  
		if(!rstn)begin  
			data_r <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end
	
	assign data_o = data_r >> 1;

endmodule 
module 	clk_div(
	input  wire			clk		,
	input  wire 		rstn	,
		   
	output wire  		clk_us 	  //
);

	parameter CNT_MAX = 19'd49;//1us的计数值为 50 * Tclk(20ns)

	reg		[5:0]	cnt		; 
	wire			add_cnt ;
	wire			end_cnt ;
	
	// 时钟分频
	always @(posedge clk or negedge rstn) begin
		if(!rstn) begin
			cnt <= 6'd0;
		end
		else if(cnt == CNT_MAX) begin
			cnt <= 6'd0;
		end
		else begin
			cnt <= cnt + 6'd1;
		end
	end
	
	assign clk_us = cnt >= CNT_MAX ;
	

endmodule 

module seg_driver(
	input	wire		clk		,  //50MHz
	input	wire		rstn	,  //low valid
 
	input	wire [18:0]	data_in	, //待显示数据
 
	output	reg	[6:0]	hex1	, // -共阳极,低电平有效
	output	reg [6:0]	hex2	, // -
    output	reg [6:0]	hex3	, // -
    output	reg [6:0]	hex4	, //连接符
    output	reg [6:0]	hex5	, //cm - 
    output	reg [6:0]	hex6	, //cm - 
    output	reg [6:0]	hex7	, //cm - 
    output	reg [6:0]	hex8	  //熄灭
);
 	//parameter define
	localparam	NUM_0	=	8'b1100_0000,
				NUM_1 	= 	8'b1111_1001,
				NUM_2   = 	8'b1010_0100,
				NUM_3   = 	8'b1011_0000,
				NUM_4   = 	8'b1001_1001,
				NUM_5   = 	8'b1001_0010,
				NUM_6   = 	8'b1000_0010,
				NUM_7   = 	8'b1111_1000,
				NUM_8   = 	8'b1000_0000,
				NUM_9   = 	8'b1001_0000,
				NUM_A   = 	8'b1000_1000,
				NUM_B   = 	8'b1000_0011,
				NUM_C   = 	8'b1100_0110,
				NUM_D   = 	8'b1010_0001,
				NUM_E   = 	8'b1000_0110,
				NUM_F   = 	8'b1000_1110,
				ALL_LIGHT = 8'b0000_0000,
				LIT_OUT = 	8'b1111_1111;
 	//reg 、wire define
	reg		[3:0]	cm_hund	;//100cm
	reg		[3:0]	cm_ten	;//10cm
	reg		[3:0]	cm_unit	;//1cm
	reg		[3:0]	point_1	;//1mm
	reg		[3:0]	point_2	;//0.1mm
	reg		[3:0]	point_3	;//0.01mm
 
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin  
			cm_hund	<= 'd0;
			cm_ten	<= 'd0;
			cm_unit	<= 'd0;
			point_1	<= 'd0;
			point_2	<= 'd0;
			point_3	<= 'd0;
		end
		else begin
			cm_hund <= data_in / 10 ** 5;
			cm_ten	<= data_in / 10 ** 4 % 10;
			cm_unit <= data_in / 10 ** 3 % 10;
			point_1 <= data_in / 10 ** 2 % 10;
			point_2 <= data_in / 10 ** 1 % 10;
			point_3 <= data_in / 10 ** 0 % 10;
		end
	end
 
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin  
			hex1 <= ALL_LIGHT;
			hex2 <= ALL_LIGHT;
			hex3 <= ALL_LIGHT;
			hex4 <= ALL_LIGHT;
			hex5 <= ALL_LIGHT;
			hex6 <= ALL_LIGHT;
			hex7 <= ALL_LIGHT;
			hex8 <= ALL_LIGHT;
		end
		else begin
			hex1 <= hex_data(point_3);
			hex2 <= hex_data(point_2);
			hex3 <= hex_data(point_1);
			hex4 <= 7'b011_1111;
			hex5 <= hex_data(cm_unit);
			hex6 <= hex_data(cm_ten);
			hex7 <= hex_data(cm_hund);
			hex8 <= LIT_OUT;
		end
	end //always end
 
	function  [6:0]	hex_data; //函数不含时序逻辑相关
		input   [03:00]	data_i;//至少一个输入
		begin
			case(data_i)
				'd0:hex_data = NUM_0;
				'd1:hex_data = NUM_1;
				'd2:hex_data = NUM_2;
				'd3:hex_data = NUM_3;
				'd4:hex_data = NUM_4;
				'd5:hex_data = NUM_5;
				'd6:hex_data = NUM_6;
				'd7:hex_data = NUM_7;
				'd8:hex_data = NUM_8;
				'd9:hex_data = NUM_9;
				default:hex_data = ALL_LIGHT;
			endcase
		end
	endfunction
 
endmodule

引脚配置图:
在这里插入图片描述

五、RTL视图

在这里插入图片描述

六、实验结果

七、总结

通过本次实验,了解了HC-SR04超声波测距模块,懂得了如何通过超声波进行测距的原理,同时将测距模块与之前学习的FPGA联系起来,对数码管这些模块也更加熟练,让我能够将FPGA与实际的项目联系起来,收获很大。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值