计数器
一、写在前面
计数器是数字系统和计算机系统常用的基本模块,是计数寄存器的简称74LS161模块是一个同步加法计数器(通用计数器) 下图为其的接口描述
下图为功能描述
二、进入正题
废话不多说,我们进入正题——74LS161的设计:
开门见山给出我的Verilog代码(经过仿真验证过):
module My74LS161(input CP,CR,input CTP,CTT,input L_D,input [3:0] D,output reg [3:0] Q,output CO);parameter State_0 = 4'b0000,State_1 = 4'b0001,State_2 = 4'b0010,State_3 = 4'b0011,State_4 = 4'b0100,State_5 = 4'b0101,State_6 = 4'b0110,State_7 = 4'b0111,State_8 = 4'b1000,State_9 = 4'b1001,State_10 = 4'b1010,State_11 = 4'b1011,State_12 = 4'b1100,State_13 = 4'b1101,State_14 = 4'b1110,State_15 = 4'b1111;always @(posedge CP,negedge CR) beginif(~CR) beginQ <= 0;endelse if(~L_D) beginQ <= D;endelse beginif(CTT & CTP)begincase(Q)State_0 : Q <= State_1;State_1 : Q <= State_2;State_2 : Q <= State_3;State_3 : Q <= State_4;State_4 : Q <= State_5;State_5 : Q <= State_6;State_6 : Q <= State_7;State_7 : Q <= State_8;State_8 : Q <= State_9;State_9 : Q <= State_10;State_10 : Q <= State_11;State_11 : Q <= State_12;State_12 : Q <= State_13;State_13 : Q <= State_14;State_14 : Q <= State_15;State_15 : Q <= State_0;endcaseendendendassign CO = (&Q) &CTT;endmodule
实现思想是:有限状态机,这里一共0~15,十六个状态,实现这些状态之间的相互转换即可,当然也可以通过其他方法给出。
顺便给出我的仿真代码
initial beginCR = 0;D = 0;CTP = 0;CTT = 0;L_D = 0;#100;CR = 1;L_D= 1;D = 4'b1100;CTT = 0;CTP = 0;#30 CR = 0;#20 CR = 1;#10 L_D = 0;#30 CTT = 1;CTP = 1;#10 L_D = 1;#510;CR = 0;#20 CR = 1;#500;endalways beginCP = 0;#20;CP = 1;#20;end
仿真结果(ISE)
三、24,60进制计数器
设计好了74LS141模块后,就可以设计24,60进制计数器了,这里给出电路图
实际上我们可以通过两个74LS161模块搭成24进制计数器,这里我们采用BCD编码,也就是说个位是逢9清零或者是碰到23就清零,十位是碰到23清零。
可以采取两个与非门用来检测这个9或者23,从而判断是否清零。
献上代码:
module Counter_24(input clk,input rst,output C24,output [7:0] Q );//BCD编码,Q[7:4]是十位数,Q[3:0]是个位数wire LD1;wire CT;wire NAND_1,NAND_2;assign NAND_1 = ~(Q[0]&Q[3]);//检测9的出现assign NAND_2 = ~(Q[0]&Q[1]&Q[5]);//检测23的出现assign LD1 = NAND_1 & NAND_2;assign C24 = NAND_2;assign CT = ~NAND_1;//两个74LS161分别计数My74LS161 m1 (.CP(clk),.CR(rst),.CTP(1'b1),.CTT(1'b1),.L_D(LD1),.D(4'b0000),.Q({Q[3],Q[2],Q[1],Q[0]}));My74LS161 m2 (.CP(clk),.CR(rst),.CTP(CT),.CTT(CT),.L_D(NAND_2),.D(4'b0000),.Q({Q[7],Q[6],Q[5],Q[4]}));endmodule
同理,献上60进制计数器
module Counter_60(input clk,input rst,output C60,output [7:0] Q );wire LD1;wire CT;wire NAND_1,NAND_2;assign NAND_1 = ~(Q[0]&Q[3]);assign NAND_2 = ~(Q[5]&Q[6]);assign LD1 = NAND_1 & NAND_2;assign C60 = NAND_2;assign CT = ~NAND_1;My74LS161 m1 (.CP(clk),.CR(rst),.CTP(1'b1),.CTT(1'b1),.L_D(LD1),.D(4'b0000),.Q({Q[3],Q[2],Q[1],Q[0]}));My74LS161 m2 (.CP(clk),.CR(rst),.CTP(CT),.CTT(CT),.L_D(NAND_2),.D(4'b0000),.Q({Q[7],Q[6],Q[5],Q[4]}));endmodule
四、附加思考
在某位同学的要求下,我考虑了一下关于计数器初始值的问题,上面默认计数器从0开始计数,逢60或24再清为0;但是我们也可以要求计数器从比如23开始计数。
下面是Verilog代码:
module My74LS161(input CP,CR,//时钟CP,清零CRinput CTP,CTT,//CTP和CTT使能端input L_D,//load信号input [3:0] D,//清零值input [3:0] D_CR,//初始值output reg [3:0] Q,output CO);parameter State_0 = 4'b0000,State_1 = 4'b0001,State_2 = 4'b0010,State_3 = 4'b0011,State_4 = 4'b0100,State_5 = 4'b0101,State_6 = 4'b0110,State_7 = 4'b0111,State_8 = 4'b1000,State_9 = 4'b1001,State_10 = 4'b1010,State_11 = 4'b1011,State_12 = 4'b1100,State_13 = 4'b1101,State_14 = 4'b1110,State_15 = 4'b1111;always @(posedge CP,negedge CR) beginif(~CR) beginQ <= D_CR;//这里从0改为D_CR,表示初始值endelse if(~L_D) beginQ <= D;endelse beginif(CTT & CTP)begincase(Q)//时钟来临,到达下一周期State_0 : Q <= State_1;State_1 : Q <= State_2;State_2 : Q <= State_3;State_3 : Q <= State_4;State_4 : Q <= State_5;State_5 : Q <= State_6;State_6 : Q <= State_7;State_7 : Q <= State_8;State_8 : Q <= State_9;State_9 : Q <= State_10;State_10 : Q <= State_11;State_11 : Q <= State_12;State_12 : Q <= State_13;State_13 : Q <= State_14;State_14 : Q <= State_15;State_15 : Q <= State_0;endcaseendendendassign CO = (&Q) &CTT;endmodule
于是设定初始值为13的24进制计数器可以修改为:
module Counter_24(input clk,input rst,output C24,output [7:0] Q );wire LD1;wire CT;wire NAND_1,NAND_2;assign NAND_1 = ~(Q[0]&Q[3]);assign NAND_2 = ~(Q[0]&Q[1]&Q[5]);assign LD1 = NAND_1 & NAND_2;assign C24 = NAND_2;assign CT = ~NAND_1;My74LS161 m1 (.CP(clk),.CR(rst),.CTP(1'b1),.CTT(1'b1),.L_D(LD1),.D(4'b0000),.D_CR(4'b0011),//設置初值.Q({Q[3],Q[2],Q[1],Q[0]}));My74LS161 m2 (.CP(clk),.CR(rst),.CTP(CT),.CTT(CT),.L_D(NAND_2),.D(4'b0000),.D_CR(4'b0001),//設置初值.Q({Q[7],Q[6],Q[5],Q[4]}));endmodule