基于单片机超声波测距系统的设计_「每周FPGA案例」基于FPGA的超声波测距系统设计

本文为明德扬原创及录用文章,转载请注明出处!1.1 总体设计1.1.1 概述
学习了明德扬至简设计法和明德扬设计规范,本人用FPGA设计了一个测距系统。该系统采用超声波进行测量距离再在数码管上显示。在本案例的设计过程中包括了超声波的驱动、三线式数码管显示等技术。经过逐步改进、调试等一系列工作后,最终完成了此设计,并进行上板验证,下面将完整的设计记录与大家分享。1.1.2 设计目标
此系统将实时显示前方障碍与装置之间的距离。1.1.3 系统结构框图
系统结构框图如下所示:

81fcea391e3044842ad1687d22c42e26.png

1.1.4 模块功能hc_sr04模块实现功能:该模块通过控制触发信号trig(10us的TTL)使内部循环发出8个40KHZ脉冲即驱动超声波,接收回响信号echo,通过echo得到距离。

显示模块实现功能:该模块完成了对所测距离通过数码管对其显示。

1.1.5顶层信号

9c0e7faa0f4aad0b8eea8911007cfca7.png

1.1.6顶层代码

module top(    clk    ,    rst_n  ,    echo   ,    trig   ,    sel,        seg    );    input               clk     ;    input               rst_n   ;    input               echo    ;    output              trig    ;                  wire    [3:0]       s_g     ;         wire    [3:0]       s_s     ;         wire    [3:0]       s_b     ;         wire    [3:0]       s_q     ;         output  [7:0]       sel     ;         output  [7:0]       seg     ;                  hc_sr04 hc_sr04_1(                .clk      (clk)   ,                .rst_n    (rst_n) ,                .echo     (echo)  ,                .trig     (trig)  ,        .s_g      (s_g ),        .s_s      (s_s ),        .s_b      (s_b ),        .s_q      (s_q )    );    seg_disp u_seg_disp(        .clk         (clk  ),        .rst_n       (rst_n),        .segment_data({s_q,s_b,s_s,s_g}),        .segment     (seg  ),        .seg_sel     (sel  )    );                          endmodule

1.2 hc_sr04模块设计1.2.1 接口信号

af663f39ae6ab6cb0c8386aa4093a126.png

1.2.2 设计思路
我们只需要提供一个短期的10uS脉冲触发信号trig,该模块内部将发出8个40kHz周期电平并检测回波,一旦检测到有回波信号则输出回响信号,回响信号echo是一个脉冲的宽度成正比的距离变量,可通过发射信号到收到的回响信号时间间隔可以计算得到距离。建议测量周期为60ms以上,以防止发射信号对回响信号的影响,这里我们采用的是1s测量一次。


时钟计数器cnt0:用于计算 1 秒的时钟个数,加一条件为1,表示一直计数;结束条件为数到 TIME_1S ,表示数到 1 秒就清零。


距离计数器 h_cnt:用于计算flag为高电平的宽度的时间,如果flag为1,h_cnt就加一;每完成1秒计数后h_cnt就变为0,此外h_cnt等于h_cnt。

模块时序图

68e082b1fc78e54b54ea008d05377887.png

1.2.3 参考代码

module hc_sr04(    clk    ,    rst_n  ,    echo   ,    trig   ,    s_g    ,    s_s    ,    s_b    ,    s_q          );       parameter      DATA_W = 14  ;        parameter                 TIME_1S = 50_000_000;    input               clk     ;    input               rst_n   ;    input               echo    ;    output              trig    ;    output[ 3:0]        s_g     ;        output[ 3:0]        s_s     ;        output[ 3:0]        s_b     ;        output[ 3:0]        s_q     ;                  wire                trig    ;    reg   [ 3:0]        s_g     ;        reg   [ 3:0]        s_s     ;        reg   [ 3:0]        s_b     ;        reg   [ 3:0]        s_q     ;        reg   [DATA_W-1:0]  distance;             reg   [25:0]        cnt0    ;    reg   [20:0]        h_cnt   ;    reg                 echo_2  ;    reg                 echo_1  ;    wire                add_cnt0;    wire                end_cnt0;             wire                flag_h  ;    wire                flag_l  ;                        always @(posedge clk or negedge rst_n)begin        if(!rst_n)begin            cnt0 <= 0;        end        else if(add_cnt0)begin            if(end_cnt0)                cnt0 <= 0;            else                cnt0 <= cnt0 + 1'b1;        end    end    assign add_cnt0 = 1;           assign end_cnt0 = add_cnt0 && cnt0 == TIME_1S - 1;                     assign trig = (cnt0>=500&&cnt0<1000)?1:0;    always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            echo_1 <= 0;            echo_2 <= 0;        end        else begin            echo_1 <= echo  ;            echo_2 <= echo_1;        end    end    always @(posedge clk or negedge rst_n)begin        if(!rst_n)begin            h_cnt <= 0;        end        else if(add_h_cnt)begin            if(end_h_cnt)                h_cnt <= 0;            else                h_cnt <= h_cnt + 1;        end        else if(end_cnt0)begin            h_cnt <= 0;        end    end    assign add_h_cnt = echo_2;           assign end_h_cnt = 0 ;           always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            distance <= 0;        end        else if(add_cnt0 && cnt0 == 45_000_000-1)begin            distance <= h_cnt*34/10000;        end    end     always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            s_g <= 0;        end        else begin            s_g <= distance%10;        end    end    always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            s_s <= 0;        end        else begin            s_s <= (distance/10)%10;        end    end      always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            s_b <= 0;        end        else begin            s_b <= (distance/100)%10;        end    end    always  @(posedge clk or negedge rst_n)begin        if(rst_n==1'b0)begin            s_q <= 0;        end        else begin            s_q <= (distance/1000)%10;        end    endendmodule

