一、介紹超聲波測距模塊HC_SR04
HC-SR04是一種基于超聲波的測距模塊。該模塊向前15度內(nèi)發(fā)送超聲波并接收回響,通過發(fā)出超聲波到收到回響的這個(gè)時(shí)間間隔計(jì)算前方的障礙物距離,可以用來給智能小車做障礙物監(jiān)測??商峁?cm- 400cm的非接觸式距離感測功能,測距精度可達(dá)高到3mm;模塊包括超聲波發(fā)射器、接收器與控制電路。
該模塊的時(shí)序圖如下:
我們在編寫代碼的時(shí)候,想要發(fā)出測距命令,需要先保持觸發(fā)信號(hào)輸入(trig引腳)為低電平,然后保持大于10us的高電平,再變成低電平即可(時(shí)序圖第一行所示)。
發(fā)出測距命令后,回響信號(hào)輸出(echo引腳)會(huì)保持一段時(shí)間的高電平,這個(gè)高電平的持續(xù)時(shí)間與距離有關(guān)。我們在FPGA編寫代碼測量高電平持續(xù)時(shí)間,然后將時(shí)間轉(zhuǎn)化為距離即可。
經(jīng)過測試,得到以下結(jié)論:
1、發(fā)送測距的時(shí)候,每個(gè)脈沖之間的間隔不要過近,我用的間隔是300ms,即每300ms測一次距離,也可以根據(jù)需要修改。
2、接收端高電平時(shí)間與距離的關(guān)系式是:距離(cm)= 高電平持續(xù)時(shí)間(us)x 0.034cm / 2 (除以2是因?yàn)槌掷m(xù)時(shí)間是往返時(shí)間,除以2才是單程時(shí)間)
二、模塊框圖
我們需要設(shè)計(jì)以下模塊:
1、測距信號(hào)源模塊,輸入時(shí)鐘與復(fù)位,每隔300ms輸出15us高電平。
2、距離計(jì)算模塊,輸入時(shí)鐘、復(fù)位與回響信號(hào)echo,輸出距離(cm)
3、數(shù)據(jù)顯示模塊,將得到的距離可視化,我用的是2個(gè)1位數(shù)碼管模塊(小腳丫自帶兩個(gè)1位共陰極數(shù)碼管)
4、頂層模塊
框圖如下:
三、模塊編寫
1. 測距信號(hào)源
在此模塊,寫一個(gè)計(jì)時(shí)周期為300us的循環(huán)計(jì)數(shù)器,當(dāng)計(jì)數(shù)器值小于15時(shí)輸出高電平,其他時(shí)候輸出低電平即可。
代碼如下:
module trigger_send #(
parameter TIME_1S = 12_000_000
) (
input clk ,
input rst_n ,
output trigger
);
//1us生成
wire clk_1us;
PLL UPLL(
.inclk0 (clk),
.c0 (clk_1us)
);
reg [25:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
if (!rst_n) begin
cnt_1us <= 20'd0;
end
else if (cnt_1us == 20'd300_000 - 1)begin
cnt_1us <= 20'd0;
end
else begin
cnt_1us <= cnt_1us + 1'b1;
end
end
assign trigger = cnt_1us < 15 ? 1'b1 : 1'b0;
endmodule
2. 距離計(jì)算
這個(gè)模塊輸入了HC_SR04的回響引腳,要做的就是計(jì)算它的高電平持續(xù)時(shí)間,并轉(zhuǎn)化為距離數(shù)據(jù)輸出。
這里持續(xù)時(shí)間的單位用us最合適,因此同樣生成一個(gè)1us時(shí)鐘,用這個(gè)時(shí)鐘監(jiān)測回響信號(hào)的上升沿與下降沿。檢測到上升沿,就每過一個(gè)時(shí)鐘周期就把計(jì)時(shí)器數(shù)值加1(可以自己設(shè)置上限,表示最大檢測距離);等檢測到下降沿,就把計(jì)時(shí)器的數(shù)據(jù)保存起來,然后把計(jì)時(shí)器清空準(zhǔn)備下次計(jì)時(shí)。
拿到保存好的計(jì)時(shí)后,使用上文提到的公式計(jì)算出距離輸出。
代碼如下:
module data_rec #(
parameter TIME_1S = 12_000_000
) (
input clk ,//系統(tǒng)時(shí)鐘
input rst_n ,//復(fù)位
input rec_data ,//回響,早知道取名echo了
output [11:0] distance //計(jì)算好的距離
);
//鎖相環(huán)生成1us周期時(shí)鐘,因?yàn)楹竺娴挠?jì)時(shí)單位全是1us,這樣方便
wire clk_1us;
PLL UPLL(
.inclk0 (clk),
.c0 (clk_1us)
);
//給回響信號(hào)打拍,檢測上升沿下降沿
reg rec_data2;
reg rec_data3;
wire rec_negedge;
wire rec_posedge;
assign rec_negedge = (!rec_data2) && rec_data3;
assign rec_posedge = rec_data2 && (!rec_data3);
always @(posedge clk_1us or negedge rst_n) begin
if (!rst_n) begin
rec_data2 <= 1'b0;
end
else begin
rec_data2 <= rec_data;
end
end
always @(posedge clk_1us or negedge rst_n) begin
if (!rst_n) begin
rec_data3 <= 1'b0;
end
else begin
rec_data3 <= rec_data2;
end
end
//計(jì)時(shí)啟動(dòng)標(biāo)志,上升沿啟動(dòng),下降沿結(jié)束
reg flag;
always @(posedge clk_1us or negedge rst_n) begin
if (!rst_n) begin
flag <= 1'b0;
end
else if (rec_posedge)begin
flag <= 1'b1;
end
else if (rec_negedge)begin
flag <= 1'b0;
end
else begin
flag <= flag;
end
end
//計(jì)時(shí)器數(shù)值,flag期間計(jì)數(shù),有下降沿就清0,急了多少數(shù)就是保持了多少us,因?yàn)槭怯?us時(shí)鐘驅(qū)動(dòng)的
reg [14:0] cnt_1us;
always @(posedge clk_1us or negedge rst_n) begin
if (!rst_n) begin
cnt_1us <= 15'd0;
end
else if (rec_negedge)begin
cnt_1us <= 15'd0;
end
else if (flag && cnt_1us < 15'd15_000)begin
cnt_1us <= cnt_1us + 1'b1;
end
else begin
cnt_1us <= cnt_1us;
end
end
//因?yàn)橛?jì)時(shí)器結(jié)束計(jì)時(shí)會(huì)變0,因此要用另外的變量,在它清0的時(shí)候把值保存下來
reg [14:0] high_time;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
high_time <= 15'd0;
end
else if (rec_negedge)begin
high_time <= cnt_1us ;
end
else begin
high_time <= high_time;
end
end
//計(jì)算距離,Verilog不能直接用浮點(diǎn)數(shù),就這樣實(shí)現(xiàn)乘以0.017
//為什么不是0.034看前面
reg [11:0] distance_buf;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
distance_buf <= 12'd0;
end
else begin
distance_buf <= high_time * 17 / 1000;
end
end
assign distance = distance_buf;
endmodule
3. 數(shù)碼管模塊
距離模塊的distance就是測到的距離,你拿去數(shù)碼管輸出,串口打印都可以。我的小腳丫自帶兩個(gè)1位的共陰極數(shù)碼管,就用它們來顯示,畢竟自己在面包板上給數(shù)碼管插線插電阻還是挺麻煩的。
用的時(shí)候取出測的距離的十位個(gè)位分別給兩個(gè)模塊就行。
1位七段式共陰極數(shù)碼管十進(jìn)制顯示模塊如下:
module nixietube_1 (
input clk,
input rst_n,
input [3:0] din, //輸入0-9
output drive_out, //使能
output [6:0] _dig, //輸出數(shù)碼管
output dot_out //小數(shù)點(diǎn)要亮嗎
);
//dot小數(shù)點(diǎn)輸出
assign dot_out = 1'b0;
//使能,陰極為0
assign drive_out = 1'b0;
//dig段選輸出
parameter ZER = 7'b0111111,
ONE = 7'b0000110,
TWO = 7'b1011011,
THR = 7'b1001111,
FOU = 7'b1100110,
FIV = 7'b1101101,
SIX = 7'b1111101,
SEV = 7'b0000111,
EIG = 7'b1111111,
NIN = 7'b1101111;
reg [6:0] dig;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dig <= ZER;
end
else begin
case (din)
0 : dig <= ZER;
1 : dig <= ONE;
2 : dig <= TWO;
3 : dig <= THR;
4 : dig <= FOU;
5 : dig <= FIV;
6 : dig <= SIX;
7 : dig <= SEV;
8 : dig <= EIG;
9 : dig <= NIN;
default : dig <= ZER;
endcase
end
end
assign _dig = dig;
endmodule
4. 頂層模塊
module Ultrasound (
input clk,
input rst_n,
input rec_data ,
output trigger ,
output [6:0] dig1,
output [6:0] dig2,
output dot1,
output dot2,
output drive1,
output drive2
);
trigger_send u_trigger_send(
.clk (clk),
.rst_n (rst_n),
.trigger (trigger)
);
wire [11:0] distance;
data_rec u_data_rec(
.clk (clk),
.rst_n (rst_n),
.rec_data (rec_data),
.distance (distance)
);
nixietube_1 u_nixietube_1(
.clk (clk),
.rst_n (rst_n),
.din ((distance/10)%10),
._dig (dig1),
.dot_out (dot1),
.drive_out (drive1)
);
nixietube_1 u_nixietube_2(
.clk (clk),
.rst_n (rst_n),
.din ((distance/1)%10),
._dig (dig2),
.dot_out (dot2),
.drive_out (drive2)
);
endmodule
引腳設(shè)置的時(shí)候,兩個(gè)數(shù)碼管,時(shí)鐘按照小腳丫的原理圖來設(shè)置,trig與echo自己設(shè)置,復(fù)位鍵可以用它自帶的按鈕。
四、實(shí)驗(yàn)現(xiàn)象
文章來源:http://www.zghlxwxcb.cn/news/detail-471573.html
總結(jié)
超聲波模塊主要是要將模塊時(shí)序搞清楚,建立測距信號(hào)源模塊,距離計(jì)算模塊,數(shù)據(jù)顯示模塊。文章來源地址http://www.zghlxwxcb.cn/news/detail-471573.html
到了這里,關(guān)于基于MAX-10 FPGA 超聲波測距模塊HC_SR04的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!