原创 用Verilog-HDL做CPLD设计(时序逻辑电路的实现)

2009-7-18 11:51 5427 10 10 分类: FPGA/CPLD

用Verilog-HDL做CPLD设计(时序逻辑电路的实现)



Verilog-HDL与CPLD/FPGA设计应用讲座

 
第 8 讲 用Verilog-HDL做CPLD设计


      时序逻辑电路的实现
8.1 闪烁灯的实现  
8.2 流水灯的实现  
8.3 可编程单脉冲发生器  


  在第七讲中,已经介绍了组合逻辑电路的实现。组合逻辑电路的特点是:在任意时刻,电路产生的稳定输出仅与当前时刻的输入有关。组合逻辑电路的特点是:在任意时刻,电路产生的稳定输出仅与当前时刻的输入有关。时序逻辑电路则不同于它,其特点是:在任意时刻电路产生的稳定输出不仅与当前时刻的输入有关,而且还与电路过去的输入有关。本讲中将介绍时序逻辑电路的实现。



8.1 闪烁灯的实现
  在目标板上,设计有一个10MHz的时钟源。假如直接把它输出到发光二级管LED,由于人眼的延迟性,我们将无法看到LED闪烁,认为它一直亮着。如果我们期望看到闪烁灯,就需要将时钟源的频率降低后再输出。因此,可以采用如图1所示的逻辑功能框图。


  
               图1 闪烁灯的逻辑功能框图


  其中,CLK表示10MHz的时钟源,作为输入;LED0-LED7表示发光二极管,作为输出;6、44、43、38、37、36、35、40和42是上述变量对应芯片XC9536的引脚。虚线框中的部分是CPLD设计,用于实现闪烁灯的功能。
  如图1所示,在XC9536中,加入计数电路与判别电路。计数电路可用计数器实现。每来一个时钟脉冲CLK,计数器就加1。而每当判断出计数器达到某个数值时,就使得灯LED0-LED7的亮灭反转一次,即:周期性地输出高电平"1"和低电平"0"。这样设计也就相当于把10MHz的时钟源分频后再输出。如果最终要使得灯1s闪烁一次,即:输出1Hz的时钟脉冲,就需要把10MHz的时钟经过107分频。根据上述分析,可以得到下面的Verilog- HDL描述。


