Verilog/Verilog 실습
Verilog HC-SR04 초음파센서 제어
오버헤드프레스
2023. 5. 16. 17:39
HC-SR04는 40kHz의 초음파 송신부와 수신부로 구성되어있다.
모듈 스펙
입력 전원 : 5v
측정 거리 : 2cm ~ 4m
측정 각도 범위 : 15°
트리거 입력 신호 : 10us
1. 모듈의 Trig에 10 us의 High Pulse를 준다.
2. 40KHz의 8개 sonic burst 발생. [1번 과정을 거쳐야만 발생]
3. 에코는 초음파 발신 직후 HIGH level이 되고, 물체를 감지하면 LOW level이 된다.
-> 에코 펄스는 즉, 초음파가 장애물을 만나 다시 에코로 돌아올때까지의 왕복 시간을 나타낸다,
4. 거리 = 에코 High Pulse 시간(왕복시간) x 소리의 속도(340m/s) / 2
-> 왕복이므로 2로 나누어 주어야한다.
초음파센서 TOP 모듈 코드
`timescale 1ns / 1ps
module ultrasonic_1_top(
input clk,
input btn,
input echo,
output t,
output [7:0] led,
output [3:0] com_an,
output [6:0] seg
);
wire reset_n;
wire [15:0] bcd_echo;
wire clk_160ns, clk_2560ns, clk_40us, debounced_btn;
wire [11:0] echo_value;
wire [11:0] echo_cm;
assign echo_cm = echo_value/58;
clock_divider cd_16(.clk(clk), .sel(3), .clk_out(clk_160ns)); //160ns
clock_divider cd_256(.clk(clk_160ns), .sel(3), .clk_out(clk_2560ns)); //2560ns
clock_divider cd_4096(.clk(clk_2560ns), .sel(3), .clk_out(clk_40us)); //40us
ultrasonic_1 uccc(.clk(clk), .reset_n(reset_n), .echo(echo), .t(t), .echo_value(echo_value), .led(led));
D_flip_flop_posedge dff(.D(btn), .E(clk_40us), .Q(debounced_btn));
assign reset_n = ~debounced_btn;
bin_to_dec btd_humi (.bin(echo_cm), .bcd(bcd_echo));
FND_4digit_switcher fnd(
.value_1(bcd_echo [3:0]),
.value_10(bcd_echo[7:4]),
.value_100(bcd_echo[11:8]),
.value_1000(bcd_echo[15:12]),
.clk(clk),
.com_an(com_an),
.seg(seg)
);
endmodule
초음파센서 코드
`timescale 1ns / 1ps
module ultrasonic_1(
input clk,
input reset_n,
input echo,
output reg t,
output reg [11:0] echo_value,
output reg [7:0] led
);
parameter TRIG_WAIT = 3'b000;
parameter TRIG_PULSE = 3'b001;
parameter ECHO_PULSE = 3'b010;
wire echo_p, echo_n;
reg [2:0] state = TRIG_WAIT, next_state = TRIG_WAIT;
reg [21:0] cnt_usec;
reg cnt_usec_e = 0;
clock_usec u(.clk(clk), .reset_n(1), .clk_usec(clk_usec));
edge_detect usec(.clk(clk_usec), .cp_in(echo), .reset_n(1), .p_edge(echo_p), .n_edge(echo_n));
always @(negedge clk_usec or negedge reset_n)begin
if(!reset_n)begin cnt_usec = 0;end
else if (cnt_usec_e) begin cnt_usec = cnt_usec + 1;end
else begin cnt_usec = 0; end
end
always @(negedge clk_usec or negedge reset_n)begin
if (!reset_n)begin state = TRIG_WAIT; end
else begin
state = next_state;
case (state)
TRIG_WAIT : begin cnt_usec_e = 1;
if (cnt_usec < 100000)begin
cnt_usec_e = 1;
t = 0;
led[0] = 1;
end
else begin
next_state = TRIG_PULSE ;
cnt_usec_e = 0;
end
end
TRIG_PULSE : begin cnt_usec_e = 1;
led[1] = 1;
if (cnt_usec <= 15)begin
cnt_usec_e = 1;
t = 1;
end
else begin
t = 0;
cnt_usec_e = 0;
next_state = ECHO_PULSE;
end
end
ECHO_PULSE: begin
led[2] = 1;
if(echo_p) begin
led[3] = 1;
cnt_usec_e = 1;
end
else if(echo_n) begin
cnt_usec_e = 0;
echo_value = cnt_usec[11:0];
next_state = TRIG_WAIT;
end
end
default : next_state = TRIG_WAIT;
endcase
end
end
endmodule
테스터 벤치 코드
`timescale 1ns / 1ps
module ultrasonic_tb2();
reg clk;
reg echo;
reg reset_n;
wire t;
wire [11:0] echo_value;
ultrasonic_1 DUT(.clk(clk), .reset_n(reset_n), .echo(echo), .t(t), .echo_value(echo_value));
initial begin clk = 0; reset_n = 1; echo = 0; end
always #5 clk = ~clk;
initial begin
#100000000
#20000 echo = 1;
#1000000 echo = 0;
#100020000 echo = 1;
#2000000 echo = 0;
#98000000
$finish;
end
endmodule