__________

Designing the Future with Circuits

반도체 회로설계 취준기

자습시간/Verilog

Verilog 복습 프로젝트(1) - 7세그먼트 제어

semicon_circuitdesigner 2025. 2. 11. 17:44

스탑워치를 설계하기에 앞서, 숫자를 표시하기 위한 네자리 7세그먼트 디스플레이를 제어하기 위한 코드를 작성했습니다.

이번에 사용한 디스플레이는 이전에 반도체 설계교육 중 임베디드 시스템 설계 과정에서 사용한 디스플레이를 사용했습니다.

 

하만(Harman) 세미콘 아카데미 11일차 - SW 구조설계( 데이터 입출력, 버튼 LED 점멸, 7세그먼트 출력 )

[2024.03.21.목] 인천인력개발원 하만 세미콘 아카데미임베디드 시스템을 위한 SW 구조설계디지털 데이터 입출력1. 디지털 데이터 출력 PORT 레지스터 (출력 레지스터) 포트: 8개의 핀을 하나로 묶어

semicon-circuit.tistory.com

 

하만(Harman) 세미콘 아카데미 12일차 - SW 구조설계( 7세그먼트 - 16진수 출력, 스톱워치 구현)

[2024.03.22.금] 인천인력개발원 하만 세미콘 아카데미임베디드 시스템을 위한 SW 구조설계실습 1: 7세그먼트로 0~F까지 16진수로 표시 코드 수정 #define F_CPU 16000000L//Board CLK 정보(16MHz) #include #include int

semicon-circuit.tistory.com


7세그먼트 제어 모듈 정의


Module Name: segment_display
Inputs
  • rst
  • clk
  • [13:0] bcds: 최대 9999까지 값을 수신
  • [1:0] mode :스탑워치는 Mode1에서 동작하는데, 이 때 중앙에 "."을 통해 분/초/0.01초를 구분하기 위해 segments값 제어
Outputs
  • reg [7:0] segments: 세그먼트를 제어하기 위한 레지스터.
    segments[6]~ segments[0] 은 Anode A~Anode G, segments[7]은 DP 제어
  • reg [3:0] com_dig: 출력할 위치를 low로 선택하여 출력 자리 제어
Registers
  • reg [3:0] bcd1000, bcd100, bcd10, bcd1:  자리별 BCD 저장 변수
  • reg [7:0] seg1000, seg100, seg10, seg1:  자리별 세그먼트 출력 변수
  • reg [19:0] clkcnt: 매 clock마다 값이 증가하여 clkcnt의 값을 확인하여 segment 제어 동작
  • curr_state, next_state: 현재 상태와 다음 상태 업데이트를 통해 FSM 동작

Logic


Segment 디스플레이 핀 설정

 

상단에 첨부한 게시물을 참고하여 출력할 자리를 선택할 때에는 해당 Common Digit을 0으로 설정하고, 1ms마다 자리를 바꿔가며 출력할 위치를 정하도록 설계했습니다. 자릿수를 변경할 때 0.1ms씩 모든 digit을 1로 설정하여 OFF시켰으며, 각 자리에 할당된 변수가 다른 자릿수로 입력되는 것을 방지했습니다.

segment 제어 과정

 

각 자릿수에 숫자를 할당하는 작업은 FSM을 통해 진행했는데, 두 가지 상태만 사용하여 다음과 같이 설계했습니다.

1. input으로 들어온 14비트의 숫자를 각 4비트의 자리별 BCD 저장 변수인 bcd1, bcd10, bcd100, bcd1000에 저장

2. 이 값을 기반으로 각 자리에 출력할 값을 seg1, seg10, seg100, seg1000 변수에 저장

 

이렇게 저장된 값은 위에서 설명한 com_dig가 순환됨에 따라 segment로 전송됩니다.

 

 

segment_display.v

