Language/Verilog

Vivado : Basys3 종합 시계 프로젝트 (타이머, 스톱워치, 시계)

짱도르딘 2024. 7. 30. 15:03
728x90

이번에는 여러 기능을 갖춘 종합 시계 프로젝트를 진행하려고 한다.


종합 시계 프로젝트

 

구현할 종합시계의 기능은 일반 시계 기능, 스톱워치 기능 그리고 타이머 기능을 갖는다.

 

일반 시계 기능에서는 분과 초를 제어할 수 있으며 59분 59초가 넘을 시 00분 00초로 다시 리셋이 되는 특징을 지닌다.

 

스톱워치 기능에서는 기본적으로 ms단위로 시계가 흐르며, Lap 기능을 갖추어 원하는 시간에 동작을 멈춘 후, 멈춘 시간으로부터 Lap을 해제할 때까지의 시간을 잴 수 있다.

 

타이머 기능에서는 초와 분을 설정하여, 설정된 시간으로부터 00분 00초가 될 때까지의 타이머 기능을 구현한다. 타이머가 00분 00초가 되었을 때에는 부저가 울리며, 외부의 스위치로 부저를 제어할 수 있다.


타이머

타이머를 동작시킬 코드는 아래와 같다.

 

기본적으로 모듈의 입출력은 아래와 같다.

 

모듈의 입출력에는 리셋버튼, 버튼입력, 알람 제어 그리고 알람을 직접 확인할 수 있도록 부저와 LED의 출력을 선언하였다.

module cook_timer_for_multi_top(
    input clk, reset_p,
    input [2:0] btn,
    input alarm_off,
    output [3:0] com,
    output [7:0] seg_7,
    output led_alarm, led_start, buzz
    );

 

버튼을 사용하여 타이머를 제어할 코드는 아래와 같다.

 

기존 Basys3에 달려있는 3개의 버튼(reset 제외)과 외부적으로 브레드보드에 연결한 버튼을 추가하였다. 외부 버튼은 타이머의 알람이 울릴 때 LED와 부저의 울림을 제어한다.

// Button setting    
    wire btn_start, btn_sec, btn_min, btn_alarmoff;
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_start));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_sec));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_min));
    button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(alarm_off), .btn_pedge(btn_alarmoff));

 

타이머의 알람을 직접 확인할 수 있는 LED와 부저의 코드는 아래와 같다.

 

알람이 발생할 시 LED와 부저에 입력을 주어 동작을 구현한다.

// LED setting
    assign led_alarm = alarm;
    assign buzz = alarm;
    assign led_start = start_set;

 

최종적으로 타이머의 기능을 구현할 전체적인 코드는 아래와 같다.

