基于FPGA的超声波测距系统设计

首先介绍超声波测量距离的原理,其次介绍超声波测距模块。超声波测距的基本原理可以这样认为,我们知道声音在空气里的传播速度大约是0.34千米/秒。超声波在空气中的传播速度大概也是0.34千米/秒,而这个速度受外界环境变化特别的小;况且超声波的波长相对于空气中的悬浮颗粒直径较大,因而可以有效的绕射过空气中的悬浮颗粒等直径比较小的障碍物,所以可以认为它在空气中的传播速度基本可以维持在0.34千米/秒。基于这个基本不变的速度,只需测出其发出去以及反射回来的时间差,然后在通过一定的计算,就可以得到发射端到目标物体的距离了。

由以上的超声波测量距离的原理图就可以知道距离S可以被很简洁的表达出来了。可以把声速表示成V,超声波从发射到接收的时间差为T,这样距离就可以被表达成S=V*T/2。图3.2中的方法可称为间接测距法。还有一种直接测距的方法,直接测距就是将测距系统的发射端口和接收端口对准。发射的超声波直接进入接收端,这样就可以直接计算出其测量的距离了。这种测距系统并不仅仅局限于超声波测距系统,在一些激光测距、红外测距等系统方面也有着一定价值的应用。

 

基于FPGA的超声波测距系统设计

图3.2 超声波测量距离的原理图

 

在本设计中利用超声波在空气中的传播原理,按照S=V*T/2的关系计算出1毫米的时钟高电平个数。利用距离单位的逐项叠加,逐个进位的方式计算出其距离。

 

基于FPGA的超声波测距系统设计

图3.3 超声波模块

 

基于FPGA的超声波测距系统利用的超声波模块型号为HC_SR04,它实际上采用的是给模块上的trig端口一个触发电平,让其触发超声波的发出。

首先,在使用该模块之前,对该超声波模块进行了简单的端口测试。利用电压源给该模块接上5V的电压。利用信号发生器产生一个10us的高电平脉冲信号,将此信号加到trig接口上,这样就完成了对该超声波模块的触发。然后将示波器探头接在超声波模块的echo端口上,观察示波器会显示以下信号:

 

基于FPGA的超声波测距系统设计

图3.4 示波器观测图

 

基于FPGA的超声波测距系统设计

图3.5 信号源信号图

 

由图3.5中的信号源可以看出,设置占空比为20%,脉冲电压为5V,周期为50us。这样信号源就可以产生一个10us的连续脉冲,将此脉冲信号送给trig端口,然后在超声波模块上的echo端口上加上示波器来测量echo上的信号变化。图3.4所示,可以清楚的看到echo信号也呈现周期性变化,其原因就是给trig输入的信号成周期性变化,每次经过10us的连续高电平,超声波就会发出一个调制的脉冲信号,该调制信号返回后,echo端的信号就会由高电平瞬间变回低电平了,所以echo信号的周期性变化是由trig信号的周期性变化引起的。还有一个值得注意的问题,观察示波器的峰峰值可以看出echo反馈的高电平和给超声波模块的VCC端口所输入的电压信号的高电平值是一样大的,因此就要考虑FPGA开发板的I/O接口所承受的最大耐压值;比如像Xilinx的Basys系列的开发板I/O接口电压承受值为3.3V,这种情况就要给echo接口加一个分压电阻。以免返回电压过大而对芯片造成一定程度的损伤。而ALTERA系列开发板的I/O接口一般情况可以承受5V的电压值,因此可以直接将I/O接口与echo端口和trig端口接在一起。

 

超声波测距系统程序设计及仿真

 

下图给出了系统软件设计的整体框架,实际上由于FPGA内的各个子进程都是并行执行的,且每个子进程都是是独立的模块,因此程序设计并不是按照顺序的方法设计的,而是分离成各个小的子模块进行设计综合的,需要严格控制时序。

超声波收发部分负责产生超声波驱动信号,要求频率为50MHz,占空比为50的方波信号以驱动超声波换能器,同时高速计数器开始计数,检测回波后,计数器停止计数,计算后控制显示输出。

基于FPGA的超声波测距系统设计            

图4.1 系统软件设计框图

 

