HC-SR04は40kHzの超音波を発信して,反射して音波が戻ってくるまでの時間によって対象物までの距離を測定するセンサです.

●電気回路図

●センサの使い方
マイコンやFPGAから10usのパルスを60ms以上の測定間隔でTrig入力に与えます.Echo端子から出力されるパルスの幅をus単位で測定し,58で割った値が反射対象物までの距離 (cm) となります.

※ 詳細は,HC-SR04のデータシートを参照してください.
●I/O制約

●RTLコード
top.sv:超音波センサの制御
disp_dist.sv:4桁7セグLEDの表示内容算出
clkdiv.sv:分周器
drv7seg4.sv:1桁の7セグの表示制御
mux7seg.sv:ダイナミック駆動する4桁7セグLEDの桁の切り替え
top.sv
module top (
input logic clk,
input logic nrst,
input logic echo,
output logic trigger,
output logic [7:0] seg,
output logic [3:0] dig
) ;
parameter MAX1MHZ = 26'd26 ; // (27MHz / 1MHz) - 1
parameter MAX5HZ = 26'd199999 ; // (200ms / 1us) - 1
logic clk_1mhz ;
logic pls_5hz ; // 200ms interval
logic count_nrst ;
logic [2:0] state = 3'd0 ;
logic [15:0] count ;
logic [15:0] measure ;
logic [3:0] trig_count ;
logic overflow ;
clkdiv clkdiv_1 (.clk(clk), .nrst(nrst), .max(MAX1MHZ), .clk_out(clk_1mhz), .tc()) ;
clkdiv dlkdiv_2 (.clk(clk_1mhz), .nrst(nrst), .max(MAX5HZ), .clk_out(), .tc(pls_5hz)) ;
count16 counter16_1 (.clk(clk_1mhz), .nrst(count_nrst), .count(count), .ov(ov)) ;
disp_dist disp_dist_1(.*, .measure(measure)) ;
always @(negedge nrst or posedge clk_1mhz) begin
if (nrst == 1'b0) begin
count_nrst <= 1'b0 ; // clear counter
measure <= 16'd0 ;
trigger <= 1'b0 ;
trig_count <= 4'd0 ;
end else begin
if (state == 3'd0) begin
if (pls_5hz == 1'b1) begin
count_nrst <= 1'b0 ; // clear couner
trigger <= 1'b0 ;
trig_count <= 4'd0 ;
state <= state + 3'd1 ; // next state
end
end else if (state == 3'd1) begin
if (trig_count < 4'd10) begin
trigger <= 1'b1 ;
trig_count <= trig_count + 4'd1 ;
end else begin
trigger <= 1'b0 ;
trig_count <= 4'd0 ;
state <= state + 3'd1 ; // next state
end
end else if (state == 3'd2) begin
if (echo == 1'b1) begin // wait echo rise
count_nrst <= 1'b1 ; // start counter
state <= state + 3'd1 ; // next state
end
end else if (state == 3'd3) begin
if (ov == 1'b1) begin // couner overflow!
state <= 3'd0 ;
end
if (echo == 1'b0) begin // echo fall
measure <= count ; // get distance
state <= state + 3'd1 ; // next state
count_nrst <= 1'b0 ;
end
end else begin // state = 3'd0 ~
state <= 3'd0 ;
end
end
end
endmodule : top
disp_dist.sv
module disp_dist (
input logic clk,
input logic nrst,
input logic [15:0] measure,
output logic [7:0] seg,
output logic [3:0] dig
) ;
parameter MAX270HZ = 26'd99999 ;
logic [15:0] distance ;
logic [3:0][7:0] seg_in ;
logic clk270hz ;
clkdiv clkdiv_3 (.*, .max(MAX270HZ), .clk_out(clk270hz), .tc()) ;
always @ (negedge nrst or posedge clk) begin
if (nrst == 1'b0) begin
distance <= 16'd0 ;
end else begin
distance <= measure / 58 ; // cm distance
end
end
drv7seg4 drv_7seg4_1(.in( distance % 10), .dp(1'b0), .seg(seg_in[0])) ;
drv7seg4 drv_7seg4_2(.in((distance / 10) % 10), .dp(1'b0), .seg(seg_in[1])) ;
drv7seg4 drv_7seg4_3(.in((distance / 100) % 10), .dp(1'b0), .seg(seg_in[2])) ;
drv7seg4 drv_7seg4_4(.in((distance / 1000) % 10), .dp(1'b0), .seg(seg_in[3])) ;
mux7seg mux7seg_1 (.*, .clk(clk270hz)) ;
endmodule : disp_dist
count16.sv
module count16 (
input logic clk,
input logic nrst,
output logic [15:0] count,
output logic ov
) ;
parameter MAX_VALUE = 16'hFFFF ;
always @(negedge nrst or posedge clk) begin
if (nrst == 1'b0) begin
ov <= 1'b0 ;
count <= 16'd0 ;
end else begin
if (count == MAX_VALUE) begin
ov <= 1'b1 ;
end else begin
count <= count + 16'd1 ;
end
end
end
endmodule : count16
clkdiv.sv
module clkdiv (
input logic clk,
input logic nrst,
input logic [25:0] max,
output logic clk_out,
output logic tc
) ;
logic [25:0] count ;
always_ff @(posedge clk or negedge nrst) begin
if (nrst == 1'b0) begin // reset asserted
count <= 26'd0 ;
clk_out <= 1'b0 ;
tc <= 1'b0 ;
end else begin
if (count >= max) begin
tc <= 1'b1 ;
count <= 26'd0 ;
end else begin
tc <= 1'b0 ;
count <= count + 26'd1 ;
end
if (count <= {1'b0, max[25:1]}) begin
clk_out <= 1'b1 ;
end else begin
clk_out <= 1'b0 ;
end
end
end
endmodule : clkdiv
drv7seg4.sv
module drv7seg4 (
input logic [3:0] in,
input logic dp,
output logic [7:0] seg
) ;
function [6:0] f ;
input [3:0] in ;
begin
case (in)
4'h0: f = 7'h7E ;
4'h1: f = 7'h30 ;
4'h2: f = 7'h6d ;
4'h3: f = 7'h79 ;
4'h4: f = 7'h33 ;
4'h5: f = 7'h5B ;
4'h6: f = 7'h5F ;
4'h7: f = 7'h70 ;
4'h8: f = 7'h7F ;
4'h9: f = 7'h7B ;
4'hA: f = 7'h77 ;
4'hB: f = 7'h1F ;
4'hC: f = 7'h4E ;
4'hD: f = 7'h3D ;
4'hE: f = 7'h4F ;
4'hF: f = 7'h47 ;
endcase
end
endfunction : f
assign seg = { f(in), dp } ;
endmodule : drv7seg4
mux7seg.sv
module mux7seg (
input logic clk,
input logic nrst,
input logic [3:0][7:0] seg_in,
output logic [7:0] seg,
output logic [3:0] dig
) ;
logic [1:0] col ;
always @(negedge nrst or posedge clk) begin
if (nrst == 1'b0) begin
col <= 2'd0 ;
end else begin
if (col >= 2'd3) begin
col <= 2'd0 ;
end else begin
col <= col + 2'd1 ;
end
case (col)
2'd0: { dig, seg } <= { 4'b1110, seg_in[0] } ;
2'd1: { dig, seg } <= { 4'b1101, seg_in[1] } ;
2'd2: { dig, seg } <= { 4'b1011, seg_in[2] } ;
2'd3: { dig, seg } <= { 4'b0111, seg_in[3] } ;
endcase
end
end
endmodule : mux7seg