module cook_timer_for_multi_top(
    input clk, reset_p,
    input [2:0] btn,
    input alarm_off,
    output [3:0] com,
    output [7:0] seg_7,
    output led_alarm, led_start, buzz
    );
    
    // Clock setting
    wire clk_usec, clk_msec, clk_sec, clk_min;
    clock_div_100 usec_clk(.clk(clk), .reset_p(reset_p), .clk_div_100(clk_usec));
    clock_div_1000 msec_clk(.clk(clk), .reset_p(reset_p), .clk_source(clk_usec), .clk_div_1000(clk_msec));
    clock_div_1000 sec_clk(.clk(clk), .reset_p(reset_p), .clk_source(clk_msec), .clk_div_1000_nedge(clk_sec));
    clock_div_60 min_clk(.clk(clk), .reset_p(reset_p), .clk_source(clk_sec), .clk_div_60_nedge(clk_min));
    
    // Button setting    
    wire btn_start, btn_sec, btn_min, btn_alarmoff;
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_start));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_sec));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_min));
    button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(alarm_off), .btn_pedge(btn_alarmoff));
    
    // 60 up counter
    wire [3:0] set_min10, set_min1, set_sec10, set_sec1;
    wire [3:0] cur_min10, cur_min1, cur_sec10, cur_sec1;
    counter_bcd_60 counter_sec(.clk(clk), .reset_p(reset_p), .clk_time(btn_sec), .bcd1(set_sec1), .bcd10(set_sec10));
    counter_bcd_60 counter_min(.clk(clk), .reset_p(reset_p), .clk_time(btn_min), .bcd1(set_min1), .bcd10(set_min10));
    
    // 60 down counter
    wire dec_clk;
    loadable_down_counter_bcd_60 cur_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .load_enable(btn_start),
    .load_bcd1(set_sec1), .load_bcd10(set_sec10), .bcd1(cur_sec1), .bcd10(cur_sec10), .dec_clk(dec_clk));
    loadable_down_counter_bcd_60 cur_min(.clk(clk), .reset_p(reset_p), .clk_time(dec_clk), .load_enable(btn_start),
    .load_bcd1(set_min1), .load_bcd10(set_min10), .bcd1(cur_min1), .bcd10(cur_min10));
        
    // FND control
    wire [15:0] value, set_time, cur_time;
    assign set_time = {set_min10, set_min1, set_sec10, set_sec1};
    assign cur_time = {cur_min10, cur_min1, cur_sec10, cur_sec1};
    
    // Start/Set Toggle (T F/F)
    reg start_set, alarm;
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            start_set = 0;
            alarm = 0;
        end
        else begin
            if(btn_start) start_set = ~start_set;
            else if(cur_time == 0 && start_set)begin
                start_set = 0;
                alarm = 1;
            end
            else if(btn_alarmoff) alarm = 0;
        end
    end
    
    // LED setting
    assign led_alarm = alarm;
    assign buzz = alarm;
    assign led_start = start_set;

    assign value = start_set ? cur_time : set_time;
    fnd_cntr fnd(.clk(clk), .reset_p(reset_p), .value(value), .com(com), .seg_7(seg_7)); 
endmodule

타이머의 외부적 버튼은 풀다운(Pull-Down) 저항 방식으로 구현하였다.

 

풀다운 저항 방식으로 구현을 하게 될 시, 스위치의 푸시 버튼을 누르지 않았을 때에는 OFF, 푸시 버튼을 눌렀을 때에는 ON 기능을 하게 된다. 풀다운 방식은 저항이 Ground 쪽에 위치한다는 특징을 지닌다.

 

Pull-Down 스위치

 

3V(주황색 선)은 저항과 신호선(흰색 선)과 반대에 위치하는 것을 확인할 수 있다.


타이머의 동작 영상은 아래와 같다.

 

Basys3의 스위치를 활용하여 타이머의 분과 초를 제어할 수 있으며, 타이머가 00분 00초가 되었을 시 부저와 LED가 작동하게 되며, 외부의 버튼을 누르게 될 시 부저와 알림이 꺼지는 것을 확인할 수 있다.

 

 

카운터 동작 영상

스톱워치

스톱워치를 구현할 코드는 아래와 같다.

 

스톱워치 모듈의 입출력은 아래와 같다.

 

기본적으로 리셋, 버튼입력, 7-segment 입력을 받고, Lap기능을 표현할 lap_start, led_lap 출력을 선언하였다. 

module stop_watch_ms_top(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7,
    output led_start, led_lap);

 

스톱워치의 시간을 표현할 분주 부분의 코드는 아래와 같다.

 

ms단위까지 표현을 해야 하므로 100 분주(usec 구현) 다음에 1000 분주를 하여 1ms 단위의 시간을 표현할 수 있도록 하였다. 10ms단위를 표현하기 위해 1000 분주 다음에 10 분주를 선언하였고, 초단위를 구현하기 위하여 1000 분주(msec)에 다시 1000 분주를 하여 초단위를 구현하였다.

// clock
    clock_div_100 usec_clk(.clk(clk_start), .reset_p(reset_start), .clk_div_100(clk_usec));
    clock_div_1000 msec_clk(.clk(clk_start), .reset_p(reset_start), .clk_source(clk_usec), .clk_div_1000(clk_msec));
    clock_div_10 cm_clk(.clk(clk_start), .reset_p(reset_start),.clk_source(clk_msec), .clk_div_10(clk_10msec));
    clock_div_1000 sec_clk(.clk(clk_start), .reset_p(reset_start), .clk_source(clk_msec), .clk_div_1000_nedge(clk_sec));

 

