闲来无事打个嵌入式校赛玩玩,旨在用FPGA实现4位计数器,其功能包括上计、下计、置位、复位、暂停。
具体实现大概要先从JK触发器的功能表入手:
JK触发器在J、K两个引脚接的输入信号不同时可以分别代替SR锁存器、T触发器,这也是日常中SR锁存器、T触发器生产量小而JK触发器生产量大。emmm具体功能表查一下百度啥的吧,反正在这个4位计数器中主要用了JK触发器的“翻转”以及“保持”功能吧。为了让其通用性更强,采用了异步复位、异步置位:在复位信号和置位信号的上升沿做处理让输出为0和1(采用下降沿或者电平触发或者脉冲触发都行的)
下面是JK触发器的verilog实现及vivado生成的电路图:
//JK触发器一共7个引脚分别是输入J、K,时钟CLK,
// 输入复位、置位RST、SET以及输出Q和Q'
module JKtrigger(J, K, CLK, RST, SET, Q);
input wire J, K, CLK, RST, SET;
output reg Q;
//RESET SET单独取上升沿做异步操作
always @(posedge CLK or posedge RST or posedge SET) begin
if (RST)
Q <= 1'b0;
else if (SET)
Q <= 1'b1;
else if (J && ~K)
Q <= 1'b1;
else if (~J && K)
Q <= 1'b0;
else if (J && K)
Q <= ~Q;
end
endmodule
其实这个JK触发器在写的过程中就已经把复位、置位信号的处理方式做好了,所以在顶层设计4位计数器的时候只要在例化传对信号即可做复位、置位的操作。
由于计数器还应有一个暂停功能,且显然在这个计数器中信号的优先级是复位>=置位>=暂停>上、下计选择。由于JK触发器在J、K引脚的输入都为0时JK触发器的输出是保持不变,也即4位计数器的结果可以保持不变,而在J、K引脚的输入都为1时JK触发器的输出是翻转,为此JK信号的逻辑是if pause -> J=K=0 else ->J=K=1 emmm具体细节就直接看代码吧。
下面是例化4个JK触发器的4位计数器verilog实现及vivado生成的电路图:
//四位计数器一共6个引脚分别是时钟CLK,输入复位、置位RST、SET
// 计数选择上计、下计count_choice,暂停信号pause
// 输出信号count
module four_bit_counter(CLK, RST, SET, count_choice, pause, count);
input wire CLK, RST, SET, count_choice, pause;
output wire [3:0] count;
//中间值
wire [3:0] Q;
wire [3:0] J,K;
reg [3:0] Q_reg;
//控制JK触发器的J和K输入(pause信号进来时为0让JK触发器保持)
assign J = pause ? {4{1'b0}} : {4{1'b1}};
assign K = pause ? {4{1'b0}} : {4{1'b1}};
//实例化4个JK触发器
JKtrigger jk0(
.J(J[0]),
.K(K[0]),
.CLK(CLK),
.RST(RST),
.SET(SET),
.Q(Q[0])
);
JKtrigger jk1(
.J(J[1]),
.K(K[1]),
.CLK(count_choice?Q[0]:~Q[0]),
.RST(RST),
.SET(SET),
.Q(Q[1])
);
JKtrigger jk2(
.J(J[2]),
.K(K[2]),
.CLK(count_choice?Q[1]:~Q[1]),
.RST(RST),
.SET(SET),
.Q(Q[2])
);
JKtrigger jk3(
.J(J[3]),
.K(K[3]),
.CLK(count_choice?Q[2]:~Q[2]),
.RST(RST),
.SET(SET),
.Q(Q[3])
);
assign count = Q;
endmodule
整体来说还是比较简单的,后续会在当前基础上将比特流文件下到PYNQ-Z2的开发板上利用Arm核与上位机实现串口通信将4位计数器的结果实时回传到上位机的串口界面中。
后面再见!