1. 理论
时序逻辑电路中最基本的单元—寄存器,我们可以使用寄存器来做计数器。基本上关于时间的设计都离不开计数器。
计数器在数字系统中主要是对脉冲的个数进行计数,以实现测量、计数和控制的功能,同时兼有分频功能。计数器一般都是从 0 开始计数,计数到我们需要的值或者计数满溢出后清零,并可以进行不断的循环, 3 位数的十进制计数器最大可以计数到 999, 4 位数的最大可以计数到 9999; 3 位数的二进制计数器最大可以计数到 111(7), 4 位数的最大可以计数到 1111(15)。
分频器:一般开发板上面只有一个晶振,即只有一种频率的时钟。要想获得其他频率的时钟有pll ip和写代码实现。pll后面会讲。
计数器
2.实操
实验目标:使小灯闪烁10次,闪烁频率为一秒。
2.1 模块框图
2.2 波形设计
2.3 编写rtl代码
`timescale 1ns/1ns
module ledflash10
#(
parameter CNT_MAX = 25'd24_999_999
)
(
input wire sys_clk,
input wire sys_rst_n,
output reg led_out
);
reg [24:0] cnt;
reg [4:0] led_flag;
reg cnt_flag;
//cnt:定时0.5s
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 0)
cnt <= 0;
else if ((cnt == CNT_MAX) || (led_flag > 19))
cnt <= 0;
else
cnt <= cnt + 1'b1;
//cnt_flag:标记cnt是否计满0.5s
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 0)
cnt_flag <= 0;
else if (cnt == CNT_MAX - 25'b1)
cnt_flag <= 1;
else
cnt_flag <= 0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 0)
led_flag <= 0;
else if(cnt_flag == 1 )
led_flag <= led_flag + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 0)
led_out <= 0;
else if((cnt_flag == 1) && (led_flag < 5'd20 ))
led_out <= ~led_out;
endmodule
3. 分频器
使用 parmaeter 参数化的方法做成通用的任意分频模块,方便以后的调用。
`timescale 1ns/1ns
module divider
#(
parameter CNT_MAX = 3'd6 //六分频计数器
)
(
input wire sys_clk ,
input wire sys_rst_n ,
output reg clk_flag
);
reg [3:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 1'b0;
else if(cnt == CNT_MAX )
cnt <= 1'b0;
else
cnt <= cnt + 1'b1;
//clk_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_flag <= 1'b0;
else if(cnt == CNT_MAX-1)
clk_flag <= 1'b1;
else
clk_flag <= 1'b0;
endmodule
这里不使用图一的分频的思想,而采用图二倍频的思想。一是因为实现奇分频更方便,二是因为分频的方式产生的 clk_out 信号并没有连接到全局时钟网络上,在高速系统会出现问题。
图一
图二
说明:
本人使用的是野火家Xilinx Spartan6系列开发板及配套教程,以上内容如有疑惑或错误欢迎评论区指出,或者移步B站观看野火家视频教程。
开发软件:ise14.7 仿真:modelsim 10.5
如需上述资料私信或留下邮箱。