초음파 센서로부터 측정된 거리를 사용자에게 직관적으로 7세그먼트 디스플레이로 보여주는 임베디드 하드웨어 시스템을 Verilog로 구현하는 것
HC-SR04 제어
trig를 통해 센서에 초음파 발사 신호를 주고
echo 신호의 길이를 측정해 물체까지의 거리(cm)를 계산
거리 = echo 시간(us) / 58 공식 사용.
이진 거리 → BCD 변환
계산된 거리 값은 이진(binary)로 저장
7세그먼트에 표시하려면 BCD(Binary Coded Decimal)로 변환
7세그먼트에 출력
변환된 BCD 값을 4자리 7세그먼트 디스플레이에 반복적으로 출력하여
Datasheet
Distance 공식
사용 코드_ 상위 모듈
module hc_sr04_top(
input clk, // 시스템 클럭 입력
input reset_p, // 비동기 리셋 입력 (active high)
input echo, // 초음파 센서의 Echo 신호 입력
output trig, // 초음파 센서의 Trig 신호 출력
output [7:0] seg_7, // 7-세그먼트 디스플레이 제어 신호 (a~g, dp)
output [3:0] com, // 7-세그먼트 디스플레이 공통 단자 (자릿수 선택)
output [15:0] debug_led // 디버깅용 LED 출력 (센서 내부 상태 등을 확인)
);
// 초음파 센서 거리 측정 결과 (단위: cm 또는 us, 내부 정의에 따름)
wire [15:0] distance;
// 초음파 센서 제어 및 거리 계산 모듈 인스턴스화
hc_sr04_cntr sr04 (
.clk(clk),
.reset_p(reset_p),
.echo(echo), // 센서의 Echo 입력
.trig(trig), // 센서에 Trig 출력
.distance(distance),// 측정된 거리 값 출력
.debug_led(debug_led) // 디버그용 내부 신호 출력
);
// 이진 거리 값을 BCD (Binary-Coded Decimal)로 변환
wire [15:0] distance_bcd;
bin_to_dec bcd_sec (
.bin(distance),
.bcd(distance_bcd) // 변환된 BCD 값 출력 (각 자리수 4비트씩)
);
// 4자리 7세그먼트 디스플레이 컨트롤러
fnd_4digit_cntr fnd (
.clk(clk),
.reset_p(reset_p),
.value({distance_bcd[15:8], distance_bcd[7:0]}), // 상위 2자리 + 하위 2자리
.seg_7(seg_7), // 각 자리의 세그먼트 출력
.com(com) // 공통 단자 제어 (4자리 중 어떤 자리인지 선택)
);
endmodule
사용 코드_하위 모듈
module hc_sr04_cntr(
input clk, reset_p, // 시스템 클럭과 비동기 리셋 입력 (reset_p: active-high)
input echo, // 초음파 센서로부터의 Echo 신호 입력
output reg trig, // 초음파 센서로의 Trig 출력 (펄스 발생)
output reg [15:0] distance, // 계산된 거리 값 출력 (단위: cm)
output [15:0] debug_led // 디버깅용 LED 출력 (현재 상태 확인용)
);
// 상태 정의 (1-hot 인코딩 방식)
parameter S_IDLE = 4'b0001; // 거리 측정 대기 상태
parameter S_TRIGGER = 4'b0010; // Trig 신호 10us 출력
parameter S_ECHO_HIGH = 4'b0100; // Echo 상승 에지 대기 상태
parameter S_ECHO_LOW = 4'b1000; // Echo 하강 에지 대기 및 거리 계산 상태
// 1us 주기의 클럭 생성 (100분주기 사용)
wire clk_usec;
clock_div_100 us_clk(
.clk(clk),
.reset_p(reset_p),
.nedge_div_100(clk_usec) // 1us마다 falling edge 발생
);
// Echo 펄스 시간 측정용 카운터 (단위: us)
reg [19:0] count_usec; // 최대 측정 거리 3~4m 이상도 커버 가능
reg count_usec_e; // 카운터 활성화 신호
// us 단위 카운터: clk_usec이 발생할 때마다 증가
always @(negedge clk or posedge reset_p) begin
if(reset_p)
count_usec = 0;
else if(clk_usec && count_usec_e)
count_usec = count_usec + 1;
else if(!count_usec_e)
count_usec = 0;
end
// Echo 신호의 상승/하강 에지 검출
wire echo_nedge, echo_pedge;
edge_detector_p ed (
.clk(clk),
.reset_p(reset_p),
.cp(echo),
.p_edge(echo_pedge), // echo가 0→1일 때 HIGH
.n_edge(echo_nedge) // echo가 1→0일 때 HIGH
);
// 상태 레지스터 및 전이 상태
reg [3:0] state, next_state;
// 현재 상태 디버깅용 출력
assign debug_led[3:0] = state;
// 상태 전이: 네거티브 클럭 에지에서 상태 업데이트
always @(negedge clk or posedge reset_p) begin
if(reset_p)
state = S_IDLE;
else
state = next_state;
end
// Echo 길이를 저장할 레지스터
reg [19:0] echo_end;
// 메인 FSM (모든 제어 로직 포함)
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
next_state = S_IDLE;
count_usec_e = 0;
distance = 0;
echo_end = 0;
trig = 0;
end else begin
case(state)
// 1. IDLE 상태: Trig 전 대기 (약 500ms 간격으로 측정)
S_IDLE: begin
if(count_usec < 500_000) begin // 약 500ms 기다림
count_usec_e = 1;
end else begin
count_usec_e = 0;
next_state = S_TRIGGER;
end
end
// 2. Trig 출력 상태: 약 10us 동안 trig=1
S_TRIGGER: begin
trig = 1; // Trig 핀 HIGH
if(count_usec < 10) begin // 약 10us 유지
count_usec_e = 1;
end else begin
count_usec_e = 0;
trig = 0; // Trig LOW로 복원
next_state = S_ECHO_HIGH;
end
end
// 3. Echo 신호 상승 에지 대기 상태 (시작 시간 기준점 설정)
S_ECHO_HIGH: begin
if(echo_pedge) begin
count_usec_e = 1; // 시간 측정 시작
next_state = S_ECHO_LOW;
end
end
// 4. Echo 신호 하강 에지 감지 후 시간 계산 및 거리 계산
S_ECHO_LOW: begin
if(echo_nedge) begin
echo_end = count_usec; // Echo 지속 시간 저장
count_usec_e = 0;
distance = echo_end / 58; // 거리 계산 (단위: cm)
next_state = S_IDLE;
end
end
default: next_state = S_IDLE;
endcase
end
end
endmodule