明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫一扫,快捷登录!

查看: 13799|回复: 1

【每周FPGA案例】基于FPGA的超声波测距系统设计 编号:000700000011

[复制链接]
发表于 2020-8-19 15:21:58 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
至简设计系列_基于FPGA的测距系统

--作者:喝喝
本案例的编号为:000700000011,如果有疑问,请按编号在下面贴子查找答案:MDY案例交流【汇总贴】_FPGA-明德扬科教 (mdy-edu.com)
本文为明德扬原创及录用文章,转载请注明出处

1.1 总体设计

1.1.1 概述

学习了明德扬至简设计法和明德扬设计规范,本人用FPGA设计了一个测距系统。该系统采用超声波进行测量距离再在数码管上显示。在本案例的设计过程中包括了超声波的驱动、三线式数码管显示等技术。经过逐步改进、调试等一系列工作后,最终完成了此设计,并进行上板验证,下面将完整的设计记录与大家分享。

1.1.2 设计目标

此系统将实时显示前方障碍与装置之间的距离。

1.1.3 系统结构框图


系统结构框图如下所示:

1.png
1.1.4 模块功能

hc_sr04模块实现功能
该模块通过控制触发信号trig10usTTL)使内部循环发出840KHZ脉冲即驱动超声波,接收回响信号echo,通过echo得到距离。

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

1.1.5顶层信号
  
信号名
  
接口方向
定义
clk
输入
系统时钟
rst_n
输入
系统复位
echo
输入
输出回响信号
trig
输出
10us高电平的触发信号,驱动超声波
1.1.6顶层代码
  1. module top(
  2.     clk    ,
  3.     rst_n  ,
  4.     echo   ,

  5.     trig   ,
  6.     sel,
  7.         seg
  8.     );


  9.     input               clk     ;
  10.     input               rst_n   ;
  11.     input               echo    ;


  12.     output              trig    ;

  13.          
  14.          wire    [3:0]       s_g     ;
  15.          wire    [3:0]       s_s     ;
  16.          wire    [3:0]       s_b     ;
  17.          wire    [3:0]       s_q     ;
  18.          output  [7:0]       sel     ;
  19.          output  [7:0]       seg     ;
  20.          
  21.          hc_sr04 hc_sr04_1(
  22.                 .clk      (clk)   ,
  23.                 .rst_n    (rst_n) ,
  24.                 .echo     (echo)  ,

  25.                 .trig     (trig)  ,
  26.         .s_g      (s_g ),
  27.         .s_s      (s_s ),
  28.         .s_b      (s_b ),
  29.         .s_q      (s_q )
  30.     );

  31.     seg_disp u_seg_disp(
  32.         .clk         (clk  ),
  33.         .rst_n       (rst_n),
  34.         .segment_data({s_q,s_b,s_s,s_g}),
  35.         .segment     (seg  ),
  36.         .seg_sel     (sel  )
  37.     );
  38.          

  39.          

  40.         endmodule

复制代码




1.2 hc_sr04模块设计

1.2.1 接口信号


  
信号
  
接口方向
定义
  
clk
  
输入
系统时钟
  
rst_n
  
输入
系统复位
  
echo
  
输入
输出回响信号
  
trig
  
输出
10us高电平的触发信号,用于驱动发出超声波
  
s_g
  
输出
显示distance的个位数字
  
s_s
  
输出
显示distance的十位数字
  
s_b
  
输出
显示distance的百位数字
  
s_q
  
输出
显示distance的千位数字

1.2.2 设计思路

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

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

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

块时序图

2.png

