基于FPGA的超声波测距

1、 实验目的

使用 DE2-115 开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到开发板上的数码管上,或者通过用UART通信方式上传到笔记本串口助手上显示(可采用UART IP核)。

2、实验平台

DE2-E115 FPGA开发板 + Quartus + Modelsim
学习并掌握HC_SR04模块的使用

3. 实验原理

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

模块测距工作原理:

(1) 主控设备给 Trig 脚提供一个 10us 的脉冲信号。

(2) HC-SR04 接收到信号,开始发送超声波,并把 Echo置为高电平,然后准备接收返回的超声波。

(3) HC-SR04 接收到返回的超声波,把 Echo 置为低电平。

(4) Echo 高电平持续的时间就是超声波从发射到返回的时间间隔。

产品实物图:在这里插入图片描述
模块框图:
在这里插入图片描述

5、Verilog 实现数码管显视驱动模块

数码管:本质上为一组发光二极管按照一定顺序排列而成,其显示原理与LED无异。
在这里插入图片描述
根据硬件原理图所示,发光二极管,所有的阳极都接通3.3V的正电压,也即—高电平,所以如果我们想要
发光二极管导通的话,需要在阴极接通低电平,就可以让LED亮起来。

信号定义
在这里插入图片描述
设计文件

/*================================================*\
		  Filename ﹕data_gen.v
			Author ﹕Adolph
	  Description  ﹕产生数码管需要显示的数据. 32'h11111111~32'h33333333;
		 Called by ﹕seg_top.v
Revision History   ﹕ 2022-6-6 15:49:24
		  			  Revision 1.0
  			  Email﹕adolph1354238998@gmail.com
			Company﹕ 
\*================================================*/
module data_gen(
	input	clk	,
	input	rst_n,
	
	output	reg [31:0] data_dis
);

	parameter TIME_DELAY = 25'd2500;
	
	reg		[24:0]	cnt_delay;
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt_delay <= 25'd0;
		end
		else if(cnt_delay >= TIME_DELAY - 25'd1)begin
			cnt_delay <= 25'd0;
		end
		else begin
			cnt_delay <= cnt_delay + 25'd1;
		end
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			data_dis <= 32'h1111_1111;
		end
		else if(data_dis == 32'h3333_3333)begin
			data_dis <= 32'h1111_1111;
		end
		else if(cnt_delay >= TIME_DELAY - 25'd1)begin
			data_dis <= data_dis + 32'h1;
		end
		else begin
			data_dis <= data_dis;
		end
	end

endmodule 

数码管驱动模块
信号定义
在这里插入图片描述
设计文件

/*================================================*\
		  Filename ﹕seg_driver.v
			Author ﹕Adolph
	  Description  ﹕对输入的数据译码,并驱动数码管显示对应数据
		 Called by ﹕seg_top.v
Revision History   ﹕ 2022-5-30 14:27:22
		  			  Revision 1.0
  			  Email﹕adolph1354238998@gmail.com
			Company﹕ 
\*================================================*/
module seg_driver(
	input			clk		,
	input			rst_n	,
	
	input	  [31:0]dis_data,//待显示的数据
	output reg[7:0]	dig_sel	,
	output reg[7:0]	dig_seg	 
);
//wire  [31:0]dis_data;


//	assign dig_seg = 8'd0;
//	assign dig_sel = 1'b0;
	localparam
		NUM_0  	= 8'hC0,
		NUM_1  	= 8'hF9,
		NUM_2  	= 8'hA4,
		NUM_3  	= 8'hB0,
		NUM_4  	= 8'h99,
		NUM_5  	= 8'h92,
		NUM_6  	= 8'h82,
		NUM_7  	= 8'hF8,
		NUM_8  	= 8'h80,
		NUM_9  	= 8'h90,
		NUM_A  	= 8'h88,
		NUM_B  	= 8'h83,
		NUM_C  	= 8'hC6,
		NUM_D  	= 8'hA1,
		NUM_E  	= 8'h86,
		NUM_F  	= 8'h8E,
		LIT_ALL	= 8'h00,
		BLC_ALL	= 8'hFF;
	parameter CNT_REF = 25'd1000;
	
	reg	[9:0]	cnt_20us; //20us计数器
	reg	[3:0] 	data_tmp; //用于取出不同位选的显示数据
	
//	assign dis_data = 32'hABCD_4413;
//描述位选信号切换
	//描述刷新计数器
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt_20us <= 25'd0;
		end
		else if(cnt_20us >= CNT_REF - 25'd1)begin
			cnt_20us <= 25'd0;
		end
		else begin
			cnt_20us <= cnt_20us + 25'd1;
		end
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			dig_sel <= 8'hfe;//8'b1111_1110
		end
		else if(cnt_20us >= CNT_REF - 25'd1)begin
			dig_sel <= {dig_sel[6:0],dig_sel[7]};
		end
		else begin
			dig_sel <= dig_sel;
		end
	end
	
//段选信号描述
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			data_tmp <= 4'd0;
		end
		else begin
			case(dig_sel)
				8'b1111_1110:data_tmp <= dis_data[ 3-:4];
				8'b1111_1101:data_tmp <= dis_data[ 7-:4];
				8'b1111_1011:data_tmp <= dis_data[11-:4];
				8'b1111_0111:data_tmp <= dis_data[15-:4];
				8'b1110_1111:data_tmp <= dis_data[19-:4];
				8'b1101_1111:data_tmp <= dis_data[23-:4];
				8'b1011_1111:data_tmp <= dis_data[27-:4];
				8'b0111_1111:data_tmp <= dis_data[31-:4];
				default: data_tmp <= 4'hF;
			endcase
		end
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			dig_seg <= BLC_ALL;
		end
		else begin
			case(data_tmp)
				4'h0 : dig_seg <= NUM_0;
				4'h1 : dig_seg <= NUM_1;
				4'h2 : dig_seg <= NUM_2;
				4'h3 : dig_seg <= NUM_3;
				4'h4 : dig_seg <= NUM_4;
				4'h5 : dig_seg <= NUM_5;
				4'h6 : dig_seg <= NUM_6;
				4'h7 : dig_seg <= NUM_7;
				4'h8 : dig_seg <= NUM_8;
				4'h9 : dig_seg <= NUM_9;
				4'hA : dig_seg <= NUM_A;
				4'hB : dig_seg <= NUM_B;
				4'hC : dig_seg <= NUM_C;
				4'hD : dig_seg <= NUM_D;
				4'hE : dig_seg <= NUM_E;
				4'hF : dig_seg <= NUM_F;
				default: ;
			endcase 
		end
	end

endmodule 

仿真验证

`timescale 1ns/1ns

module tb_dig;
	reg		clk;
	reg		rst_n;
	
	wire	[7:0]	dig_sel;
	wire    [7:0]	dig_seg;
	
	reg		[39:0]	CHARAC;//1个 ASCII 码,需要8bit 二进制表示
	
	defparam seg_driver.CNT_REF = 100;
	
	localparam
		NUM_0 = 8'hC0,
		NUM_1 = 8'hF9,
		NUM_2 = 8'hA4,
		NUM_3 = 8'hB0,
		NUM_4 = 8'h99,
		NUM_5 = 8'h92,
		NUM_6 = 8'h82,
		NUM_7 = 8'hF8,
		NUM_8 = 8'h80,
		NUM_9 = 8'h90,
		NUM_A = 8'h88,
		NUM_B = 8'h83,
		NUM_C = 8'hC6,
		NUM_D = 8'hA1,
		NUM_E = 8'h86,
		NUM_F = 8'h8E;
		
	always@(*)begin
		case(dig_seg)
			NUM_0 : CHARAC = "NUM_0";
			NUM_1 : CHARAC = "NUM_1";
			NUM_2 : CHARAC = "NUM_2";
			NUM_3 : CHARAC = "NUM_3";
			NUM_4 : CHARAC = "NUM_4";
			NUM_5 : CHARAC = "NUM_5";
			NUM_6 : CHARAC = "NUM_6";
			NUM_7 : CHARAC = "NUM_7";
			NUM_8 : CHARAC = "NUM_8";
			NUM_9 : CHARAC = "NUM_9";
			NUM_A : CHARAC = "NUM_A";
			NUM_B : CHARAC = "NUM_B";
			NUM_C : CHARAC = "NUM_C";
			NUM_D : CHARAC = "NUM_D";
			NUM_E : CHARAC = "NUM_E";
			NUM_F : CHARAC = "NUM_F";
			default : CHARAC = "NUM_0";
		endcase
	end
	
	seg_driver		seg_driver(
	/*input				*/.clk		(clk	),
	/*input				*/.rst_n	(rst_n	),

	/*output reg[7:0]	*/.dig_sel	(dig_sel),
	/*output reg[7:0]	*/.dig_seg	(dig_seg) 
);

	initial clk = 1'b0;
	always #10 clk = ~clk;
	
	initial begin
		rst_n = 1'b0;
		#36 rst_n = 1'b1;
		
		wait (seg_driver.lut == 15);
		
		#(20 * seg_driver.CNT_REF * 3);
		
		$stop(2);
	end

endmodule 

在这里插入图片描述

在这里插入图片描述

实验总结

经过此次实验大致了解了模块测距工作原理,但是由于时间关系还没有来得及上板测试。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值