一、簡介
聲音是我們日常生活中不可缺少的一種信號,在傳遞信息的同時,也在生活中的各個領域有較多的應用。根據聲音的頻率,我們將聲音大致劃分為三個階段,人耳的聽力范圍,一般在20Hz~20000Hz之間。低于這個范圍,我們稱之為次聲波;高于這個范圍,稱之為超聲波。超聲波的應用比較廣泛,比如:超聲波檢查、超聲波碎石、超聲波清洗、超聲波測速、超聲波測距等等。此次我們就來研究一下它的其中一項應用:超聲波測距。
我們用到的試驗模塊為HC-SR04超聲波模塊,它的測量距離在2cm~400cm之間。測量精度在3mm左右。模塊包含了超聲波的發射器、接收器和控制電路。超聲波發射器在啟動后會發出固定頻率的方波,用聲波去測量距離,不需要我們接觸被測物體,在空間上使得我們測距變得方便很多。
二、工作原理
1、采用IO口TRIG觸發測距,給至少10us的高電平信號,測量周期建議在60ms以上,以防止發射的信號對回響信號造成影響。
2、模塊會自動發送8個40Khz的方波信號,接收器自動檢測是否有回響信號返回。
3、有信號返回時,通過IO口ECHO輸出一個高電平信號,高電平持續的時間就是方波從發射到返回的時間。測量距離=(高電平時間*聲速(340m/s))/2;
在此需要我們注意的事,發射器是自動發送方波信號的,而且會自動檢測是否有信號返回,這讓我們省去了一大部分工作,使得測量變得簡單。其次,在計算測量距離時,我們要將計算出來的結果除以2,因為我們測得的時間是往返的時間,也就是雙倍的路程。
三、實物圖
五、超聲波時序圖
在時序圖中,我們可以看出,我們需要生成一個周期至少為60ms,且高電平維持時間至少為10us的一個觸發信號。
六、實驗要求
此次設計,要求能夠正常驅動模塊,計算出的距離,計算其平均值以保證準確性。數碼管上顯示出距離,單位為m,精確到mm。并且,蜂鳴器能夠根據距離響出不同頻率的報警聲音,距離越近,響聲頻率越頻繁。
七、設計框架
?
八、設計實現
在計算回響信號的時間時,我們可以檢測回響信號的上升沿和下降沿來作為計時器的開始和結束。在我們計算出距離之后,可以每三個數據計算一次平均值。然后將數據輸出給其他模塊。
首先,我們新建工程。
選擇新建文件,然后先新建頂層文件
按照我們所畫框架,寫入頂層端口。
重復上述新建文件的過程,新建ultrasonic_driver文件,代碼如下:?
?
1 module ultrasonic_driver( 2 3 input wire clk, 4 input wire rst_n, 5 input wire echo, 6 output reg trig, 7 output reg [11:0] distance, 8 output reg data_valid 9 ); 10 11 parameter t = 3_000_000; 12 13 reg [21:0] cnt; 14 reg state; 15 reg echo_r, echo_rr; 16 reg [20:0] echo_cnt; 17 reg [20:0] cnt_temp; 18 wire [11:0] d_r; 19 reg [35:0] temp; 20 reg data_valid_r; 21 22 always @ (posedge clk) echo_r <= echo; 23 always @ (posedge clk) echo_rr <= echo_r; 24 25 always @ (posedge clk, negedge rst_n) 26 begin 27 if(rst_n == 1'b0) 28 cnt <= 22'd0; 29 else if(cnt == t - 1) 30 cnt <= 22'd0; 31 else 32 cnt <= cnt + 1'b1; 33 end 34 35 always @ (posedge clk, negedge rst_n) 36 begin 37 if(rst_n == 1'b0) 38 trig <= 1'b0; 39 else if(cnt < 1000) 40 trig <= 1'b1; 41 else 42 trig <= 1'b0; 43 end 44 45 always @ (posedge clk, negedge rst_n) 46 begin 47 if(rst_n == 1'b0) 48 begin 49 echo_cnt <= 21'd0; 50 state <= 1'd0; 51 data_valid_r <= 1'b0; 52 echo_cnt <= 21'd0; 53 end 54 else 55 case(state) 56 1'd0 : begin 57 if(echo_r & (~echo_rr)) 58 state <= 1'd1; 59 else 60 begin 61 state <= 1'd0; 62 data_valid_r <= 1'b0; 63 end 64 end 65 1'd1 : begin 66 if((~echo_r) & echo_rr) 67 begin 68 state <= 1'd0; 69 echo_cnt <= 21'd0; 70 cnt_temp <= echo_cnt; 71 data_valid_r <= 1'b1; 72 end 73 else 74 begin 75 state <= 1'd1; 76 echo_cnt <= echo_cnt + 1'b1; 77 cnt_temp <= cnt_temp; 78 end 79 end 80 endcase 81 end 82 83 assign d_r = cnt_temp * 34 / 10_000; 84 85 always @ (posedge clk, negedge rst_n) 86 begin 87 if(rst_n == 1'b0) 88 temp <= 36'd0; 89 else if(data_valid_r) 90 temp <= {temp[23:0],d_r}; 91 else 92 temp <= temp; 93 end 94 95 always @ (posedge clk) data_valid <= data_valid_r; 96 97 always @ (posedge clk, negedge rst_n) 98 begin 99 if(rst_n == 1'b0) 100 distance <= 12'd0; 101 else if(data_valid) 102 distance <= (temp[35:24] + temp[23:12] + temp[11:0]) / 3; 103 else 104 distance <= distance; 105 end 106 107 endmodule
?
在完成測距時,輸出一個valid信號,這個信號要作為后續我們保存數據以及計算平均值的標志信號。
數碼管代碼如下:
?
1 module seven_tube_driver( 2 3 input wire clk, 4 input wire rst_n, 5 input wire [11:0] data, 6 7 output reg [5:0] sel, 8 output wire [7:0] seg 9 ); 10 11 parameter t = 50000; 12 13 reg [15:0] cnt; 14 reg [3:0] show_data; 15 reg [7:0] seg_r; 16 17 always @ (posedge clk, negedge rst_n) 18 begin 19 if(rst_n == 1'b0) 20 cnt <= 16'd0; 21 else if(cnt == t - 1) 22 cnt <= 16'd0; 23 else 24 cnt <= cnt + 1'b1; 25 end 26 27 always @ (posedge clk, negedge rst_n) 28 begin 29 if(rst_n == 1'b0) 30 sel <= 6'b111_110; 31 else if(cnt == t - 1) 32 sel <= {sel[4:0],sel[5]}; 33 else 34 sel <= sel; 35 end 36 37 always @ (*) 38 begin 39 case(sel) 40 6'b111_110 : show_data = 4'hf; 41 6'b111_101 : show_data = 4'hf; 42 6'b111_011 : show_data = data/1000; 43 6'b110_111 : show_data = data/100%10; 44 6'b101_111 : show_data = data/10%10; 45 6'b011_111 : show_data = data%10; 46 default : show_data = 4'd0; 47 endcase 48 end 49 50 always @ (*) 51 begin 52 case(show_data) 53 4'd0 : seg_r = 8'b1100_0000; 54 4'd1 : seg_r = 8'b1111_1001; 55 4'd2 : seg_r = 8'b1010_0100; 56 4'd3 : seg_r = 8'b1011_0000; 57 4'd4 : seg_r = 8'b1001_1001; 58 4'd5 : seg_r = 8'b1001_0010; 59 4'd6 : seg_r = 8'b1000_0010; 60 4'd7 : seg_r = 8'b1111_1000; 61 4'd8 : seg_r = 8'b1000_0000; 62 4'd9 : seg_r = 8'b1001_0000; 63 default: seg_r = 8'd0; 64 endcase 65 end 66 67 assign seg = (sel == 6'b111_011) ? (seg_r & 8'b0111_1111) : seg_r; 68 69 endmodule
?
第67行的作用是為了在顯示時,顯示一個小數點,這樣數碼管顯示的數值單位就為米,精確度為毫米。
在蜂鳴器模塊中,蜂鳴器的響聲為“嘀嘀”的響聲,我們可以根據距離的大小,讓蜂鳴器響聲的快慢作出改變。
我們根據距離改變計數器的最大計數次數,以達到兩次“嘀嘀”響聲的時間間隔發生變化。
寫好代碼之后,我們做一下仿真,代碼如下:
?
1 `timescale 1ns / 1ps 2 3 module ultrasonic_tb; 4 5 reg clk; 6 reg rst_n; 7 reg echo; 8 wire trig; 9 wire [5:0] sel; 10 wire [7:0] seg; 11 wire beep; 12 13 defparam ultrasonic_inst.ultrasonic_driver_inst.t = 3000; 14 15 initial begin 16 clk = 1'b0; 17 rst_n = 1'b0; 18 echo = 1'b0; 19 #105; 20 rst_n = 1'b1; 21 #1000; 22 23 repeat(10) begin 24 @ (negedge trig); 25 #1002; 26 echo = 1'b1; 27 #20000; 28 echo = 1'b0; 29 end 30 #10000; 31 $stop; 32 end 33 34 always #10 clk = ~clk; 35 36 ultrasonic ultrasonic_inst( 37 .clk (clk ), 38 .rst_n (rst_n ), 39 .echo (echo ), 40 .trig (trig ), 41 .sel (sel ), 42 .seg (seg ), 43 .beep (beep ) 44 ); 45 46 endmodule
?
仿真圖如下:
從圖中我們可以看出,距離在多次采樣之后達到了穩定值。由于我們仿真時間給的較短,所以距離的數值不大,但是已經足夠看出結果。
審核編輯:劉清
?
評論
查看更多