스탑워치를 설계하기에 앞서, 숫자를 표시하기 위한 네자리 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
상단에 첨부한 게시물을 참고하여 출력할 자리를 선택할 때에는 해당 Common Digit을 0으로 설정하고, 1ms마다 자리를 바꿔가며 출력할 위치를 정하도록 설계했습니다. 자릿수를 변경할 때 0.1ms씩 모든 digit을 1로 설정하여 OFF시켰으며, 각 자리에 할당된 변수가 다른 자릿수로 입력되는 것을 방지했습니다.
각 자릿수에 숫자를 할당하는 작업은 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값을 임의로 할당한 뒤 출력해보았습니다.
'자습시간 > Verilog' 카테고리의 다른 글
Verilog 복습 프로젝트(3) - Decoder 설계 [Pmod KYPD 이용] (0) | 2025.02.12 |
---|---|
Verilog 복습 프로젝트(2) - 스탑워치 설계 (0) | 2025.02.12 |
Verilog 복습 프로젝트 - 스탑워치 / 계산기 / 타이머 / Pmod OLED (0) | 2025.02.11 |
UART(Universal Asynchronous Receiver/Transmitter) (1) | 2024.07.30 |