概述
若计数器由n个触发器组成,则计数器的位数为n,所能计数的最大模数为2的n次幂。以下为同步二进制加法计数器电路;
驱动方程:状态图
状态方程(此时的Q0,Q1为上一次状态值):
下例是同步4位2进制计数器的设计:该计数器具有异步清零,同步置数的功能,具有时钟端:clk;置数端:s;清零端:r;使能端:en;置数端: d[3:0];输出端:q [3:0];进位端:co。
module counter(clk,co,q,r,s,en,d); input clk,r,s,en; // 时钟,清零端,置数端,使能端 input[3:0] d; // 置数输入端 output co; // 进位端 output[3:0] q; // 计数输出端 reg[3:0] q; //4 位的计数寄存器 reg co; //1 位进位寄存器 always@(posedge clk) // 时钟上升沿触发 if(r) // 判断清零端是否为 1 begin q=0;end // 是的话把计数寄存器清 0 else begin if(s) // 判断置数端是否为 1 begin q=d;end// 是的话把置数输入端的值赋予计数寄存器 else if(en) // 判断使能端是否为 1 begin q=q+4'b1; // 是的话 q 自加 1 if(q==4'b1111) // 判断 q 是否计满 begin co=1;end // 是的话进位端置 1 else begin co=0;end // 否的话进位端置 0 end else begin q=q;end // q 保持原值 end endmodule
时序仿真图:
在编程时关于阻塞赋值和非阻塞赋值注意点:
1.阻塞赋值操作用“=”,阻塞是指在在进程语句(initial和always)中,当前的赋值语句阻断了其后的语句,也就是后面的语句必须等到当前的赋值语句执行完毕才能执行。赋值时实时的,计算完后面的马上赋值给左边的,然后再执行下一句,操作是串行的,且在一个always内完成。从理论上讲,它与后面的赋值语句只有概念上的先后,而无实质上的延迟。
always@(posedge clk) begin x=next_x; y=x; end
当执行”x=next_x“,x会立即到next_x,而下一句y=x之后执行,由于两条语句没有延迟(为导线),导致”y=next_x”。
2.非阻塞赋值用<=表示,非阻塞是指在进程语句中,当前的赋值不会阻断其后的语句,在进入进城后,所有的非阻塞语句同时赋值。
当执行“x<=next_x”时,并不会阻断“y<=x”的执行。因此语句”y<=x”中的x的值与语句“x<=next_x”的值不同,语句”x<=next_x”中的x的值是D触发器经过一个同步脉冲后的输出值,“y<=x”的x是第一个D触发器的初值。
综上总结即是:阻塞赋值是按需执行,非阻塞赋值是并行执行。
在verilog编程中,谨记以下八条原则:
1) 时序电路建模时,用非阻塞赋值。
2) 锁存器电路建模时,用非阻塞赋值。
3) 用always块建立组合逻辑模型时,用阻塞赋值。
4) 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。
5) 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
6) 不要在一个以上的always块中为同一个变量赋值。
7) 用$strobe系统任务来显示用非阻塞赋值的变量值
8) 在赋值时不要使用 #0 延迟
Tips:1.在always块内部的每一个信号都必须定义成寄存器类型;
2.if else的使用
if (表达式1)语句1;
else if (表达式2)语句2;
else if (表达式3)语句3;
….
else 语句n;
3.在每个always块里,必须要有begin…end。其他如if…else,case的分支语句,超过一句的也都要有begin…end.
转载于:https://www.cnblogs.com/Fun-with-FPGA/p/4705981.html
最后
以上就是曾经悟空为你收集整理的计数器的原理,设计及verilog实现的全部内容,希望文章能够帮你解决计数器的原理,设计及verilog实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复