Verilog实现任意占空比任意分频的方法.docx

上传人:b****4 文档编号:24104129 上传时间:2023-05-24 格式:DOCX 页数:15 大小:22.06KB
下载 相关 举报
Verilog实现任意占空比任意分频的方法.docx_第1页
第1页 / 共15页
Verilog实现任意占空比任意分频的方法.docx_第2页
第2页 / 共15页
Verilog实现任意占空比任意分频的方法.docx_第3页
第3页 / 共15页
Verilog实现任意占空比任意分频的方法.docx_第4页
第4页 / 共15页
Verilog实现任意占空比任意分频的方法.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

Verilog实现任意占空比任意分频的方法.docx

《Verilog实现任意占空比任意分频的方法.docx》由会员分享,可在线阅读,更多相关《Verilog实现任意占空比任意分频的方法.docx(15页珍藏版)》请在冰豆网上搜索。

Verilog实现任意占空比任意分频的方法.docx

Verilog实现任意占空比任意分频的方法

Verilog-实现任意占空比、任意分频的方法

分频程序虽然简单,但我觉得由简入难是学习的一个必然阶段,慢慢的我们自然会成长起来。

所以如果有时间的话,大家都可以将自己的这种“小程序”贴到论坛上来。

如果你的程序好,其他人也可以学习;如果你的程序有问题,大家可以一起帮你找问题,共同进步。

还有,我觉得在发贴的时候,最好能将原理说一下。

一来大家看你的贴能学到东西;二来也方便解答你的问题,不然还得解答者自己去找资料搞懂原理,然后再回答你,回答你问题的人自然也就不多了。

说了一些题外话,下面转入正文:

在verilog程序设计中,我们往往要对一个频率进行任意分频,而且占空比也有一定的要求这样的话,对于程序有一定的要求,现在我在前人经验的基础上做一个简单的总结,实现对一个频率的任意占空比的任意分频。

比如:

我们FPGA系统时钟是50MHz,而我们要产生的频率是880Hz,那么,我们需要对系统时钟进行分频。

我们很容易想到用计数的方式来分频:

50000000/880=56818

这个数字不是2的整幂次方,那么怎么办呢?

我们可以设定一个参数,让它到56818的时候重新计数不就完了吗?

呵呵,程序如下:

modulediv(clk,clk_div);

inputclk;

outputclk_div;

reg[15:

0]counter;

always@(posedgeclk)

if(counter==56817)counter<=0;

elsecounter<=counter+1;

assignclk_div=counter[15];

endmodule

//

modulediv(clk,rst,clk_div);

inputclk,rst;

outputregclk_div;

reg[15:

0]counter;s

always@(posedgeclk)

if(!

rst)

begin

counter<=0;

clk_div<=0;

end

elseif(counter==56817)

begin

counter<=0;

clk_div<~clk_div;

end

else

counter<=counter+1;

endmodule

下面我们来算一下它的占空比:

我们清楚地知道,这个输出波形在counter为0到32767的时候为低,在32767到56817的时候为高,占空比为40%多一些,如果我们需要占空比为50%,那么怎么办呢?

不用急,慢慢来。

我们再设定一个参数,使它为56817的一半,使达到它的时候波形翻转,那不就完了吗?

呵呵,再看看:

modulediv(clk,clk_div);

inputclk;

outputclk_div;

reg[14:

0]counter;

always@(posedgeclk)

if(counter==28408)counter<=0;

elsecounter<=counter+1;

regclk_div;

always@(posedgeclk)

if(counter==28408)clk_div<=~clk_div;

endmodule

占空比是不是神奇地变成50%了呢?

呵呵。

继续让我们来看如何实现任意占空比,比如还是由50M分频产生880Hz,而分频得到的信号的占空比为30%。

56818×30%=17045

modulediv(clk,reset,clk_div,counter);

inputclk,reset;

outputclk_div;

output[15:

0]counter;

reg[15:

0]counter;

regclk_div;

always@(posedgeclk)

if(!

reset)counter<=0;

elseif(counter==56817)counter<=0;

elsecounter<=counter+1;

always@(posedgeclk)

if(!

reset)clk_div<=0;

elseif(counter<17045)clk_div<=1;

elseclk_div<=0;

endmodule

三分频的Verilog实现

//很实用也是笔试面试时常考的,已经经过仿真

