Verilog_RTL 설계/Basys_3

[Basys_3]_Alarm / Timer

juniha 2025. 7. 9. 18:24

목표

  • 타이머 시작/정지 토글
  • 정지 상태에서 초 증가
  • 정지 상태에서 분 증가
  • 알람 끄고, 마지막 설정 시간 복구
  • 타이머 종료 시 알람 출력 / LED 점등
  • 타이머 작동 중 led 점등
  • 7세그먼트로 출

사용 코드

module timer_top(
    input clk, reset_p,             // 시스템 클록과 비동기 리셋 입력 (reset_p: active-high)
    input [3:0] btn,                // 버튼 입력: [0] 시작/정지, [1] 초 증가, [2] 분 증가, [3] 알람 끄기
    output [7:0] seg_7,             // 7세그먼트 제어 신호 (a~g, dp)
    output [3:0] com,               // 7세그먼트 공통 단자
    output reg alarm,              // 알람 상태 출력 (1일 때 알람 울림)
    output alarm_led,              // 알람 상태를 LED로 출력
    output start_led               // 타이머 동작 상태를 LED로 출력
);
     
    // 버튼 음에지(떼는 순간) 감지 신호
    wire btn_start, btn_inc_sec, btn_inc_min, btn_alarm_off;
    
    // 각 버튼에 대해 디바운서 + 네거티브 엣지 감지 모듈 인스턴스
    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_inc_sec));      // 초 증가 버튼
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_nedge(btn_inc_min));      // 분 증가 버튼
    button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_nedge(btn_alarm_off));    // 알람 끄기 버튼

    // 현재 시간 및 저장 시간 관련 레지스터
    wire [15:0] cur_time;       // 현재 시간 (분:초를 16비트로 묶음)
    reg [15:0] set_time;        // 사용자가 시작 시점에 설정한 시간 저장
    reg start_stop;             // 타이머 동작 상태 (1: 작동 중, 0: 멈춤)

    // LED 출력 신호 연결
    assign alarm_led = alarm;        // 알람이 켜지면 LED 점등
    assign start_led = start_stop;   // 타이머 작동 중일 때 LED 점등

    // 타이머 상태 제어 로직 (시작, 정지, 알람 트리거)
    always @(posedge clk, posedge reset_p) begin
        if(reset_p) begin
            start_stop = 0;          // 정지 상태 초기화
            alarm = 0;               // 알람 초기화
            set_time = 0;            // 설정 시간 초기화
        end
        else if(btn_start && start_stop == 0 && cur_time != 0) begin
            start_stop = 1;          // 타이머 시작
            set_time = cur_time;     // 시작 시점의 시간을 저장
        end
        else if(btn_start && start_stop) begin
            start_stop = 0;          // 타이머 정지
        end
        else if({cnt_min, cnt_sec} == 0 && start_stop == 1) begin
            start_stop = 0;          // 시간이 0이 되면 정지
            alarm = 1;               // 알람 ON
        end
        else if(btn_alarm_off) begin
            alarm = 0;               // 알람 OFF
        end
    end

    // 클록 카운터 및 시간 저장 레지스터
    reg [26:0] cnt_sysclk;       // 1Hz 분주용 카운터 (100MHz 기준이면 1초 = 99,999,999)
    reg [7:0] cnt_sec, cnt_min;  // 초 및 분 카운터

    assign cur_time = {cnt_min, cnt_sec};  // 현재 시간 = 분(상위 8비트) + 초(하위 8비트)

    // 시간 증가/감소 및 설정 복구 로직
    always @(posedge clk, posedge reset_p) begin
        if(reset_p) begin
            cnt_sysclk = 0;
            cnt_sec = 0;
            cnt_min = 0;
        end
        else begin
            if(start_stop) begin  // 타이머 작동 중
                if(cnt_sysclk >= 99_999_999) begin  // 1초 경과
                    cnt_sysclk = 0;

                    if(cnt_sec == 0) begin
                        if(cnt_min == 1) begin
                            cnt_sec = 59;
                            cnt_min = cnt_min - 1;
                        end
                        // cnt_min == 0이면 그대로 유지 (알람 제어에서 종료됨)
                    end
                    else begin
                        cnt_sec = cnt_sec - 1;
                    end
                end
                else begin
                    cnt_sysclk = cnt_sysclk + 1;
                end
            end
            else begin  // 정지 상태에서는 시간 설정 가능
                if(btn_inc_sec) begin
                    if(cnt_sec >= 59)
                        cnt_sec = 0;
                    else
                        cnt_sec = cnt_sec + 1;
                end
                else if(btn_inc_min) begin
                    if(cnt_min >= 99)
                        cnt_min = 0;
                    else
                        cnt_min = cnt_min + 1;
                end
                else if(btn_alarm_off) begin
                    // 알람을 끄면 마지막 설정 시간으로 복구
                    cnt_sec = set_time[7:0];
                    cnt_min = set_time[15:8];
                end
            end
        end
    end

    // BCD 변환 및 7세그먼트 표시
    wire [7:0] sec, min;
    bin_to_dec bcd_sec(.bin(cnt_sec), .bcd(sec));   // 초 -> BCD 변환
    bin_to_dec bcd_min(.bin(cnt_min), .bcd(min));   // 분 -> BCD 변환

    // FND 표시: MMSS 포맷으로 출력
    fnd_4digit_cntr fnd(
        .clk(clk),
        .reset_p(reset_p),
        .value({min, sec}),      // 4자리 FND: min(2자리), sec(2자리)
        .seg_7(seg_7),
        .com(com));
endmodule

 

사용 코드_7_Segment

##7 Segment Display
set_property -dict { PACKAGE_PIN W7   IOSTANDARD LVCMOS33 } [get_ports {seg_7[7]}]
set_property -dict { PACKAGE_PIN W6   IOSTANDARD LVCMOS33 } [get_ports {seg_7[6]}]
set_property -dict { PACKAGE_PIN U8   IOSTANDARD LVCMOS33 } [get_ports {seg_7[5]}]
set_property -dict { PACKAGE_PIN V8   IOSTANDARD LVCMOS33 } [get_ports {seg_7[4]}]
set_property -dict { PACKAGE_PIN U5   IOSTANDARD LVCMOS33 } [get_ports {seg_7[3]}]
set_property -dict { PACKAGE_PIN V5   IOSTANDARD LVCMOS33 } [get_ports {seg_7[2]}]
set_property -dict { PACKAGE_PIN U7   IOSTANDARD LVCMOS33 } [get_ports {seg_7[1]}]

set_property -dict { PACKAGE_PIN V7   IOSTANDARD LVCMOS33 } [get_ports seg_7[0]]

set_property -dict { PACKAGE_PIN U2   IOSTANDARD LVCMOS33 } [get_ports {com[0]}]
set_property -dict { PACKAGE_PIN U4   IOSTANDARD LVCMOS33 } [get_ports {com[1]}]
set_property -dict { PACKAGE_PIN V4   IOSTANDARD LVCMOS33 } [get_ports {com[2]}]
set_property -dict { PACKAGE_PIN W4   IOSTANDARD LVCMOS33 } [get_ports {com[3]}]

사용 코드_Button

##Buttons
set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports reset_p]
set_property -dict { PACKAGE_PIN T18   IOSTANDARD LVCMOS33 } [get_ports btn[0]]
set_property -dict { PACKAGE_PIN W19   IOSTANDARD LVCMOS33 } [get_ports btn[1]]
set_property -dict { PACKAGE_PIN T17   IOSTANDARD LVCMOS33 } [get_ports btn[2]]
set_property -dict { PACKAGE_PIN U17   IOSTANDARD LVCMOS33 } [get_ports btn[3]]

사용 코드_LED

## LEDs
set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports {mode_led}]
set_property -dict { PACKAGE_PIN E19   IOSTANDARD LVCMOS33 } [get_ports {alarm_led}]
set_property -dict { PACKAGE_PIN U19   IOSTANDARD LVCMOS33 } [get_ports {start_led}]

사용 코드_Header_JA

set_property -dict { PACKAGE_PIN J1   IOSTANDARD LVCMOS33 } [get_ports {alarm}];#Sch name = JA1

 

Pin-out Diagram

 

동작 영상