스톱워치의 버튼 동작을 구현할 코드는 아래와 같다.

 

총 3개의 버튼을 활용하며, 시작/정지 버튼, lap기능 버튼 그리고 clear기능을 갖춘 버튼을 선언하였다.

 // button Mode    
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_start));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_lap));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_clear));

 

스톱워치의 동작에 따라 LED를 제어하는 코드는 아래의 코드와 같다.

 

스톱워치가 Start/Stop 할 때마다 LED는 점등이 되며, led_lap은 lap의 동작에 따라 점등이 된다.

    // button/lap control
    T_flip_flop_p t_start(.clk(clk), .reset_p(reset_start), .t(btn_start), .q(start_stop));
    assign led_start = start_stop; // LED ON = START, LED OFF = STOP
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)lap = 0;
        else begin
            if(btn_lap) lap = ~lap;
            else if(btn_clear) lap = 0;
        end
    end    
    
    // Lap control
    assign led_lap = lap;

 

스톱워치를 구현할 코드의 전체적인 내용은 아래와 같다.

module stop_watch_ms_top(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7,
    output led_start, led_lap);
    
    reg lap;
    wire start_stop;
    wire clk_start;
    wire btn_start, btn_lap, btn_clear;
    wire clk_usec, clk_msec, clk_10msec, clk_sec;
    wire reset_start;
    
    assign clk_start = start_stop ? clk : 0;
    
    // clock
    clock_div_100 usec_clk(.clk(clk_start), .reset_p(reset_start), .clk_div_100(clk_usec));
    clock_div_1000 msec_clk(.clk(clk_start), .reset_p(reset_start), .clk_source(clk_usec), .clk_div_1000(clk_msec));
    clock_div_10 cm_clk(.clk(clk_start), .reset_p(reset_start),.clk_source(clk_msec), .clk_div_10(clk_10msec));
    clock_div_1000 sec_clk(.clk(clk_start), .reset_p(reset_start), .clk_source(clk_msec), .clk_div_1000_nedge(clk_sec));
    
    // button Mode    
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_start));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_lap));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_clear));
    
    assign reset_start = reset_p | btn_clear;
    
    // button/lap control
    T_flip_flop_p t_start(.clk(clk), .reset_p(reset_start), .t(btn_start), .q(start_stop));
    assign led_start = start_stop; // LED ON = START, LED OFF = STOP
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)lap = 0;
        else begin
            if(btn_lap) lap = ~lap;
            else if(btn_clear) lap = 0;
        end
    end    
    
    // Lap control
    assign led_lap = lap;
            
    wire [3:0] sec10, sec1, mil10, mil1;
    counter_bcd_100_clear counter_mil(.clk(clk), .reset_p(reset_p), .clk_time(clk_10msec), .clear(btn_clear), .bcd1(mil1), .bcd10(mil10));
    counter_bcd_60_clear counter_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .clear(btn_clear) , .bcd1(sec1), .bcd10(sec10));
    
    // Time Save Register
    reg [15:0] lap_time;
    wire [15:0] cur_time;
    assign cur_time = {sec10, sec1, mil10, mil1};
    always @(posedge clk or posedge reset_p)begin
        if(reset_p) lap_time = 0;
        else if(btn_lap) lap_time = cur_time;
        else if(btn_clear) lap_time = 0;
    end
        
    // Fnd controler
    wire [15:0] value;
    assign value = lap ? lap_time : cur_time;
    fnd_cntr fnd(.clk(clk), .reset_p(reset_p), .value(value), .com(com), .seg_7(seg_7));
    
endmodule

스톱워치를 동작시키면 아래의 영상처럼 동작하는 것을 확인할 수 있다.

 

Start/Stop을 할 때마다 LED가 점등이 되는 것을 확인할 수 있으며, Lap 제어 버튼을 눌렀을 시 LED 점등과 동시에 잠시 시간이 멈추게 되며, 다시 Lap을 누르게 되면 안 누른 동안의 시간이 흐르는 것을 확인할 수 있다. 마지막으로 Clear 버튼을 누르면 스톱워치의 시간이 초기화가 되는 것을 확인할 수 있다.

 

 

스톱워치 동영상

 


