HDLBits学习------Problem 98~105

参考链接:HDLBits导学


Problem 98 Four-bit binary counter

        问题:设计一个4bit的计数器,从0~15,共16个周期。reset是同步复位且复位为0

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
	
always @(posedge clk) begin
	if(reset)
		q <= 4'd0;
	else
		q <= q + 1'b1;
end

endmodule

Problem 99 Decade counter

        问题:构建一个十进制计数器,从 0 到 9(含)计数,周期为 10。复位信号是同步的

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
	
always @(posedge clk) begin
	if(reset)
		q <= 4'd0;
	else begin
		if(q <= 4'd9)
			q <= q +1'b1;
		else
			q <= 4'd0;
	end
		
end

endmodule

Problem 100 Decade counter again

        问题:构建一个从 1 到 10(包括 1 到 10)计数的十位计数器。复位信号是同步的,应将计数器复位为 1

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
	
always @(posedge clk) begin
	if(reset)
		q <= 4'd1;
	else begin
		if(q < 4'd10)
			q <= q +1'b1;
		else
			q <= 4'd1;
	end
		
end

endmodule

Problem 101 Slow decade counter

        问题:构建一个从 0 到 9 计数的十进制计数器,周期为 10。复位信号是同步的,应该将计数器重置为 0。我们希望能够暂停计数器而不是每个时钟周期总是递增,所以slowena信号指示计数器何时应该增加

        解决:

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

endmodule

Problem 102 Counter 1-12

        问题:根据以下输入输出信号设计一个1~12的计数器

Reset:同步复位信号,高复位,将计数器复位为1.

Enable:使能信号高有效

Clk:时钟上升沿触发计数器工作

Q[3:0]:计数器输出

c_enable, c_load, c_d[3:0]:题目中给我们提供了一个4-bit的计数器,这三个信号是用于该4-bit计数器的控制信号

题目给出具有使能和同步加载的4bit计数器模块

module count4(
	input clk,
	input enable,
	input load,
	input [3:0] d,
	output reg [3:0] Q
);

        思路:这个4位的计数器没有复位信号,所以只能通过置数来复位

复位条件1:复位信号有效

复位条件2:达到最大计数值(12),且此时使能信号处于高电平

要置入的数c_d就是复位后的值1

        解决:

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_load = ((Q == 4'hC &&enable) || reset) ? 1 : 0;
assign c_d = 4'd1;
assign c_enable = enable;

count4 the_counter (
	.clk(clk),
	.enable(c_enable),
	.load(c_load),
	.d(c_d),
	.Q(Q)
);

endmodule

Problem 103 Counter 1000

        问题:利用一个模10的BCD计数器和尽量少的逻辑门来建立一个时钟分频器。同时输出每个BCD计算器的使能信号(c_enable[0]为高位,c_enable[2]为低位)。

题目已经给我们提供了BCD计数器。Enable信号高有效。Reset信号高有效且复位为0。我们设计的电路中均要采用1000Hz的时钟

module bcdcount (
	input clk,
	input reset,
	input enable,
	output reg [3:0] Q
);

        思路:刚开始的想法是一个计数器分频之后的高位作为下一个计数器的时钟,以这种方式来实现1000分频(后面才发现是自己没看懂题目),最后参考了大佬的写法

一个计数器计数到最大值后使能下一个计数,依次使能三个计数器,其中低计数器是一直处于使能状态的

然后分频信号在三个计数器都达到最大值的产生

        解决:

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
reg [4:0] q1,q2,q3;
assign c_enable = {q2 == 4'd9 && q1 == 4'd9, q1 == 4'd9, 1'b1};
assign OneHertz = {q3 == 4'd9 && q2 == 4'd9 && q1 == 4'd9};
bcdcount counter1 (
	.clk(clk),
	.reset(reset), 
	.enable(c_enable[0]),
	.Q(q1)
);

bcdcount counter2 (
	.clk(clk),
	.reset(reset), 
	.enable(c_enable[1]),
	.Q(q2)
);

bcdcount counter3 (
	.clk(clk),
	.reset(reset), 
	.enable(c_enable[2]),
	.Q(q3)
);

endmodule

Problem 104 4-digit decimal counter

        问题:设计一个4位BCD(二进制编码十进制)计数器。每个十进制数字使用4-bit来表示:q[3:0]是个位,q[7:4]是十位等。对于ena[3:1],该信号用来表示个位、十位和百位的进位。时序图如下图所示:

        解决:

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
	
assign ena = {q[11:8]==4'd9&&q[7:4]==4'd9&&q[3:0]==4'd9,q[7:4]==4'd9&&q[3:0]==4'd9,q[3:0]==4'd9};
	
bcdcnt ge (
	.clk(clk),
	.reset(reset), 
	.enable(1),
	.q(q[3:0])
);

bcdcnt shi (
	.clk(clk),
	.reset(reset), 
	.enable(ena[1]),
	.q(q[7:4])
);

bcdcnt bai (
	.clk(clk),
	.reset(reset), 
	.enable(ena[2]),
	.q(q[11:8])
);

bcdcnt qian (
	.clk(clk),
	.reset(reset), 
	.enable(ena[3]),
	.q(q[15:12])
);

endmodule

module bcdcnt(
	input clk,
	input enable,
	input reset,
	output reg [3:0] q
);

always @(posedge clk) begin
	if(reset)
		q <= 4'd0;
	else if(enable) begin
		if(q < 4'd9)
			q <= q + 1'b1;
		else
			q <= 4'd0;
	end
end

endmodule

        注意:output [3:1] ena 定义的只是一个3bit的信号,使用时应该1~3


Problem 105 12-hour clock

        问题:用计数器设计一个带am/pm的12小时时钟。该计数器通过一个CLK进行计时,用ena使能信号来驱动时钟的递增。

reset信号将时钟复位为12:00 AM。 信号pm为0代表AM,为1代表PM。hh、mm和ss由两个BCD计数器构成hours(01~12), minutes(00~59) , second(00~59)。Reset信号比enable信号有更高的优先级,即使没有enable信号也可以进行复位操作。

下图所示的时序图给出了从11:59:59 AM 到12 :00 : 00 PM的变化

        提示:需要注意的是从11:59:59 PM 到12:00:00 AM和从12:59:59 PM到01:00:00 PM的变化

        思路:这个题开始也只有一个比较粗略的想法,针对模值,复位值等等不同应该怎么做,然后很多细节的地方都没有考虑到,甚至于PM一开始我都没写就去编译了(因为我也不知道要满足什么条件的时候才改变值)

        后来就是不断的对照错误的时序图去查看自己哪个地方有问题,哪个地方需要改,有些实在看不出来的地方,可以使用verilog编译软件调试看看,才能发现问题

        解决:

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 

//s2使能信号 也就是秒的高位 当低位达到最大值,且此时使能信号是有效的 s2的使能信号就有效	
wire s2_ena = (ss[3:0]==4'd9&&ena) ? 1 : 0;

//分的低位的使能信号 秒的高位达最大值且此时高位的使能信号有效,也就是59要进入下一个时刻了
wire m1_ena = (ss[7:4]==4'd5&&s2_ena) ? 1 : 0;

//分的高位使能信号 分的低位达最大值且分低位的使能信号有效
wire m2_ena = (mm[3:0]==4'd9&&m1_ena) ? 1 : 0;

//时的低位使能信号 分的高位达最大值且分高位的使能信号有效
wire h1_ena = (mm[7:4]==4'd5&&m2_ena) ? 1 : 0;

//时的高位使能信号 时的低位达最大值且时低位使能 信号有效
wire h2_ena = ((hh[3:0]==4'd9&&h1_ena)||h_load) ? 1 : 0; 

//时的加载信号
//但高位为1低位为2 且低位使能信号有效时 加载新的初始值
wire h_load = (hh[7:4]==4'd1&&hh[3:0]==4'd2&&h1_ena) ? 1 : 0;

assign pm = r_pm;
	 
reg r_pm;//锁存pm的值
	 
always @(posedge clk) begin
	if(reset)
		r_pm <= 1'b0;
	else
		//时的高位为1,低位为1且低位使能信号有效的时候 pm要改变状态
		if(hh[7:4]==4'd1&&hh[3:0]==4'd1&&h1_ena)
			r_pm <= ~r_pm;
		else
			r_pm <= r_pm;
end

//模值默认为9 特殊的需要修改
bcdcnt s1(
	.clk(clk),
	.reset(reset), 
    .enable(ena),
	.load(0),//不需要加载值
	.q(ss[3:0])
);

//模值为5
bcdcnt #(.mo(4'd5))s2(
	.clk(clk),
	.reset(reset), 
    .enable(s2_ena),
	.load(0),//不需要加载值
	.q(ss[7:4])
);

bcdcnt m1(
	.clk(clk),
	.reset(reset), 
	.enable(m1_ena),
	.load(0),//不需要加载值
	.q(mm[3:0])
);

//模值为5
bcdcnt #(.mo(4'd5))m2(
	.clk(clk),
	.reset(reset), 
	.enable(m2_ena),
	.load(0),//不需要加载值
	.q(mm[7:4])
);

//模值为9 复位值为2
bcdcnt #(.mo(4'd9),.rstd(4'd2)) h1(
	.clk(clk),
	.reset(reset),
	.enable(h1_ena),
	.load(h_load),//当12点过后需要加载为1
	.d(4'd1),//加载的值
	.q(hh[3:0])
);

//模值为1 复位值为2
bcdcnt #(.mo(4'd1),.rstd(4'd1)) h2(
	.clk(clk),
     .reset(reset), 
	.enable(h2_ena),
	.load(h_load),//当12点过后需要加载为0 其实复位也可以 但是毕竟有个加载信号嘛
    .d(4'd0),//加载的值
	.q(hh[7:4])
);

endmodule

//bcd计数器
module bcdcnt(
	input clk,
	input enable,
	input reset,
	input load,//加载使能信号
	input [3:0] d,//加载的值
	output reg [3:0] q
);

parameter mo = 4'd9;//计数器的模值 方便实例化的时候更改
parameter rstd = 4'd0;//计数器复位的值 对小时复位有要求

always @(posedge clk) begin
	if(reset)//复位
		q <= rstd;
	else if(enable) begin
		if(load)//加载
			q <= d;
		else if(q < mo)
			q <= q + 1'b1;
		else
			q <= 4'd0;
	end
end

endmodule

        学习了一下大佬的代码,还是大佬的牛逼,逻辑更清晰一点

        详情请看:传送门

module top_module 
    (
        input clk,
        input reset,
        input ena,
        output pm,
        output [7:0] hh,
        output [7:0] mm,
        output [7:0] ss
    );

reg p;  //0 is am, 1 is pm
reg [7:0] h;
reg [7:0] m;
reg [7:0] s;

always @ (posedge clk)
    begin
        if(reset)   //reset to 12:00:00 AM
            begin
                p <= 0;
                h <= 8'h12;
                m <= 8'h00;
                s <= 8'h00;
            end
        else
            begin
                if(ena)
                    begin
                        if(s < 8'h59)
                            begin
                                if(s[3:0] < 4'h9)   //s[3:0] is ones digit
                                    begin
                                        s[3:0] <= s[3:0] + 1'h1; 
                                    end
                                else
                                    begin
                                        s[3:0] <= 0;    //59->00
                                        s[7:4] <= s[7:4] + 1'h1; //tens digit 
                                    end 
                            end
                        else
                            begin
                                s <= 0; //s清零
                                if(m < 8'h59)   //m同理s
                                    begin
                                        if(m[3:0] < 4'h9)
                                            begin
                                                m[3:0] <= m[3:0] + 1'h1; 
                                            end 
                                        else
                                            begin
                                                m[3:0] <= 0;
                                                m[7:4] <= m[7:4] + 1'h1;
                                            end
                                    end
                                else
                                    begin
                                        m <= 1'h0;
                                        if(h == 8'h11)  //AM / PM 转换
                                            p = !p;
                                        if(h < 8'h12)
                                            begin
                                                if(h[3:0] < 4'h9)
                                                    h[3:0] <= h[3:0] + 1'h1;
                                                else
                                                    begin
                                                        h[3:0] <= 4'h0;
                                                        h[7:4] <= h[7:4] + 1'h1;
                                                    end
                                            end
                                        else
                                            begin //hour 12 -> 1
                                                h <= 1'h1; 
                                            end
                                    end
                            end
                    end
            end
    end

assign pm = p;
assign hh = h;
assign mm = m;
assign ss = s;

endmodule

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值