主控制模块代码:

  1. <font style="font-size: 12pt">module temper(
  2. input        CLOCK_50,               // 板载时钟50MHz
  3. input        Q_KEY,                  // 板载按键RST
  4. input        clk_1_sec,            
  5. input        echo,                     //回响信号输出
  6. output       reg   trig,                //超声波模块触发信号输入     
  7.     output   [15:0]codeshow     
  8. );  
  9. //-------------------------------------
  10. //reg   trig;
  11.               reg   [11:0]cnt;            //计数器,计250个50ns,12.5us,为echo提供时序
  12.               reg   [13:0] cnt1;           //计数器,计8000个12.5us,100ms
  13.               reg   [20:0]cnt3;             //计数124个时钟周期是1mm
  14.               reg   [19:0] dis  ;     
  15.               reg
  16.               echo_buf,                  //echo的上一个时钟的状态
  17.               echo_rising,               //捕捉echo的上升沿
  18.               echo_falling,              //捕捉echo的下降沿
  19.               flag1;                     //echo为高电平时flag1会是1,低电平时会是0
  20.     reg[3:0]beed1;   
  21.     reg[3:0]beed2;   
  22.     reg[3:0]beed3;
  23.     reg[3:0]beed4;
  24. assign codeshow={beed4,beed3,beed2,beed1};
  25. //产生echo控制信号250*8000*50ns,echo高电平持续12.5us,即250个时钟周期
  26. [email protected](posedge CLOCK_50)                  
  27.               begin
  28.               if(cnt == 2)//599
  29.               cnt <= 1'b0;
  30.               else
  31.               cnt <= cnt +1;
  32.               end
  33. [email protected](posedge CLOCK_50)
  34. begin
  35.               if(cnt == 2)//599
  36.               if(cnt1 == 20)//9999
  37.                             begin
  38.                                           trig <= 1'b1;
  39.                                           cnt1 <= 1'b0;
  40.                             end
  41.               else
  42.                             begin
  43.                                           trig <= 1'b0;
  44.                                           cnt1 <= cnt1 + 1'b1;
  45.                             end
  46. end
  47. //捕捉trig上升沿与下降沿,并产生标志位
  48. [email protected](posedge CLOCK_50, negedge Q_KEY)
  49. begin
  50. if (!Q_KEY) echo_buf <= 1'b0;
  51. else
  52.               begin
  53.               echo_buf <= echo;
  54.               echo_rising <= echo & (~echo_buf);
  55.               echo_falling <= (~echo) & echo_buf;
  56.   end
  57. end
  58. [email protected](posedge CLOCK_50)
  59.               begin
  60.               if(echo_rising == 1'b1)
  61.               begin
  62.     flag1 = 1'b1;                       //echo已经变为高电平
  63.     end
  64.     else if(echo_falling == 1'b1)
  65.               begin
  66.               flag1 = 1'b0;                       //echo已经变为低电平
  67.               end
  68.               end
  69. //在flag1 = 1 期间计时,即对时钟进行计数。(4m的距离会是25ms,1mm是125个时钟周期)
  70. [email protected](posedge CLOCK_50, negedge Q_KEY)
  71.               begin
  72.                   if (!Q_KEY) dis<= 19'b0;
  73.                   else
  74.                   begin
  75.                             if(flag1 == 1'b1)
  76.                             begin
  77.                             if(cnt3 == 25)      // 700000              //1mm
  78.                                           cnt3 <= 1'b0;
  79.                             else
  80.                                           cnt3 <= cnt3 + 1'b1;
  81.                             end
  82.                             else if(echo_rising == 1'b1)
  83.                             begin
  84.                                 dis <=cnt3/1;   //dis <=cnt3/290;
  85.                                           cnt3 <= 1'b0;
  86.                   end
  87.                   end
  88.               end
  89. always @ (posedge clk_1_sec, negedge Q_KEY)
  90.   begin
  91.   if (!Q_KEY)
  92.   Begin
  93. beed    <= 1'b0
  94.       beed1   <= 4'b0;
  95.       beed2   <= 4'b0;
  96.       beed3   <= 4'b0;
  97.       beed4   <= 4'b0;
  98. end
  99. else begin
  100.               beed1 <=dis/1000;
  101.               beed2 <=dis%1000/100;
  102.               beed3 <=dis%100/10;
  103.               beed4 <=dis%10;
  104. if(dis>16)begin beed<= 1'b0; end
  105.      else begin beed<=1'b1; end
  106.   end
  107. end
  108. endmodule</font>
     

通过主控制程序,可以实现超声波测距以及当测量距离小于一定长度时,蜂鸣器报警,报警距离可以通过改代码,实现想要的报警的距离。下面是通过波形仿真的结果。如图所示:

基于FPGA的超声波测距系统设计

图4.2 测距并报警

 

分频模块代码:

  1. <font style="font-size: 12pt">module div_50M(
  2.   input      clk,//50
  3.   input      rst_n,//
  4.   output     o_clk,//1HZ
  5.   output     o_clk1hz//1KHZ
  6. );
  7. // 分频模块开始
  8. reg [25:0] cnt;                         // 计数子
  9. reg [25:0] cntt;                         // 计数子
  10. reg regclk1hz;
  11. reg rego_clk;
  12. assign o_clk1hz=regclk1hz;
  13. assign o_clk=rego_clk;
  14. always @ (posedge clk, negedge rst_n)
  15.   if (!rst_n)
  16.     cntt <= 0;
  17.   else
  18.     if (cntt == 2)//cnt == 24_999_)//50M/1000=X,X/2-1=24999
  19.       begin
  20.       cntt <= 0;
  21.       regclk1hz=(~regclk1hz);//1KHZ
  22.       end
  23.     else
  24.     cntt <= cntt + 1'b1;
  25. always @ (posedge clk, negedge rst_n)
  26.   if (!rst_n)
  27.     cnt <= 0;
  28.   else
  29.     if (cnt == 1)//cnt == 24_999_999)
  30.     begin
  31.       cnt <= 0;
  32.       rego_clk=(~rego_clk);//1KHZ
  33.       end
  34.     else
  35.     cnt <= cnt + 1'b1;                  
  36. // 分频模块结束</font>

Endmodule

 

上述代码中输出的1KHZ时钟,在之后进行译码器扫描。分频模块仿真如下图示:基于FPGA的超声波测距系统设计

图4.3 分频模块仿真

 

译码器模块代码:

  1. <font style="font-size: 12pt">module yimaqi(clkshow ,codeshow,duan,wei);
  2. input clkshow;//1K的扫描时钟输入
  3. input [15:0]codeshow;//4个数码管的显示数据输入,共16位,每4位一个密码
  4. output [7:0]duan;//数据段选输出
  5. output [3:0]wei;//动态扫描的位选输出
  6. reg  [3:0]dig1;
  7. reg [3:0]SEGAA;
  8. reg [3:0]countt;
  9. reg [7:0]LED;
  10. always @(posedge clkshow )
  11. begin
  12.      countt=countt+1'b1;
  13.      if(countt>3)begin countt=0;end
  14.               case (countt)
  15.               0: SEGAA<=codeshow[3 : 0];
  16.      1: SEGAA<=codeshow[7 :4];
  17.      2: SEGAA<=codeshow[11 : 8];
  18.      3: SEGAA<=codeshow[15 : 12];                                            
  19.      default: countt=0;
  20.               endcase
  21.                 case (countt)//动态扫描的位选输出
  22.                             0:dig1=4'b0001 ;
  23.                             1:dig1=4'b0010 ;
  24.                             2:dig1=4'b0100 ;
  25.                             3:dig1=4'b1000 ;                                            
  26.      default: countt=0;
  27.               endcase
  28. end
  29. assign wei=dig1;
  30. always @(SEGAA )//数据段选输出
  31. begin
  32.     case (SEGAA)            //hgfedcba
  33.                             4'h0:LED=8'b11000000;//--0
  34.                             4'h1:LED=8'b11111001;//--1
  35.                             4'h2:LED=8'b10100100;//--2
  36.                             4'h3:LED=8'b10110000;//--3
  37.                             4'h4:LED=8'b10011001;//--4
  38.                             4'h5:LED=8'b10010010;//--5
  39.                             4'h6:LED=8'b10000010;//--6
  40.                             4'h7:LED=8'b11111000;//--7
  41.                             4'h8:LED=8'b10000000;//--8
  42.                             4'h9:LED=8'b10010000;//--9
  43.                             4'ha:LED=8'b10001000;//--a
  44.                             4'hb:LED=8'b10000011;//--b
  45.                             4'hc:LED=8'b11000110;//--c
  46.                             4'hd:LED=8'b10100001;//--d
  47.                             4'he:LED=8'b10000110;//--e
  48.                             4'hf:LED=8'b11111111;//--off
  49. endcase
  50. end
  51. assign duan=(dig1==4'b0001)?(LED&8'b01111111):LED;
  52. Endmodule</font>
  53.  

译码器模块,通过扫描检测到的1KHZ时钟输入,把测量到的距离显示到数码管上,译码器模块仿真如下图所示:

基于FPGA的超声波测距系统设计

图4.4 数码管显示仿真

 

顶层原理

顶层原理图主要分为三个模块,分别为分频模块,主控制模块,译码器模块。还有超声波模块接口,以及数码管模块接口。如下图所示:

基于FPGA的超声波测距系统设计

图4.5 原理图