module stop_watch(
input clk, reset_p, // 시스템 클록, 비동기 리셋 (active high)
input [2:0] btn, // 버튼 입력: [0] 시작/정지, [1] 랩, [2] 초기화
output [7:0] seg_7, // 7세그먼트 출력 제어 신호 (a~g, dp)
output [3:0] com // 7세그먼트 공통 단자 제어
);
// 버튼의 네거티브 엣지(떼는 순간)를 감지하는 신호
wire btn_start, btn_lap, btn_clear;
// 각 버튼에 대해 디바운서 및 음엣지 감지 모듈 인스턴스
button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start)); // 시작/정지
button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_nedge(btn_lap)); // 랩
button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_nedge(btn_clear)); // 초기화
// 제어 상태 및 랩 시간 저장용 레지스터
reg start_stop, lap; // start_stop: 1이면 작동 중, lap: 1이면 랩 모드
reg [7:0] lap_sec, lap_csec; // 랩 시간 저장 (초, 센티초)
reg [19:0] cnt_sysclk; // 클록 분주기 (0.01초 타이머용)
reg [7:0] cnt_csec, cnt_sec; // 센티초 및 초 카운터
// 상태 제어: 시작/정지, 랩 저장, 초기화
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
start_stop = 0; lap = 0;
lap_sec = 0; lap_csec = 0;
end
else if(btn_start) // 시작/정지 버튼
start_stop = ~start_stop;
else if(btn_lap) begin // 랩 버튼 → 현재 시간 저장 및 lap 모드 토글
lap_sec = cnt_sec;
lap_csec = cnt_csec;
lap = ~lap;
end
else if(btn_clear) begin // 초기화 버튼 → 모든 값 리셋
start_stop = 0; lap = 0;
lap_sec = 0; lap_csec = 0;
end
end
// lap 상태를 토글하는 중복 블록 (❗비효율적 - 삭제 권장)
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap = 0;
else if(btn_lap) lap = ~lap;
end
// 시간 카운터: 1초를 100등분하여 센티초 단위로 측정
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
cnt_sysclk = 0;
cnt_csec = 0;
cnt_sec = 0;
end
else begin
if(start_stop) begin
if(cnt_sysclk >= 999_999) begin // 약 0.01초 경과 (100MHz 기준)
cnt_sysclk = 0;
if(cnt_csec >= 99) begin // 센티초 100개 = 1초
cnt_csec = 0;
if(cnt_sec >= 59) // 59초까지 측정 후 0으로 초기화
cnt_sec = 0;
else
cnt_sec = cnt_sec + 1;
end
else begin
cnt_csec = cnt_csec + 1;
end
end
else begin
cnt_sysclk = cnt_sysclk + 1;
end
end
end
end
// BCD 변환 및 출력 처리
wire [7:0] csec, sec; // BCD 변환 결과
wire [7:0] fnd_sec, fnd_csec; // FND에 표시할 초/센티초
assign fnd_sec = lap ? fnd_sec : cnt_sec;
assign fnd_csec = lap ? lap_csec : cnt_csec;
// BCD 변환기: 2자리씩 7세그먼트에 표시하기 위한 BCD 변환
bin_to_dec bcd_sec(.bin(cnt_csec), .bcd(csec)); // 센티초
bin_to_dec bcd_min(.bin(cnt_sec), .bcd(sec)); // 초
// 4자리 7세그먼트 디스플레이 출력
fnd_4digit_cntr fnd(
.clk(clk),
.reset_p(reset_p),
.value({sec, csec}), // sec: 상위 2자리, csec: 하위 2자리
.seg_7(seg_7),
.com(com)
);
endmodule