순차 회로 설계 및 검증 Sun, Hye-Seung
8비트 배럴 시프터(Barrel Shifter) 왼쪽으로 순환이동(cyclic shift) 동작을 수행하는 8비트 배럴 시프터 active-high 비동기 리셋 load=1이면, 8비트의 입력 data_in[7:0]이 레지스터에 병렬로 입력 load=0이면, 시프팅 동작을 수행 1 data_in[7:0] data_out[7:0] 8비트 배럴 시프터
8비트 배럴 시프터(Barrel Shifter) module barrel_shifter (clk, button_clk, rst, load, data_in, data_out); input clk, rst, load, button_clk; input [7:0] data_in; output [7:0] data_out; reg [7:0] data_tmp; reg mclk; assign pout = data_tmp; endmodule 소스코드 Ex_16_1_2 //블록-①:버튼 스위치 클록 입력의 채터링을 제거하기 위한 플립플롭 always @(posedge clk) mclk <= button_clk; //블록-②:배럴 시프터 모델링 always @(posedge mclk or posedge rst) begin * Active-high 비동기 리셋 동작과 시프트 레지스터 동작을 모델링 * if(load) 조건문에 의해 ▪ load=1인 경우, data_in을 레지스터에 병렬입력 ▪ load=0인 경우, 결합 연산자 { }를 사용하여 cyclic 왼쪽 시프팅 end
8비트 배럴 시프터(Barrel Shifter) 기능 검증 테스트벤치 작성 시뮬레이션 동작 확인 실습 회로 : 그림 16.6 Pin Table : 표 16.4 barrel_shifter data_out[7:0] LED Array data_in[7:0] BUS SW 1 1 2 3 4 5 6 7 8 button_clk load rst C D clk [100 Hz]
8비트 링 계수기(Ring Counter) 8비트 링 계수기의 상태천이도 8비트 링 계수기 clk rst DFF Q D 1000_0000 0000_0001 0000_0010 0000_1000 0000_0100 0001_0000 0010_0000 0100_0000 0000_0000 8비트 링 계수기의 상태천이도 clk rst DFF Q D cnt[7] cnt[2] cnt[1] cnt[0] 8비트 링 계수기
8비트 링 계수기(Ring Counter) 링 계수기 (Ring Counter) 하나의 1이 순환하며 이동하는 계수기 rst=0일 때, 링 계수기로 동작 rst=1 또는 레지스터의 값이 0000_0000일 때, 초기상태 0000_0001로 복귀 active-high 비동기 리셋 코딩 시프트 연산자 << 를 사용하는 방법 for 반복문을 사용하는 방법 결합 연산자 { } 를 사용하는 방법
8비트 링 계수기(Ring Counter) 소스코드 16_2 module ring_counter (clk, rst, cnt); input clk, rst; output [7:0] cnt; reg [7:0] cnt; always @(posedge clk or posedge rst) begin if (rst) cnt <= 1; else begin if ((cnt == 0) || (cnt == 128)) else cnt <= cnt << 1; end endmodule 소스코드 16_2
8비트 링 계수기(Ring Counter) 소스코드 16_2 module ring_counter_for (clk, rst, cnt); input clk, rst; output [7:0] cnt; reg [7:0] cnt; integer i; always @(posedge clk or posedge rst) begin end endmodule 소스코드 16_2 * for 반복문을 사용하여 코드를 완성한다. module ring_counter_conop (clk, rst, cnt); input clk, rst; output [7:0] cnt; reg [7:0] cnt; always @(posedge clk or posedge rst) begin end endmodule * 결합 연산자 { }를 사용하여 코드를 완성한다.
8비트 링 계수기(Ring Counter) 시뮬레이션 결과
8비트 링 계수기(Ring Counter) ring_counter 동작 확인 LED Array clk (10 Hz) cnt rst LED Array clk (10 Hz)
좌/우 시프팅 기능을 갖는 8비트 링 계수기 좌/우 시프팅 기능을 갖는 링 계수기를 다음의 방법으로 모델링 시프트 연산자 << 와 >>를 사용하는 방법 for 반복문을 사용하는 방법 결합 연산자 { } 를 사용하는 방법 표 16.6 링 계수기의 동작 모드 rst mode cnt 동 작 0000 0000, 0000 0001 1000 0000으로 복귀 - 오른쪽으로 시프팅 1 1000 0000 0000 0001로 복귀 왼쪽으로 시프팅 0000 0001으로 초기화
좌/우 시프팅 기능을 갖는 8비트 링 계수기 소스코드 Ex_16_2_1 module ring_counter2_sop (clk, rst, mode, cnt); input clk, rst, mode; output [7:0] cnt; reg [7:0] cnt; endmodule 소스코드 Ex_16_2_1 *코드 16.7과 유사한 구조를 가지며, *rst=0인 정상동작 모드에서 if(mode) 조건문에 의해 ▪ mode=1인 경우; ∙ cnt=0 또는 cnt=128이면, 초기상태(0000_0001)로 복귀 ∙ 왼쪽 시프트 연산자 <<를 사용하여 시프팅 동작을 구현 ▪ mode=0인 경우; ∙ cnt=0 또는 cnt=1이면, 초기상태(1000_0000)로 복귀 ∙ 오른쪽 시프트 연산자 >>를 사용하여 시프팅 동작을 구현
좌/우 시프팅 기능을 갖는 8비트 링 계수기 소스코드 Ex_16_2_1 module ring_counter2_for (clk, rst, mode, cnt); input clk, rst, mode; output [7:0] cnt; reg [7:0] cnt; integer i; endmodule 소스코드 Ex_16_2_1 ∙ 코드 16.11과 유사한 구조를 가지며 ∙ for 반복문을 사용하여 왼쪽 시프팅과 오른쪽 시프팅 동작을 구현 module ring_counter2_conop (clk, rst, mode, cnt); input clk, rst, mode; output [7:0] cnt; reg [7:0] cnt; endmodule ∙ 코드 16.11과 유사한 구조를 가지며 ∙ 결합 연산자를 사용하여 왼쪽 시프팅과 오른쪽 시프팅 동작을 구현
좌/우 시프팅 기능을 갖는 8비트 링 계수기 ring_counter2 기능 검증 동작 확인 테스트벤치 작성 시뮬레이션 cnt rst LED Array clk (10 Hz) mode
8비트 증가 계수기 8비트(256진) 증가 계수기(up counter) 0 → 1 → 2 → . . . → 255 → 0으로 계수 Active-high 비동기 리셋 1111_1111 0000_0000 0000_0001 0000_0011 0000_0010 0000_0100 1111_1110 8비트 증가 계수기의 상태 천이도
8비트 증가 계수기 소스코드 Ex_16_2_2 module counter_up (clk, rst, cnt); input clk, rst; output [7:0] cnt; reg [7:0] cnt; endmodule ▪ rst=1인 경우 cnt를 0으로 초기화 ▪ rst=0인 경우, cnt가 1씩 증가되도록 설계
8비트 증가 계수기 counter_up 기능 검증 동작 확인 테스트벤치 작성 시뮬레이션 LED Array clk (10 Hz) cnt rst LED Array clk (10 Hz)
8비트 증가/감소 계수기 8비트(256진) 증가/감수 계수기 mode=0 ; +1씩 증가하는 증가 계수기(up counter)로 동작 mode=1 ; -1씩 감소하는 감소 계수기(down counter)로 동작 Active-high 비동기 리셋 1111_1111 0000_0000 0000_0001 0000_0011 0000_0010 0000_0100 1111_1110 counting up counting down 증가/감소 계수기의 동작 rst mode 동작 +1씩 증가 1 -1씩 감소 - 0000 0000으로 초기화 증가/감소 계수기의 상태천이도
8비트 증가/감소 계수기 소스코드 Ex_16_2_3 module counter_ud (clk, rst, mode, cnt); endmodule ▪ 코드 16.14와 유사한 구조를 가지며, ▪ rst=0인 경우; ∙ mode=0이면, cnt가 +1씩 증가되도록 설계 ∙ mode=1이면, cnt가 -1씩 감소되도록 설계
8비트 증가/감소 계수기 ring_counter2 기능 검증 동작 확인 테스트벤치 작성 시뮬레이션 LED Array cnt rst LED Array clk (10 Hz) mode
BCD 계수기 BCD (Binary Coded Decimal) 계수기 0 → 1 → 2 → . . . → 9 → 0 → 1을 계수 함수 bcd_to_seg를 이용하여 7-segment에 표시될 수 있는 형태로 변환 Active-high 비동기 리셋 1000 0000 0010 0100 0011 0101 0110 0111 1001 0001 bcd_counter bcd_to_seg (function) clk seg_data[7:0] rst seg_com[7:0] cnt[3:0] BCD 계수기 및 7-seg 표시회로 BCD 계수기의 상태천이도
BCD 계수기 소스코드 Ex_16_2_4 module bcd_counter (clk, rst, cnt); input clk, rst; output [3:0] cnt; reg [3:0] cnt; endmodule 소스코드 Ex_16_2_4 ▪ rst=1인 경우, cnt를 0으로 초기화 ▪ rst=0인 경우; ∙ cnt=9이면 cnt=0으로 초기화 ∙ cnt가 9가 아닌 경우, cnt를 1씩 증가시키는 증가 계수기
BCD 계수기 module bcd_counter_segdis (clk, rst, seg_com, seg_data); input clk, rst; output [7:0] seg_com, seg_data; wire [3:0] cnt; assign seg_com = 8'b0111_1111; endmodule ▪ 코드 16.16에서 설계된 모듈 bcd_counter를 인스턴스 ▪ 15.6.3에서 설계된 함수 bcd_to_seg를 호출하여 seg_data로 변환 소스코드 Ex_16_2_4
BCD 계수기 기능 검증 동작 확인 bcd_counter_segdis 테스트벤치 작성 시뮬레이션 7-segment Array seg_data[7:0] 7-segment Array seg_com[7:0] clk (10 Hz) rst
1/10 주파수 분주기 1/10 주파수 분주기 10Hz의 마스터 클록을 1/10로 분주하여 1Hz의 분주 클록을 생성 Active-high 비동기 리셋 frq_div10 mclk (10 Hz) rst clk_1hz 1/10 주파수 분주기
1/10 주파수 분주기 module frq_div10 (mclk, rst, mclk_out, clk_1hz); input rst, mclk; output clk_1hz, mclk_out; reg [2:0] cnt; reg clk_1hz; assign mclk_out = mclk; always @(posedge mclk or posedge rst) begin if (rst) begin cnt <= 0; clk_1hz <= 0; end else begin if (cnt == 4) begin cnt <=0; clk_1hz <= ~clk_1hz; else cnt <= cnt + 1; endmodule 소스코드 16_3
1/10 주파수 분주기 시뮬레이션 결과
1/10 주파수 분주기 frq_div10 기능 검증 동작 확인 테스트벤치 작성 시뮬레이션 LED Array clk_1hz rst LED Array clk (10 Hz) mclk
LED Shifter with 8 modes 8가지 동작모드를 갖는 LED 시프터 0 → 1 → 2 → . . . → 9 → 0 → 1을 계수 함수 bcd_to_seg를 이용하여 7-segment에 표시될 수 있는 형태로 변환 Active-high 비동기 리셋 LED 시프터의 동작 모드 mode[3:0] 동작 모드 클록 주파수 x000 mclk 100Hz x001 clk1 10Hz x010 clk2 1Hz x100 clk3 0.5Hz 0xxx 좌→우 시프팅 0.5~100Hz 1xxx 우→좌 시프팅
LED Shifter with 8 modes 소스코드 Ex_16_3_1 module led_shifter_8modes (mclk, rst, mode, led_data); input mclk, rst; input [3:0] mode; output[7:0] led_data; reg [7:0] led_data; reg [2:0] cnt1, cnt2; reg cnt3; reg clk1, clk2, clk3, clk_shift; 소스코드 Ex_16_3_1 //블록-①:1/10 Frequency Divider always @(posedge mclk or posedge rst) begin ▪ 100Hz의 mclk를 1/10로 분주하여 10Hz의 clk1을 생성(50% duty cycle) end //블록-②:1/10 Frequency Divider always @(posedge clk1 or posedge rst) begin ▪ 10Hz의 clk1을 1/10로 분주하여 1Hz의 clk2를 생성(50% duty cycle) end
LED Shifter with 8 modes endmodule //블록-③:1/2 Frequency Divider always @(posedge clk2 or posedge rst) begin ▪ 1Hz의 clk2를 1/2로 분주하여 0.5Hz의 clk3를 생성(50% duty cycle) end //블록-④:mclk, clk1, clk2, clk3 중 하나를 선택하여 clk_shift를 생성 always @(mode or mclk or clk1 or clk2 or clk3) begin ▪ case(mode[2:0])을 사용하여 모델링 end //블록-⑤:mode[3]에 따른 LED 불빛의 좌ㆍ우 시프팅을 구현 always @(posedge clk_shift or posedge rst) begin ▪ 블록-④에서 생성된 clk_shift를 받아 LED를 왼쪽 또는 오른쪽으로 시프팅시켜 led_data[7:0]을 생성 end
LED Shifter with 8 modes led_shifter_8modes 기능 검증 동작 확인 C D E 테스트벤치 작성 시뮬레이션 동작 확인 led_shifter_8modes led_data rst LED Array mclk (100 Hz) mode[3:0] C D E
Finite State Machine (FSM) 연속된 0 또는 1 입력 검출기 입력 din_bit에 ‘00’ 또는 ‘11’의 패턴이 발견되면 1을 출력하고, 그 이외의 경우에는 0을 출력 1 din_bit : dout_bit : start rd1_once rd0_twice 1 rd1_twice rd0_once reset
연속된 0 또는 1 입력 검출기 module seq_det_moore (clk, rst, button_clk, din_bit, dout_bit); input clk, rst, button_clk, din_bit; output dout_bit; reg mclk; reg [2:0] state_reg, next_state; 소스코드 16_4 //블록-①:FSM의 상태를 parameter로 선언 parameter start = 3'b000; parameter rd0_once = 3'b001; parameter rd1_once = 3'b010; parameter rd0_twice = 3'b011; parameter rd1_twice = 3'b100; //블록-②:버튼 스위치 안정화(채터링 제거) 회로 always @(posedge clk) mclk <= button_clk;
연속된 0 또는 1 입력 검출기 소스코드 16_4 //블록-③:FSM의 상태 결정 always @(state_reg or din_bit) begin case (state_reg) start :if (din_bit == 0) next_state <= rd0_once; else if (din_bit == 1) next_state <= rd1_once; else next_state <= start; rd0_once :if (din_bit == 0) next_state <= rd0_twice; rd0_twice:if (din_bit == 0) next_state <= rd0_twice; rd1_once :if (din_bit == 0) next_state <= rd0_once; else if (din_bit == 1) next_state <= rd1_twice; rd1_twice:if (din_bit == 0) next_state <= rd0_once; default: next_state <= start; endcase end 소스코드 16_4
연속된 0 또는 1 입력 검출기 소스코드 16_4 endmodule //블록-④:상태 레지스터(state_reg) 구현 always @(posedge mclk or posedge rst) begin if (rst == 1) state_reg <= start; else state_reg <= next_state; end //블록-⑤:FSM의 출력 dout_bit assign dout_bit =((state_reg == rd0_twice) || (state_reg == rd1_twice)) ? 1:0;
연속된 0 또는 1 입력 검출기 시뮬레이션 결과
연속된 0 또는 1 입력 검출기 c seq_det_moore 동작 확인 LED Array dout_bit button_clk din_bit button_clk LED Array dout_bit c rst clk [100Hz]
비트패턴 ‘0110’ 검출기 비트패턴 ‘0110’ 검출기 입력 din_bit에서 비트패턴 ‘0110’이 검출되면 출력 detect_out는 1이 되고, 그렇지 않은 경우에는 0을 출력 1 din_bit : detect_out : start st1 st3 st2 st4 1 reset
비트패턴 ‘0110’ 검출기 module detect_0110 (clk, rst, button_clk, din_bit, detect_out); input clk, rst, button_clk, din_bit; output detect_out; reg mclk; reg [2:0] state_reg, next_state; 소스코드 Ex_16_4_1 //블록-①:FSM의 상태를 parameter로 선언 parameter start = 3'b000; parameter st1 = 3'b001; parameter st2 = 3'b010; parameter st3 = 3'b011; parameter st4 = 3'b100; //블록-②:버튼 스위치 안정화(채터링 제거) 회로 always @(posedge clk) mclk <= button_clk;
비트패턴 ‘0110’ 검출기 소스코드 Ex_16_4_1 endmodule //블록-③:FSM의 상태 결정 always @(state_reg or din_bit) begin case (state_reg) ▪ FSM의 각 상태에 대해 din_bit에 따른 다음상태 next_state를 결정 endcase end //블록-④:상태 레지스터(state_reg) 구현 always @(posedge mclk or posedge rst) begin ▪ next_state 값을 상태 레지스터 state_reg에 저장 ▪ Active-high 리셋 end //블록-⑤:FSM의 출력 detect_out을 assign 문과 조건연산자로 구현
비트패턴 ‘0110’ 검출기 c detect_0110 기능 검증 동작 확인 테스트벤치 작성 시뮬레이션 LED Array din_bit button_clk LED Array detect_out c rst clk [100Hz]
keypad 스캔회로 keypad 스캔회로 keypad_scan HBE-Combo II 실습장비에 부착되어 있는 keypad를 열(column) 스캔방식으로 스캔하여 12비트의 출력 key_data[11:0]을 생성 keypad의 각 열에 순차적으로 1을 인가하면서 keypad에서 들어오는 행의 값을 읽어 어떤 키가 눌려졌는지 판별 keypad_scan key_row[3:0] key_col[2:0] key_data[11:0] clk keypad scan 회로
keypad 스캔 출력에 따른 key 입력 판별 key_col key_row key_data Key 입력 001 0001 0000 0000 0001 1 0010 0000 0000 1000 4 0100 0000 0100 0000 7 1000 0010 0000 0000 * 010 0000 0000 0010 2 0000 0001 0000 5 0000 1000 0000 8 0100 0000 0000 100 0000 0000 0100 3 0000 0010 0000 6 0001 0000 0000 9 1000 0000 0000 #
key_col 신호를 생성하는 implicit FSM의 상태 천이도 keypad 스캔회로 column1 no_scan column2 column3 key_col 신호를 생성하는 implicit FSM의 상태 천이도
keypad 스캔회로 module keypad_scan (clk, rst, key_col, key_row, key_data); input clk, rst; input [3:0] key_row; output [2:0] key_col; output [11:0] key_data; reg [11:0] key_data; reg [2:0] state; wire key_stop; assign key_stop=key_row[0] | key_row[1] | key_row[2] | key_row[3]; assign key_col = state; 소스코드 16_5 //블록-①:FSM의 상태를 parameter로 선언 parameter no_scan = 3'b000; parameter column1 = 3'b001; parameter column2 = 3'b010; parameter column3 = 3'b100;
keypad 스캔회로 소스코드 16_5 //블록-②: FSM 구현 always @(posedge clk or posedge rst) begin if (rst) state <= no_scan; else begin if (!key_stop) begin case (state) no_scan : state <= column1; column1 : state <= column2; column2 : state <= column3; column3 : state <= column1; default: state <= no_scan; endcase end 소스코드 16_5
keypad 스캔회로 소스코드 16_5 //블록-③: key_data 출력 always @(posedge clk) begin case (state) column1 : case (key_row) 4'b0001 : key_data <= 12'b0000_0000_0001; //key_1 4'b0010 : key_data <= 12'b0000_0000_1000; //key_4 4'b0100 : key_data <= 12'b0000_0100_0000; //key_7 4'b1000 : key_data <= 12'b0010_0000_0000; //key_* default: key_data <= 12'b0000_0000_0000; endcase column2 : 4'b0001 : key_data <= 12'b0000_0000_0010; //key_2 4'b0010 : key_data <= 12'b0000_0001_0000; //key_5 4'b0100 : key_data <= 12'b0000_1000_0000; //key_8 4'b1000 : key_data <= 12'b0100_0000_0000; //key_0 소스코드 16_5
keypad 스캔회로 endmodule column3 : case (key_row) 4'b0001 : key_data <= 12'b0000_0000_0100; //key_3 4'b0010 : key_data <= 12'b0000_0010_0000; //key_6 4'b0100 : key_data <= 12'b0001_0000_0000; //key_9 4'b1000 : key_data <= 12'b1000_0000_0000; //key_# default: key_data <= 12'b0000_0000_0000; endcase default : key_data <= 12'b0000_0000_0000; end
keypad 스캔회로 시뮬레이션 결과
keypad 스캔회로 keypad_scan 동작 확인 LED Array key_row[3:0] key_col[2:0] key_data[7:0] clk (10kHz) LED Array key_data[11:8] rst
keypad 입력의 7-segment 디스플레이 HBE-Combo II 실습장비에 있는 keypad의 키를 누르면 해당 숫자가 7-segment에 표시되는 회로 keypad_ scan seg_dis clk key_row[3:0] key_col[2:0] key_data[11:0] keypad_7segdis seg_com[7:0] seg_data[7:0] module function rst keypad
keypad 입력의 7-segment 디스플레이 module keypad_7segdis (clk, rst, key_col, key_row, seg_com, seg_data); input clk, rst; input [3:0] key_row; output [2:0] key_col; output [7:0] seg_com, seg_data; wire [11:0] key_data; assign seg_com = 8'b0111_1111; endmodule 소스코드 Ex_16_5_1 ▪ 코드 16.24에서 설계된 keypad_scan 모듈을 인스턴스 ▪ 함수 seg_dis를 호출하여 key_data를 seg_data로 변환
keypad 입력의 7-segment 디스플레이 소스코드 Ex_16_5_1 function [7:0] seg_dis; input [11:0] key_data; begin case (key_data) endcase end endfunction ▪ 12비트의 key_data를 7-segment 표시형식으로 변환
keypad 입력의 7-segment 디스플레이 기능 검증 테스트벤치 작성, 시뮬레이션 동작 확인 keypad_7segdis key_row[3:0] key_col[2:0] seg_data[7:0] 7-segment Array seg_com[7:0] clk (10kHz) rst
VFD 문자 디스플레이 회로 VFD 문자 디스플레이 회로 HBE-Combo II 실습장비에 탑재되어 있는 16문자×2라인의 VFD (Vacuum Fluorescent Display) 장치에 문자를 디스플레이하는 회로 VFD 초기화 과정 VFD 모듈의 초기화를 위해 100ms 동안 기다린다. Function Set 명령(001xxx00)을 보내 데이터 인터페이스 비트 수와 디스플레이 라인 수를 설정한다. Entry Mode 명령(000001xx)을 보내 커서가 움직이는 방향과 디스플레이 시프트 등을 설정한다. Display ON/OFF 제어 명령(00001xxx)을 보내 전체 디스플레이의 ON/OFF, 커서의 ON/OFF, 커서 위치의 문자 깜박임 등을 설정한다. D i g t a l e s n W h V r o H L VFD에 디스플레이될 문자
VFD 문자 디스플레이 회로 vfd_display 회로의 상태 천이도 function_set entry_mode disp_on delay_100ms function_set entry_mode disp_on delay_2sec brightness_set disp_line1 disp_line2 초기화 디스플레이 vfd_display 회로의 상태 천이도
VFD 문자 디스플레이 회로 module vfd_display (clk, resetn, vfd_e, vfd_rs, vfd_rw, vfd_data); input clk; // 클록 신호 (1kHz) input resetn; // active-high 리셋 신호 output vfd_e; // VFD enable 신호 output vfd_rs; // VFD rs 신호 (rs=0:명령어, rs=1:데이터) output vfd_rw; // VFD r/w 신호 (r/w=0:쓰기, r/w=1:읽기) output [7:0] vfd_data; // 명령어 및 문자 데이터 //필요한 변수 및 wire 선언 wire [2:0] cnt_clk_half; wire vfd_rw; reg [3:0] vfd_routine; reg [7:0] vfd_data; reg [2:0] cnt_clk; reg [4:0] cnt_delay_20m; reg [8:0] cnt_delay_2sec; reg [4:0] cnt_line; reg [1:0] cnt_brightness; reg vfd_e; reg vfd_rs; 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 //블록-①:그림 16.36의 FSM 상태를 parameter로 선언 parameter delay_100ms = 0; parameter function_set = 1; parameter entry_mode = 2; parameter disp_on = 3; parameter disp_line1 = 4; parameter disp_line2 = 5; parameter delay_2sec = 6; parameter brightness_set = 7; // VFD 라인 1과 라인 2의 시작 주소 설정 parameter address_line1 = 8'b1000_0000; parameter address_line2 = 8'b1100_0000; 소스코드 16_6 //블록-②:함수로 정의된 문자 데이터를 삽입 ‘include "data_line1.v" //라인 1의 문자 데이터(함수로 정의된 파일) ‘include "data_line2.v" //라인 2의 문자 데이터(함수로 정의된 파일)
VFD 문자 디스플레이 회로 소스코드 16_6 // VFD Data Register에 쓰기 설정 assign vfd_rw = 1'b0; // vfd_e 제어신호 정의를 위한 cnt_clk_half 값 설정 assign cnt_clk_half = 3; //블록-③:5ms 주기의 cnt_clk 생성 always @(posedge resetn or posedge clk) begin if (resetn) cnt_clk <= 0; else begin if (cnt_clk == 4) cnt_clk <= 0; else cnt_clk <= cnt_clk +1; end 소스코드 16_6
VFD 문자 디스플레이 회로 //블록-④:블록-③의 cnt_clk를 이용하여 100ms (=5×20ms)의 지연을 생성 always @(posedge resetn or posedge clk) begin if (resetn) cnt_delay_20m <= 0; else begin if (vfd_routine == delay_100ms) begin //delay_100ms state if (cnt_clk == 4) begin if (cnt_delay_20m == 19) cnt_delay_20m <= 0; else cnt_delay_20m <= cnt_delay_20m + 1; end else cnt_delay_20m <= 0; 소스코드 16_6
VFD 문자 디스플레이 회로 //블록-⑤:블록-③의 cnt_clk를 이용하여 2sec(=5×400ms)의 지연을 생성 always @(posedge resetn or posedge clk) begin if (resetn) cnt_delay_2sec <= 0; else begin if (vfd_routine == delay_2sec) begin //delay_2s state if (cnt_clk == 4) begin if (cnt_delay_2sec == 399) cnt_delay_2sec <= 0; else cnt_delay_2sec <= cnt_delay_2sec + 1; end else cnt_delay_2sec <= 0; 소스코드 16_6
VFD 문자 디스플레이 회로 //블록-⑥:블록-③의 cnt_clk를 이용하여 80ms(=5×16ms)의 지연을 생성 //VFD 각 라인의 디스플레이를 위해 필요한 80ms의 지연을 생성 always @(posedge resetn or posedge clk) begin if (resetn) cnt_line <= 0; else begin if ((vfd_routine==disp_line1) ||(vfd_routine==disp_line2)) begin if (cnt_clk == 4) begin if (cnt_line == 16) cnt_line <= 0; else cnt_line <= cnt_line + 1; end else cnt_line <=0; 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 //블록-⑦:그림 16.36의 상태 천이도를 정의 //각 routine에 설정된 시간이 경과하면 다음상태로 천이 always @(posedge resetn or posedge clk) begin if (resetn) vfd_routine <= delay_100ms; else begin if (cnt_clk == 3'b100) begin case (vfd_routine) delay_100ms : if(cnt_delay_20m == 19) vfd_routine <= function_set; function_set: vfd_routine <= entry_mode; entry_mode : vfd_routine <= disp_on; disp_on : vfd_routine <= disp_line1; disp_line1 : if(cnt_line == 16) vfd_routine <= disp_line2; disp_line2 : if(cnt_line == 16) vfd_routine <= delay_2sec; delay_2sec : if(cnt_delay_2sec == 399) vfd_routine <= brightness_set; brightness_set : vfd_routine <= delay_2sec; endcase end 소스코드 16_6
VFD 문자 디스플레이 회로 //블록-⑧:VFD enable 신호 vfd_e 생성(루틴 별로 '0' 과 '1' 값을 정의) always @(posedge resetn or posedge clk) begin if (resetn) vfd_e <= 1'b0; else begin case (vfd_routine) delay_100ms : vfd_e <= 1'b0; function_set : begin if(cnt_clk >= 1 && cnt_clk <= cnt_clk_half) vfd_e <= 1'b1; else vfd_e <= 1'b0; end entry_mode : begin disp_on : begin 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 disp_line1 : begin if(cnt_clk >= 1 && cnt_clk <= cnt_clk_half) vfd_e <= 1'b1; else vfd_e <= 1'b0; end disp_line2 : begin delay_2sec : vfd_e <= 1'b0; brightness_set : begin else vfd_e <= 1'b0; endcase 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 //블록-⑨:vfd_rs 신호에 대한 정의 always @(posedge resetn or posedge clk) begin if (resetn) vfd_rs <= 1'b0; else begin if (vfd_routine == disp_line1 || vfd_routine == disp_line2) begin if (cnt_line == 0) vfd_rs <= 0; //for address else vfd_rs <= 1; //for data end else vfd_rs <= 1'b0; //블록-⑩:brightness_set 상태일 때, VFD의 밝기 값을 변경 always @(posedge resetn or posedge clk) begin if (resetn) cnt_brightness <= 2'b00; else begin if (vfd_routine == brightness_set) begin if (cnt_brightness == 2'b11) cnt_brightness <= 2'b00; else cnt_brightness <= cnt_brightness + 1; end 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 함수 data_line1 //라인-1에 디스플레이될 문자 데이터(표 12.5의 ASCII 코드값을 할당) function [7:0] data_line1; input [3:0] addr_in; begin case (addr_in) 0 : data_line1 = 8'b0010_0000; // 1 : data_line1 = 8'b0100_0100; // D 2 : data_line1 = 8'b0110_1001; // i 3 : data_line1 = 8'b0110_0111; // g 4 : data_line1 = 8'b0110_1001; // i 5 : data_line1 = 8'b0111_0100; // t 6 : data_line1 = 8'b0110_0001; // a 7 : data_line1 = 8'b0110_1100; // l 8 : data_line1 = 8'b0010_0000; // 9 : data_line1 = 8'b0100_0100; // D 10 : data_line1 = 8'b0110_0101; // e 11 : data_line1 = 8'b0111_0011; // s 12 : data_line1 = 8'b0110_1001; // i 13 : data_line1 = 8'b0110_0111; // g 14 : data_line1 = 8'b0110_1110; // n 15 : data_line1 = 8'b0010_0000; // default : data_line1 = 8'b0000_0000; endcase end endfunction 함수 data_line1 소스코드 16_6
VFD 문자 디스플레이 회로 소스코드 16_6 함수 data_line1 //라인-2에 디스플레이될 문자 데이터(표 12.5의 ASCII 코드값을 할당) function [7:0] data_line2; input [3:0] addr_in; begin case (addr_in) 0 : data_line2 = 8'b0111_0111; // w 1 : data_line2 = 8'b0110_1001; // i 2 : data_line2 = 8'b0111_0100; // t 3 : data_line2 = 8'b0110_1000; // h 4 : data_line2 = 8'b0010_0000; // 5 : data_line2 = 8'b0101_0110; // V 6 : data_line2 = 8'b0110_0101; // e 7 : data_line2 = 8'b0111_0010; // r 8 : data_line2 = 8'b0110_1001; // i 9 : data_line2 = 8'b0110_1100; // l 10 : data_line2 = 8'b0110_1111; // o 11 : data_line2 = 8'b0110_0111; // g 12 : data_line2 = 8'b0010_1101; // - 13 : data_line2 = 8'b0100_1000; // H 14 : data_line2 = 8'b0100_0100; // D 15 : data_line2 = 8'b0100_1100; // L default : data_line2 = 8'b0000_0000; endcase end endfunction 함수 data_line1 소스코드 16_6
VFD 문자 디스플레이 회로 vfd_display 동작 확인 VFD Module vfd_data[7:0] vfd_rw clk (1kHz) resetn vfd_e vfd_rs
vfd_2frame의 프레임별 디스플레이 문자 설계 과제 : 2프레임 문자 디스플레이 회로 D i g t a l e s n W h V r o H L 프레임-1 Y o u r N a m e E l c t n i g 프레임-2 vfd_2frame의 프레임별 디스플레이 문자
VFD 문자 디스플레이 회로 회로 설계 동작 확인 소스코드 Ex_16_6_1 vfd_2frame의 상태 천이도 disp_line1 disp_line2 delay_100ms function_set entry_mode disp_on 초기화 디스플레이 clear disp_line4 disp_line3 delay_2sec 회로 설계 코드 16.31 ~ 16.33 동작 확인 소스코드 Ex_16_6_1 vfd_2frame의 상태 천이도
Piezo와 keypad를 이용한 tone 발생기 keypad의 key1 ~ key8을 누르면 각각 도, 레, 미, 파, 솔, 라, 시, 도의 소리를 내는 간이 piezo 연주기 회로 앞서 소개된 keypad_scan.v (Ex16_5_1) 를 이용
Piezo와 keypad를 이용한 tone 발생기 module top_piezo_tone (clk, rst, key_row, key_col, piezo_out); input clk, rst; input [3:0] key_row; output [2:0] key_col; output piezo_out; wire [11:0] key_data; keypad_scan U0_keypad ( .clk (clk), .rst (rst), .key_col (key_col), .key_row (key_row), .key_data (key_data) ); piezo_tone U0_piezo_tone ( .clk (clk), .rst (rst), .key_in (key_data[7:0]), .piezo_freq (piezo_out) ); endmodule 소스코드 16_7
Piezo와 keypad를 이용한 tone 발생기 module piezo_tone (clk, rst, key_in, piezo_freq); input clk, rst; input [7:0] key_in; output piezo_freq; //Tone 주파수 생성을 위한 분주기 계수값 설정 (clk=500kHz의 경우) parameter C_tone = 956; // 도 parameter D_tone = 851; // 레 parameter E_tone = 758; // 미 parameter F_tone = 716; // 파 parameter G_tone = 638; // 솔 parameter A_tone = 568; // 라 parameter B_tone = 506; // 시 reg [9:0] piezo_cnt; reg piezo_freq; reg [9:0] cnt; //key 입력에 따라 주파수 분주기의 계수값 piezo_cnt를 선택 //1옥타브 상승시 주파수는 2배가 되므로, 분주기 계수값은 1/2이 됨. always @(key_in) begin 소스코드 16_7
Piezo와 keypad를 이용한 tone 발생기 case (key_in) 8'b0000_0001 : piezo_cnt = C_tone; 8'b0000_0010 : piezo_cnt = D_tone; 8'b0000_0100 : piezo_cnt = E_tone; 8'b0000_1000 : piezo_cnt = F_tone; 8'b0001_0000 : piezo_cnt = G_tone; 8'b0010_0000 : piezo_cnt = A_tone; 8'b0100_0000 : piezo_cnt = B_tone; 8'b1000_0000 : piezo_cnt = C_tone/2; default : piezo_cnt = 0; endcase end always @(posedge clk or posedge rst) begin if (rst) begin cnt <= 0; piezo_freq <= 0; else begin if (cnt == piezo_cnt) begin piezo_freq <= ~piezo_freq; else cnt <= cnt + 1; endmodule 소스코드 16_7
Piezo와 keypad를 이용한 tone 발생기 동작 확인 top_piezo_tone key_row[3:0] key_col[2:0] piezo_out clk (500kHz) Piezo
Step Motor 구동 회로 Step Motor 구동 회로 스텝모터 : 4비트의 신호(A, B, /A, /B)에 의해 제어되며, 인가되는 신호의 주파수에 따라 모터의 회전속도를 제어 모터가 2상 여자 방식으로 구동되도록 하며, 구동신호 형식은 12.2.11을 참고 모터 옆에 부착된 자기센서(magnetic sensor)를 통해 모터의 회전 수를 계수하고, 모터가 20회 회전하면 회전방향을 반대로 바꾸어 회전하도록 설계 자기센서는 모터가 회전할 때 자석에 의한 자기를 감지하여 펄스를 출력하며, 이 펄스를 이용하여 모터의 회전 수를 계수
Step Motor 구동 회로 module motor_drive (clk, sensor, motor_data); input clk, sensor; //clk=1kHz output [3:0] motor_data; reg [1:0] m_cnt; reg [6:0] cnt_d; reg [4:0] cnt_s; reg [3:0] motor_data; reg clk_div, mode; // 2상 여자 방식의 모터 구동신호를 생성 (12.2.11절 참고) // 모터의 회전속도를 제어하기 위해 클록신호를 분주 always @(posedge clk) begin if (cnt_d == 99) begin cnt_d <= 0; clk_div <= ~ clk_div; end else cnt_d <= cnt_d + 1; 소스코드 16_7
Step Motor 구동 회로 소스코드 16_7 // mode에 따른 모터 회전 방향을 반대로 제어 always @(posedge clk_div) begin if (~mode) begin case (m_cnt) 0 : motor_data <= 4'b0011; 1 : motor_data <= 4'b1001; 2 : motor_data <= 4'b1100; 3 : motor_data <= 4'b0110; default : motor_data <= 4'b0011; endcase end else begin 1 : motor_data <= 4'b0110; 3 : motor_data <= 4'b1001; m_cnt <= m_cnt + 1; 소스코드 16_7
Step Motor 구동 회로 소스코드 16_7 // 자기센서를 통해 모터의 회전을 계수하여 회전방향을 조정 always @(posedge sensor) begin if (cnt_s == 19) begin mode <= ~mode; cnt_s <= 0; end else cnt_s <= cnt_s + 1; endmodule 소스코드 16_7
Step Motor 구동 회로 Step Motor motor_drive 동작 확인 motor_data[3:0] clk (1kHz) Step Motor sensor
Dot Matrix 디스플레이 회로 Dot Matrix 디스플레이 회로 실습장비의 dot matrix LED에 14×10의 문자 10개를 디스플레이하는 회로 dot matrix에 관해서는 소스 16_7 를 참고 표시될 문자는 별도의 파일에 함수로 정의 하나의 문자를 함수로 정의
Dot Matrix 디스플레이 회로 소스코드 16_7 module dot_display (clk, rst, dot_col, dot_row); input clk, rst; //clk=1kHz output [13:0] dot_col; output [9:0] dot_row; reg [13:0] dot_col; reg [9:0] dot_row; reg [3:0] cnt_row, cnt_fra; reg [7:0] cnt_col; reg clk_col, clk_fra; // 디스플레이될 문자 수 만큼 파일을 만들고 추가한다. ‘include "dot_rom1.v" ‘include "dot_rom2.v" . . . . . . 소스코드 16_7
Dot Matrix 디스플레이 회로 소스코드 16_7 //클록에 동기하여 cnt_row를 카운트하여 11개의 row 스캔 신호를 만든다. //row 스캔이 끝날 때마다 한 번의 clk_col 신호 생성한다. always @(posedge clk or posedge rst) begin if (rst) begin dot_row <= 1; cnt_row <= 0; clk_col <= 0; end else begin if (cnt_row == 9 || dot_row == 512) begin clk_col <= 1; dot_row <= dot_row << 1; cnt_row <= cnt_row + 1; 소스코드 16_7
Dot Matrix 디스플레이 회로 소스코드 16_7 //clk_col에 동기하여 cnt_col을 0~13까지 카운트 //카운트가 끝날 때마다 한 번의 clk_fra 신호 생성 always @(posedge clk_col or posedge rst) begin if (rst) begin cnt_col <= 0; end else begin if (cnt_col == 255) begin clk_fra <= 1; cnt_col <= cnt_col + 1; clk_fra <= 0; 소스코드 16_7
Dot Matrix 디스플레이 회로 소스코드 16_7 //clk_fra에 동기하여 cnt_fra를 카운트 always @(posedge clk_fra or posedge rst) begin if (rst) cnt_fra <= 0; else begin if (cnt_fra == 9) cnt_fra <= 0; else cnt_fra <= cnt_fra + 1; end //cnt_row, cnt_fra를 주소로 하는 롬의 데이터를 dot_col로 출력 always @(cnt_fra) begin case (cnt_fra) 0 : dot_col = rom1(cnt_row); 1 : dot_col = rom2(cnt_row); 2 : dot_col = rom3(cnt_row); 3 : dot_col = rom4(cnt_row); 4 : dot_col = rom5(cnt_row); 5 : dot_col = rom6(cnt_row); 6 : dot_col = rom7(cnt_row); 7 : dot_col = rom8(cnt_row); 8 : dot_col = rom9(cnt_row); 9 : dot_col = rom10(cnt_row); default : dot_col = 0; endcase endmodule 소스코드 16_7
Dot Matrix 디스플레이 회로 소스코드 16_7 function [13:0] rom1; input [3:0] addr_in; begin // 문자 코드를 배열형 변수에 대입 case (addr_in) 0 : rom1 = 14'b00000000000000; 1 : rom1 = 14'b00000111111111; 2 : rom1 = 14'b00111111111111; 3 : rom1 = 14'b01111000000000; 4 : rom1 = 14'b11000000000000; 5 : rom1 = 14'b11000000000000; 6 : rom1 = 14'b01111000000000; 7 : rom1 = 14'b00111111111111; 8 : rom1 = 14'b00000111111111; 9 : rom1 = 14'b00000000000000; default : rom1 = 14'b00000000000000; endcase end endfunction 소스코드 16_7 함수 rom1
Dot Matrix 디스플레이 회로 dot_display 동작 확인 dot_col[13:0] clk (1kHz) dot_row[9:0]