Verilog 카운터
비동기식 카운터
T플립플롭 4개가 사용되어서 T플립플롭의 코드를 가지고와 작성
count 0은 01010101, count 1은 00110011, count 2는 00001111을 반복, count 3은 0000000011111111을 반복한다.
동기식 카운터
16진 카운터
10진 카운터
reset_10은 count가 10이 되었을 때, 작동하여 count를 다시 0부터 시작하게 만듦
nand(reset_10, count[3], count[1])은 reset_10에 카운터 3과 카운터 1을 둔 이유는 카운터 1 과 카운터 3이 1010이기 때문에 10 = 1010
하향 비동기식 방식
기존에 작성했던 T_flip_flop 코드에 clk를 posedge로 바꿔주고 실행한다.
하향 비동기식 방식의 타이밍도와 같이 1111111100000000, 11110000, 11001100, 10101010
up_counter_sync_BCD를 사용하여 버튼 클릭 제어 설계
10진카운터 7세그먼트로 동작하기
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
0에서 0 5ns부터 1 10ns마다
카운터같은 레지스터는 초기값이 있어야함
`timescale 1ns / 1ps
module btn_click_counter(
input clk,
input button,
output [3:0] com_an,
output [6:0] seg,
output [3:0] led
);
wire [3:0] count_value;
wire debounced_button;
wire clk_100MHz; //wire에 clk_100MHz = 0처럼 하면 접지된다. 오류.
reg [6:0] cnt_usec; //reg에 0으로 초기화한거나 initial문으로 한거랑 똑같다.
reg [9:0] cnt_msec;
reg clk_usec, clk_msec;
initial begin //initial문은 초기화문
cnt_usec = 0;
cnt_msec = 0;
clk_usec = 0;
clk_msec = 0;
end
assign led = count_value;
assign clk_100MHz = clk;
always @ (negedge clk_100MHz)begin
if(cnt_usec >= 99) cnt_usec = 0;
else cnt_usec = cnt_usec + 1;
if(cnt_usec <= 49) clk_usec = 0; //0.5ms 동안은 0 0.5ms 동안은 1
else clk_usec = 1;
end
always @ (negedge clk_usec)begin
if(cnt_msec >= 999) cnt_msec = 0;
else cnt_msec = cnt_msec + 1;
if(cnt_msec <= 499) clk_msec = 0; //0.5ms 동안은 0 0.5ms 동안은 1
else clk_msec = 1;
end
up_counter_sync_BCD ucounter(.clk(button), .reset_n(1), .count(count_value));
decoder_7_seg decoder(.hex_value(count_value), .seg(seg), .com_an(com_an));
D_flip_flop_posedge dff1 (.D(button), .E(clk_msec), .Q(debounced_button)); //1ms 딜레이를 줌 E에
endmodule
맨 아랫줄 E에 1ms딜레이를 주기위함
버튼 자체의 진동때문에 인식되는 것을 막기위해 delay를 주고 최대한 오류를 줄이기 위함
세그먼트에 다른 수 보여주기
1234
FND_4digit_switcher 코드를 받아 작성
`timescale 1ns / 1ps
module FND_4digit_switcher(
input [3:0] value_1,
input [3:0] value_10,
input [3:0] value_100,
input [3:0] value_1000,
input clk,
output reg [3:0] com_an = 4'b1110,
output reg [3:0] hex_value
);
wire clk_100MHz;
reg [6:0] cnt_usec = 0; //reg에 0으로 초기화한거나 initial문으로 한거랑 똑같다.
reg [9:0] cnt_msec = 0;
reg clk_usec, clk_msec;
assign clk_100MHz = clk;
always @ (negedge clk_100MHz)begin
if(cnt_usec >= 99) cnt_usec = 0;
else cnt_usec = cnt_usec + 1;
if(cnt_usec <= 49) clk_usec = 0;
else clk_usec = 1;
end
always @ (negedge clk_usec)begin
if(cnt_msec >= 999) cnt_msec = 0;
else cnt_msec = cnt_msec + 1;
if(cnt_msec <= 499) clk_msec = 0; //0.5ms 동안은 0 0.5ms 동안은 1
else clk_msec = 1;
end
always @ (negedge clk_msec)begin
case (com_an)
4'b1110: begin //1의 자리 0000일 땐다 켜진거
com_an = 4'b1101;
hex_value = value_10;
end
4'b1101: begin
com_an = 4'b1011;
hex_value = value_100;
end
4'b1011: begin
com_an = 4'b0111;
hex_value = value_1000;
end
4'b0111: begin
com_an = 4'b1110;
hex_value = value_1;
end
default : begin
com_an = 4'b1110;
hex_value = value_1;
end
endcase
end
endmodule
FND_4digit_switcher 코드
basys3 에 실행시킨 결과
7세그먼트가 0에서 작동하기 때문에(anode방식)
1의 자리는 1110, 10의 자리는 1101, 100의 자리는 1011, 1000의 자리는 0111.
decimal로 1의 자리에 4, 10의 자리에 3, 100의 자리에 2, 1000의 자리에 1을 주고 1 2 3 4 출력
타이머를 통해 1 2 3 4 출력하기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/04/21 15:07:01
// Design Name:
// Module Name: clock_library
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module clock_usec(
input clk,
output reg clk_usec
);
reg [6:0] cnt_usec = 0;
wire clk_100MHz;
assign clk_100MHz = clk;
always @ (negedge clk_100MHz)begin //us
if(cnt_usec >= 99) cnt_usec = 0;
else cnt_usec = cnt_usec + 1;
if(cnt_usec <= 49) clk_usec = 0;
else clk_usec = 1;
end
endmodule
module clock_msec(
input clk_usec,
output reg clk_msec
);
reg [9:0] cnt_msec = 0;
always @ (negedge clk_usec)begin //us
if(cnt_msec >= 999) cnt_msec = 0;
else cnt_msec = cnt_msec + 1;
if(cnt_msec <= 499) clk_msec = 0;
else clk_msec = 1;
end
endmodule
우선 clock library를 만들어 usec, msec를 설정한다.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/04/21 13:33:23
// Design Name:
// Module Name: FND_4digit_switcher
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module FND_4digit_switcher(
input [3:0] value_1,
input [3:0] value_10,
input [3:0] value_100,
input [3:0] value_1000,
input clk,
output reg [3:0] com_an = 4'b1110,
output reg [3:0] hex_value
);
// wire clk_100MHz;
// reg [6:0] cnt_usec = 0; //reg에 0으로 초기화한거나 initial문으로 한거랑 똑같다.
// reg [9:0] cnt_msec = 0;
wire clk_usec, clk_msec;
assign clk_100MHz = clk;
clock_usec UCLK(.clk(clk), .clk_usec(clk_usec));
clock_msec MCLK(.clk_usec(clk_usec), .clk_msec(clk_msec));
// always @ (negedge clk_100MHz)begin
// if(cnt_usec >= 99) cnt_usec = 0;
// else cnt_usec = cnt_usec + 1;
// if(cnt_usec <= 49) clk_usec = 0;
// else clk_usec = 1;
// end
// always @ (negedge clk_usec)begin
// if(cnt_msec >= 999) cnt_msec = 0;
// else cnt_msec = cnt_msec + 1;
// if(cnt_msec <= 499) clk_msec = 0; //0.5ms 동안은 0 0.5ms 동안은 1
// else clk_msec = 1;
// end
always @ (negedge clk_msec)begin
case (com_an)
4'b1110: begin //1의 자리 0000일 땐 다 켜진거
com_an = 4'b1101;
hex_value = value_10;
end
4'b1101: begin
com_an = 4'b1011;
hex_value = value_100;
end
4'b1011: begin
com_an = 4'b0111;
hex_value = value_1000;
end
4'b0111: begin
com_an = 4'b1110;
hex_value = value_1;
end
default : begin
com_an = 4'b1110;
hex_value = value_1;
end
endcase
end
endmodule
기존에 있던 always @문을 clock library에서 정의했으므로 인스턴트로 대체할 수 있다.
`timescale 1ns / 1ps
module FND_test_top(
input clk,
output [3:0] com_an,
output [6:0] seg
);
wire [3:0] hex_value;
FND_4digit_switcher FND_4digit (
.value_1(4'd4),
.value_10(4'd3),
.value_100(4'd2),
.value_1000(4'd1),
.clk(clk),
.com_an(com_an),
.hex_value(hex_value)
);
decoder_7_seg dec7seg(
.hex_value(hex_value),
.seg(seg)
);
endmodule
동작은 이 코드로 진행하며 1 2 3 4가 나오면 성공이다.
1ms로 초기화되기 때문에 눈으로 확인할 수 없으니 1 2 3 4가 나와있으면 됨.
원하는 결과로 출력되는 것을 확인했다.