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

Gowin IDE用のプロジェクト一式

左にある箱までの距離を超音波センサで計測する(このページの下部に動画があります)

●電気回路図

「Stump Board+Kiwi Tiny 1P5」とHC-SR04の接続

●センサの使い方

 マイコンや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

●動作確認

コメントを残す