stm32超声波测距代码_至简设计系列_基于FPGA的超声波测距系统

--作者:喝喝

本文为明德扬原创及录用文章,转载请注明出处!

1.1 总体设计

1.1.1 概述

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

1.1.2 设计目标

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

1.1.3 系统结构框图

系统结构框图如下所示:

8c73e8f73c19cf6aab302ea46222ed76.png

1.1.4 模块功能

Ø hc_sr04模块实现功能

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

Ø 显示模块实现功能

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

1.1.5 顶层信号

2bcfdecf01087dc0772069301094bf7c.png

1.1.6 顶层代码

 1. module top(
 2.  clk ,
 3.  rst_n ,
 4.  echo ,
 5.  
 6.  trig ,
 7.  sel,
 8.  seg
 9.  );
 10.  
 11.  
 12.  input clk ;
 13.  input rst_n ;
 14.  input echo ;
 15.  
 16.  
 17.  output trig ;
 18.  
 19.   
 20.   wire [3:0] s_g ;
 21.   wire [3:0] s_s ;
 22.   wire [3:0] s_b ;
 23.   wire [3:0] s_q ;
 24.   output [7:0] sel ;
 25.   output [7:0] seg ;
 26.   
 27.   hc_sr04 hc_sr04_1(
 28.  .clk (clk) ,
 29.  .rst_n (rst_n) ,
 30.  .echo (echo) ,
 31.  
 32.  .trig (trig) ,
 33.  .s_g (s_g ),
 34.  .s_s (s_s ),
 35.  .s_b (s_b ),
 36.  .s_q (s_q ) 
 37.  );
 38.  
 39.  seg_disp u_seg_disp(
 40.  .clk (clk ),
 41.  .rst_n (rst_n),
 42.  .segment_data({s_q,s_b,s_s,s_g}),
 43.  .segment (seg ),
 44.  .seg_sel (sel ) 
 45.  );
 46.   
 47.  endmodule

1.2 hc_sr04模块设计

1.2.1 接口信号

f0cbe529b3f775c40d6811bdb1cb8019.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。

Ø

7be0e784a7196d901b48521dae0a2475.png