占空比要求50%和不要求占空比差别会很大,先看一个占空比50%的描述

modulediv3(CLKIN,CLKOUT,RESETn);

inputCLKIN,RESETn;

outputCLKOUT;

 

//internalcountersignals

reg[1:

0]count_a;

reg[1:

0]count_b;

reg     CLKOUT;

 

always@(negedgeRESETnorposedgeCLKIN)

begin

   if(RESETn==1'b0)

       count_a<=2'b00;

   else

       if(count_a==2'b10)

           count_a<=2'b00;

       else

           count_a<=count_a+1;

end

 

always@(negedgeRESETnornegedgeCLKIN)

begin

   if(RESETn==1'b0)

       count_b<=2'b0;

   else

       if(count_b==2'b10)

           count_b<=2'b00;

       else

           count_b<=count_b+1;

end

 

always@(count_aorcount_borRESETn)

begin

 if(RESETn==1'b0)

  CLKOUT=1'b0;

 elseif((count_a+count_b==4)||(count_a+count_b==1))

  CLKOUT=~CLKOUT;

end

endmodule

 

0   1    2    0    1    2

\ /   / \    \  /    / \

 0    1    2    0    1    2

 

下面是一个非50%的描述,只用了上升沿

 

modulediv3(CLKIN,CLKOUT,RESETn);

inputCLKIN,RESETn;

outputCLKOUT;

 

 

wired;

reg    q1,q2;

wire        CLKOUT;

 

always@(negedgeRESETnorposedgeCLKIN)

begin

   if(RESETn==1'b0)

       q1<=1'b0;

   else

       q1<=d;

end

 

always@(negedgeRESETnorposedgeCLKIN)

begin

   if(RESETn==1'b0)

       q2<=1'b0;

   else

       q2<=q1;

end

assignd=~q1&~q2;

assignCLKOUT=q2;

endmodule

占空比不是50%,只用了单沿触发器,寄存器输出。

至于其他奇数要求50%的或者不要求的占空比的,都可以参照上面两个例子做出。

占空比为50%的一个更好的实现。

  

modulediv3(CLKIN,CLKOUT,RESETn);

inputCLKIN,RESETn;

outputCLKOUT;

//internalcountersignals

reg[1:

0]count_a;

reg           b,c;

//reg       CLKOUT;

wireCLKOUT;

always@(negedgeRESETnorposedgeCLKIN)

begin

   if(RESETn==1'b0)

       count_a<=2'b00;

   else

       if(count_a==2'b10)

           count_a<=2'b00;

       else

           count_a<=count_a+1;

end

always@(negedgeRESETnornegedgeCLKIN)

begin

   if(RESETn==1'b0)

       b<=1'b0;

   else

       if(count_a==2'b01)

           b<=2'b0;

       else

           b<=1'b1;

end

always@(negedgeRESETnorposedgeCLKIN)

begin

   if(RESETn==1'b0)

       c<=1'b0;

   else

       if(count_a==2'b10)

           c<=1'b1;

       elseif(count_a==2'b01)

           c<=1'b0;

end

assign         CLKOUT=b&c;

endmodule

时钟选择器的Verilog写法!

CPRI有3种数据时钟,61.44M122.88M245.76M,需要模块能够根据外部的速率指示信号(一个2位的输入信号,由模块外部给定)选择其中的一种时钟作为模块的工作时钟

但由于所选用的FPGA工作频率关系,不能超过400M,无法通过寄存器方式实现时钟源的选择.

使用双边触发的方式将最高的频率进行分频,代码如下,已经通过ModelSim的仿真,可以实现。

moduleclk_div(

                  reset,        //复位信号

                  data_rate,    //数据速率指示

                  clk2,        //245.76M的时钟输入

                  time1,        //分频计数器

                  clk          //选择后的时钟输出

                  );

input      reset;

input[1:

0]data_rate;

input      clk2;

output[1:

0]time1;

output      clk;

reg[1:

0]time1;

reg      clk;                  

                  

always@(clk2orreset)

if(reset)

  begin

    time1=2'b00;

    clk=1'b0;

  end

else

  begin

    time1=time1+1'b1;

    case(data_rate)

      2'b00:

if(time1==2'b00)

                clk=~clk;

            else

                clk=clk;  

      2'b01:

if(time1[0]==1'b1)

                clk=~clk;

            else

                clk=clk;

      2'b10:

clk=clk;

      2'b11:

clk=~clk;

    endcase

  end

endmodule      

verilog实现gray码计数器

//16位gray码计数器,gary码状态改变时候每次只改变一个bit

//,可以有效防止竞争和毛刺的产生。

modulegray_counter(clk,clr,start,stop,q,cout);

 inputclk;

 inputclr;

 inputstart,stop;

 outputreg[3:

0]q;

 outputregcout;

 regflag=1;

 reg[3:

0]s,next_s;

 

 //parameterS0=0,S1=1,S2=2,S3=3,S4=4,S5=5,S6=6,S7=7;

 //parameterS8=8,S9=9,S10=10,S11=11,S12=12,S13=13,S14=14,S15=15;

 parameters0=0000,s1=0001,s2=0011,s3=0010;

 parameters4=0110,s5=0111,s6=0101,s7=0100;

 parameters8=1100,s9=1101,s10=1111,s11=1110;

 parameters12=1010,s13=1011,s14=1001,s15=1000;

 always@(posedgeclk)

 begin

  if(clr)s<=s0;

  else  s<=next_s;

 end 

 /*always@(posedgestartorposedgestop)

 begin

  if(start)flag=1;

  elseif(stop)flag=0;

 end*/

 always@(sorflag)    /*该进程实现状态的转换*/

 begin    

  case(s)

   s0:

begin

   if(flag) next_s<=s1;

   //else      next_s<=s0;

    end

   s1:

begin

   if(flag)   next_s<=s2;

   end

   s2:

begin

   if(flag)  next_s<=s3;

   ////else       next_s<=s0;

   end

   s3:

begin

   if(flag)   next_s<=s4;

   //else       next_s<=s3;

   end

   s4:

begin

   if(flag)    next_s<=s5;

   end

   s5:

begin

   if(flag)  next_s<=s6;

   //else       next_s<=s0;

   end

   s6:

begin

   if(flag)  next_s<=s7;

   //else       next_s<=s3;

   end

   s7:

begin

   if(flag) next_s<=s8;

   //else      next_s<=s0;

   end

   s8:

begin

   if(flag)   next_s<=s9;

   end

   s9:

begin

   if(flag)  next_s<=s10;

   ////else       next_s<=s0;

   end

   s10:

begin

   if(flag)   next_s<=s11;

   //else       next_s<=s3;

   end

   s11:

begin

   if(flag)    next_s<=s12;

   end

   s12:

begin

   if(flag)  next_s<=s13;

   //else       next_s<=s0;

   end

   s13:

begin

   if(flag)  next_s<=s14;

   //else       next_s<=s3;

   end

   s14:

begin

   if(flag)  next_s<=s15;

   ////else       next_s<=s0;

   end

   s15:

begin

   if(flag)   next_s<=s0;

   //else       next_s<=s3;

   end

   default:

   next_s<=s0;  /*default语句*/

  endcase

 end

 always@(s)         /*该进程定义组合逻辑(FSM的输出)*/ 

 begin

  case(s)

  s0:

q=0;

  s1:

q=4;

  s2:

q=2;

  s3:

q=3;

  s4:

q=4;

  s5:

q=5;

  s6:

q=6;

  s7:

q=7;

  s8:

q=8;

  s9:

q=9;

  s10:

q=10;

  s11:

q=11;

  s12:

q=12;

  s13:

q=13;

  s14:

q=14;

  s15:

q=15;    

  default:

q=0;    /*default语句,避免锁存器的产生*/

  endcase

 end

 always@(s)

   begin

  if(s==s15)cout=1;//assigncout=q;

  elsecout=0;

 end

endmodule

如何解决FPGA电路设计中的毛刺问题

随着半导体技术的飞速发展,FPGA(FieldProgrammableGateArray)的计算能力、容量以及可靠性也有了很大的提高。

它正以高度灵活的用户现场编程功能、灵活的反复改写功能、高可靠性等优点,成为数字电路设计、数字信号处理等领域的新宠。

但和所有的数字电路一样,毛刺也是FPGA电路中的棘手问题。

它的出现会影响电路工作的稳定性、可靠性,严重时会导致整个数字系统的误动作和逻辑紊乱。

因此,如何有效正确的解决设计中出现的毛刺,就成为整个设计中的关键一环。

  本文就FPGA设计中出现的毛刺问题,根据笔者自己的经验和体会,提出了几种简单可行的解决方法和思路,供同行供交流与参考。

  

1:

FPGA电路中毛刺的产生 

 我们知道,信号在FPGA器件中通过逻辑单元连线时,一定存在延时。

延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。

因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。

这时,往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。

另外,由于FPGA以及其它的CPLD器件内部的分布电容和电感对电路中的毛刺基本没有什么过滤作用,因此这些毛刺信号就会被“保留”并传递到后一级,从而使得毛刺问题更加突出。

  可见,即使是在最简单的逻辑运算中,如果出现多路信号同时跳变的情况,在通过内部走线之后,就一定会产生毛刺。

而现在使用在数字电路设计以及数字信号处理中的信号往往是由时钟控制的,多数据输入的复杂运算系统,甚至每个数据都由相当多的位数组成。

这时,每一级的毛刺都会对结果有严重的影响,如果是多级的设计,那么毛刺累加后甚至会影响整个设计的可靠性和精确性。

下面我们将以乘法运算电路来说明毛刺的产生以及去除,在实验中,我们使用的编程软件是QuartusII2.0,实验器件为CycloneEP1CF400I7。

需要说明一点,由于示波器无法显示该整数运算的结果,我们这里将只给出软件仿真的结果。

而具体的编程以及程序的下载我们在这里也不再详述,可以参考相关的文献书籍。

  

2:

毛刺的消除方法  

首先,我们来设计一个简单的乘法运算电路。

运算电路如图1所示。

  图1乘法运算运算电路及结果(略)  如图1(c)所示,如果在不加任何的去除毛刺的措施的时候,我们可以看到结果c中含有大量的毛刺。

产生的原因就是在时钟的上升沿,每个输入(a和b)的各个数据线上的数据都不可能保证同时到达,也就是说在时钟读取数据线上的数据的时候,有的数据线上读取的已经是新的数据,而有的数据线上读取的仍然是上一个数据,这样无疑会产生毛刺信号,而当数据完全稳定的时候,毛刺信号也就自然消失了。

 

 a:

输出加D触发器  这是一种比较传统的去除毛刺的方法。

原理就是用一个D触发器去读带毛刺的信号,利用D触发器对输入信号的毛刺不敏感的特点,去除信号中的毛刺。

这种方法在简单的逻辑电路中是常见的一种方法,尤其是对信号中发生在非时钟跳变沿的毛刺信号去除效果非常的明显。

  但是对于大多数的时序电路来说,毛刺信号往往发生在时钟信号的跳变沿,这样D触发器的效果就没有那么明显了(见图2,加D触发器以后的输出q,仍含有毛刺)。

另外,D触发器的使用还会给系统带来一定的延时,特别是在系统级数较多的情况下,延时也将变大,因此在使用D触发器去除毛刺的时候,一定要视情况而定,并不是所有的毛刺都可以用D触发器来消除。

  图2加D触发器后的运算电路及结果(略)  

 b:

信号同步法  在很多文章中都提到,设计数字电路的时候采用同步电路可以大大减少毛刺。

另外,由于大多数毛刺都比较短(大概几个纳秒),只要毛刺不出现在时钟跳变沿,毛刺信号就不会对系统造成危害了。

因此很多人认为,只要在整个系统中使用同一个时钟就可以达到系统同步的目标了。

但是这里面有一个非常严重的问题,就是时钟信号和其他所有的信号一样,在FPGA器件中传递的时候是有延时的,这样根本就无法预知时钟跳变沿的精确位置。

也就是说我们无法保证在某个时钟的跳变沿读取的数据是一个稳定的数据,尤其是在多级设计中,这个问题就更加突出了。

因此,做到真正的"同步"就是去除毛刺信号的关键问题。

我认为这里同步的关键就是保证在时钟的跳变沿读取的数据是稳定的数据而不是毛刺数据。

以这个思想为出发点,提出了以下几种具体的信号同步方法。

 c:

信号延时同步法  首先,我们给出了一个两级乘法(c=ab;q=dc)的运算结果(如图3所示,这里不再给出运算电路)。

可以看到,在没加任何处理过程的时候,两级结

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1