赞
踩
欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的超声波(HC-SR04)测距系统设计—第一版
功能说明:
利用HC-SR 04超声波模块进行测距。
在数码管上面显示测量出来的距离。
数码管显示精度为cm。
测量结果进行滑动均值处理(窗口长度为:4)
由于HC-SR 04模块限制,测量范围:2cm-400cm,测量频率: 100ms测量一次。
如果实际距离大于400cm,会出现测量不准确的情况。
如果测量距离大于400cm,数码管显示E。
使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。
仿真平台:Modelsim。
作者QQ:746833924
说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;
HC-SR04模块简介:
VCC为5V电源;GND为地线;TRIG为触发信号输入;ECHO为回响信号输出。
HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达到3mm。
基本工作原理:
给TRIG端口一个至少10us的高电平信号(建议给15us)。
模块自动发送8个40Khz的方波,自动检测是否有信号返回(模块自动完成,不需要外部干预)。
有信号返回时,模块会给ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
测量距离时,要求被测量的物体为一个平面,否则会影响测量结果。
模块将声波发出去,到达物体表面,反射回来到模块。所以ECHO输出高电平的时间是测量物体与模块之间声波往返的时间。
测量距离=(高电平时间 x 声速(340m/s))/2;(需要注意单位,一般FPGA测量的时间单位为ns)
设计思想如下:
ultrasonic_drive模块负责产生触发trig信号,接收并且判断echo信号高电平的时间长度,然后计算距离,并且将距离换算成为BCD输出。
seven_tube_drive模块负责将距离的BCD码显示出来。
ultrasonic_drive模块设计思路:
产生trig信号思路:每100ms产生15us的高电平。
a. 计数器记录100ms。
b. 达到100ms后,启动15us计时器。
c. 在启动15us计时器期间,拉高trig信号。
// 计数器记录100ms。 always @ (posedge clk) begin if (rst_n == 1'b0) cnt_100ms <= 23'd0; else if (cnt_100ms < T_100ms - 1'b1) cnt_100ms <= cnt_100ms + 1'b1; else cnt_100ms <= 23'd0; end // 达到100ms后,启动15us计时器。 always @ (posedge clk) begin if (rst_n == 1'b0) cnt_15us <= 10'd0; else if (cnt_100ms == T_100ms - 1'b1 && cnt_15us == 10'd0) cnt_15us <= cnt_15us + 1'b1; else if (cnt_15us > 10'd0 && cnt_15us < T_15us) cnt_15us <= cnt_15us + 1'b1; else cnt_15us <= 10'd0; end // 在启动15us计时器期间,拉高trig信号。 always @ (posedge clk) begin if (rst_n == 1'b0) ultrasonic_trig <= 1'b0; else if (cnt_15us > 10'd0 && cnt_15us < T_15us) ultrasonic_trig <= 1'b1; else ultrasonic_trig <= 1'b0; end
记录echo信号的高电平的周期数。
a. 高电平期间计数,低电平清零。
b. 下降沿检测。
c. 检测到下降沿进行存储。
外部echo信号为异步信号,需要同步处理。并且下图时序也表明在下降沿时,正好可以保存记录的高电平的周期数。
// 同步 always @ (posedge clk) echo_r <= ultrasonic_echo; always @ (posedge clk) echo_rr <= echo_r; // 边沿检测 always @ (posedge clk) echo_rrr <= echo_rr; assign flag_neg = echo_rrr & (~echo_rr); assign flag_pos = (~echo_rrr) & echo_rr; // 记录高电平的周期数 always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt <= 32'd0; else if (echo_rr == 1'b1) echo_high_cnt <= echo_high_cnt + 1'b1; else echo_high_cnt <= 32'd0; end // 存储记录的周期数 always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_0 <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_0 <= echo_high_cnt; else echo_high_cnt_0 <= echo_high_cnt_0; end
滑动均值滤波(四次平均)。
a. 存储四次。
b. 假设最开始为0, 所以和的结果为0;以后都是减去最早的,加上最新的。
c. 和除以四,得到均值
// 存储四次测量的结果 always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_0 <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_0 <= echo_high_cnt; else echo_high_cnt_0 <= echo_high_cnt_0; end always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_1 <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_1 <= echo_high_cnt_0; else echo_high_cnt_1 <= echo_high_cnt_1; end always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_2 <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_2 <= echo_high_cnt_1; else echo_high_cnt_2 <= echo_high_cnt_2; end always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_3 <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_3 <= echo_high_cnt_2; else echo_high_cnt_3 <= echo_high_cnt_3; end // 默认前四次结果为0,和也为0,所以最新的四次的和计算方式为加上最新的,减去最早缓存的距离。 always @ (posedge clk) begin if (rst_n == 1'b0) echo_high_cnt_sum <= 32'd0; else if (flag_neg == 1'b1) echo_high_cnt_sum <= echo_high_cnt_sum + echo_high_cnt - echo_high_cnt_3; else echo_high_cnt_sum <= echo_high_cnt_sum; end // 除以4,等于右移两位 assign result_echo_high_cnt = echo_high_cnt_sum >> 2;
根据均值,计算距离。
计算公式: result_echo_high_cnt * 20 *340/2/1_000_000_000
周期为20ns,声速为340m/s,需要换算统一单位为ns
除以1_000_000_000是将s换位ns,但是结果为m
再将结果乘以100,即:除以10_000_000 则结果为cm。
最终计算公式:result_echo_high_cnt * 20 *340/2/10_000_000
always @ (posedge clk) begin
if (rst_n == 1'b0)
distance <= 32'd0;
else
distance <= result_echo_high_cnt * 20 * 340/20_000_000;
end
将数字的每一位计算出来(BCD码表示),用于显示。
测量距离大于400cm,最后一个数码管显示E。
//计算每一个数码管应该亮什么 //距离大于400cm,数码管最后一个显示E. // 输出F时,数码管不亮。 initial show_data = 24'hffffff; always @ (posedge clk) begin if (rst_n == 1'b0) show_data <= 24'hffffff; else if (distance > 400) show_data <= 24'hfffffe; else begin show_data[23:12] <= 12'hfff; show_data[11:8] <= distance/100; show_data[7:4] <= distance/10 % 10; show_data[3:0] <= distance % 10; end end
以上就是ultrasonic_drive的设计原理。
七段数码管为普通六位一体的共阳极数码,采用动态驱动的方式,在此不再赘述。
下板后,我们就可以看到超声波测量的运行情况。
利用卷尺测量的结果和超声波测量的结果基本相同。
注:测量时,a.测量物体是平面,b.测量时,测量路径上不要有干扰的东西(路径方圆20cm之内不要有东西)。
讲解和演示视频(链接)如下:
https://www.bilibili.com/video/BV1MS421o7FL/?spm_id_from=333.999.0.0&vd_source=b5405faeab8632f02533bcbfc5e52e55
本设计所有内容(设计代码、设计工程)链接为:
链接:https://pan.baidu.com/s/1BfPVHx_8VSTeebRwxzd61A
提取码:ctqe
本篇内容中有部分资源来源于网络,如有侵权,请联系作者。
如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。