더보기
`timescale 1ns / 1ps

/*=========================================
                            [Module Declaration]
=========================================*/
module segment_display  (
    input rst,                  // 리셋 버튼
    input clk,                  // 100 MHz 시스템 클럭
    input [13:0] bcds,         //값 입력 변수(최대 9999까지)
    input [1:0] mode,
    output reg [7:0] segments,  // 세그먼트 제어 (A-G), DP: DP가 segment[7]
    output reg [3:0] com_dig     // 출력 자리  제어
);

/*=========================================
                            [Register Declaration]
=========================================*/
reg [3:0] bcd1000, bcd100, bcd10, bcd1;       // 자리별 BCD 저장 변수
reg [7:0] seg1000, seg100, seg10, seg1;           // 자리별 세그먼트 출력 변수
reg curr_state=1'b0, next_state = 1'b0;

initial com_dig = 4'b1111;  //common anode
reg [19:0] clkcnt;

localparam      CLK_FREQ = 125_000_000;
localparam      ONE_MS = CLK_FREQ / 1000;
localparam      O_1_MS = CLK_FREQ / 10000;   //0.1ms


/*=========================================
                            [Behavioral Logic]
=========================================*/
always@(posedge clk) begin
    if(clkcnt < 550000) begin
        clkcnt <= clkcnt + 1;

        if(clkcnt < ONE_MS) begin  // seg1000 출력 (1ms)
            segments <= seg1000;
            com_dig <= 4'b1110;
        end
        else if(clkcnt < ONE_MS+O_1_MS) begin  // 자리 전환 전 OFF (100µs)
            segments <= 8'b00000000;
            com_dig <= 4'b1111;
        end
        else if(clkcnt < 2*ONE_MS+O_1_MS) begin  // seg100 출력 (1ms)
            segments = seg100;
            com_dig <= 4'b1101;
            if(mode == 1) segments <= segments + 8'b1000_0000;
        end
        else if(clkcnt < 2*ONE_MS+2*O_1_MS) begin  // 자리 전환 전 OFF (100µs)
            segments <= 8'b00000000;
            com_dig <= 4'b1111;
        end
        else if(clkcnt < 3*ONE_MS+2*O_1_MS) begin  // seg10 출력 (1ms)
            segments <= seg10;
            com_dig <= 4'b1011;
        end
        else if(clkcnt < 3*ONE_MS+3*O_1_MS) begin  // 자리 전환 전 OFF (100µs)
            segments <= 8'b00000000;
            com_dig <= 4'b1111;
        end
        else if(clkcnt < 4*ONE_MS+3*O_1_MS) begin  // seg1 출력 (1ms)
            segments <= seg1;
            com_dig <= 4'b0111;
        end
        else if(clkcnt < 4*ONE_MS+4*O_1_MS) begin  // 자리 전환 전 OFF (100µs)
            segments <= 8'b00000000;
            com_dig <= 4'b1111;
        end
        else clkcnt <= 0;
    end
    else begin
        clkcnt <= 0;
    end
end    

//FSM: save bcds to bcd1000~bcd1 => convert bcds to segment value => print segment as com_dig changes
always @(posedge clk) curr_state <= next_state;

always @(posedge clk) begin
    case(curr_state)
        1'b0: begin
            bcd1000 <= (bcds / 1000) % 10;
            bcd100 <= (bcds / 100) % 10;
            bcd10 <= (bcds / 10) % 10;
            bcd1 <= (bcds % 10);
            if(bcd1000*1000 + bcd100*100 + bcd10*10 + bcd1 == bcds) next_state <= 1'b1;
            else next_state <= 1'b0;
        end
        //convert bcd to seg value
        1'b1: begin
                case(bcd1000)
                    4'h0: seg1000 <= 8'b00111111; // 0
                    4'h1: seg1000 <= 8'b00000110; // 1
                    4'h2: seg1000 <= 8'b01011011; // 2
                    4'h3: seg1000 <= 8'b01001111; // 3
                    4'h4: seg1000 <= 8'b01100110; // 4
                    4'h5: seg1000 <= 8'b01101101; // 5
                    4'h6: seg1000 <= 8'b01111101; // 6
                    4'h7: seg1000 <= 8'b00000111; // 7
                    4'h8: seg1000 <= 8'b01111111; // 8
                    4'h9: seg1000 <= 8'b01101111; // 9
                    4'hA: seg1000 <= 8'b01110111; // A
                    4'hB:seg1000 <= 8'b01111111; // B
                    4'hC: seg1000 <= 8'b00111001; // C
                    4'hD: seg1000 <= 8'b00111111; // D
                    4'hE: seg1000 <= 8'b01111001; // E
                    4'hF: seg1000 <= 8'b01110001; // F
                    default: seg1000 <= 8'b01000000; // -
                endcase
                case(bcd100)
                    4'h0: seg100 <= 8'b00111111; // 0
                    4'h1: seg100 <= 8'b00000110; // 1
                    4'h2: seg100 <= 8'b01011011; // 2
                    4'h3: seg100 <= 8'b01001111; // 3
                    4'h4: seg100 <= 8'b01100110; // 4
                    4'h5: seg100 <= 8'b01101101; // 5
                    4'h6: seg100 <= 8'b01111101; // 6
                    4'h7: seg100 <= 8'b00000111; // 7
                    4'h8: seg100 <= 8'b01111111; // 8
                    4'h9: seg100 <= 8'b01101111; // 9
                    4'hA: seg100 <= 8'b01110111; // A
                    4'hB:seg100 <= 8'b01111111; // B
                    4'hC: seg100 <= 8'b00111001; // C
                    4'hD: seg100 <= 8'b00111111; // D
                    4'hE: seg100 <= 8'b01111001; // E
                    4'hF: seg100 <= 8'b01110001; // F
                    default: seg100 <= 8'b01000000; // -
                endcase
                case(bcd10)
                    4'h0: seg10 <= 8'b00111111; // 0
                    4'h1: seg10 <= 8'b00000110; // 1
                    4'h2: seg10 <= 8'b01011011; // 2
                    4'h3: seg10 <= 8'b01001111; // 3
                    4'h4: seg10 <= 8'b01100110; // 4
                    4'h5: seg10 <= 8'b01101101; // 5
                    4'h6: seg10 <= 8'b01111101; // 6
                    4'h7: seg10 <= 8'b00000111; // 7
                    4'h8: seg10 <= 8'b01111111; // 8
                    4'h9: seg10 <= 8'b01101111; // 9
                    4'hA: seg10 <= 8'b01110111; // A
                    4'hB:seg10 <= 8'b01111111; // B
                    4'hC: seg10 <= 8'b00111001; // C
                    4'hD: seg10 <= 8'b00111111; // D
                    4'hE: seg10 <= 8'b01111001; // E
                    4'hF: seg10 <= 8'b01110001; // F
                    default: seg10 <= 8'b01000000; // -
                endcase
                case(bcd1)
                    4'h0: seg1 <= 8'b00111111; // 0
                    4'h1: seg1 <= 8'b00000110; // 1
                    4'h2: seg1 <= 8'b01011011; // 2
                    4'h3: seg1 <= 8'b01001111; // 3
                    4'h4: seg1 <= 8'b01100110; // 4
                    4'h5: seg1 <= 8'b01101101; // 5
                    4'h6: seg1 <= 8'b01111101; // 6
                    4'h7: seg1 <= 8'b00000111; // 7
                    4'h8: seg1 <= 8'b01111111; // 8
                    4'h9: seg1 <= 8'b01101111; // 9
                    4'hA: seg1 <= 8'b01110111; // A
                    4'hB:seg1 <= 8'b01111111; // B
                    4'hC: seg1 <= 8'b00111001; // C
                    4'hD: seg1 <= 8'b00111111; // D
                    4'hE: seg1 <= 8'b01111001; // E
                    4'hF: seg1 <= 8'b01110001; // F
                    default: seg1 <= 8'b01000000; // -
                endcase
                next_state <= 1'b0;
            end
        endcase //curr_state case end
end

endmodule

동작 테스트


동작을 테스트하기 위해 bcds에 0123값을 임의로 할당한 뒤 출력해보았습니다.

임의로 입력한 값이 정상 출력