1.2.3 参考代码

 1. module hc_sr04(
 2.  clk ,
 3.  rst_n ,
 4.  echo ,
 5.  
 6.  trig ,
 7.  s_g ,
 8.  s_s ,
 9.  s_b ,
 10.  s_q 
 11.  );
 12.  
 13.  
 14.  parameter DATA_W = 14 ;
 15.   parameter  TIME_1S = 50_000_000;
 16.  
 17.  input clk ;
 18.  input rst_n ;
 19.  input echo ;
 20.  
 21.  output trig ;
 22.  output[ 3:0] s_g ; 
 23.  output[ 3:0] s_s ; 
 24.  output[ 3:0] s_b ; 
 25.  output[ 3:0] s_q ; 
 26.  
 27.   
 28.  wire trig ;
 29.  reg [ 3:0] s_g ; 
 30.  reg [ 3:0] s_s ; 
 31.  reg [ 3:0] s_b ; 
 32.  reg [ 3:0] s_q ; 
 33.  reg [DATA_W-1:0] distance;
 34.   
 35.  
 36.  reg [25:0] cnt0 ;
 37.  reg [20:0] h_cnt ;
 38.  reg echo_2 ;
 39.  reg echo_1 ;
 40.  wire add_cnt0;
 41.  wire end_cnt0;  
 42.  wire flag_h ;
 43.  wire flag_l ;
 44.   
 45.  
 46.  
 47.  always @(posedge clk or negedge rst_n)begin
 48.  if(!rst_n)begin
 49.   cnt0 <= 0;
 50.  end
 51.  else if(add_cnt0)begin
 52.  if(end_cnt0)
 53.  cnt0 <= 0;
 54.  else
 55.  cnt0 <= cnt0 + 1'b1;
 56.  end
 57.  end
 58.  
 59.  assign add_cnt0 = 1; 
 60.  assign end_cnt0 = add_cnt0 && cnt0 == TIME_1S - 1;
 61.  
 62.  
 63.  
 64.  assign trig = (cnt0>=500&&cnt0<1000)?1:0;
 65.  
 66.  
 67.  always @(posedge clk or negedge rst_n)begin
 68.  if(rst_n==1'b0)begin
 69.  echo_1 <= 0;
 70.  echo_2 <= 0;
 71.  end
 72.   else begin
 73.  echo_1 <= echo ;
 74.  echo_2 <= echo_1;
 75.  end
 76.  end
 77.  
 78.  always @(posedge clk or negedge rst_n)begin
 79.  if(!rst_n)begin
 80.  h_cnt <= 0;
 81.  end
 82.  else if(add_h_cnt)begin
 83.  if(end_h_cnt)
 84.  h_cnt <= 0;
 85.  else
 86.  h_cnt <= h_cnt + 1;
 87.  end
 88.  else if(end_cnt0)begin
 89.  h_cnt <= 0;
 90.  end
 91.  end
 92.  
 93.  assign add_h_cnt = echo_2; 
 94.  assign end_h_cnt = 0 ; 
 95.  
 96.  
 97.  
 98.  always @(posedge clk or negedge rst_n)begin
 99.  if(rst_n==1'b0)begin
 100.  distance <= 0;
 101.  end
 102.  else if(add_cnt0 && cnt0 == 45_000_000-1)begin
 103.  distance <= h_cnt*34/10000;
 104.  end
 105.  end
 106.  
 107.  
 108.  
 109.  always @(posedge clk or negedge rst_n)begin
 110.  if(rst_n==1'b0)begin
 111.  s_g <= 0;
 112.  end
 113.  else begin
 114.   s_g <= distance%10;
 115.  end
 116.  end
 117.  
 118.  
 119.  always @(posedge clk or negedge rst_n)begin
 120.  if(rst_n==1'b0)begin
 121.  s_s <= 0;
 122.  end
 123.  else begin
 124.  s_s <= (distance/10)%10;
 125.  end
 126.  end 
 127.  
 128.  
 129.  always @(posedge clk or negedge rst_n)begin
 130.  if(rst_n==1'b0)begin
 131.  s_b <= 0;
 132.  end
 133.  else begin
 134.  s_b <= (distance/100)%10;
 135.  end
 136.  end
 137.  
 138.  
 139.  always @(posedge clk or negedge rst_n)begin
 140.  if(rst_n==1'b0)begin
 141.  s_q <= 0;
 142.  end
 143.  else begin
 144.  s_q <= (distance/1000)%10;
 145.  end
 146.  
 147.  end
 148.  
 149.  
 150.  
 151.  
 152. endmodule

1.3 显示模块设计

1.3.1 接口信号

ae273127c62b83007709060a6110458e.png

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.  
 9. parameter ZERO = 8'b1100_0000 ;
 10. parameter ONE = 8'b1111_1001 ;
 11. parameter TWO = 8'b1010_0100 ;
 12. parameter THREE = 8'b1011_0000 ;
 13. parameter FOUR = 8'b1001_1001 ;
 14. parameter FIVE = 8'b1001_0010 ;
 15. parameter SIX = 8'b1000_0010 ;
 16. parameter SEVEN = 8'b1111_1000 ;
 17. parameter EIGHT = 8'b1000_0000 ;
 18. parameter NINE = 8'b1001_0000 ;
 19.  
 20. input  clk ; 
 21. input rst_n ; 
 22. input [31:0] segment_data ;
 23. output [7:0 ] segment ; 
 24. output [7:0 ] seg_sel ;
 25.  
 26. reg [7:0 ] segment ;
 27. reg [7:0 ] seg_sel ;
 28. reg  [10:0] delay ;
 29. reg [3:0 ] delay_time ;
 30. wire add_delay_time ;
 31. wire end_delay_time ;
 32. wire add_delay ;
 33. wire end_delay ;
 34. wire [3:0 ] segment_tmp ;
 35.  
 36.  
 37.  
 38.  
 39. always @(posedge clk or negedge rst_n) begin 
 40.  if (rst_n==0) begin
 41.  delay <= 0; 
 42.  end
 43.  else if(add_delay) begin
 44.  if(end_delay)
 45.  delay <= 0; 
 46.  else
 47.  delay <= delay+1 ;
 48.  end
 49. end
 50. assign add_delay = 1;
 51. assign end_delay = add_delay && delay == 2000-1 ;
 52.  
 53.  
 54.  
 55.  
 56. always @(posedge clk or negedge rst_n) begin 
 57.  if (rst_n==0) begin
 58.  delay_time <= 0; 
 59.  end
 60.  else if(add_delay_time) begin
 61.  if(end_delay_time)
 62.  delay_time <= 0; 
 63.  else
 64.  delay_time <= delay_time+1 ;
 65.  end
 66. end
 67. assign add_delay_time = end_delay;
 68. assign end_delay_time = add_delay_time && delay_time == 8-1 ;
 69.  
 70.  
 71. assign segment_tmp = segment_data[(1+delay_time)*4-1 -:4];
 72. always @(posedge clk or negedge rst_n)begin
 73.  if(rst_n==1'b0)begin
 74.  segment <= ZERO;
 75.  end
 76.  else begin
 77.  case(segment_tmp)
 78.  4'd0:segment <= ZERO;
 79.  4'd1:segment <= ONE ;
 80.  4'd2:segment <= TWO ;
 81.  4'd3:segment <= THREE;
 82.  4'd4:segment <= FOUR ;
 83.  4'd5:segment <= FIVE ;
 84.  4'd6:segment <= SIX ;
 85.  4'd7:segment <= SEVEN;
 86.  4'd8:segment <= EIGHT;
 87.  4'd9:segment <= NINE ;
 88.  default:begin
 89.  segment <= segment;
 90.  end
 91.  endcase
 92.  end
 93. end
 94.  
 95.  
 96. always @(posedge clk or negedge rst_n)begin
 97.  if(rst_n==1'b0)begin
 98.  seg_sel <= 8'b1111_1111;
 99.  end
 100.  else begin
 101.  seg_sel <= ~(8'b1<<delay_time);
 102.  end
 103. end
 104.  
 105.  
 106. endmodule
 

1.4 效果和总结

Ø 上板验证效果

3aace2a1db1787bd7dc58432013d62e0.png

121b90bab8da341a230b3295eafe8e0a.png

de6ebc1a8feb5471c49f65350bc418cf.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值