시계

일반적인 시계를 동작시킬 코드는 아래와 같다.

 

시계의 버튼 기능은 아래와 같다.

 

총 3개의 버튼이 존재하며, 분과 초를 설정할수 있는 시간 조절 버튼, 모드 버튼이 존재한다.

 // button Mode    
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_mode));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_sec));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_min));

 

시계 동작을 구현할 전체적인 코드 내용은 아래와 같다.

module loadable_watch_top(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7);
    
    // wire
    wire btn_mode;
    wire btn_sec;
    wire btn_min;
    wire set_watch;
    wire inc_sec, inc_min; // inc = increment
    wire clk_usec, clk_msec, clk_sec, clk_min;
    
    // button Mode    
    button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_mode));
    button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_sec));
    button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_min));
    
    // button control
    T_flip_flop_p t_mode(.clk(clk), .reset_p(reset_p), .t(btn_mode), .q(set_watch));
    
    wire clk_source_nedge;
    edge_detector_n ed_source(.clk(clk), .reset_p(reset_p), .cp(set_watch), .p_edge(set_load_en), .n_edge(watch_load_en));
    
    assign inc_sec = set_watch ? btn_sec : clk_sec; 
    assign inc_min = set_watch ? btn_min : clk_min;
    
    // Time Setting
    clock_div_100 usec_clk(.clk(clk), .reset_p(reset_p), .clk_div_100(clk_usec));
    clock_div_1000 msec_clk(.clk(clk), .reset_p(reset_p), .clk_source(clk_usec), .clk_div_1000(clk_msec));
    clock_div_1000 sec_clk(.clk(clk), .reset_p(reset_p), .clk_source(clk_msec), .clk_div_1000_nedge(clk_sec));
    clock_div_60 min_clk(.clk(clk), .reset_p(reset_p), .clk_source(inc_sec), .clk_div_60_nedge(clk_min));
      
    loadable_counter_bcd_60 sec_watch(
        .clk(clk), .reset_p(reset_p),
        .clk_time(clk_sec),
        .load_enable(watch_load_en),
        .load_bcd1(set_sec1), .load_bcd10(set_sec10),
        .bcd1(watch_sec1), .bcd10(watch_sec10));
         
    loadable_counter_bcd_60 min_watch(
        .clk(clk), .reset_p(reset_p),
        .clk_time(clk_min),
        .load_enable(watch_load_en),
        .load_bcd1(set_min1), .load_bcd10(set_min10),
        .bcd1(watch_min1), .bcd10(watch_min10)); 
        
    loadable_counter_bcd_60 sec_set(
        .clk(clk), .reset_p(reset_p),
        .clk_time(btn_sec),
        .load_enable(set_load_en),
        .load_bcd1(watch_sec1), .load_bcd10(watch_sec10),
        .bcd1(set_sec1), .bcd10(set_sec10));
         
    loadable_counter_bcd_60 min_set(
        .clk(clk), .reset_p(reset_p),
        .clk_time(btn_min),
        .load_enable(set_load_en),
        .load_bcd1(watch_min1), .load_bcd10(watch_min10),
        .bcd1(set_min1), .bcd10(set_min10));
              
    wire [15:0] value, watch_value, set_value;              
    wire [3:0] watch_sec1, watch_sec10, watch_min1, watch_min10;
    wire [3:0] set_sec1, set_sec10, set_min1, set_min10;    
    assign watch_value = {watch_min10, watch_min1, watch_sec10, watch_sec1};
    assign set_value = {set_min10, set_min1, set_sec10, set_sec1};
    assign value = set_watch ? set_value : watch_value;   
    
    fnd_cntr fnd(.clk(clk), .reset_p(reset_p), .value(value), .com(com), .seg_7(seg_7));
    
endmodule

시계를 동작시키면 아래의 영상과 같이 동작하는 것을 확인할 수 있다.

 

시계의 동작을 멈춘 후, 분과 초를 세팅할 수 있으며, 세팅된 결과에 따라 다시 시계가 작동하는 것을 확인할 수 있다.

 

 

시계 동작 영상

멀티 기능 시계

