基于FPGA的超声波测距

一、实验原理

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

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

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

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

模块时序图:
在这里插入图片描述

二、代码实现

测距信号源:

module trigger_send #(
    parameter TIME_1S = 12_000_000
) (
    input   clk ,
    input   rst_n   ,
    output  trigger
);

//1us生成
wire clk_1us;
PLL UPLL(
	.inclk0 (clk),
	.c0 (clk_1us)
);

reg [25:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1us <= 20'd0;
    end
    else if (cnt_1us == 20'd300_000 - 1)begin
        cnt_1us <= 20'd0;
    end
	 else begin
        cnt_1us <= cnt_1us + 1'b1;
    end
end

assign trigger = cnt_1us < 15 ? 1'b1 : 1'b0;

endmodule

数码管模块:


module nixietube_1 (
    input   clk,
    input   rst_n,
    input   [3:0]   din, //输入0-9
    output  drive_out, //使能
    output  [6:0]   _dig, //输出数码管
    output  dot_out //小数点要亮吗
);
//dot小数点输出
assign dot_out = 1'b0;

//使能,阴极为0
assign drive_out = 1'b0;

//dig段选输出
parameter   ZER = 7'b0111111,
            ONE = 7'b0000110,
            TWO = 7'b1011011,
            THR = 7'b1001111,
            FOU = 7'b1100110,
            FIV = 7'b1101101,
            SIX = 7'b1111101,
            SEV = 7'b0000111,
            EIG = 7'b1111111,
            NIN = 7'b1101111;
            
reg [6:0]   dig;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dig <= ZER;
    end
    else begin
        case (din)
            0 : dig <= ZER;
            1 : dig <= ONE;
            2 : dig <= TWO;
            3 : dig <= THR;
            4 : dig <= FOU;
            5 : dig <= FIV;
            6 : dig <= SIX;
            7 : dig <= SEV;
            8 : dig <= EIG;
            9 : dig <= NIN;
            default : dig <= ZER;
        endcase
    end
end

assign _dig = dig;

endmodule

距离计算:

module data_rec #(
    parameter TIME_1S = 12_000_000
) (
    input   clk ,//系统时钟
    input   rst_n   ,//复位
    input   rec_data    ,//回响,早知道取名echo了
    output  [11:0] distance	//计算好的距离
);
//锁相环生成1us周期时钟,因为后面的计时单位全是1us,这样方便
wire clk_1us;
PLL UPLL(
	.inclk0 (clk),
	.c0 (clk_1us)
);

//给回响信号打拍,检测上升沿下降沿
reg rec_data2;
reg rec_data3;
wire rec_negedge;
wire rec_posedge;
assign rec_negedge = (!rec_data2) && rec_data3;
assign rec_posedge = rec_data2 && (!rec_data3);
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        rec_data2 <= 1'b0;
    end
    else begin
        rec_data2 <= rec_data;
    end
end
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        rec_data3 <= 1'b0;
    end
    else begin
        rec_data3 <= rec_data2;
    end
end

//计时启动标志,上升沿启动,下降沿结束
reg flag;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
    end
    else if (rec_posedge)begin
        flag <= 1'b1;
    end
    else if (rec_negedge)begin
        flag <= 1'b0;
    end
    else begin
        flag <= flag;
    end
end

//计时器数值,flag期间计数,有下降沿就清0,急了多少数就是保持了多少us,因为是用1us时钟驱动的
reg [14:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1us <= 15'd0;
    end
    else if (rec_negedge)begin
        cnt_1us <= 15'd0;
    end
    else if (flag && cnt_1us < 15'd15_000)begin
        cnt_1us <= cnt_1us + 1'b1;
    end
    else begin
        cnt_1us <= cnt_1us;
    end
end

//因为计时器结束计时会变0,因此要用另外的变量,在它清0的时候把值保存下来
reg [14:0] high_time;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        high_time <= 15'd0;
    end
    else if (rec_negedge)begin
        high_time <= cnt_1us ;
    end
    else begin
        high_time <= high_time;
    end
end

//计算距离,Verilog不能直接用浮点数,就这样实现乘以0.017
//为什么不是0.034看前面
reg [11:0] distance_buf;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        distance_buf <= 12'd0;
    end
    else begin
        distance_buf <= high_time * 17 / 1000;
    end
end
assign distance = distance_buf;

endmodule

最后是顶层模块:

module Ultrasound  (
    input   clk,
    input   rst_n,
    input   rec_data    ,
    output  trigger ,
    output  [6:0]   dig1,
	 output  [6:0]   dig2,
    output  dot1,
	 output  dot2,
	 output  drive1,
	 output  drive2
); 
    trigger_send u_trigger_send(
        .clk (clk),
        .rst_n (rst_n),
        .trigger (trigger)
    );

    wire [11:0] distance;
    data_rec u_data_rec(
        .clk (clk),
        .rst_n (rst_n),
        .rec_data (rec_data),
        .distance (distance)
    );
		
	 nixietube_1 u_nixietube_1(
        .clk (clk),
        .rst_n (rst_n),
        .din    ((distance/10)%10),
        ._dig (dig1),
        .dot_out (dot1),
		  .drive_out (drive1)
    );
	 
	 nixietube_1 u_nixietube_2(
        .clk (clk),
        .rst_n (rst_n),
        .din    ((distance/1)%10),
        ._dig (dig2),
        .dot_out (dot2),
		  .drive_out (drive2)
    );

endmodule  

三、实验现象

在这里插入图片描述

四、总结

本次实验实现了使用FPGA驱动超声波模块HC_SR04,有了很多收获,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值