【組込みシステムアプリケーション開発】FPGA - HC-SR04超音波測距ベース

序文

環境

  • ハードウェア
    DE2-115
    HC-SR04 超音波センサー
  • ソフトウェア
    Quartus 18.1

目標の結果

DE2-115 開発ボードを使用して HC-SR04 モジュールを駆動し、測定データを開発ボード上のデジタル管に表示します。

1 実験原理

1.1 超音波の原理

HC-SR04超音波測距モジュールは、2cm~400cmの非接触距離感知機能を提供でき、測距精度は3mmに達することができ、モジュールには超音波送信機、受信機、制御回路が含まれています。図1にHC-SR04外観を示しますが、基本的な動作原理は、超音波測距モジュールにトリガ信号を与えると超音波を発し、超音波が物体に照射され反射されるとエコー信号を出力します。トリガ信号とエコー信号の時間差によって判断され、物体の距離がわかります。
ここに画像の説明を挿入
ここに画像の説明を挿入
モジュールの動作原理は次のとおりです。

  1. メイン制御デバイスは、10us のパルス信号を Trig ピンに提供します。
  2. HC-SR04は信号を受信して​​超音波の送信を開始し、Echoをハイレベルにして戻ってくる超音波の受信準備をします。
  3. HC-SR04は戻ってきた超音波を受信し、Echoをローレベルに設定します。
  4. エコーの高レベルの継続時間は、超音波が戻ってくるまでの時間間隔です。

超音波モジュールの前方約 4 メートル以内に障害物がない場合、Trig ピンに 10μs 以上のパルストリガー信号が供給されると、モジュールは内部で 8 つの 40kHz 超音波パルスを送信し、エコーを検出します。エコーピンが受信する信号がハイレベルに達し、それが 38 ミリ秒続くとローレベル状態になるため、38 ミリ秒の値を取得すると、前方に障害物が検出されていないことがわかります。

前方に障害物がある場合、超音波パルスの送信後に信号が反射され、信号を受信するとすぐにエコーピンがローレベル状態に切り替わり、エコーピンがハイレベルに留まる時間が長くなります。レベル状態 信号が送信されて戻ってくるまでにかかる時間です。

1.2 ハードウェアモジュールのタイミング図

ここに画像の説明を挿入
上のタイミング図は、10uS を超えるパルス トリガー信号を提供するだけで、モジュールが内部で 8 つの 40kHz サイクル レベルを送信し、エコーを検出することを示しています。エコー信号が検出されると、エコー信号が出力されます。エコー信号のパルス幅は測定された距離に比例します。したがって、信号を送信してからエコー信号を受信するまでの時間間隔から距離を計算できます。計算式: uS/58 = cm または uS/148= = インチ; または: 距離 = 高レベル時間 * 音速 (340M/S) /2; 送信信号の影響を防ぐため、推奨測定期間は 60ms 以上です。エコー信号上で。

1.3 モジュールの説明

DE2-115 のピン割り当ては次のとおりです:
ここに画像の説明を挿入
HC-SR04 超音波測距モジュールには 5V の電源が必要で、残りのトリガーとエコーは自由に接続できます。この記事では GPIO[0] と GPIO[1] を使用します。

超音波モジュールの 4 つのピンの機能は次のとおりです。

ピン 効果
VCC 電源ピン、超音波モジュールの動作電圧は 5V です。
トリガー Trigger(トリガー)という言葉の略で、超音波パルスをトリガーするために使用されるピンです。
エコー この端子はハイレベルとローレベルを切り替え、障害物を検知したときに信号が発信されて反射されるまでの時間を示します。
GND アースピン。

2つのデザインファイル

2.1 クロックの分周

1us周期のクロック信号を生成するクロック分周モジュールを定義します。

module 	clk_div(
	input  wire			Clk		, //system clock 50MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	output wire  		clk_us 	  //
);
//Parameter Declarations
	parameter CNT_MAX = 19'd50;//1us的计数值为 50 * Tclk(20ns)

