基于DE2-115开发板的超声波测距

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

HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能,测
距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。

实验平台

DE2-E115 FPGA开发板 + Quartus + Modelsim

实验要求

使用DE2开发板驱动HC_SR04模块,并将所测得数据显示到开发板上的数码管。

1.基本工作原理

(1)采用 IO 口 TRIG 触发测距,给最少 10us 的高电平信呈。
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声
波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;

2.硬件模块时序图

请添加图片描述
以上时序图表明你只需要提供一个 10uS 以上脉冲触发信号,该模块内部将
发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。
回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号
时间间隔可以计算得到距离。公式:uS/58=厘米或者 uS/148=英寸;或是:距离= 高电平时间*声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对回响信号的影响。

3.设计文件

我这里设计的测量周期是60ms,可以稍微调高点
然后TTL是15us脉冲触发信号
distance.v代码如下:

module distance (
    input  wire           clk          ,
    input  wire           rst_n        ,
    input  wire           echo         ,
    output wire           trig         ,
    output wire [19:0]    distance_data
);
parameter       MAX1_us = 6'd50      ;
parameter       MAX60_ms = 16'd60_000;
parameter       T_MAX = 15'd20_000;
reg  [5:0]      cnt_1us              ;
reg  [15:0]     cnt_60ms             ;
wire            addcnt               ;
wire            endcnt               ;
wire            echo_pos,echo_neg    ;
reg	            r1_echo,r2_echo      ;
reg	  [14:0]	 cnt		         ; 
reg     [15:0]  data_r               ;
wire			add_cnt              ; 
wire			end_cnt              ; 
reg				us_clk	             ;
assign distance_data[3:0]  =data_r%10;
assign distance_data[7:4]  =data_r/10%10;
assign distance_data[11:8] =data_r/100%10;
assign distance_data[15:12]=data_r/1000%10;
assign distance_data[19:16]=data_r/10000%10;
//1us计数器 
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_1us <= 1'd0;
    end
    else if(endcnt)begin
        cnt_1us <= 1'd0;
    end
    else begin
        cnt_1us <= cnt_1us + 1'd1;
    end
end


always@(posedge clk or negedge rst_n)begin
	if(rst_n == 1'b0)begin
		us_clk  <=  1'b0  ;
	end
	else if(endcnt)begin
		us_clk  <=  ~us_clk  ;
	end
	else begin
		us_clk  <=  us_clk ;
	end
end
		

assign endcnt = (cnt_1us==MAX1_us-1'd1);
//60ms计数器
always @(posedge us_clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_60ms <= 1'd0;
    end
    else if(cnt_60ms==MAX60_ms - 16'd1)begin
        cnt_60ms <= 1'd0;
    end
    else begin
        cnt_60ms <= cnt_60ms + 1'b1;
    end
end   

assign trig = cnt_60ms < 15 ? 1'b1 : 1'b0;

always @(posedge clk or negedge rst_n)begin  
	if(!rst_n)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 us_clk or negedge rst_n)begin  
	if(!rst_n)begin  
		cnt <= 1'd0; 
	end 
	else if(add_cnt)begin  
		if(end_cnt)begin  
			cnt <= cnt; 
		end  
		else begin  
			cnt <= cnt + 1'b1; 
		end  
	end  
	else begin  //echo 低电平 归零
		cnt <= 1'd0;  
	end  
end 

assign add_cnt = echo; 
assign end_cnt = add_cnt && cnt >= T_MAX - 1;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_r <= 1'd0;
    end
	 else if(echo_neg)begin  
		data_r <= cnt*340/200;
	 end  
	 else begin  
		data_r <= data_r;
	 end  
end 


endmodule

数码管segdrive.v代码如下:

module segdrive (input			wire						clk           ,
                 input			wire						rst_n         ,
                 input			wire		[ 23:0 ]		distance_data ,
                 output			reg		[ 6:0 ]				hex0          ,           
                 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          
                 );
    localparam	ZERO  = 7'b100_0000;
    localparam	ONE   = 7'b111_1001;
    localparam	TWO   = 7'b010_0100;
    localparam	THREE = 7'b011_0000;
    localparam	FOUR  = 7'b001_1001;
    localparam	FIVE  = 7'b001_0010;
    localparam	SIX   = 7'b000_0010;
    localparam	SEVEN = 7'b111_1000;
    localparam	EIGHT = 7'b000_0000;
    localparam	NINE  = 7'b001_0000;
    localparam	N     = 7'b010_1011;
    localparam	P     = 7'b000_1111;
    reg dot;
    localparam state0 = 3'd0;
    localparam state1 = 3'd1;
    localparam state2 = 3'd2;
    localparam state3 = 3'd3;
    localparam state4 = 3'd4;
    localparam state5 = 3'd5;
    reg              flag;
    reg    [20:0]	  cnt;
parameter	MAX_NUM = 1_000;
    reg [ 3:0 ] num1;
    reg [ 3:0 ] num2;
    reg [ 3:0 ] num3;
    reg [ 3:0 ] num4;
    reg [ 3:0 ] num5;
    reg [ 3:0 ] num6;
    reg [2:0] current_state;
    reg [2:0] next_state;
always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		current_state <= state0;
	end
	else if(flag) begin
		current_state <= next_state;
	end
end
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		flag <= 1'b0;
		cnt <= 0;
	end
	else if(cnt == 0)begin//一轮计数完毕
		flag <= 1'b1;
		cnt <= 1;
	end
	else	begin 
		flag <= 1'b0;
		cnt <= (cnt + 1'b1) % MAX_NUM;//循环+1
	end
end
always @(*) begin
	if(!rst_n) begin
		next_state <= state0;
	end
	else if(flag) begin
		case(current_state)
			state0: begin
				next_state <= state1;
			end
			state1: begin
				next_state <= state2;
			end
			state2: begin
				next_state <= state3;
			end
			state3: begin
				next_state <= state4;
			end
			state4: begin
				next_state <= state5;
			end
			state5: begin
				next_state <= state0;
			end
			default:begin
				next_state <= state0;
			end
		endcase
	end
	else begin
		next_state <= next_state;
	end
end


//状态输出
always@(current_state) begin
	case (current_state)
		state0: begin
            num1 = distance_data[3 :0];
            num2=num2;
            num3=num3;
            num4=num4;
            num5=num5;
            num6=num6;
            dot = 1;                
		end
		state1: begin
            num1=num1;
			num2 = distance_data[7 :4];
            num3=num3;
            num4=num4;
            num5=num5;
            num6=num6;
            dot = 1;                
		end
		state2: begin
            num1=num1;
            num2=num2;
            num3 = distance_data[11 :8];
            num4=num4;
            num5=num5;
            num6=num6;
            dot = 0;                
		end
		state3: begin
            num1=num1;
            num2=num2;
            num3=num3;
            num4 = distance_data[15:12];
            num5=num5;
            num6=num6;
            dot = 1;                
		end
		state4: begin
            num1=num1;
            num2=num2;
            num3=num3;
            num4=num4;
            num5 = distance_data[19 :16];
            num6=num6;
            dot = 1;                
		end
		state5: begin
            num1=num1;
            num2=num2;
            num3=num3;
            num4=num4;
            num5=num5;
            num6 = distance_data[23:20];
            dot = 1;                
		end
		default:begin
        num1=num1;
        num2=num2;
        num3=num3;
        num4=num4;
        num5=num5;
        num6=num6;
        dot=dot;
        end
	endcase
end
always @ ( * ) begin
    case( num1 )
        4'd0:   hex0 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex0 = {ONE};
        4'd2:   hex0 = {TWO};
        4'd3:   hex0 = {THREE};
        4'd4:   hex0 = {FOUR};
        4'd5:   hex0 = {FIVE};
        4'd6:   hex0 = {SIX};
        4'd7:   hex0 = {SEVEN};
        4'd8:   hex0 = {EIGHT};
        4'd9:   hex0 = {NINE};
        default : hex0 = {ZERO};
    endcase
end
always @ ( * ) begin
    case( num2 )
        4'd0:   hex1 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex1 = {ONE};
        4'd2:   hex1 = {TWO};
        4'd3:   hex1 = {THREE};
        4'd4:   hex1 = {FOUR};
        4'd5:   hex1 = {FIVE};
        4'd6:   hex1 = {SIX};
        4'd7:   hex1 = {SEVEN};
        4'd8:   hex1 = {EIGHT};
        4'd9:   hex1 = {NINE};
        default : hex1 = {ZERO};
    endcase
end
always @ ( * ) begin
    case( num3 )
        4'd0:   hex2 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex2 = {ONE};
        4'd2:   hex2 = {TWO};
        4'd3:   hex2 = {THREE};
        4'd4:   hex2 = {FOUR};
        4'd5:   hex2 = {FIVE};
        4'd6:   hex2 = {SIX};
        4'd7:   hex2 = {SEVEN};
        4'd8:   hex2 = {EIGHT};
        4'd9:   hex2 = {NINE};
        default : hex2 = {ZERO};
    endcase
end
always @ ( * ) begin
    case( num4 )
        4'd0:   hex3 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex3 = {ONE};
        4'd2:   hex3 = {TWO};
        4'd3:   hex3 = {THREE};
        4'd4:   hex3 = {FOUR};
        4'd5:   hex3 = {FIVE};
        4'd6:   hex3 = {SIX};
        4'd7:   hex3 = {SEVEN};
        4'd8:   hex3 = {EIGHT};
        4'd9:   hex3 = {NINE};
        default : hex3 = {ZERO};
    endcase
end
always @ ( * ) begin
    case( num5 )
        4'd0:   hex4 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex4 = {ONE};
        4'd2:   hex4 = {TWO};
        4'd3:   hex4 = {THREE};
        4'd4:   hex4 = {FOUR};
        4'd5:   hex4 = {FIVE};
        4'd6:   hex4 = {SIX};
        4'd7:   hex4 = {SEVEN};
        4'd8:   hex4 = {EIGHT};
        4'd9:   hex4 = {NINE};
        default : hex4 = {ZERO};
    endcase
end
always @ ( * ) begin
    case( num6 )
        4'd0:   hex5 = {ZERO}; // 匹配到后参考共阳极真值表
        4'd1:   hex5 = {ONE};
        4'd2:   hex5 = {TWO};
        4'd3:   hex5 = {THREE};
        4'd4:   hex5 = {FOUR};
        4'd5:   hex5 = {FIVE};
        4'd6:   hex5 = {SIX};
        4'd7:   hex5 = {SEVEN};
        4'd8:   hex5 = {EIGHT};
        4'd9:   hex5 = {NINE};
        default : hex5 = {ZERO};
    endcase
end
e![请添加图片描述](https://img-blog.csdnimg.cn/6ca96bbfe0f94d389349fa3b8eb1caad.png)
ndmodule

4.顶层文件设计:

module distance_top (
input  wire             clk          ,
input  wire             rst_n        ,
input  wire             echo         ,
output			wire		[ 6:0 ]				hex0          ,
output			wire		[ 6:0 ]				hex1          ,
output			wire		[ 6:0 ]				hex2          ,
output			wire		[ 6:0 ]				hex3          ,
output			wire		[ 6:0 ]				hex4          ,
output			wire		[ 6:0 ]				hex5          ,
output wire             trig         
);
wire     [19:0 ] distance_data;
distance distance_inst(
      .clk          (clk          ),
      .rst_n        (rst_n        ),
      .echo         (echo         ),
      .trig         (trig         ),
      .distance_data(distance_data)
);

segdrive segdrive_inst(
    .clk         (clk         ) ,
    .rst_n       (rst_n       ) ,
    .distance_data(distance_data),
    .hex0        (hex0)         ,
    .hex1        (hex1)         ,
    .hex2        (hex2)         ,
    .hex3        (hex3)         ,
    .hex4        (hex4)         ,
    .hex5        (hex5)
);




endmodule

5.仿真文件设计

`timescale 1ns/1ns 		//仿真系统时间尺度定义


module tb_distance(); 
//激励信号定义  
	reg				  clk		      ; 
	reg				  rst_n	      ; 
	reg			     echo         ; //	
	wire             trig         ;
	wire  [19:0]     distance_data;
    wire[ 6:0 ]				hex0;
    wire[ 6:0 ]				hex1;
    wire[ 6:0 ]				hex2;
    wire[ 6:0 ]				hex3;
    wire[ 6:0 ]				hex4;
    wire[ 6:0 ]				hex5;

	
//响应信号定义	  
distance i1(
      .clk  (clk  ),
      .rst_n(rst_n),
      .echo (echo ),
      .trig (trig ),
	  .distance_data (distance_data)
);
segdrive i3(
    .clk         (clk         ),
    .rst_n       (rst_n       ),
    .distance_data(distance_data),
    .hex0        (hex0)         ,
    .hex1        (hex1)         ,
    .hex2        (hex2)         ,
    .hex3        (hex3)         ,
    .hex4        (hex4)         ,
    .hex5        (hex5)
);

localparam CLK_PERIOD = 2;
always #(CLK_PERIOD/2) clk=~clk;

initial begin
    rst_n<=1'b0;
    clk<=1'b0;
    # CLK_PERIOD;
    rst_n<=1;
    echo <= 0;
    # (CLK_PERIOD * 10000);
    echo <= 1;
    # (CLK_PERIOD * 20000);
    echo <= 0;
    # (CLK_PERIOD * 30000);
    echo <= 1;
    # (CLK_PERIOD * 40000);
    echo <= 0;
    # (CLK_PERIOD *10000);
    $stop;
end

endmodule

仿真波形图:
请添加图片描述
num1-6分别对应数码管hex0-hex5

二、总结

这个实验可以帮助了我更加深入地了解硬件模块的时序图和基本工作原理,并锻炼了我使用FPGA开发板进行硬件设计和驱动的能力。此实验,需要我掌握使用IO口触发测距、发送方波和检测回波等方法,以及通过高电平持续时间计算距离的公式。此外,我还需要掌握如何将所测得数据显示到开发板上的数码管上。细致认真地完成该实验提高了我对FPGA开发板的理解,并培养了我实际操作的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值