1.2.3 参考代码

  1. module hc_sr04(
  2.     clk    ,
  3.     rst_n  ,
  4.     echo   ,

  5.     trig   ,
  6.     s_g    ,
  7.     s_s    ,
  8.     s_b    ,
  9.     s_q      
  10.     );

  11.    
  12.     parameter      DATA_W = 14  ;
  13.         parameter                 TIME_1S = 50_000_000;

  14.     input               clk     ;
  15.     input               rst_n   ;
  16.     input               echo    ;

  17.     output              trig    ;
  18.     output[ 3:0]        s_g     ;   
  19.     output[ 3:0]        s_s     ;   
  20.     output[ 3:0]        s_b     ;   
  21.     output[ 3:0]        s_q     ;   

  22.          
  23.     wire                trig    ;
  24.     reg   [ 3:0]        s_g     ;   
  25.     reg   [ 3:0]        s_s     ;   
  26.     reg   [ 3:0]        s_b     ;   
  27.     reg   [ 3:0]        s_q     ;   
  28.     reg   [DATA_W-1:0]  distance;
  29.          

  30.     reg   [25:0]        cnt0    ;
  31.     reg   [20:0]        h_cnt   ;
  32.     reg                 echo_2  ;
  33.     reg                 echo_1  ;
  34.     wire                add_cnt0;
  35.     wire                end_cnt0;         
  36.     wire                flag_h  ;
  37.     wire                flag_l  ;
  38.          
  39.    
  40.         
  41.     always @(posedge clk or negedge rst_n)begin
  42.         if(!rst_n)begin
  43.             cnt0 <= 0;
  44.         end
  45.         else if(add_cnt0)begin
  46.             if(end_cnt0)
  47.                 cnt0 <= 0;
  48.             else
  49.                 cnt0 <= cnt0 + 1'b1;
  50.         end
  51.     end

  52.     assign add_cnt0 = 1;      
  53.     assign end_cnt0 = add_cnt0 && cnt0 == TIME_1S - 1;
  54.         
  55.         

  56.     assign trig = (cnt0>=500&&cnt0<1000)?1:0;


  57.     always  @(posedge clk or negedge rst_n)begin
  58.         if(rst_n==1'b0)begin
  59.             echo_1 <= 0;
  60.             echo_2 <= 0;
  61.         end
  62.         else begin
  63.             echo_1 <= echo  ;
  64.             echo_2 <= echo_1;
  65.         end
  66.     end

  67.     always @(posedge clk or negedge rst_n)begin
  68.         if(!rst_n)begin
  69.             h_cnt <= 0;
  70.         end
  71.         else if(add_h_cnt)begin
  72.             if(end_h_cnt)
  73.                 h_cnt <= 0;
  74.             else
  75.                 h_cnt <= h_cnt + 1;
  76.         end
  77.         else if(end_cnt0)begin
  78.             h_cnt <= 0;
  79.         end
  80.     end

  81.     assign add_h_cnt = echo_2;      
  82.     assign end_h_cnt = 0 ;   


  83.    
  84.     always  @(posedge clk or negedge rst_n)begin
  85.         if(rst_n==1'b0)begin
  86.             distance <= 0;
  87.         end
  88.         else if(add_cnt0 && cnt0 == 45_000_000-1)begin
  89.             distance <= h_cnt*34/10000;
  90.         end
  91.     end



  92.      always  @(posedge clk or negedge rst_n)begin
  93.         if(rst_n==1'b0)begin
  94.             s_g <= 0;
  95.         end
  96.         else begin
  97.             s_g <= distance%10;
  98.         end
  99.     end


  100.     always  @(posedge clk or negedge rst_n)begin
  101.         if(rst_n==1'b0)begin
  102.             s_s <= 0;
  103.         end
  104.         else begin
  105.             s_s <= (distance/10)%10;
  106.         end
  107.     end  


  108.     always  @(posedge clk or negedge rst_n)begin
  109.         if(rst_n==1'b0)begin
  110.             s_b <= 0;
  111.         end
  112.         else begin
  113.             s_b <= (distance/100)%10;
  114.         end
  115.     end


  116.     always  @(posedge clk or negedge rst_n)begin
  117.         if(rst_n==1'b0)begin
  118.             s_q <= 0;
  119.         end
  120.         else begin
  121.             s_q <= (distance/1000)%10;
  122.         end

  123.     end




  124. endmodule
复制代码


1.3 显示模块设计

1.3.1接口信号


  
信号
  
接口方向
定义
clk
输入
系统时钟
rst_n
输入
系统复位
segment_data
输入
测得距离
seg_sel
输出
数码管位选,选择当前要显示的数码管
segment
输出
数码管段选,当前要显示的内容

1.3.2设计思路

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

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

1.3.3参考代码



  1. module seg_disp(
  2.     clk         ,
  3.     rst_n       ,
  4.     segment_data,
  5.     segment     ,
  6.     seg_sel      
  7. );

  8. parameter   ZERO           =   8'b1100_0000          ;
  9. parameter   ONE            =   8'b1111_1001          ;
  10. parameter   TWO            =   8'b1010_0100          ;
  11. parameter   THREE          =   8'b1011_0000          ;
  12. parameter   FOUR           =   8'b1001_1001          ;
  13. parameter   FIVE           =   8'b1001_0010          ;
  14. parameter   SIX            =   8'b1000_0010          ;
  15. parameter   SEVEN          =   8'b1111_1000          ;
  16. parameter   EIGHT          =   8'b1000_0000          ;
  17. parameter   NINE           =   8'b1001_0000          ;

  18. input             clk             ;         
  19. input             rst_n           ;   
  20. input    [31:0]   segment_data    ;
  21. output   [7:0 ]   segment         ;
  22. output   [7:0 ]   seg_sel         ;

  23. reg      [7:0 ]   segment         ;
  24. reg      [7:0 ]   seg_sel         ;
  25. reg      [10:0]   delay           ;
  26. reg      [3:0 ]   delay_time      ;
  27. wire              add_delay_time  ;
  28. wire              end_delay_time  ;
  29. wire              add_delay       ;
  30. wire              end_delay       ;
  31. wire     [3:0 ]   segment_tmp     ;




  32. always @(posedge clk or negedge rst_n) begin
  33.     if (rst_n==0) begin
  34.         delay <= 0;
  35.     end
  36.     else if(add_delay) begin
  37.         if(end_delay)
  38.             delay <= 0;
  39.         else
  40.             delay <= delay+1 ;
  41.    end
  42. end
  43. assign add_delay = 1;
  44. assign end_delay = add_delay  && delay == 2000-1 ;




  45. always @(posedge clk or negedge rst_n) begin
  46.     if (rst_n==0) begin
  47.         delay_time <= 0;
  48.     end
  49.     else if(add_delay_time) begin
  50.         if(end_delay_time)
  51.             delay_time <= 0;
  52.         else
  53.             delay_time <= delay_time+1 ;
  54.    end
  55. end
  56. assign add_delay_time = end_delay;
  57. assign end_delay_time = add_delay_time  && delay_time == 8-1 ;


  58. assign segment_tmp  = segment_data[(1+delay_time)*4-1 -:4];
  59. always  @(posedge clk or negedge rst_n)begin
  60.     if(rst_n==1'b0)begin
  61.         segment <= ZERO;
  62.     end
  63.     else begin
  64.         case(segment_tmp)
  65.             4'd0:segment <= ZERO;
  66.             4'd1:segment <= ONE  ;
  67.             4'd2:segment <= TWO  ;
  68.             4'd3:segment <= THREE;
  69.             4'd4:segment <= FOUR ;
  70.             4'd5:segment <= FIVE ;
  71.             4'd6:segment <= SIX  ;
  72.             4'd7:segment <= SEVEN;
  73.             4'd8:segment <= EIGHT;
  74.             4'd9:segment <= NINE ;
  75.             default:begin
  76.                 segment <= segment;
  77.             end
  78.         endcase
  79.     end
  80. end


  81. always  @(posedge clk or negedge rst_n)begin
  82.     if(rst_n==1'b0)begin
  83.         seg_sel <= 8'b1111_1111;
  84.     end
  85.     else begin
  86.         seg_sel <= ~(8'b1<<delay_time);
  87.     end
  88. end


  89. endmodule
复制代码



1.4 效果和总结

上板验证效果
3.JPG



4.jpg



5.jpg


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

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


也可以看一下我们往期的文章:

1.15公司简介

明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。
MP801
开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。

【设计视频教程】

【工程源码】

mdyUltraDistanRange.zip (11.65 KB, 下载次数: 1831)
FPGA视频课程  培训班 FPGA学习资料
吴老师 18022857217(微信同号) Q1241003385

35

主题

57

帖子

7025

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
7025

荣誉管理论坛元老

QQ
发表于 2021-4-27 17:21:32 | 显示全部楼层
【问题1】非MP603、MP801的管脚配置问题。
超声波模块有4根管脚,分别是VCC、GND、echo和trig。如果您使用非MP603和非MP801开发板(案例中的开发板),则记得电流和GND要接正确,而echo和trig可以插在任意通用IO口上,然后FPGA管脚要配置正确,这样就可以了。

【问题2】MP603点拨开发板中,绿色线连到哪里?图上不清晰
答:连到P1座子的1位置上,即电源3.3V位置上。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|MDYBBS ( 粤ICP备16061416号 )

GMT+8, 2024-4-26 06:32 , Processed in 0.065937 second(s), 25 queries .

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

快速回复 返回顶部 返回列表