【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters

目录

写在前面

Counters

Count15

Count10

Countslow

Counter1-12

Counter1000

Countbcd

Count clock

总结


写在前面

本篇博客对 Circuits 部分的组合逻辑前两节做答案和部分解析,一些比较简单的题目就直接给出答案,有些难度再稍作讲解,每道题的答案不一定唯一,可以有多种解决方案,欢迎共同讨论。

Counters

Count15

生成一个4位二进制计数器,其计数范围为0到15(包括0和15),周期为16。复位输入是同步的,应将计数器复位为0。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第1张图片

module top_module (
    input         clk,
    input         reset,      
    output [3:0]  q
);

always @(posedge clk) begin
	if (reset) begin
		q <= 'd0;
	end
	else begin
		q <= q + 'd1;
	end
end

endmodule

Count10

构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第2张图片

module top_module (
    input         clk,
    input         reset,  
    output [3:0]  q
);

always @(posedge clk) begin
	if (reset) begin
		q <= 'd0;
	end
	else if (q == 'd9) begin
		q <= 'd0;		
	end
	else begin
		q <= q + 'd1;
	end
end
endmodule

 Count1to10

制作一个计数为 1 到 10(包括 1)的计数器。复位输入是同步的,应将计数器复位为1。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第3张图片

module top_module (
    input         clk,
    input         reset,  
    output [3:0]  q
);

always @(posedge clk) begin
	if (reset) begin
		q <= 'd1;
	end
	else if (q == 'd10) begin
		q <= 'd1;		
	end
	else begin
		q <= q + 'd1;
	end
end
endmodule

Countslow

构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。我们希望能够暂停计数器,而不是总是在每个时钟周期递增,因此 slowena 输入指示计数器何时应该递增。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第4张图片

module top_module (
    input         clk,
    input         slowena,
    input         reset,
    output [3:0]  q
);
always @(posedge clk) begin
	if (reset) begin
		q <= 'd0;
	end
	else if (q == 'd9 && slowena) begin
		q <= 'd0;		
	end
	else if (q < 'd9 && slowena) begin
		q <= q + 'd1;
	end
end

endmodule

Counter1-12

设计具有以下输入和输出的 1-12 计数器:
重置同步高电平有效复位,强制计数器达到1
   .使设置高,使计数器运行
   .时钟正边沿触发时钟输入
   .问[3:0]计数器的输出
   .c_enable、c_load c_d[3:0]控制信号进入提供的4位计数器,因此可以验证正确的操作。

module top_module (
    input        clk,
    input        reset,
    input        enable,
    output [3:0] Q,
    output       c_enable,
    output       c_load,
    output [3:0] c_d
); 
    
    assign c_enable = enable;
    assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));
    assign c_d = c_load ? 4'd1 : 4'd0;
    
    count4 the_counter (clk, c_enable, c_load, c_d , Q);

endmodule

Counter1000

从 1000 Hz 时钟导出一个 1 Hz 信号,称为 OneHertz,可用于驱动一组小时/分/秒计数器的 Enable 信号,以创建数字挂钟。由于我们希望时钟每秒计数一次,因此必须每秒断言一个周期的OneHertz信号。使用模-10 (BCD) 计数器和尽可能少的其他门构建分频器。同时输出来自您使用的每个BCD计数器的使能信号(最快的计数器c_enable[0],最慢的计数器c_enable[2])。为您提供了以下 BCD 计数器。启用必须为高电平才能运行计数器。复位是同步的,设置为高电平以强制计数器归零。电路中的所有计数器必须直接使用相同的 1000 Hz 信号。

module top_module (
    input         clk,
    input         reset,
    output        OneHertz,
    output [2:0]  c_enable
);

wire  [3:0]    a,b,c;
assign c_enable = {b=='d9 && a=='d9,a=='d9,1'b1};
assign OneHertz = a=='d9 && b=='d9 && c=='d9;

bcdcount counter0 (clk, reset, c_enable[0], a);
bcdcount counter1 (clk, reset, c_enable[1], b);
bcdcount counter2 (clk, reset, c_enable[2], c);
endmodule

Countbcd

生成 4 位 BCD(二进制编码十进制)计数器。每个十进制数字使用4位编码:q[3:0]是1位数字,q[7:4]是十位数字,依此类推。对于数字 [3:1],还要输出一个使能信号,指示何时应递增上述三位数字中的每一位。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第5张图片

module top_module (
    input          clk,
    input          reset,
    output [3:1]   ena,
    output [15:0]  q
);
reg  [3:0]  one,ten,hundred,thousand;

//one
always @(posedge clk) begin
	if (reset) begin
		one <= 'd0;	
	end
	else if (one == 'd9) begin
		one <= 'd0;
	end
	else begin
		one <= one + 'd1;	
	end
end

//ten
always @(posedge clk) begin
	if (reset) begin
		ten <= 'd0;
	end
	else if (ten == 'd9 && one == 'd9) begin
		ten <= 'd0;
	end
	else if (ena[1]) begin
		ten <= ten + 'd1;
	end
	else begin
		ten <= ten;
	end
end

//hundred
always @(posedge clk) begin
	if (reset) begin
		hundred <= 'd0;
	end
	else if (hundred == 'd9 && ten == 'd9 && one == 'd9) begin
		hundred <= 'd0;
	end
	else if (ena[2]) begin
		hundred <= hundred + 'd1;
	end
	else begin
		hundred <= hundred;
	end
end

//thousand
always @(posedge clk) begin
	if (reset) begin
		thousand <= 'd0;
	end
	else if (thousand =='d9 && hundred == 'd9 && ten == 'd9 && one == 'd9) begin
		thousand <= 'd0;
	end
	else if (ena[3]) begin
		thousand <= thousand + 'd1;
	end
	else begin
		thousand <= thousand;
	end
end

//ena[1] ena[2] ena[3]
assign ena[1] = (one=='d9);
assign ena[2] = (ten=='d9 && one=='d9);
assign ena[3] = (hundred=='d9 && ten=='d9 && one=='d9);

//q
assign q = {thousand, hundred, ten, one};

endmodule

Count clock

创建一组适合用作 12 小时制的计数器(带有 am/pm 指示器)。计数器由快速运行的 clk 计时,只要您的时钟递增(即每秒一次),就会有一个脉冲。重置将时钟重置为 12:00 AM。pm 对于 AM为 0,对于 PM 为 1。hh、mm 和 ss 是两个 BCD(二进制编码十进制)数字,分别表示小时(01-12)、分钟 (00-59)和秒(00-59)。重置的优先级高于启用,即使未启用,也可能发生重置。以下时序图显示了从11:59:59 AM到12:00:00 PM的翻转行为以及同步重置和启用行为。

【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters_第6张图片

这里需要注意一点,就是小时、分钟、秒钟的个位十位都需要用十进制数表示,不能直接用十六进制表示,这是这道题的难点所在。 

module top_module(
    input         clk,
    input         reset,
    input         ena,
    output        pm,
    output [7:0]  hh,
    output [7:0]  mm,
    output [7:0]  ss
); 
    
    reg         pm_temp;         //pm值寄存
    reg [3:0]   ss_ones;         //ss个位部分
    reg [3:0]   ss_tens;         //ss十位部分   
    reg [3:0]   mm_ones;         //mm个位部分   
    reg [3:0]   mm_tens;         //mm十位部分
    reg [3:0]   hh_ones;         //hh个位部分
    reg [3:0]   hh_tens;         //hh十位部分
    
    wire		add_ss_ones;     //ss个位计数开始信号
    wire		end_ss_ones;     //ss个位计数结束信号
    wire		add_ss_tens;     //ss十位计数开始信号
    wire		end_ss_tens;     //ss十位计数结束信号
    wire		add_mm_ones;     //mm个位计数开始信号
    wire		end_mm_ones;     //mm个位计数结束信号
    wire		add_mm_tens;     //mm十位计数开始信号
    wire		end_mm_tens;     //mm十位计数结束信号
    wire		add_hh_ones;     //hh个位计数开始信号
    wire		end_hh_ones_0;   //hh个位计数结束信号(十位为0)
    wire		end_hh_ones_1;   //hh个位计数结束信号(十位为1)
    wire		add_hh_tens;     //hh十位计数开始信号 
    wire		end_hh_tens_0;   //hh十位计数置0标志信号
    wire		end_hh_tens_1;   //hh十位计数置1标志信号
    wire		pm_ding;         //pm翻转标志信号
    
assign add_ss_ones = ena;
assign end_ss_ones = add_ss_ones && (ss_ones == 4'd9);
always @(posedge clk)begin
    if(reset)begin
        ss_ones <= 4'b0;
    end
    else if(add_ss_ones)begin
        if(end_ss_ones)begin
            ss_ones <= 4'b0;
        end
        else begin
            ss_ones <= ss_ones + 4'b1;
        end
    end
end

assign add_ss_tens = end_ss_ones;
assign end_ss_tens = add_ss_tens && (ss_tens == 4'd5);
always @(posedge clk)begin
    if(reset)begin
        ss_tens <= 4'b0;
    end
    else if(add_ss_tens)begin
        if(end_ss_tens)begin
            ss_tens <= 4'b0;
        end
        else begin
            ss_tens <= ss_tens + 4'b1;
        end
    end
end

assign add_mm_ones = end_ss_tens;
assign end_mm_ones = add_mm_ones && (mm_ones == 4'd9);
always @(posedge clk)begin
    if(reset)begin
        mm_ones <= 4'b0;
    end
    else if(add_mm_ones)begin
        if(end_mm_ones)begin
            mm_ones <= 4'b0;
        end
        else begin
            mm_ones <= mm_ones + 4'b1;
        end
    end
end

assign add_mm_tens = end_mm_ones;
assign end_mm_tens = add_mm_tens && (mm_tens == 4'd5);
	always @(posedge clk)begin
    if(reset)begin
        mm_tens <= 4'b0;
    end
    else if(add_mm_tens)begin
        if(end_mm_tens)begin
            mm_tens <= 4'b0;
        end
        else begin
            mm_tens <= mm_tens + 4'b1;
        end
    end
end

assign add_hh_ones = end_mm_tens;
assign end_hh_ones_0 = add_hh_ones && (hh_ones == 4'd9);
assign end_hh_ones_1 = add_hh_ones && ((hh_ones == 4'd2) && (hh_tens == 4'd1));
always @(posedge clk)begin
    if(reset)begin
        hh_ones <= 4'd2;
    end
    else if(add_hh_ones)begin
        if(end_hh_ones_0)begin
            hh_ones <= 4'b0;
        end
        else if(end_hh_ones_1)begin
            hh_ones <= 4'b1;
        end
        else begin
            hh_ones <= hh_ones+4'b1;
        end
    end
end

assign add_hh_tens = end_mm_tens;
assign end_hh_tens_0 = add_hh_tens && end_hh_ones_1;
assign end_hh_tens_1 = add_hh_tens && end_hh_ones_0;
always @(posedge clk)begin
    if(reset)begin
        hh_tens <= 4'b1;
    end
    else if(add_hh_tens)begin
        if(end_hh_tens_0)begin
            hh_tens <= 4'b0;
        end
        else if(end_hh_tens_1)begin
            hh_tens <= hh_tens + 4'b1;
        end
    end
end

always@(posedge clk)begin
    if(reset)begin
        pm_temp <= 1'b0;
    end
    else if(pm_ding)begin
        pm_temp <= ~pm_temp;
    end
end

assign pm_ding = hh_tens == 4'd1 && hh_ones == 4'd1 && end_mm_tens;

assign ss = {ss_tens, ss_ones};
assign mm = {mm_tens, mm_ones};
assign hh = {hh_tens, hh_ones};
assign pm = pm_temp;
    
endmodule

总结

这部分主要学习计数器的使用,这个在实际设计中用的非常多,尤其是在处理数据的时候,计数器设计不难,但是需要注意计数值到边缘时的处理,是否有延时等情况。 

 

你可能感兴趣的:(Verilog,fpga开发,Verilog,HDLBits,刷题,数字IC)