赞
踩
主要思想是利用计数器实现分频器功能,其中按原理不同可分为分频和降频
一、先说分频。
1、第一种实现方式
输入信号为系统时钟50MHz,本例子先以偶数倍六分频为例实现分频的第一种方式:计数器对系统时钟的上升沿进行计数,最大计数M=5,即count取值范围为0~5,当计数器值在0~2时,clk_out输出为0;当计数器值在3~5时,clk_out输出为1。这样即可完成对于sys-clk的六分频,且占空比为50%。
以下为模块实现代码:
- module divider_six
- (
- input wire sys_clk ,
- input wire sys_rst_n,
-
- output reg clk_out
- );
-
- reg [2:0] count;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- count <= 3'd0;
- else if(count == 3'd5)
- count <= 3'd0;
- else
- count <= count + 3'd1;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- clk_out <= 1'b0;
- else if(count == 3'd2)
- clk_out <= 1'b1;
- else if(count == 3'd5)
- clk_out <= 1'b0;
- else
- clk_out <= clk_out;
- endmodule
以下为测试代码:
- `timescale 1ns/1ns
-
- module tb_divider_six();
- reg sys_clk;
- reg sys_rst_n;
-
- wire clk_out;
-
- initial
- begin
- sys_clk = 1'b0;
- sys_rst_n <= 1'b0;
- #20
- sys_rst_n <= 1'b1;
- end
-
- always #10 sys_clk = ~sys_clk;
- divider_six divider_six_inst
- (
- .sys_clk (sys_clk),
- .sys_rst_n (sys_rst_n),
-
- .clk_out (clk_out)
- );
- endmodule
以下为仿真波形:
从下方频率显示为8.333MHZ能看出,已完成六分频的功能。
2、第一种实现方式的改进(适用于偶数倍分频)
在计数器的计数过程中,可以发现,不必将计数器最大值设为6-1=5,将计数器的计数值设为6/2 -1 = 2,即计数范围为0~2,每次达到计数值之后,可将clk_out信号取反,这样做的目的是节省计数器表示位数,只需要两位即可表示范围为0~2的计数器,节约了系统资源。
以下为模块实现代码:
- module divider_six2
- (
- input wire sys_clk ,
- input wire sys_rst_n,
-
- output reg clk_out
- );
-
- reg [1:0] count;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- count <= 2'd0;
- else if(count == 2'd2)
- count <= 2'd0;
- else
- count <= count + 3'd1;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- clk_out <= 1'b0;
- else if(count == 2'd2)
- clk_out <= ~clk_out;
- else
- clk_out <= clk_out;
-
- endmodule
以下为测试代码:
- `timescale 1ns/1ns
-
- module tb_divider_six2();
- reg sys_clk;
- reg sys_rst_n;
-
- wire clk_out;
-
- initial
- begin
- sys_clk = 1'b0;
- sys_rst_n <= 1'b0;
- #20
- sys_rst_n <= 1'b1;
- end
-
- always #10 sys_clk = ~sys_clk;
- divider_six2 divider_six2_inst
- (
- .sys_clk (sys_clk),
- .sys_rst_n (sys_rst_n),
-
- .clk_out (clk_out)
- );
- endmodule
以下为仿真波形:
3、奇数倍分频
对于奇数倍分频,实现起来要稍微麻烦一些,需要两个中间变量clk1和clk2
其中clk1是计数器对系统时钟的上升沿进行计数,在计数器值为0~2时clk1为0;在计数器值为3~4时clk1为1。其本质为一个占空比为40%的五分频输出。
其中clk2是计数器对系统时钟的下降沿进行计数,在计数器值为0~2时clk2为0;在计数器值为3~4时clk1为1。
最终的clk_out只需要对clk1和clk2取或运算,即可完成占空比为50%的五分频输出。
以下为模块实现代码:
- module divider_five
- (
- input wire sys_clk,
- input wire sys_rst_n,
-
- output wire clk_out
- );
-
- reg [2:0] count;
- reg clk1;
- reg clk2;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- count <= 3'd0;
- else if(count == 3'd4)
- count <= 3'd0;
- else
- count <= count + 3'd1;
-
- always@(posedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- clk1 <= 1'b0;
- else if(count == 3'd2)
- clk1 <= 1'b1;
- else if(count == 3'd4)
- clk1 <= 1'b0;
- else
- clk1 <= clk1;
-
- always@(negedge sys_clk or negedge sys_rst_n)
- if(sys_rst_n == 1'b0)
- clk2 <= 1'b0;
- else if(count == 3'd2)
- clk2 <= 1'b1;
- else if(count == 3'd4)
- clk2 <= 1'b0;
- else
- clk2 <= clk2;
- assign clk_out = (clk1 | clk2);
- endmodule
以下为测试代码:
- `timescale 1ns/1ns
-
- module tb_divider_five();
-
- reg sys_clk;
- reg sys_rst_n;
-
- wire clk_out;
-
- initial
- begin
- sys_clk = 1'b0;
- sys_rst_n <= 1'b0;
- #20
- sys_rst_n <= 1'b1;
- end
- always #10 sys_clk <= ~sys_clk;
- divider_five tb_divider_five_inst
- (
- .sys_clk (sys_clk),
- .sys_rst_n (sys_rst_n),
- .clk_out (clk_out)
- );
- endmodule
以下为仿真波形:
二、降频器
见下一篇文章。
参考资料:野火Verilog实战开发指南
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。