Verilog 實(shí)現(xiàn)超聲波測(cè)距
教學(xué)視頻: https://www.bilibili.com/video/BV1Ve411x75W?p=33&spm_id_from=pageDriver&vd_source=19ae31dff4056e52d2729a4ca212602b
超聲波測(cè)距原理
參考資料:STM32的超聲波測(cè)距程序_超聲波測(cè)距stm32程序_VaderZhang的博客-CSDN博客
推薦一波自己的文章:STM32藍(lán)牙控制循跡避障小車源代碼——3.舵機(jī)、超聲波測(cè)距模塊_stem32超聲波舵機(jī)代碼_靈風(fēng)_Brend的博客-CSDN博客
- 超聲波模塊工作原理:
輸出TRIG觸發(fā)測(cè)距,需要給最少10us的高電平信呈;
模塊自動(dòng)發(fā)送8個(gè)40KHZ的方波,自動(dòng)檢測(cè)是否有信號(hào)返回;
有信號(hào)返回,通過(guò)IO口ECHO輸出高電平,高電平持續(xù)時(shí)間就是超聲波從發(fā)射到返回的時(shí)間;
測(cè)試距離=高電平持續(xù)時(shí)間*聲速/2
需求分析與功能定義:
- 每隔100ms時(shí)間,定時(shí)產(chǎn)生10us時(shí)間的TRIG高脈沖給到超聲波測(cè)距模塊,用于觸發(fā)超聲波測(cè)距模塊工作
- 采集回響信號(hào)ECHO的高脈沖保持時(shí)間
- 將ECHO高脈沖保持時(shí)間換算成距離信息:s = 0.173*t
- 人機(jī)交互
代碼思路:(詳細(xì)教學(xué)可以看最上面的鏈接)
代碼組成:
vlg_en :輸出clk_en信號(hào),對(duì)輸入時(shí)鐘clk做分頻計(jì)數(shù),產(chǎn)生1us的時(shí)鐘使能信號(hào)(計(jì)數(shù)單位為us)
module vlg_en #(
parameter P_CLK_PERIORD = 20 //clk的時(shí)鐘周期為20ms
)
(
input clk,
input rst_n,
output reg clk_en
);
localparam P_DIVCLK_MAX = 1000/P_CLK_PERIORD - 1; //分頻計(jì)數(shù)器的最大值
reg [7:0] r_divcnt;
///
//對(duì)輸入時(shí)鐘clk做分頻計(jì)數(shù),產(chǎn)生1us的時(shí)鐘使能信號(hào)
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
r_divcnt <= 8'b0;
else if(r_divcnt < P_DIVCLK_MAX)
r_divcnt <= r_divcnt + 1'b1;
else
r_divcnt <= 8'b0;
end
///
//產(chǎn)生時(shí)鐘使能信號(hào)
always @(posedge clk) begin
if(r_divcnt == P_DIVCLK_MAX)
clk_en <= 1'b1;
else
clk_en <= 1'b0;
end
endmodule
vlg_tirg :每隔100ms時(shí)間,定時(shí)產(chǎn)生10us時(shí)間的TRIG高脈沖給到超聲波測(cè)距模塊,用于觸發(fā)超聲波測(cè)距模塊工作
module vlg_tirg
(
input clk,
input rst_n,
input clk_en,
output reg trig
);
localparam P_TRIG_PERIORD_MAX = 100_000 - 1; //100ms計(jì)數(shù)最大值
localparam P_TRIG_HIGH_MAX = 10; //10us高脈沖保持時(shí)間
reg [16:0] tricnt;
///
//100ms周期計(jì)數(shù)
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
tricnt <= 'b0;
else if(clk_en)begin
if(tricnt < P_TRIG_PERIORD_MAX)
tricnt <= tricnt + 1'b1;
else
tricnt <= 'b0;
end
end
///
//產(chǎn)生保持10us的trig信號(hào)
always @(posedge clk) begin
if((tricnt > 'b0)&&(tricnt <= P_TRIG_HIGH_MAX))
trig <= 1'b1;
else
trig <= 1'b0;
end
endmodule
上面兩個(gè)信號(hào)的波形展示:
vlg_echo : 采集回響信號(hào)ECHO的高脈沖保持時(shí)間。(echo信號(hào)的高電平保持時(shí)間即為超聲波往返的時(shí)間)
module vlg_echo
(
input clk,
input rst_n,
input clk_en,
input echo,
output reg [15:0] t_us
);
reg [1:0] r_echo;
wire pos_echo,neg_echo;
reg cnt_en;
reg [15:0] echo_cnt;
///
//對(duì)echo信號(hào)鎖存兩拍,獲取邊沿檢測(cè)信號(hào),產(chǎn)生計(jì)數(shù)使能信號(hào)cnt_en
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
r_echo <= 'b0;
else
r_echo <= {r_echo[0],echo}; //高位鎖存,低位移位
end
assign pos_echo = ~r_echo[1] & r_echo[0];
assign neg_echo = r_echo[1] & ~r_echo[0];
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_en <= 'b0;
else if(pos_echo)
cnt_en <= 1'b1;
else if(neg_echo)
cnt_en <= 1'b0;
else ;
end
///
//對(duì)echo信號(hào)的高電平保持時(shí)間進(jìn)行1us為單位的計(jì)數(shù)
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
echo_cnt <= 'b0;
else if(!cnt_en)
echo_cnt <= 'b0;
else if(clk_en)
echo_cnt <= echo_cnt + 1'b1;
else ;
end
///
//對(duì)echo_cnt計(jì)數(shù)最大值做鎖存
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
t_us <= 'b0;
else if(neg_echo)
t_us <= echo_cnt;
end
endmodule
cal :將時(shí)間計(jì)算為距離。測(cè)試距離=高電平持續(xù)時(shí)間 * 聲速/2。 (s = 0.173*t)
module cal
(
input clk,
input rst_n,
input [15:0] t_us,
output [14:0] s_mm
);
/* s=0.173*t
s*4096=0.173*t*4096=709*t 避免小數(shù)部分
s=709*t/4096=709*t>>12
709實(shí)現(xiàn)方法: 1)乘法器
2)709=512+128+64+4+1
本代碼使用乘法器來(lái)實(shí)現(xiàn)。直接調(diào)用乘法器IP核
*/
wire [25:0] mult_result;
mult_gen_0 u_mult_gen_0 (
.CLK(clk), // input wire CLK
.A(10'd709), // input wire [9 : 0] A
.B(t_us), // input wire [15 : 0] B
.P(mult_result) // output wire [25 : 0] P
);
assign s_mm = mult_result[25:12];
endmodule
頂層文件 vlg_top
module vlg_top(
input clk,
input rst_n,
output trig
);
localparam P_CLK_PERIORD = 20;
//接口聲明
reg clk;
reg rst_n;
reg echo;
wire clk_en;
wire trig;
wire [15:0] t_us;
wire [14:0] s_mm;
//使能時(shí)鐘產(chǎn)生模塊
vlg_en #(
.P_CLK_PERIORD (P_CLK_PERIORD) //clk的時(shí)鐘周期為20ns
)
u_vlg_en(
.clk (clk),
.rst_n (rst_n),
.clk_en (clk_en)
);
//產(chǎn)生觸發(fā)信號(hào)trig
vlg_tirg u_vlg_tirg(
.clk (clk),
.rst_n (rst_n),
.clk_en (clk_en),
.trig (trig)
);
//測(cè)距模塊的回響信號(hào)echo的高電平采集時(shí)間
vlg_echo u_vlg_echo(
.clk (clk),
.rst_n (rst_n),
.clk_en (clk_en),
.echo (echo),
.t_us (t_us)
);
//乘法器,計(jì)算距離
cal u_cal(
.clk (clk),
.rst_n (rst_n),
.t_us (t_us),
.s_mm (s_mm)
);
endmodule
調(diào)用乘法器IP核
點(diǎn)擊IP核,輸入MUL,進(jìn)行下面的操作:
TB文件
`timescale 1ns/1ps
module tb_top();
reg clk;
reg rst_n;
reg echo;
wire [14:0] s_mm;
vlg_top u_vlg_top(
.clk (clk),
.rst_n (rst_n),
.trig (trig)
);
//產(chǎn)生時(shí)鐘
initial clk = 1;
always #10 clk = ~clk;
//測(cè)試激勵(lì)產(chǎn)生
initial begin
rst_n = 0;
echo = 0;
#200;
rst_n = 1;
end
//函數(shù)實(shí)現(xiàn) s=0.173*t
function real function_t2s;
input real t;
begin
function_t2s = 0.173*t;
end
endfunction
integer tricnt = 0;
integer dly_time;
always @(posedge trig)begin
tricnt = tricnt + 1;
#5000;
echo = 1;
dly_time = 11+{$random}%26011; //11<t<26011
#500;
$display("test %0d:\n dly_time=%0d us\n s=%0d mm\n",tricnt,dly_time,s_mm,function_t2s(dly_time));
#(dly_time*1000);
echo = 0;
end
endmodule
仿真結(jié)果
- 仿真波形
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-673690.html
- 結(jié)果
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-673690.html
到了這里,關(guān)于Verilog 實(shí)現(xiàn)超聲波測(cè)距的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!