//Interrnal wire/reg declarations
	reg		[5:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 
	
//Logic Description
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CNT_MAX - 19'd1;
	
	assign clk_us = end_cnt;
	

endmodule 

2.2 超音波測距

HC-SR04トリガー測距信号 (trig) を生成するための超音波センサーのトリガー モジュールを実装します。

module 	hc_sr_trig(
	input  wire			clk_us	, //system clock 1MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	output wire  		trig	  //触发测距信号
);
//Parameter Declarations
	parameter CYCLE_MAX = 19'd300_000;

//Interrnal wire/reg declarations
	reg		[18:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 

//Logic Description	
	
	always @(posedge clk_us or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CYCLE_MAX - 9'd1; 
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 

HC-SR04距離を測定し、検出距離データを出力するために使用される超音波センサーのエコー モジュールを定義します(data_o)

module 	hc_sr_echo(
	input  wire 		Clk		, //clock 50MHz
	input  wire			clk_us	, //system clock 1MHz
	input  wire 		Rst_n	, //reset ,low valid
		   
	input  wire 		echo	, //
	output wire [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);
/* 		S(um) = 17 * t 		-->  x.abc cm	*/
//Parameter Declarations
	parameter T_MAX = 16'd60_000;//510cm 对应计数值

//Interrnal wire/reg declarations
	reg				r1_echo,r2_echo; //边沿检测	
	wire			echo_pos,echo_neg; //
	
	reg		[15:00]	cnt		; //Counter 
	wire			add_cnt ; //Counter Enable
	wire			end_cnt ; //Counter Reset 
	
	reg		[18:00]	data_r	;
//Logic Description
	//如果使用clk_us 检测边沿,延时2us,差值过大
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end
	
	assign echo_pos = r1_echo & ~r2_echo;
	assign echo_neg = ~r1_echo & r2_echo;
	
	
	always @(posedge clk_us or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end 
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= cnt; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  //echo 低电平 归零
			cnt <= 'd0;  
		end  
	end 
	
	assign add_cnt = echo; 
	assign end_cnt = add_cnt && cnt >= T_MAX - 1; //超出最大测量范围则保持不变,极限
	
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			data_r <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end //always end
	
	assign data_o = data_r >> 1;

endmodule 

2.3 超音波駆動

プラットフォームのマニュアルを確認すると、DE2-115開発ボードにはビット選択信号が含まれておらず、各セグメント選択信号には個別のピンがあることがわかります。

ここに画像の説明を挿入
ここに画像の説明を挿入

デジタル チューブ ドライバー モジュールのコードは次のとおりで、入力データ (data_o) を対応するデジタル チューブ ディスプレイに変換するために使用されます。

module seg_driver(
    input   wire        Clk     ,
    input   wire        Rst_n   ,
    input   wire [18:0] data_o  ,

    output  wire [6:0]  hex1    ,
    output  wire [6:0]  hex2    ,
    output  wire [6:0]  hex3    ,
    output  wire [6:0]  hex4    ,
    output  wire [6:0]  hex5    ,
    output  wire [6:0]  hex6    ,
    output  wire [6:0]  hex7    ,
    output  wire [6:0]  hex8     
);

parameter   NOTION  = 4'd10,
            FUSHU   = 4'd11;
parameter   MAX20us = 10'd1000;
reg [9:0]   cnt_20us;
reg [7:0]   sel_r;
reg [3:0]   number;
reg [6:0]   seg_r;
reg [6:0]   hex1_r;
reg [6:0]   hex2_r;
reg [6:0]   hex3_r;
reg [6:0]   hex4_r;
reg [6:0]   hex5_r;
reg [6:0]   hex6_r;
reg [6:0]   hex7_r;
reg [6:0]   hex8_r;



//20微妙计数器
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        cnt_20us <= 10'd0;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        cnt_20us <= 10'd0;
    end
    else begin
        cnt_20us <= cnt_20us + 1'd1;
    end
end



//单个信号sel_r位拼接约束
always @(posedge Clk or negedge Rst_n) begin
    if (!Rst_n) begin
        sel_r <= 8'b11_11_11_10;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        sel_r <= {
    
    sel_r[6:0],sel_r[7]};
    end
    else begin
        sel_r <= sel_r;
    end
end

/*拿到数字*/
always @(*) begin
    case (sel_r)
        8'b11_11_11_10:     number  = NOTION                                        ;
        8'b11_11_11_01:     number  = data_o/10_0000                                ;
        8'b11_11_10_11:     number  = (data_o%10_0000)/1_0000                       ;
        8'b11_11_01_11:     number  = ((data_o%10_0000)%1_0000)/1000                ;
        8'b11_10_11_11:     number  = FUSHU                                         ;
        8'b11_01_11_11:     number  = (((data_o%10_0000)%1_0000)%1000)/100          ;
        8'b10_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)/10     ;
        8'b01_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)%10     ;
        default:            number  = 4'd0                                          ;
    endcase
end

/*通过数字解析出seg值*/
always @(*) begin
    case (number)
        4'd0    :       seg_r   =  7'b100_0000;
        4'd1    :       seg_r   =  7'b111_1001;
        4'd2    :       seg_r   =  7'b010_0100;
        4'd3    :       seg_r   =  7'b011_0000;
        4'd4    :       seg_r   =  7'b001_1001;
        4'd5    :       seg_r   =  7'b001_0010;
        4'd6    :       seg_r   =  7'b000_0010;
        4'd7    :       seg_r   =  7'b111_1000;
        4'd8    :       seg_r   =  7'b000_0000;
        4'd9    :       seg_r   =  7'b001_0000;
        NOTION  :       seg_r   =  7'b111_1111;
        FUSHU   :       seg_r   =  7'b011_1111;
        default :       seg_r   =  7'b111_1111;
    endcase
end

always @(*) begin
    case (sel_r)
		8'b11_11_11_10:     hex1_r = seg_r;
		8'b11_11_11_01:     hex2_r = seg_r;
		8'b11_11_10_11:     hex3_r = seg_r;
		8'b11_11_01_11:     hex4_r = seg_r;
		8'b11_10_11_11:     hex5_r = seg_r;
		8'b11_01_11_11:     hex6_r = seg_r;
		8'b10_11_11_11:     hex7_r = seg_r;
		8'b01_11_11_11:     hex8_r = seg_r;
		default:            seg_r  = seg_r;
	endcase
end

assign  hex1 = hex1_r;
assign  hex2 = hex2_r;
assign  hex3 = hex3_r;
assign  hex4 = hex4_r;
assign  hex5 = hex5_r;
assign  hex6 = hex6_r;
assign  hex7 = hex7_r;
assign  hex8 = hex8_r;

endmodule

3 実験による検証

3.1 コンパイル

以下に示すように、RTL ゲート レベルの回路を表示します。

ここに画像の説明を挿入

3.3 ハードウェアテスト

ピンバインディング:

package require ::quartus::project

set_location_assignment PIN_Y2 -to Clk
set_location_assignment PIN_M23 -to Rst_n
set_location_assignment PIN_AC15 -to echo
set_location_assignment PIN_AB22 -to trig
set_location_assignment PIN_AA14 -to hex1[6]
set_location_assignment PIN_AG18 -to hex1[5]
set_location_assignment PIN_AF17 -to hex1[4]
set_location_assignment PIN_AH17 -to hex1[3]
set_location_assignment PIN_AG17 -to hex1[2]
set_location_assignment PIN_AE17 -to hex1[1]
set_location_assignment PIN_AD17 -to hex1[0]
set_location_assignment PIN_AC17 -to hex2[6]
set_location_assignment PIN_AA15 -to hex2[5]
set_location_assignment PIN_AB15 -to hex2[4]
set_location_assignment PIN_AB17 -to hex2[3]
set_location_assignment PIN_AA16 -to hex2[2]
set_location_assignment PIN_AB16 -to hex2[1]
set_location_assignment PIN_AA17 -to hex2[0]
set_location_assignment PIN_AH18 -to hex3[6]
set_location_assignment PIN_AF18 -to hex3[5]
set_location_assignment PIN_AG19 -to hex3[4]
set_location_assignment PIN_AH19 -to hex3[3]
set_location_assignment PIN_AB18 -to hex3[2]
set_location_assignment PIN_AC18 -to hex3[1]
set_location_assignment PIN_AD18 -to hex3[0]
set_location_assignment PIN_AE18 -to hex4[6]
set_location_assignment PIN_AF19 -to hex4[5]
set_location_assignment PIN_AE19 -to hex4[4]
set_location_assignment PIN_AH21 -to hex4[3]
set_location_assignment PIN_AG21 -to hex4[2]
set_location_assignment PIN_AA19 -to hex4[1]
set_location_assignment PIN_AB19 -to hex4[0]
set_location_assignment PIN_Y19 -to hex5[6]
set_location_assignment PIN_AF23 -to hex5[5]
set_location_assignment PIN_AD24 -to hex5[4]
set_location_assignment PIN_AA21 -to hex5[3]
set_location_assignment PIN_AB20 -to hex5[2]
set_location_assignment PIN_U21 -to hex5[1]
set_location_assignment PIN_V21 -to hex5[0]
set_location_assignment PIN_W28 -to hex6[6]
set_location_assignment PIN_W27 -to hex6[5]
set_location_assignment PIN_Y26 -to hex6[4]
set_location_assignment PIN_W26 -to hex6[3]
set_location_assignment PIN_Y25 -to hex6[2]
set_location_assignment PIN_AA26 -to hex6[1]
set_location_assignment PIN_AA25 -to hex6[0]
set_location_assignment PIN_U24 -to hex7[6]
set_location_assignment PIN_U23 -to hex7[5]
set_location_assignment PIN_W25 -to hex7[4]
set_location_assignment PIN_W22 -to hex7[3]
set_location_assignment PIN_W21 -to hex7[2]
set_location_assignment PIN_Y22 -to hex7[1]
set_location_assignment PIN_M24 -to hex7[0]
set_location_assignment PIN_H22 -to hex8[6]
set_location_assignment PIN_J22 -to hex8[5]
set_location_assignment PIN_L25 -to hex8[4]
set_location_assignment PIN_L26 -to hex8[3]
set_location_assignment PIN_E17 -to hex8[2]
set_location_assignment PIN_F22 -to hex8[1]
set_location_assignment PIN_G18 -to hex8[0]
set_location_assignment PIN_E21 -to led[0]
set_location_assignment PIN_E22 -to led[1]
set_location_assignment PIN_E25 -to led[2]
set_location_assignment PIN_E24 -to led[3]
set_location_assignment PIN_AG26 -to beep

ダウンロードテスト:
ここに画像の説明を挿入

バックレーダーをシミュレートするために、ブザーインジケーターも同時に追加されます。20cm 未満の場合は 1 秒に 1 回、10cm 未満の場合は 0.5 秒に 1 回鳴ります。
このプロジェクトのソースコードを参照してください:
https://github.com/MiaOuyang/ultrasound_waves

要約する

実際の基板テストを通じて、超音波距離測定は基本的に実現されており、測定された距離は実際の距離と基本的に一致しています。ただし、コード内に設計されたレジスタの数が限られているため、コードは約 4 ~ 247cm の距離までしかテストできません。同時に、距離測定に HC-SR04 超音波測距モジュールを使用すると、多少の干渉やエラーが発生します。センサー自体のノイズ、エコーのマルチパス伝播、環境の干渉など、多くの場合に遭遇する要因により、不正確な測距結果や誤った距離値が発生する可能性があります。測距結果に干渉やエラーがある場合は、信号がフィルタリングされます。


参考記事:
https://blog.csdn.net/qq_43546203/article/details/125281386
https://blog.csdn.net/qq_45659777/article/details/124717655
https://blog.csdn.net/AM0R_/article /詳細/119303815

おすすめ

転載: blog.csdn.net/apple_52030329/article/details/131021811