__________

Designing the Future with Circuits

반도체 회로설계 취준기

자습시간/Verilog

Verilog 복습 프로젝트(2) - 스탑워치 설계

semicon_circuitdesigner 2025. 2. 12. 14:42

스탑워치를 표시할 7세그먼트 디스플레이 제어 모듈을 완성한 뒤 분, 초, 밀리초를 계산하여 세그먼트로 전송하는 스탑워치 모듈 설계를 진행했습니다.


Stopwatch 모듈 정의


Module Name: stopwatch
Inputs
  • rst
  • clk
  • [1:0] mode:스탑워치가 Mode 1에서만 값을 세그먼트로 보낼 때 사용
  • btn1: Start/Stop 버튼
  • btn0: Reset 버튼
Outputs
  • reg [13:0] value: 스탑워치를 통해 계산한 네자리 값을 출력
Registers
  • reg [3:0] sec0_1, sec0_01: 0.1초, 0.01초의 값을 저장하는 레지스터. 0~9까지의 숫자를 저장하므로 4비트 사용
  • reg [5:0] sec, min: 초, 분의 값을 저장하는 레지스터. 0~59까지의 숫자를 저장하므로 6비트 사용
  • reg [20:0] timeval: 매 clk마다 값을 증가시켜 1,250,000이 되면 0.01초 값 증가

Stopwatch

Logic


스탑워치 작동 시 start/stop 동작은 왼쪽 버튼(btn1)으로 전환되고, 오른쪽 버튼(btn0)을 누르면 동작이 멈추고 즉시 초기화하도록 설계했습니다. 이 동작을 FSM으로 구현하여 다음과 같이 설계했습니다.

 

1. IDLE

  • st 신호가 HIGH일 때 현재 상태를 IDLE로 변환
  • 레지스터 sec0_01, sec0_1, sec, min와 value를 모두 초기화
  • btn1이 눌렸을 경우에만 START상태로 이전

2. START

  • 매 clk마다 증가하는 timeval 변수를 검사하여 시간 측정: timeval이 1,250,000에 도달하면 시간은 1,250,000/125M = 0.01s
  • 0.01초마다 timeval을 초기화하며, sec0_01 값을 증가
  • sec0_01값을 검사하여 sec0_1 값 증가
  • sec0_1값을 검사하여 sec 값 증가
  • sec 값을 검사하여 min 값 증가
  • min이 0일 때(아직 1분이 지나지 않았을 때) 세그먼트로 전송하는 값 value를 초.밀리초로 구성
  • min이 1 이상일 때 value를 분.초로 구성
  • btn1이 눌리면 PAUSE 상태로 이전
  • btn0이 눌리면 IDLE 상태로 이전(초기화)

3. PAUSE

  • PAUSE상태에서는 어떠한 동작도 하지 않음(시간 증가 X)
  • btn1이 눌리면 다시 START 상태로 돌아가 기존의 값에서 계속 시간 측정
  • bnt0이 눌리면 IDLE 상태로 이전(초기화)

 

스탑워치 FSM

 

 

stopwatch.v

더보기
`timescale 1ns / 1ps

module stopwatch(
    input rst,
    input clk,
    input [1:0] mode,
    input btn1,
    input btn0,
    output reg [13:0] value
    );
    
    reg [3:0] sec0_1, sec0_01;
    reg [5:0]  sec, min;
    reg [20:0] timeval;
    
    //FSM: IDLE(0) -> START(1) <-> PAUSE(2) -> IDLE(0)
    localparam IDLE = 2'b00, START = 2'b01, PAUSE = 2'b10;
    reg [1:0] curr_state;
    
    always @(posedge clk) begin
        if(rst) begin
            sec0_01 <= 0; sec0_1 <= 0; sec <= 0; min <= 0;
            curr_state <= IDLE;
        end
        else begin
            if(mode == 1) begin
            case(curr_state)
                IDLE: begin    //IDLE
                    sec0_01 <= 0; sec0_1 <= 0; sec <= 0; min <= 0;
                    value <= 0;
                    if(btn1) curr_state <= START;
                    else        curr_state <= IDLE;
                end
                START: begin
                        if(timeval < 1250000)   timeval <= timeval+1;       //125_000_0 = 125_000_000/100 => 0.01s
                        else begin
                            timeval <= 0;
                            sec0_01 <= sec0_01+1;
                        end
                        if(sec0_01>9) begin                                                         //0.09 다음 clk에서 0.1초 증가, 0.00초로 초기화
                            sec0_01 <= 0;
                            sec0_1 <= sec0_1+1;
                            if(sec0_1 > 8) begin                                                    //0.9초가 지나면 1초 증가
                                sec0_1 <= 0;
                                sec <= sec+1;
                                if(sec > 58) begin                                                      //59초가 지나면 1분 증가
                                    sec <= 0;
                                    min <= min+1;
                                end
                            end
                        end
                        if(min)     value <= min*100+sec;                                   //1분이 넘어서 min>0이면 분.초 표시
                        else          value <= sec*100+sec0_1*10+sec0_01;   //1분이 되지 않아 min == 0이면 초.밀리초 표시
                        if(btn1) curr_state <= PAUSE;
                        else if(btn0) curr_state <= IDLE;
                end
                2: begin            //btn1을 누르면 일시정지, 이 때 btn0을 누르면 초기화, 다시 btn1을 누르면 시간 카운트
                    if(btn1) curr_state <= START;                           
                    else if(btn0) curr_state <= IDLE;
                end
            endcase
            end //if(mode == 1) end
        end //if(rst) else end
    end //always end
endmodule