基于FPGA的超声波测距(verilog)
时间:2022-09-30 13:00:00
目录
一、超声波测距模块(HC-SR04)
1、产品特色
2、产品实物
二、超声波测距原理
三、模块代码
一、超声波测距模块(HC-SR04)
1、产品特色
2、产品实物
图一、HC_SR04实物图
二、超声波测距原理
(1)采用 IO 至少触发测距 10us 高电平信号;
(2)模块自动发送 8 个 40khz 自动检测方波是否有信号返回;
(3)有信号返回,通过 IO 输出高电平,高电平持续时间
(4)超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
图2、超声波时序图
上述时序图显示,只需提供10个uS上述脉冲触发信号将发出8个40kHz周期电平并检测回波。一旦检测到回波信号,输出回声信号。脉冲宽度与测量的距离成正比。距离可以通过发射信号到收到的回响信号的时间间隔来计算。公式:uS/58=厘米或者uS/148=英寸;或:距离=高电平时间*声速(340M/S)建议测量周期为60ms防止发射信号对回响信号的影响。于是基于FPGA电路实现主要包括两个模块:触发信号生成和回响信号计时。
FPGA 产生周期性的 TRIG 脉冲信号使超声波模块定期发出测距脉冲。当这些脉冲发出时,当障碍物返回时,超声波模块将返回的脉冲处理和整形手术返回 FPGA,即 ECHO 信号。我们是对的 ECHO 超声波脉冲和障碍物之间的距离可以通过信号的高脉冲保持时间来计算。
本实例的功能如图3所示所示,FPGA 产生 10us 脉冲 TRIG 然后给出超声测距模块 10us 为单位计算超声波测距模块返回的回响信号 ECHO 高电平保持时间。ECHO 障碍物与超声波测距模块之间的距离可通过一定的转换获得高电平保持时间(距离公式计算&实现进制换算模块),我们将最终获得 mm 显示为单位的距离信息 4 位数码管上。
图三、模块框图
三、模块代码
1、vlg_en模块
//产生1us为周期时钟使信号 //1us/20ns=50,r_divcnt内计周期为0~49 module vlg_en#( parameter P_CLK_PERIORD = 20) //i_clk时钟周期为20ns,50MHZ ( input i_clk, input i_rst_n, output reg o_clk_en //o_clk_en的钟周期为1us
);
reg[7:0] r_divcnt;
//对输入时钟i_clk做分频计数,产生1us的时钟使能信号
always @(posedge i_clk)
if(!i_rst_n) r_divcnt <= 'b0;
else if(r_divcnt<50)r_divcnt <= r_divcnt+1'b1;
else r_divcnt <= 'b0;
//产生时钟使能信号
always @(posedge i_clk)
if(!i_rst_n)o_clk_en<= 'b0;
else if(r_divcnt==49)o_clk_en<= 'b1;
else o_clk_en <= 'b0;
endmodule
2、vlg_trig模块
module vlg_trig(
input i_clk,
input i_rst_n,
input i_clk_en,
output reg o_trig
);
reg[16:0] r_tricnt;
//100ms的周期计数
always @(posedge i_clk)
if(!i_rst_n) r_tricnt <= 'b0;
else if((i_clk_en==1)&&(r_tricnt<99999))r_tricnt <= r_tricnt+1'b1;
else r_tricnt <= 'b0;
//产生保持10us的高脉冲o_trig信号
always @(posedge i_clk)
if(!i_rst_n) o_trig<=1'b0;
else if((r_tricnt > 'b0) && (r_tricnt <= 10))o_trig<=1'b1;
else o_trig<=1'b0;
endmodule
3、vlg_echo模块
module vlg_echo(
input i_clk,
input i_rst_n,
input i_clk_en,
input i_echo,
output reg[15:0] o_t_us
);
reg[1:0] r_echo;
wire pos_echo,neg_echo;
reg r_cnt_en;
reg[15:0] r_echo_cnt;
//对i_echo信号同步处理,获取边沿检测信号,产生计数使能信号r_cnt_en
always @(posedge i_clk)
if(!i_rst_n) r_echo<= 'b0;
else r_echo <= {r_echo[0],i_echo};
assign pos_echo =r_echo[0] & ~r_echo[1] ;
assign neg_echo = ~r_echo[0] &r_echo[1] ;
always @(posedge i_clk)
if(!i_rst_n) r_cnt_en <= 'b0;
else if(pos_echo) r_cnt_en <= 'b1;
else if(neg_echo) r_cnt_en <= 'b0;
else ;
//对i_echo信号高脉冲计时,以us为单位
always @(posedge i_clk)
if(!i_rst_n) r_echo_cnt <= 'b0;
else if(!r_cnt_en) r_echo_cnt <= 'b0;
else if(i_clk_en) r_echo_cnt <= r_echo_cnt+1;
else ;
//对r_echo_cnt计数最大值做锁存
always @(posedge i_clk)
if(!i_rst_n) o_t_us <= 'b0;
else if(neg_echo) o_t_us <= r_echo_cnt;
endmodule
4、乘法器IP例化计算距离
module vlg_cal(
input i_clk,
input i_rst_n,
input[15:0] i_t_us,
output[13:0] o_s_mm
);
//乘法器IP例化
wire[25:0] w_mult_result;
mult_gen_0 uut_mult_gen_0 (
.CLK(i_clk), // input wire CLK
.A(10'd709), // input wire [9 : 0] A
.B(i_t_us), // input wire [15 : 0] B
.P(w_mult_result) // output wire [25 : 0] P
);
assign o_s_mm = w_mult_result[25:12];
endmodule
5、顶层模块例化
module vlg_design(
input i_clk,
input i_rst_n,
output o_trig,
input i_echo
);
localparam P_CLK_PERIORD = 20;
wire w_clk_en;
wire[15:0] w_t_us;
wire[13:0] o_s_mm;
//
//使能时钟产生模块
vlg_en #(
.P_CLK_PERIORD(P_CLK_PERIORD) //i_clk的时钟周期为20ns
)
uut_vlg_en(
.i_clk(i_clk),
.i_rst_n(i_rst_n),
.o_clk_en(w_clk_en)
);
//
//产生超声波测距模块的触发信号o_trig
vlg_trig uut_vlg_trig(
.i_clk(i_clk),
.i_rst_n(i_rst_n),
.i_clk_en(w_clk_en),
.o_trig(o_trig)
);
//
//超声波测距模块的回响信号i_echo的高电平时间采集
vlg_echo uut_vlg_echo(
.i_clk(i_clk),
.i_rst_n(i_rst_n),
.i_clk_en(w_clk_en),
.i_echo(i_echo),
.o_t_us(w_t_us)
);
//
//进行时间和距离的转换运算s = 0.179t
vlg_cal uut_vlg_cal(
.i_clk(i_clk),
.i_rst_n(i_rst_n),
.i_t_us(w_t_us),
.o_s_mm(o_s_mm)
);
//
//VIO IP例化
debug_vio uut_debug_vio (
.clk(i_clk), // input wire clk
.probe_in0(o_s_mm) // input wire [13 : 0] probe_in0
);
endmodule