基于FPGA的超声波测距

第12周


前言

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


一、实验原理

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

二、代码

1.顶层模块

module top_Ranging(
input	CLK_50M,
input RST,

//超声波测距用的端口
input wire Echo,
output Trig,

//数码管显示
output [6:0] seg_duan,
output [2:0] seg_sel

);

wire  [15:0] data;

measurement U1(
		.CLK_50M(CLK_50M),
		.RST (RST),
		.Echo (Echo),
		.Trig (Trig) ,
		.data(data)
);

display U2(
		.CLK_50M	(CLK_50M),
		.RST 		(RST),
		.data(data),
		.seg_duan (seg_duan),
		.seg_sel (seg_sel)

);

endmodule

2.测量模块

module measurement(
input CLK_50M,
input RST,
input Echo,
output reg Trig,
output  [15:0] data

);

//Trig 
reg [23:0] cnt_trig;
always @ (posedge CLK_50M or negedge RST)
begin
	if(!RST)
		cnt_trig<=1'b0;
	else
		if(cnt_trig =='d500) begin	//高电平时间		
			Trig<=0;
			cnt_trig<=cnt_trig+1'b1;
			end
		else 
			begin
				if(cnt_trig=='d1_000_000)//低电平时间,两者加起来就是周期
					begin
						Trig<=1;
						cnt_trig<=0;
					end				
				else
					cnt_trig<=cnt_trig+1'b1;
			end
end


//检测上升沿下降沿

reg Echo_2,Echo_1,cnt_en,flag;
assign pose_Echo =(~Echo_2)&&Echo_1;//这里是表示上升下降沿的方法,可以细细品味一下,以后直接用就完事了
assign nege_Echo = Echo_2&&(~Echo_1);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10; 
reg[1:0] curr_state;
reg [15:0] cnt;
reg [15:0] dis_reg;
reg [15:0] cnt_17k;
always @ (posedge CLK_50M or negedge RST)
begin
	if(!RST)
		begin
			Echo_1 <= 1'b0;
			Echo_2 <= 1'b0;
			cnt_17k <=1'b0;
			dis_reg <=1'b0;
			curr_state <= S0;
		end
	else	
		begin
			Echo_1<=Echo;
			Echo_2<=Echo_1;
			case(curr_state)
			S0:begin
					if (pose_Echo)
						curr_state <= S1;
					else
						begin
							cnt <= 1'b0;
						end
				end
			S1:begin
					if(nege_Echo)
						curr_state <= S2;
					else
						begin
							if(cnt_17k <16'd2940)//这个是因为有小数,大致的17khz计数,不是最准确的,但是也很准了
							begin
								cnt_17k <= cnt_17k + 1'b1;
							end
							else
							begin//下面大家可以看到,判断语句》=’d10咱们就进位,就不会出现例子的错误了,如果不在乎资源
								//那么你简单的cnt++也可以试一试,只是后面要用到除法取位,后面数码管那边赋值不能跟我的方法一样了
								cnt_17k <= 1'b0;
								cnt[3:0] <= cnt[3:0] +1'b1;
							end
								if(cnt[3:0] >= 'd10)
								begin
									cnt [3:0] <=1'b0;
									cnt [7:4]<=cnt[7:4]+1'b1;
								end
								if (cnt[7:4] >= 'd10)
								begin
									cnt[7:4]<=1'b0;
									cnt[11:8]<=cnt[11:8]+1'b1;
								end
								if (cnt[11:8]>='d10)
								begin
									cnt[11:8]<=1'b0;
									cnt[15:12]<=cnt[15:12]+1'b1;
								end
								
								if(cnt[15:12]>='d10)
								begin
									cnt[15:12]<=1'b0;
								end					
						end				
				end
			S2:begin
				dis_reg<=cnt;
				cnt <=1'b0;
				curr_state <= S0;
				end
			endcase	
		end
end

assign data = dis_reg ; //对输出的data赋值,因为取的时钟频率是17Khz,340*T/2=170*(1/17000)*100=T单位是cm
endmodule

3.显示模块

module display(
		input  CLK_50M,
		input  RST,
		input  [15:0]data,
		output reg [6:0]seg_duan,//显示器段选
		output reg [2:0]seg_sel//显示器位选
    );
reg [3:0]  clk_cnt;        // 时钟分频计数器
reg dri_clk;        // 数码管的驱动时钟,5MHz
reg[3:0] scan_sel;     //Scan select counter
reg[3:0] seg_data;
reg [15:0] num;
reg flag ;        // 标志信号(标志着cnt0计数达1ms)
reg [2:0] cnt_sel;        // 数码管位选计数器
reg [12:0]  cnt0;        // 数码管驱动时钟计数器
always @ (posedge CLK_50M or negedge RST) 
begin
 if(!RST) begin
       clk_cnt <= 4'd0;
       dri_clk <= 1'b1;
   end
   else if(clk_cnt ==4) begin
       clk_cnt <= 4'd0;
       dri_clk <= ~dri_clk;
   end
   else begin
       clk_cnt <= clk_cnt + 1'b1;
       dri_clk <= dri_clk;
   end
end

always @ (  posedge dri_clk or negedge RST) 
begin
    if (!RST)
        num<= 16'd0;
    else 
	 begin
			 num[15:12] <= data [15:12];
          num[11:8]  <=	data[11:8] ;
			 num[7:4]   <=	data[7:4] ;
          num[3:0]   <= data [3:0];
	end
end

always @ (posedge dri_clk or negedge RST) begin
    if (RST == 1'b0) begin
        cnt0 <= 13'b0;
        flag <= 1'b0;
     end
    else if (cnt0 < 'd4999) begin
        cnt0 <= cnt0 + 1'b1;
        flag <= 1'b0;
     end
    else begin
        cnt0 <= 13'b0;
        flag <= 1'b1;
     end
end

always @ (posedge dri_clk or negedge RST) begin
    if (RST == 1'b0)
        cnt_sel <= 3'b0;
    else if(flag) begin
        if(cnt_sel < 3'd3) //六位数码管轮流显示
            cnt_sel <= cnt_sel + 1'b1;
        else
            cnt_sel <= 3'b0;
    end
    else
        cnt_sel <= cnt_sel;
end




always@(posedge dri_clk or negedge RST)
begin
	if(!RST)
	begin
		seg_sel <= 3'b111;
		seg_data <= 4'd0;
	end
	else
	begin
		case(cnt_sel)
			//first digital led
			4'd0:
			begin
				seg_sel <= 3'b110;
				seg_data <= num[3:0];
			end
			//second digital led
			4'd1:
			begin
				seg_sel <= 3'b101;
				seg_data <= num[7:4];
			end
			//...
			4'd2:
			begin
				seg_sel <= 3'b011;
				seg_data <= num[11:8];
			end

			default:
			begin
				seg_sel <= 3'b111;
				seg_data <= 4'b0;
			end
		endcase
	end
end

	 
	 
	 
//七段译码器(显示器)
always@(*)
begin
	case(seg_data)
		//*共阳
		'd0:seg_duan<=7'b1000000;
		'd1:seg_duan<=7'b1111001;
		'd2:seg_duan<=7'b0100100;
		'd3:seg_duan<=7'b0110000;
		'd4:seg_duan<=7'b0011001;
		'd5:seg_duan<=7'b0010010;
		'd6:seg_duan<=7'b0000010;
		'd7:seg_duan<=7'b1111000;
		'd8:seg_duan<=7'b0000000;
		'd9:seg_duan<=7'b0010000;
		default seg_duan<=7'b1000000;
	endcase	
end
endmodule

三、引脚和RTL视图

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

四、效果

效果如图:
在这里插入图片描述


总结

本次实验让我学会了如何基于FPGA对超声波进行测距。了解了超声波测距的原理,并上手实践了。另外让我对相关软硬件的应用更加熟练,也学会了使用HC-SR04模块。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值