Verilog分频器的设计
大三都要结束了,才发现自己太多东西没深入学习。
对于偶分频:(计数到分频数的一半就翻转)
注:
图中只用了一个计数器,当然也可以用多个;
图中只计数到需要分频的一半,当然也可计数到更多;
图中从第一个上升沿有效,当然也可延迟多个周期开始。
例如:
1 //任意偶分频设计 2 module frequency_divider_6 (clk, rst, data_out); 3 input clk, rst; 4 output data_out; 5 reg [1:0] counter; 6 reg data_out; 7 parameter N = 6; //改变N的值变成任意偶分频,同时counter的范围需要相应修改 8 9 always @ (posedge clk or negedge rst) 10 begin 11 if (!rst) //复位置零 12 begin 13 counter <= 0; 14 data_out <= 0; 15 end 16 else //分频 17 begin 18 if (counter == N/2 - 1) //偶分频数一半时反相 19 begin 20 data_out <= ~data_out; 21 counter <= 0; //置0,从0计数 22 end 23 else 24 counter <= counter + 1; 25 end 26 end 27 endmodule
从仿真波形看出复位后并没有立刻达到分频效果,复位结束后的2.5个周期无效,之后才达到分频效果。
如果想从第一个上升沿就开始分频,那么就可以像我画的图中那样计数。如下所示:
1 /任意偶分频设计 2 module frequency_divider_6 (clk, rst, data_out); 3 input clk, rst; 4 output data_out; 5 reg [1:0] counter; 6 reg data_out; 7 parameter N = 6; //改变N的值变成任意偶分频,同时counter的范围需要相应修改 8 9 always @ (posedge clk or negedge rst) 10 begin 11 if (!rst) //复位置零 12 begin 13 data_out <= 0; 14 end 15 else //分频,也可用底下注释部分 16 begin 17 if (counter == 0) //偶分频数一半时反相 18 begin 19 data_out <= ~data_out; 20 end 21 else 22 data_out <= data_out; 23 end 24 end 25 always @ (posedge clk or negedge rst) 26 begin 27 if (!rst) 28 begin 29 counter <= 0; 30 end 31 else 32 begin 33 if (counter == (N / 2 - 1)) 34 begin 35 counter <= 0; 36 end 37 else 38 counter <= counter + 1; 39 end 40 end 41 endmodule
注意到此代码和上一个同样是6分频的,此处把计数部分和分频部分分离开来,可读性强一些吧。此处只计数到 2 就把计数器清零,计数到 0 输出的分频信号就翻转。
从仿真波形可看出从第一个上升沿就计数了。
计数到 N - 1 (注意计数器位宽)例如:
1 //任意偶分频设计 2 module frequency_divider_6 (clk, rst, data_out); 3 input clk, rst; 4 output data_out; 5 reg [2:0] counter; 6 reg data_out; 7 parameter N = 6; //改变N的值变成任意偶分频,同时counter的范围需要相应修改 8 9 always @ (posedge clk or negedge rst) 10 begin 11 if (!rst) //复位置零 12 begin 13 data_out <= 0;//此处为1也可,看需求 14 end 15 else //分频,也可用底下注释部分 16 begin 17 if (counter < (N >> 1)) //偶分频数一半时反相 18 begin 19 data_out <= 1; 20 end 21 else 22 data_out <= 0; 23 end 24 end 25 always @ (posedge clk or negedge rst) 26 begin 27 if (!rst) 28 begin 29 counter <= 0; 30 end 31 else 32 begin 33 if (counter == (N - 1)) 34 begin 35 counter <= 0; 36 end 37 else 38 counter <= counter + 1; 39 end 40 end 41 endmodule
写法多种多样,差别都不太大,不再一一举例,根据需求设计即可。
对于奇分频:(用两个计数器分别计到上升沿和下降沿达到分频数 (N - 1) / 2 和 (N + 1) / 2 时翻转)
注:
图中用了两个计数器,当然也可以用多个(两个就够了);
图中只计数到需要分频数的(N - 1) / 2 和 (N + 1) / 2,时翻转,得到的波形需要相或;
图中从第一个上升沿有效,当然也可延迟多个周期开始。
例如:
1 //任意奇分频设计 2 module frequency_divider_5 (clk, rst, clk_p, clk_n, data_out); 3 input clk, rst; 4 output clk_p, clk_n, data_out; 5 reg clk_p, clk_n; 6 reg [2:0] counter_p, counter_n; 7 parameter N = 5; //改变N的值实现任意奇分频,注意counter_p和counter_n的范围 8 //分频 9 always @ (posedge clk or negedge rst) //上升沿计数与反相 10 begin 11 if (!rst) //复位置0,从0计数 12 begin 13 counter_p <= 0; 14 clk_p <= 0; 15 end 16 else 17 begin 18 if (counter_p == N - 1) 19 counter_p <= 0; 20 else 21 counter_p <= counter_p + 1; 22 if ((counter_p == (N - 1) / 2) || (counter_p == N - 1)) 23 clk_p <= ~clk_p; 24 end 25 end 26 always @ (negedge clk or negedge rst) //下降沿计数与反相 27 begin 28 if (!rst) 29 begin 30 counter_n <= 0; 31 clk_n <= 0; 32 end 33 else 34 begin 35 if (counter_n == N - 1) 36 counter_n <= 0; 37 else 38 counter_n <= counter_n + 1; 39 if ((counter_n == (N - 1) / 2) || (counter_n == N - 1)) 40 clk_n <= ~clk_n; 41 end 42 end 43 assign data_out = clk_p | clk_n; //相或运算,得到50%占空比的分频输出信号 44 endmodule 45
和偶分频同样的情况,复位后有多个无效周期。
如果想从第一个上升沿就开始分频,那么就可以像我画的图中那样计数。如下所示:
从仿真波形可看出从第一个上升沿就计数了。
除此之外,还可以计数到这些就翻转:
1 和 (N - 1) / 2
(N - 1) / 2 和 N - 1
等等,根据需求即可
比如:
1 //任意奇分频设计 2 module frequency_divider_5 (clk, rst, clk_p, clk_n, data_out); 3 input clk, rst; 4 output clk_p, clk_n, data_out; 5 reg clk_p, clk_n; 6 reg [2:0] counter_p, counter_n; 7 parameter N = 5; //改变N的值实现任意奇分频,注意counter_p和counter_n的范围 8 9 always @ (posedge clk or negedge rst) //上升沿计数器 10 begin 11 if (!rst) 12 counter_p <= 0; 13 else 14 if (counter_p == N - 1) 15 counter_p <= 0; 16 else 17 counter_p <= counter_p + 1; 18 end 19 always @ (posedge clk or negedge rst) //上升沿反相 20 begin 21 if (!rst) 22 clk_p <= 0; 23 else 24 if (counter_p < (N >> 1)) //N整体向右移动一位,最高位补零,其实就是N/2,不过在计算奇数的时候有很明显的优越性 25 clk_p <= 1; 26 else 27 clk_p <= 0; 28 end 29 30 always @ (negedge clk or negedge rst) //下降沿计数器 31 begin 32 if (!rst) 33 counter_n <= 0; 34 else 35 if (counter_n == N - 1) 36 counter_n <= 0; 37 else 38 counter_n <= counter_n + 1; 39 end 40 always @ (negedge clk or negedge rst) //下降沿反相 41 begin 42 if (!rst) 43 clk_n <= 0; 44 else 45 if ((counter_n < (N >> 1)) 46 clk_n <= 1; 47 else 48 clk_n <= 0; 49 end 50 assign data_out = clk_p | clk_n; //相或运算,得到50%占空比的分频输出信号 51 endmodule
任意分频设计:
1 //下面是任意正整数的分频/ 此时举例是6倍频 / 2 module frequency_divider_all (clk, rst, data_out, clk_p, clk_n); 3 4 input clk, rst; 5 output data_out, clk_p, clk_n; 6 7 parameter WIDTH = 3; //计数器二进制位宽 8 parameter N = 6; //分频数(任意正整数) 9 10 reg [WIDTH-1:0] counter_p;// 上升沿计数单位 11 reg [WIDTH-1:0] counter_n;// 下降沿计数单位 12 reg clk_p;// 上升沿时钟 13 reg clk_n;// 下降沿时钟 14 15 assign data_out = (N == 1) ? clk : (N[0]) ? (clk_p | clk_n) : clk_p;//其中N==1是判断不分频,N[0]是判断是奇数还是偶数,若为1则是奇数分频,若是偶数则是偶数分频。 16 17 always @ (posedge clk or negedge rst) 18 begin 19 if (!rst) 20 counter_p <= 0; 21 else 22 if (counter_p == (N - 1)) 23 counter_p <= 0; 24 else 25 counter_p <= counter_p + 1; 26 end 27 28 always @ (posedge clk or negedge rst) 29 begin 30 if (!rst) 31 clk_p <= 1;//此处设置为0也是可以的,这个没有硬性的要求,不管是取0还是取1结果都是正确的。 32 else 33 if (counter_p < (N >> 1))//N整体向右移动一位,最高位补零,其实就是N/2,不过在计算奇数的时候有很明显的优越性 34 clk_p <= 1; 35 else 36 clk_p <= 0; 37 end 38 39 always @ (negedge clk or negedge rst) 40 begin 41 if (!rst) 42 counter_n <= 0; 43 else 44 if (counter_n == (N - 1)) 45 counter_n <= 0; 46 else 47 counter_n <= counter_n + 1; 48 end 49 50 always @ (negedge clk or negedge rst) 51 begin 52 if (!rst) 53 clk_n <= 1; 54 else 55 if (counter_n < (N >> 1)) 56 clk_n <= 1; 57 else 58 clk_n <= 0; 59 end 60 61 endmodule
总结
多思考总有新发现。
如有错误还请指出,如有侵权还请告知,如需转载请注明出处!
本人博客:http://www.cnblogs.com/yllinux/