奇数倍分频n_evendivider

  • 格式:doc
  • 大小:335.50 KB
  • 文档页数:9

标签: Verilog

分频器

N倍奇数分频器.(Verilog)

N_odd_divider.v / Verilog

module N_odd_divider (

input i_clk,

input rst_n,

output o_clk

);

parameter N = N_odd; // 设置奇数(除1外)倍分频

parameter M = ?; // M="N/2"

// bit_of_N: N_odd的二进制位宽

reg [(bit_of_N - 1):0] cnt_p; // 上升沿计数单位

reg [(bit_of_N - 1):0] cnt_n; // 下降沿计数单位

reg clk_p; // 上升沿时钟

reg clk_n; // 下降沿时钟

assign o_clk = clk_n & clk_p; // 按位与(作用:掩码)

// 上升沿计数器: 0~(N-1)

always @ (posedge i_clk or negedge rst_n)

begin

if (!rst_n)

cnt_p <= 0;

else

begin

if (cnt_p == N-1)

cnt_p <= 0;

else

cnt_p <= cnt_p + 1'b1;

end

end

// 生成上升沿时钟

// 0~(N>>1) ↑ -> 1;((N/2)+1)~(N-1) ↑ -> 0

always @ (posedge i_clk or negedge rst_n)

begin

if (!rst_n)

clk_p <= 0; else

begin

if (cnt_p <= M)

// 0 ~ (N/2)

clk_p <= 1;

else

clk_p <= 0;

end

end

// 下降沿计数器: 0~(N-1)

always @ (negedge i_clk or negedge rst_n)

begin

if (!rst_n)

cnt_n <= 0;

else

begin

if (cnt_n == N-1)

cnt_n <= 0;

else

cnt_n <= cnt_n + 1'b1;

end

end

// 生成下降沿时钟

// 0~(N>>1) ↓ -> 1;((N/2)+1)~(N-1) ↓ -> 0

always @ (negedge i_clk or negedge rst_n)

begin

if (!rst_n)

clk_n <= 0;

else

begin

if (cnt_n <= M) // 0 ~ (N/2)

clk_n <= 1;

else

clk_n <= 0;

end

end

endmodule

仿真波形

图1. N_odd = 3

图2. N_odd = 5

另见

N倍偶数分频器.(Verilog)

参考资料

1. 真OO 无双的(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)

2. 位运算.(C)

奇数倍分频(Verilog)

奇数倍分频的方法:(以5分频为例)

(n=N-1),图中,COUNT0采用上沿计数,COUNT1采用下沿计数,DIV0和DIV1是分别是上沿触发器和下沿触发器的输出,计数为0~(n/2-1)时DIV0、DIV1<='1'此处为0~1,计数为n/2~(n-1)时DIV0、DIV1<='0'此处为2~4,DIV5_CLK是DIV0和DIV1的或门输出。

在使用该电路时,需要注意:

(1)DIV0和DIV1到DIV5_CLK的约束要严,越快越好。不然,无法保证1:1的占空比。

(2)MCLK频率要求较高,尽量不要出现窄脉冲,尤其是在高频电路里。

(3)COUNT1可有可无,视时钟频率高低而定。频率越高,COUNT1越需要。

奇数倍分频(5分频)的方法:

`timescale 1ns / 1ps

module div(MCLK,DIV5_CLK,DIV0,DIV1,COUNT0);

input MCLK; //时钟输入

output DIV5_CLK; //5分频输出

output DIV0,DIV1; //(N-1)/2分频输出

reg DIV0;

reg DIV1;

parameter N = 5; //设置分频数N(奇数)

parameter M = 2; // (N-1)/2

output [2:0]COUNT0; //计数器计数寄存器

reg[2:0] COUNT0;

reg[2:0] COUNT1;

always@(posedge MCLK) //MCLK上升沿分频

begin

if(COUNT0==2)

begin

DIV0=0; end

else if(COUNT0==5)

begin

COUNT0=0;

DIV0=1;

end

COUNT0=COUNT0+1;

end

always@(negedge MCLK) //MCLK下降沿分频

begin

if(COUNT1==2)

begin

DIV1=0;

end

else if(COUNT1==5)

begin

DIV1=1;

COUNT1=0;

end

COUNT1=COUNT1+1;

end

assign DIV5_CLK=DIV0|DIV1; //两路(N-1)/2分频输出相或

endmodule

Post-Route Simulation仿真输出:

当要去其他奇数分频数时,可以改变N、M的值

parameter N = 5; //设置分频数N(奇数)

parameter M = 2; // (N-1)/2

为了方便观察,增加DIV0、DIV1两个输出信号,波形仿真如下:

我在编写程序的时候,开始的时候always里写成了非阻塞赋值了,仿真结果错误,错误程序如下:

always@(posedge MCLK) //MCLK上升沿分频

begin

if(COUNT0==M)

begin

DIV0<=0;

end

else if(COUNT0==N)

begin

COUNT0<=0;

DIV0<=1;

end

COUNT0<=COUNT0+1;

end

仿真波形如下:

可以看到计数器COUNT0根本没有在COUNT0==5的时候归零,这是为什么呢?这是由于我没有很好理解非阻塞和阻塞赋值的区别,这里用到非阻塞,导致if里面的幅值与COUNT0<=COUNT0+1是同时进行的,也就是说当COUNT==5时,理应COUNT归零,当这时COUNT0<=COUNT0+1,COUNT0==6,if也就无效了。所以要注意非阻塞与阻塞赋值的差别:(可参考我转载的另两篇博文)

Verilog 非阻塞赋值的仿真/综合问题(一)

Verilog 非阻塞赋值的仿真/综合问题(二)

也可以改成

always@(posedge MCLK)

begin

if(COUNT0==1)

begin

DIV0<=0;

COUNT0<=COUNT0+1;

end

else if(COUNT0==4)

begin

COUNT0<=0;

DIV0<=1;

end

else COUNT0<=COUNT0+1;

end

always@(negedge MCLK)

begin

if(COUNT1==1)

begin

DIV1<=0;

COUNT1<=COUNT1+1;

end

else if(COUNT1==4)

begin

COUNT1<=0;

DIV1<=1;

end

else COUNT1<=COUNT1+1;

end

assign DIV5_CLK=DIV0|DIV1;

Post-Route Simulation仿真输出:

通常的计数器都是用非阻塞赋值的,基本上的代码如上,if……else……

本文工程文件: