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

一、采用verilog和HC-SR04超声波模块, 使用标准库或HAL库+ 定时器中断,完成1或2路的超声波障碍物测距功能。

1)测试数据包含噪声,程序需要进行滤波处理;将测距数值通过串口上传到上位机串口助手;

2)根据障碍物距离远近,控制一个蜂鸣器(可以用LED灯代替)发出频率不同的声音(或LED不同闪烁),即输出占空比变化的PWM波形;

3)在没有超声波模块硬件的场景下,先使用Keil中的仿真逻辑分析仪,观察分析对应管脚上的时序波形,判读是否符合协议规范。

实验平台

verilog + Quartus

实验要求

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

1.基本工作原理

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

2.硬件模块时序图

![](C:\Users\asus\AppData\Roaming\marktext\images\2024-06-01-19-47-53-0YTJ4 V ‘ V` VU42T5K([}D646X.png)信号。
回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号
时间间隔可以计算得到距离。公式: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

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

在这里插入图片描述

二、总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值