1.3 显示模块设计1.3.1接口信号

89bd6bc5ed06b3c60129624b61650373.png

1.3.2设计思路
该模块对数码管的位选信号sel每隔1ms的时间移位一次,也就是1ms循环亮一个灯,由于1ms的频率肉眼观察不出,我们看到的就是4个灯全亮。


对输入距离distance进行求余处理,得到每一位的数据,通过case语句,让每一位数据形成段选信号,通过位选信号的控制显示在对应的数码管上。

1.3.3参考代码

module seg_disp(    clk         ,    rst_n       ,    segment_data,    segment     ,    seg_sel      );parameter   ZERO           =   8'b1100_0000          ;parameter   ONE            =   8'b1111_1001          ;parameter   TWO            =   8'b1010_0100          ;parameter   THREE          =   8'b1011_0000          ;parameter   FOUR           =   8'b1001_1001          ;parameter   FIVE           =   8'b1001_0010          ;parameter   SIX            =   8'b1000_0010          ;parameter   SEVEN          =   8'b1111_1000          ;parameter   EIGHT          =   8'b1000_0000          ;parameter   NINE           =   8'b1001_0000          ;input             clk             ;         input             rst_n           ;   input    [31:0]   segment_data    ;output   [7:0 ]   segment         ; output   [7:0 ]   seg_sel         ;reg      [7:0 ]   segment         ;reg      [7:0 ]   seg_sel         ;reg      [10:0]   delay           ;reg      [3:0 ]   delay_time      ;wire              add_delay_time  ;wire              end_delay_time  ;wire              add_delay       ;wire              end_delay       ;wire     [3:0 ]   segment_tmp     ;always @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        delay <= 0;     end    else if(add_delay) begin        if(end_delay)            delay <= 0;         else            delay <= delay+1 ;   endendassign add_delay = 1;assign end_delay = add_delay  && delay == 2000-1 ;always @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        delay_time <= 0;     end    else if(add_delay_time) begin        if(end_delay_time)            delay_time <= 0;         else            delay_time <= delay_time+1 ;   endendassign add_delay_time = end_delay;assign end_delay_time = add_delay_time  && delay_time == 8-1 ;assign segment_tmp  = segment_data[(1+delay_time)*4-1 -:4];always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        segment <= ZERO;    end    else begin        case(segment_tmp)            4'd0:segment <= ZERO;            4'd1:segment <= ONE  ;            4'd2:segment <= TWO  ;            4'd3:segment <= THREE;            4'd4:segment <= FOUR ;            4'd5:segment <= FIVE ;            4'd6:segment <= SIX  ;            4'd7:segment <= SEVEN;            4'd8:segment <= EIGHT;            4'd9:segment <= NINE ;            default:begin                segment <= segment;            end        endcase    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        seg_sel <= 8'b1111_1111;    end    else begin        seg_sel <= ~(8'b1<

1.4 效果和总结

上板验证效果

377d5d8e68686a2fbbca9b14fc0a4e99.png

在FPGA实验箱上的效果

0a6ac5fe5e6cbe089b683dcf0fd40d57.png

在MP801开发板上的效果

934da26e94fede0b896f85facda843bd.png

在点拨开发板上的效果

在这个设计中,使用明德扬的至简设计法,让我的思路非常清晰,逻辑非常严谨,虽然没有做到一遍成功,但在调试过程中我都比较快速的找到问题,并快速解决。对于学习FPGA的同学,我非常推荐使用明德扬至简设计法和明德扬模块进行学习和设计。

详细的教学视频和工程源代码请移步明德扬论坛学习!


感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也欢迎大家在评论与我进行讨论!
也可以看一下我们往期的文章:

《基于FPGA的密码锁设计》

《波形相位频率可调DDS信号发生器》

《基于FPGA的曼彻斯特编码解码设计》

《基于FPGA的出租车计费系统》

《数电基础与Verilog设计》《基于FPGA的频率、电压测量》

《基于FPGA的汉明码编码解码设计》

《关于锁存器问题的讨论》

《阻塞赋值与非阻塞赋值》

《参数例化时自动计算位宽的解决办法》


1.15公司简介
明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。

点拨开发板——学习FPGA的入门之选。
MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。

网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。

周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。

就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。

专题课程——高手修炼课:提升设计能力;

实用调试技巧课:提升定位和解决问题能力;

FIFO架构设计课:助你快速成为架构设计师;

时序约束、数字信号处理、PCIE、综合项目实践课等你来选。

项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值