超声波测距(1)

一.实验原理

1.模块介绍

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

在这里插入图片描述

2.硬件时序图

在这里插入图片描述

二.代码设计

  • clk_div模块
/*================================================*\
		  Filename ﹕
			Author ﹕
	  Description  ﹕产生周期为1us的时钟信号
		 Called by ﹕
Revision History   ﹕ mm/dd/202x
		  			  Revision 1.0
  			  Email﹕ 
			Company﹕ 
\*================================================*/
module 	clk_div(
	input  wire			Clk		, //system clock 50MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	output wire  		clk_us 	  //
);
//Parameter Declarations
	parameter CNT_MAX = 19'd50;//1us的计数值为 50 * Tclk(20ns)

//Interrnal wire/reg declarations
	reg		[5:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 
	
//Logic Description
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CNT_MAX - 19'd1;
	
	assign clk_us = end_cnt;
	

endmodule 
  • hc_sr_echo
/*================================================*\
		  Filename ﹕
			Author ﹕
	  Description  ﹕超声波检测距离模块
					本模块理论测试距离 2cm~510cm
						输出结果保留两位小数
		 Called by ﹕
Revision History   ﹕ mm/dd/202x
		  			  Revision 1.0
  			  Email﹕ 
			Company﹕ 
\*================================================*/
module 	hc_sr_echo(
	input  wire 		Clk		, //clock 50MHz
	input  wire			clk_us	, //system clock 1MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	input  wire 		echo	, //
	output wire [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);
/* 		S(um) = 17 * t 		-->  x.abc cm	*/
//Parameter Declarations
	parameter T_MAX = 16'd60_000;//510cm 对应计数值

//Interrnal wire/reg declarations
	reg				r1_echo,r2_echo; //边沿检测	
	wire			echo_pos,echo_neg; //
	
	reg		[15:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 
	
	reg		[18:00]	data_r	;
//Logic Description
	//如果使用clk_us 检测边沿,延时2us,差值过大
	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 clk_us or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= '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 <= '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 <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end //always end
	
	assign data_o = data_r >> 1;

endmodule 
  • hc_sr_trig
/*================================================*\
		  Filename ﹕
			Author ﹕
	  Description  ﹕超声波触发测距模块
					波形周期300ms,前10us高电平
		 Called by ﹕
Revision History   ﹕ mm/dd/202x
		  			  Revision 1.0
  			  Email﹕ 
			Company﹕ 
\*================================================*/
module 	hc_sr_trig(
	input  wire			clk_us	, //system clock 1MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	output wire  		trig	  //触发测距信号
);
//Parameter Declarations
	parameter CYCLE_MAX = 19'd300_000;

//Interrnal wire/reg declarations
	reg		[18:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 

//Logic Description	
	
	always @(posedge clk_us or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CYCLE_MAX - 9'd1; 
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 
  • hc_sr_dirver(上述三个模块的顶层文件)
module hc_sr_driver (
    input   wire        Clk     ,
    input   wire        Rst_n   ,
    input   wire        echo    ,

    output  wire        trig    ,
    output  wire [18:0] data_o  
);

wire        clk_us;


hc_sr_echo u_hc_sr_echo(
	.Clk		(Clk    ), //clock 50MHz
	.clk_us	    (clk_us ), //system clock 1MHz
	.Rst_n	    (Rst_n  ), //reset ,low valid
	
	.echo	    (echo   ), //
	.data_o	    (data_o )  //检测距离,保留3位小数,*1000实现
);

hc_sr_trig u_hc_sr_trig(
	.clk_us	    (clk_us ), //system clock 1MHz
	.Rst_n	    (Rst_n  ), //reset ,low valid
	
	.trig	    (trig   )//触发测距信号
);

clk_div u_clk_div(
	.Clk		(Clk    ), //system clock 50MHz
	.Rst_n	    (Rst_n  ), //reset ,low valid
	
	.clk_us     (clk_us )//
);


endmodule
  • seg_dirver(数码管模块)
module seg_driver(
    input   wire        Clk     ,
    input   wire        Rst_n   ,
    input   wire [18:0] data_o  ,

    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 [6:0]  hex6    ,
    output  wire [6:0]  hex7    ,
    output  wire [6:0]  hex8     
);

parameter   NOTION  = 4'd10,
            FUSHU   = 4'd11;
parameter   MAX20us = 10'd1000;
reg [9:0]   cnt_20us;
reg [7:0]   sel_r;
reg [3:0]   number;
reg [6:0]   seg_r;
reg [6:0]   hex1_r;
reg [6:0]   hex2_r;
reg [6:0]   hex3_r;
reg [6:0]   hex4_r;
reg [6:0]   hex5_r;
reg [6:0]   hex6_r;
reg [6:0]   hex7_r;
reg [6:0]   hex8_r;



//20微妙计数器
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        cnt_20us <= 10'd0;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        cnt_20us <= 10'd0;
    end
    else begin
        cnt_20us <= cnt_20us + 1'd1;
    end
end



//单个信号sel_r位拼接约束
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        sel_r <= 8'b11_11_11_10;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        sel_r <= {sel_r[6:0],sel_r[7]};
    end
    else begin
        sel_r <= sel_r;
    end
end

/*拿到数字*/
always @(*) begin
    case (sel_r)
        8'b11_11_11_10:     number  = NOTION                                        ;
        8'b11_11_11_01:     number  = data_o/10_0000                                ;
        8'b11_11_10_11:     number  = (data_o%10_0000)/1_0000                       ;
        8'b11_11_01_11:     number  = ((data_o%10_0000)%1_0000)/1000                ;
        8'b11_10_11_11:     number  = FUSHU                                         ;
        8'b11_01_11_11:     number  = (((data_o%10_0000)%1_0000)%1000)/100          ;
        8'b10_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)/10     ;
        8'b01_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)%10     ;
        default:            number  = 4'd0                                          ;
    endcase
end

/*通过数字解析出seg值*/
always @(*) begin
    case (number)
        4'd0    :       seg_r   =  7'b100_0000;
        4'd1    :       seg_r   =  7'b111_1001;
        4'd2    :       seg_r   =  7'b010_0100;
        4'd3    :       seg_r   =  7'b011_0000;
        4'd4    :       seg_r   =  7'b001_1001;
        4'd5    :       seg_r   =  7'b001_0010;
        4'd6    :       seg_r   =  7'b000_0010;
        4'd7    :       seg_r   =  7'b111_1000;
        4'd8    :       seg_r   =  7'b000_0000;
        4'd9    :       seg_r   =  7'b001_0000;
        NOTION  :       seg_r   =  7'b111_1111;
        FUSHU   :       seg_r   =  7'b011_1111;
        default :       seg_r   =  7'b111_1111;
    endcase
end

always @(*) begin
    case (sel_r)
		8'b11_11_11_10:     hex1_r = seg_r;
		8'b11_11_11_01:     hex2_r = seg_r;
		8'b11_11_10_11:     hex3_r = seg_r;
		8'b11_11_01_11:     hex4_r = seg_r;
		8'b11_10_11_11:     hex5_r = seg_r;
		8'b11_01_11_11:     hex6_r = seg_r;
		8'b10_11_11_11:     hex7_r = seg_r;
		8'b01_11_11_11:     hex8_r = seg_r;
		default:            seg_r  = seg_r;
	endcase
end

assign  hex1 = hex1_r;
assign  hex2 = hex2_r;
assign  hex3 = hex3_r;
assign  hex4 = hex4_r;
assign  hex5 = hex5_r;
assign  hex6 = hex6_r;
assign  hex7 = hex7_r;
assign  hex8 = hex8_r;

endmodule
  • beepled(报警模块包括蜂鸣器LED)
module beepled (
    input   wire        Clk,
    input   wire        Rst_n,
    input   wire [18:0] data_o,
    output  wire        beep,
    output  wire [3:0]  led
);

parameter	MAX1S	=	26'd2500_0000	;
parameter	MAX1_2S	=	26'd1250_0000	;
reg [25:0]	cnt1s						;
reg [25:0]  cnt1_2s                     ;
reg [3:0]	led_r						;
reg         beep_r                      ;

//1s计数器
always @(posedge Clk or negedge Rst_n) begin
	if (!Rst_n) begin
		cnt1s <= 26'd0;						//复位,重新计数
	end
	else if (cnt1s == MAX1S - 1'd1) begin
		cnt1s <= 26'd0;						//记到最大数4999_9999后复位
	end
	else begin
		cnt1s <= cnt1s + 1'd1;				//其他情况+1
	end
end

//0.5s计数器
always @(posedge Clk or negedge Rst_n) begin
	if (!Rst_n) begin
		cnt1_2s <= 26'd0;						//复位,重新计数
	end
	else if (cnt1s == MAX1_2S - 1'd1) begin
		cnt1_2s <= 26'd0;						//记到最大数2499_9999后复位
	end
	else begin
		cnt1_2s <= cnt1_2s + 1'd1;				//其他情况+1
	end
end

//led灯
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        led_r <= 4'b0000;
    end
    else if(data_o/1000 <= 20) begin
        led_r <= 4'b1111;
    end
    else begin
        led_r <= 4'b0000;
    end
end

//蜂鸣器

always@(posedge Clk or negedge Rst_n)begin
	if(!Rst_n)begin//复位信号
		beep_r <= 1'b0;//蜂鸣器默认设置为0
	end
	else if (data_o/1000 > 20)begin
		beep_r <= 1'b0;
	end
	else if (data_o/1000 <= 20)begin
		if (cnt1s == MAX1S - 1'd1)begin
			beep_r <= ~beep_r;
		end
		else if (data_o/1000 <= 10 && cnt1s == MAX1_2S - 1'd1)begin
			beep_r <= ~beep_r;
		end
		else begin
			beep_r <= beep_r;
		end
	end
	else begin 
		beep_r <= 1'b0;//否则不变 
    end
end


assign beep = beep_r;
assign led = led_r;
endmodule
  • karman_filter(卡尔曼滤波)
module karman_filter (
    input                   clk     ,
    input                   rst     ,
    input   wire [18:0]     data_o  ,
    output  wire [18:0]     data    
);

/**
    x_hat:状态估计量,表示系统状态的估计值。
    p:协方差矩阵,表示状态估计量的不确定性。
    kg:卡尔曼增益,用于调整测量值和状态估计值之间的权重。
    q:过程噪声方差,表示系统模型中的噪声。
    r:测量噪声方差,表示测量值中的噪声。
**/
reg [18:0] x_hat, p, kg;
reg [18:0] q, r;

always @(posedge clk or negedge rst) begin
  if (!rst) begin
    x_hat <= 0;
    p <= 0;
  end 
  else begin
    // 预测步骤
    x_hat <= x_hat;
    p <= p + q;
    // 更新步骤
    kg <= p / (p + r);
    x_hat <= x_hat + kg * (data_o - x_hat);
    p <= (1 - kg) * p;
  end
end
assign data = x_hat;

endmodule
  • hc_sr_top(上述模块整体的顶层文件)
module hc_sr_top (
    input   wire        Clk     ,
    input   wire        Rst_n   ,
    input   wire        echo    ,

    output  wire        trig    ,
    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 [6:0]  hex6    ,
    output  wire [6:0]  hex7    ,
    output  wire [6:0]  hex8    ,
    output  wire        beep    ,
    output  wire [3:0]  led 
);

wire    [18:0]  data_o  ;
wire    [18:0]  data    ;


karman_filter u_karman_filter(
    .clk         (Clk        ),
    .rst         (Rst_n      ),
    .data_o      (data_o     ),
    .data        (data       )
);

hc_sr_driver u_hc_sr_driver(
    .Clk        (Clk        ),
    .Rst_n      (Rst_n      ),
    .echo       (echo       ),

    .trig       (trig       ),
    .data_o     (data_o     )
);

seg_driver u_seg_driver(
    .Clk        (Clk        ),
    .Rst_n      (Rst_n      ),
    .data_o     (data       ),

    .hex1       (hex1       ),
    .hex2       (hex2       ),
    .hex3       (hex3       ),
    .hex4       (hex4       ),
    .hex5       (hex5       ),
    .hex6       (hex6       ),
    .hex7       (hex7       ),
    .hex8       (hex8       ) 
);

beepled u_beepled(
    .Clk        (Clk        ),
    .Rst_n      (Rst_n      ),
    .data_o     (data_o     ),
    .beep       (beep       ),
    .led        (led        )
);
endmodule

三.RTL viewer模块图

在这里插入图片描述

四.参考

https://blog.youkuaiyun.com/qq_43546203/article/details/125281386

五.总结

  • 本次实验暂时完成了初步设计,实现了FPGA超声波测距功能。后续将完善串口及网络模块,可以期待一下后续博客的发布。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值