/* 闪烁灯的Verilog-HDL描述 */
module LIGHT ( CLK, LED ); // 模块名及端口参数,范围至endmodule
  input CLK;       // 输入端口定义,对应第6脚
  output [7:0] LED;
              // 输出端口定义,LED[0]-LED[7]分别对应第44、43、38、37、36、35、40和42脚
  reg [7:0] LED;     // 输出端口定义为寄存器型
  reg [22:0] buffer;   // 中间变量buffer定义为寄存器型


  always @ ( posedge CLK )


             // always语句,表示每当CLK的上升沿到来时,完成begin-end之间语句的操作


    begin // 顺序语句,到end止
      buffer = buffer +1; // 缓冲器buffer按位加1
      if ( buffer == 23'b11111111111111111111111)
               // 判别buffer中的数值为(2^23-1)≈10^7时,做输出处理
             //"23"表示以位计的数值长度,"b"表示二进制,"11…1"表示二进制的数字序列
        begin
          LED=~LED; // LED[0]-LED[7]反转一次,即:由0变为1,或由1变为0
        end
      end


endmodule


  把以上闪烁灯的描述,用WebPACK Project Navigator软件,生成目标文件,并通过下载电缆写入芯片XC9536中。然后,将芯片插到目标板上,即可看到闪烁灯的景象了。图2示出了下载过程中出现的引脚配置画面。


  
            图2 闪烁灯的引脚配置画面


8.2 流水灯的实现
  下面,做一个流水灯的设计。如果把流水做慢动作播放,可以想象到其实就是移动,即:把水块不断地向同一方向移动,而原来的水块保持不动,就形成了流水。同样,如果使得最右边的灯先亮;然后,通过移位,在其左侧的灯,由右向左依次点亮,而已经亮的灯又不灭,不就形成了向左的流水灯!
  因此,同样可以采用如图1所示的逻辑功能框图。初始状态时,8个灯都不亮。每来一个时钟脉冲CLK,计数器就加1。每当判断出计数器中的数值达到 107时,就会点亮一个灯,并进行移位。这样,依次点亮所有的灯,就形成了流水灯。而当8个灯都点亮时,需要一个操作使得所有的灯恢复为初始状态,即:灯都不亮。然后,再一次流水即可。如果是左移位,就出现向左流水的现象;反之,向右流水。根据上述分析,可以得到下面的Verilog-HDL描述。


/* 流水灯的Verilog-HDL描述* /
module LEDWATER ( CLK, LED );  // 模块名及端口参数,范围至endmodule
  input CLK;         // 输入端口定义,对应第6脚
  output [7:0] LED;
           // 输出端口定义,LED[0]-LED[7]分别对应第44、43、38、37、36、35、40和42脚
  reg [7:0] LED;        // 输出端口定义为寄存器型
  reg [22:0] buffer;      // 中间变量buffer定义为寄存器型


  initial           // initial语句,用于对8个灯进行初始化,即:使得8个灯都不亮
    LED=8'b11111111;     // 依照图1可知,输出为高电平时,LED灭,反之亮
  always @ ( posedge CLK )
            // always语句,表示每当CLK的上升沿到来时,完成begin-end之间语句的操作
    begin            // 顺序语句,到end止
      buffer = buffer +1;     // 缓冲器buffer按位加1,
      if ( buffer == 23'b11111111111111111111111)
                 // 判别buffer中的数值为(2^23-1)≈10^7时,做输出处理
           //"23"表示以位计的数值长度,"b"表示二进制,"11…1"表示二进制的数字序列
        begin
         LED=LED<<1;
           // LED向左移位,空闲位自动添0补位。例:第一次移位后,LED=8'b11111110
         if ( LED==8'b00000000 ) // 条件判断语句,表示如果8个灯全亮
            LED=8'b11111111; // 恢复为初始状态,即:8个灯都不亮
       end
    end
endmodule


  把以上流水灯的描述,用WebPACK Project Navigator软件,生成目标文件,并通过下载电缆写入芯片XC9536中。然后,将芯片插到目标板上,即可看到流水灯的景象了。下载过程中出现的引脚配置画面和图2相同。


8.3 可编程单脉冲发生器


  可编程单脉冲发生器是一种脉冲宽度可编程的信号发生器,其输出为TTL电平。在输入按键的控制下,产生单次的脉冲,脉冲的宽度由8位的输入数据控制(以下称之为脉宽参数)。由于是8位的脉宽参数,故可以产生255种宽度的单次脉冲。
  在目标板上,I0~I7用作脉宽参数输入,PULSE_OUT用做可编程单脉冲输出,而KEY和/RB作为启动键和复位键。图3示出了可编程单脉冲发生器的电路图。


 点击看大图 
                  图3 可编程单脉冲发生器的电路图



8.3.1 由系统功能描述时序关系
  可编程单脉冲发生器的操作过程是:
  (1) 预置脉宽参数。
  (2) 按下复位键,初始化系统。
  (3) 按下启动键,发出单脉冲。
  以上三步可用三个按键来完成。但是,由于目标板已确定,故考虑在复位键按下后,经过延时自动产生预置脉宽参数的动作。这一过程可用图4的时序来描述。


  
         图4 可编程单脉冲发生器的时序图



  图中的/RB为系统复位脉冲,在其之后自动产生LOAD脉冲,装载脉宽参数N。之后,等待按下/KEY键。/KEY键按下后,单脉冲P_PULSE便输出。在此,应注意到:/KEY的按下是与系统时钟CLK不同步的,不加处理将会影响单脉冲P_PULSE的精度。为此,在/KEY按下期间,产生脉冲 P1,它的上跳沿与时钟取得同步。之后,在脉宽参数的控制下,使计数单元开始计数。当达到预定时间后,再产生一个与时钟同步的脉冲P2。由P1和P2就可以算出单脉冲的宽度Tw。


8.3.2 流程图的设计
  根据时序关系,可以做出图5所示的流程图。
  在系统复位后,经一定的延时产生一个预置脉冲LOAD,用来预置脉宽参数。应该注意:复位脉冲不能用来同时预置,要在其之后再次产生一个脉冲来预置脉宽参数。
  为了产生单次的脉冲,必须考虑到在按键KEY有效后,可能会保持较长的时间,也可能会产生多个尖脉冲。因此,需要设计一种功能,使得当检测到KEY有效后就封锁KEY的再次输入,直到系统复位。这是本设计的一个关键所在。
  
 
           图5 可编程单脉冲发生器的流程图


8.3.3 系统功能描述
  根据时序和流程图,可以进一步描述系统的功能。图6给出了系统功能描述。
 点击看大图 
 
                图6 可编程单脉冲发生器的系统功能
  与系统的时序相呼应,功能框图较详细地描述了系统应有的功能。系统主要有以下三大模块组成:
  (1) 延时模块P_DLY。
  (2) 输入检测模块P_DETECT。
  (3) 计数模块LE_EN_DCNT。
  在此阶段,应尽可能详细地描述系统,给出合理的逻辑关系,进行正确的功能模块分配。例如:不要把计数模块LE_EN_DCNT与延时模块P_DLY混在一起,否则给后续的设计带来不必要的麻烦。对每一个模块有了详细的功能描述,下一步就可以将其细化为具体的逻辑电路了。



8.3.4 逻辑框图
   将系统功能描述用逻辑框图来描述,可以用图7来说明。


 点击看大图 
                  图7 可编程单脉冲发生器的逻辑功能


  (1) 延时模块P_DLY。CLK给延时单元提供计数时基,在复位脉冲/RB从有效变为无效时,启动延时单元。延时时间到后便输出一个负有效的脉冲,其宽度为一个时钟周期。
  (2) 输入检测模块P_DETECT。/RB复位系统后,该模块等待/KEY的输入,一旦检测到有下跳,便一方面封锁输入,一方面产生并保持与时钟同步的一个上跳脉冲。该脉冲用以开启计数模块LE_EN_DCNT的计数允许端EN。
  (3) 计数模块LE_EN_DCNT。脉宽参数端IN接受8位的数据,经数据预置端LOAD装载脉宽参数,在计数允许端有效后便开始计数。该计数器设计成为减法计数的模式,当其计数到0时,输出端OUT由高电平变为低电平。该输出与来自延时模块P_DETECT的输出进行"与"运算,便可得到单脉冲的输出。
  但是,根据以上的逻辑功能,还不能方便地用Verilog-HDL来描述,需要进一步分析、细化各模块的功能。另外,即使分析清楚了各模块,也应该将各模块分别进行仿真,正确无误后,再将所有的模块连接起来,进行系统级的仿真。


8.3.5 延时模块的详细描述及仿真
  如图8所示,/RB的下跳沿将U1复位,上跳沿将U1的输出端置"1"。同时,/RB将U3复位,其输出端开启"三与门"。在这种情况下,时钟CLK 通过"三与门"输入到U2的IN端,U2延时一定时间(本设计为5个时钟周期)后输出下跳的脉冲,该脉冲持续一个时钟周期后又上跳,上跳沿输入到T触发器,T触发器的输出端封锁"三与门"。这一时序关系如图9所示。
 点击看大图 
                图8 延时模块的逻辑功能描述
 
  
           图9 延时脉冲的时序关系


  图8中的延时单元DLY_UNIT可用图10的逻辑电路实现。
  
        图10 延时模块中的计数器


  至此,延时模块P_DLY已可用Verilog-HDL来描述了。


/* 延时模块P_DLY的Verilog-HDL描述 */
module pulse ( CLK, RB, DLY_OUT);   // 模块名及端口定义,范围至endmodule
  input CLK, RB;          // 输入端口定义
  output DLY_OUT;          // 输出端口定义
  wire Q, QB, CNT_CLK;       // 中间变量定义
  DFF_R U1 ( CLK, Q, RB);      // D触发器
  assign CNT_CLK = CLK & Q & QB;  // 赋值语句,实现把三与门的输出赋给CNT_CLK
  DELAY U2 ( RB, CNT_CLK , DLY_OUT); // 延时单元
T  FF U3 ( DLY_OUT, QB, RB );    // T触发器
endmodule


/* 延时单元DELAY */
module DELAY ( RESET_B, CLK, DIV_CLK ); // 模块名及端口定义,范围至endmodule
  input RESET_B, CLK;         // 输入端口定义
  output DIV_CLK;           // 输出端口定义


  reg [2:0] Q;             // 中间变量定义



  always @ ( posedge CLK or negedge RESET_B )
   // always语句,表示每当CLK的上升沿或RESET_B的下降沿到来时,完成begin-end之间语句的操作
    if ( !RESET_B )      // 如果RESET_B=0


      Q <= 0;        // 则Q = 0,即:计数器清0


    else if ( Q == 5 )    // 否则,如果Q=5,即:计数器计数已满


        Q <= 0;      // 则Q = 0,即:计数器清0


      else


        Q <= Q + 1;    // 否则,计数器加1



   assign DIV_CLK = ~(Q[2] & ~Q[1] & Q[0]);


                 // 赋值语句,实现把三与门的输出反向后赋值给DIV_CLK


endmodule


  由于D触发器和T触发器的设计比较简单,这里就不做描述了,具体描述见参考文献(3)。图11为延时模块的仿真结果。从仿真结果可以看出与设计是相吻合的。


 点击看大图 
                         图11 延时模块的仿真结果


8.3.6 输入检测模块的详细描述及仿真
  图12为输入检测模块的逻辑电路。工作原理简述如下:
  (1) 系统复位脉冲/RB使U1、U2复位。
  (2) U2的输出端允许CLK进入U1的CLK端。
  (3) U1的反相输出端开启与/KEY相关的与门,允许/KEY的第一次有效。
  (4) /KEY无效(高电平),使U1的D端为低电平。
  (5) P_DETECT的输出始终为低电平。
  (6) /KEY有效(低电平)。
  (7) U1的D端为高电平。
  (8) 待时钟CLK的上跳沿到来时,将U1的D端高电平打至U1的输出端并保持。此输出的上跳沿与时钟CLK同步。
  (9) 此时,U1的反相输出端为低电平,该电平封锁与/KEY相关的与门,从而禁止/KEY的再次输入,直到复位脉冲/RB的到来。
  
       图12 输入检测模块的逻辑功能描述
/* 输入检测模块P_DETECT的Verilog-HDL描述 */
module pulse ( CLK, RB, KEY , OUT); // 模块名及端口定义,范围至endmodule
  input CLK, RB, KEY;       // 输入端口定义
  output OUT;           // 输出端口定义
  wire CLK2, T_QB ;        // 中间变量定义


  assign CLK2 = CLK & T_QB;    // 赋值语句,实现把与门的输出赋给CLK2
  DFF_R U1 ( CLK2 , ~KEY & ~OUT, OUT, ~ OUT, RB ); // D触发器
  TFF U2 ( OUT, T_QB, RB );    // T触发器
endmodule


  由于D触发器和T触发器的设计比较简单,这里就不做描述了,具体描述见参考文献(3)。
  图13为输入检测模块的仿真结果。可以看出,在复位脉冲之后,KEY的有效(低电平)使检测模块的输出为高电平,其一直保持到系统复位脉冲的到来。还可以看出,KEY有效后,输出并不一定立刻出现高电平,而要等到时钟CLK的上跳沿到来。在输出为高电平的情况下,即使KEY再次有效,也不会影响输出。这说明模块一旦接受到了输入,便立刻禁止在其之后的输入,除非接收到复位脉冲的到来。
  在仿真时,应该给出尽可能多的信号组合来测试系统,否则会常常将人引入误区。
点击看大图  
              图13 输入检测模块的仿真结果


8.3.7 计数模块的详细描述
  计数模块的逻辑电路如图14所示。数据预置端IN的数据在LOAD有效(高电平)时被打入内部的寄存器。在EN有效的情况下,计数器开始做减法计数。当计数值减为0时,输出为低电平。此模块描述较简单,故省略模块的仿真。
  
          图14 计数模块的逻辑功能描述


8.3.8 可编程单脉冲发生器的系统仿真
  以上,已经对各个模块进行了描述。下面,就可以进行系统仿真了。可编程单脉冲发生器的系统描述可见参考文献(3)。
  图15为可编程单脉冲发生器的逻辑仿真结果。由仿真结果可以看出,单脉冲输出的持续时间(脉冲宽度)由输入的脉宽参数DATA_IN决定。


 点击看大图 
             图15 可编程单脉冲发生器的逻辑仿真结果


8.3.9 可编程单脉冲发生器的硬件实现
  仿真工作结束后,按照第六讲介绍的方法,用WebPACK Project Navigator软件,把源文件生成目标文件,并通过下载电缆将目标代码写入芯片。这样,就可以实际检测该硬件电路的工作情况了。
  图16为可编程单脉冲发生器的实测波形。本例中,脉宽参数的设定值为1。因此,应该产生宽度为一个时钟周期的单脉冲。又由于时钟为10MHz,即周期为100ns。所以图16的脉宽为100ns。实测的数据显示了本设计的正确性。


  
        图16 可编程单脉冲发生器的实测波形
参考文献:
(1) J.B hasker著,徐振林等译:Verilog HDL,机械工业出版社,北京,2000.10.
(2) 周立功,夏宇闻:单片机与CPLD综合应用技术,北京航空航天大学出版社,p191-p196,2003.9.
(3) 常晓明:Verilog-HDL实践与应用系统设计,北京航空航天大学出版社, 2003.1.

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
10
关闭 站长推荐上一条 /3 下一条