위에 언급되었던 타이머, 스톱워치, 시계를 모두 합쳐 멀티 기능 시계를 구현하려고 한다.

 

멀티 기능 시계의 코드는 아래와 같다.

 

우선 아래의 코드와 같이 각각의 시계를 구동시킬 wire들을 따로 선언하였다.

 

각각의 wire들은 모드가 바뀔 때마다 모드에 알맞은 동작을 전달한다.

    // wire 선언
    wire [3:0] com_watch, com_stopwatch, com_timer;
    wire [7:0] seg_7_watch, seg_7_stopwatch, seg_7_timer;
    wire led_start_timer, led_start_stopwatch, led_lap_stopwatch, led_alarm_timer, alarm_off_timer;
    wire buzz_timer;
    reg [3:0] watch_btn, stop_watch_btn, cooktimer_btn;

 

 

아래의 코드는 멀티 시계에서 모드 변경 버튼 동작을 감지하는 동작을 수행할 코드이다.

// 모드 변경 버튼 감지
   	wire btn_off;
   	button_cntr btn_m(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_mode)); //버튼 모드 컨트롤러

 

다음은 구현하였던 타이머, 스톱워치, 시계를 불러오는 인스턴스화 코드이다.

 

각각의 모듈을 선언한 뒤, 따로 선언되었던 wire들을 각 모듈의 동작에 맞게 선언하였다.

    //  TIMER
    cook_timer_for_multi_top timer_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(cooktimer_btn),
        .alarm_off(alarm_off), // 외부 버튼으로 타이머 알람 제어
        .com(com_timer),
        .seg_7(seg_7_timer),
        .led_alarm(led_alarm_timer),
        .led_start(led_start_timer),
        .buzz(buzz_timer)
    );
    
    // STOP_WATCH
    stop_watch_ms_top stopwatch_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(stop_watch_btn),
        .com(com_stopwatch),
        .seg_7(seg_7_stopwatch),
        .led_start(led_start_stopwatch),
        .led_lap(led_lap_stopwatch)
    );
    
    // WATCH
     loadable_watch_top watch_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(watch_btn),
        .com(com_watch),
        .seg_7(seg_7_watch)
    );

 

아래의 코드는 리셋 버튼이 눌릴 시 타이머 모드로 초기화 되며, 그 외의 경우에는 다음 단계의 모드로 이동하는 동작을 수행하는 코드이다.

    // State machine
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            state = S_TIMER; //리셋시 초기 상태를 타이머로 설정 
        end
        else begin
            state = next_state; // 다음 상태로 이동
        end
    end

 

아래의 코드는 state의 변경됨에 따라 어떤 모드로 동작이 될지 결정되는 코드이다.

 

처음 시작과, 리셋 버튼을 누를 시 타이머 모드로 변경되며, 타이머 - 스톱워치 - 시계 순서로 모드 버튼을 누를 시 변경된다.

    // 상태 결정 및 버튼 입력 처리
    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            next_state = S_TIMER;  // 초기 상태는 타이머로 설정
        end 
        else if (btn_mode) begin  // 버튼 눌림 감지 
            case (state)
                S_TIMER: next_state = S_STOPWATCH;
                S_STOPWATCH: next_state = S_WATCH;
                S_WATCH: next_state = S_TIMER;
                default: next_state = S_TIMER;
            endcase
        end 
        else begin
            next_state = state;  // 버튼이 눌리지 않은 경우 상태 유지
        end
    end

 

위의 코드들을 종합하여 멀티 기능 시계 코드를 구현하면 아래와 같은 코드가 만들어짐을 확인할 수 있다.

module multi_watch(
    input clk, reset_p,
    input [3:0] btn,
    input alarm_off,
    output reg [3:0] com,
    output reg [7:0] seg_7,
    output reg led_start, led_lap, led_alarm, buzz
    );
    
    // wire 선언
    wire [3:0] com_watch, com_stopwatch, com_timer;
    wire [7:0] seg_7_watch, seg_7_stopwatch, seg_7_timer;
    wire led_start_timer, led_start_stopwatch, led_lap_stopwatch, led_alarm_timer, alarm_off_timer;
    wire buzz_timer;
    reg [3:0] watch_btn, stop_watch_btn, cooktimer_btn;
    
    // 모드 변경 버튼 감지
   	wire btn_off;
   	button_cntr btn_m(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_mode)); //버튼 모드 컨트롤러
   
    //  TIMER
    cook_timer_for_multi_top timer_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(cooktimer_btn),
        .alarm_off(alarm_off), // 외부 버튼으로 타이머 알람 제어
        .com(com_timer),
        .seg_7(seg_7_timer),
        .led_alarm(led_alarm_timer),
        .led_start(led_start_timer),
        .buzz(buzz_timer)
    );
    
    // STOP_WATCH
    stop_watch_ms_top stopwatch_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(stop_watch_btn),
        .com(com_stopwatch),
        .seg_7(seg_7_stopwatch),
        .led_start(led_start_stopwatch),
        .led_lap(led_lap_stopwatch)
    );
    
    // WATCH
     loadable_watch_top watch_instance (
        .clk(clk),
        .reset_p(reset_p),
        .btn(watch_btn),
        .com(com_watch),
        .seg_7(seg_7_watch)
    );
    
    //  PARAMETER
    parameter S_TIMER = 3'b001;
    parameter S_STOPWATCH = 3'b010;
    parameter S_WATCH = 3'b100;
    
    reg [2:0] state, next_state; // 상태 변경
    
    // State machine
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)begin
            state = S_TIMER; //리셋시 초기 상태를 타이머로 설정 
        end
        else begin
            state = next_state; // 다음 상태로 이동
        end
    end
    
    // 상태 결정 및 버튼 입력 처리
    always @(posedge clk or posedge reset_p) begin
        if (reset_p) begin
            next_state = S_TIMER;  // 초기 상태는 타이머로 설정
        end 
        else if (btn_mode) begin  // 버튼 눌림 감지 
            case (state)
                S_TIMER: next_state = S_STOPWATCH;
                S_STOPWATCH: next_state = S_WATCH;
                S_WATCH: next_state = S_TIMER;
                default: next_state = S_TIMER;
            endcase
        end 
        else begin
            next_state = state;  // 버튼이 눌리지 않은 경우 상태 유지
        end
    end
    
   // 상태에 따라 모듈의 출력 선택
    always @(*) begin
        case (state)
            S_WATCH: begin
                com = com_watch;
                seg_7 = seg_7_watch;
                led_start = 1'b0; // START LED 초기화 
                led_lap = 1'b0; // LAP LED 초기화 
                led_alarm = led_alarm_timer; 
                buzz = buzz_timer; 
                watch_btn = btn;
                stop_watch_btn = 0;
                cooktimer_btn = 0;
            end
            S_STOPWATCH: begin
                com = com_stopwatch;
                seg_7 = seg_7_stopwatch;
                led_start = led_start_stopwatch;
                led_lap = led_lap_stopwatch;
                led_alarm = led_alarm_timer;
                buzz = buzz_timer;
                watch_btn = 0;
                stop_watch_btn = btn;
                cooktimer_btn = 0;
            end
            S_TIMER: begin
                com = com_timer;
                seg_7 = seg_7_timer;
                led_start = led_start;
                led_alarm = led_alarm_timer;
                buzz = buzz_timer;
                watch_btn = 0;
                stop_watch_btn = 0;
                cooktimer_btn = btn;
            end
            default: begin
                com = com_timer;
                seg_7 = seg_7_timer;
                led_start = led_start;
                led_alarm = led_alarm_timer;
                buzz = buzz_timer;
                watch_btn = 0;
                stop_watch_btn = 0;
                cooktimer_btn = btn;
            end
        endcase
    end 
endmodule

멀티 기능 시계 코드를 동작시키면 아래와 같은 물리적 동작이 수행되는 것을 확인할 수 있다.

멀티 기능 시계 동작 결과

 

728x90

'Language > Verilog' 카테고리의 다른 글

Vivado : RGB LED, DC motor  (0) 2024.08.01
Vivado : PWM 제어  (0) 2024.07.31
Vivado : 온도 습도 센서  (0) 2024.07.25
Vivado : 키패드  (0) 2024.07.25
Vivado : 초음파 센서  (0) 2024.07.25