0
点赞
收藏
分享

微信扫一扫

常见时序逻辑电路

ivy吖 2022-04-08 阅读 35
经验分享

目录


与组合逻辑电路不同,时序逻辑电路的输出不仅与当前时刻输入变量的取值有关,而且与电路的原状态(即过去的输入情况有关)。
时序逻辑电路的结构框图如下:
在这里插入图片描述

  • 与组合电路相比,时序逻辑电路有两个优点:
  1. 时序逻辑电路包括组合逻辑电路和存储电路两部分,存储电路具有记忆功能,通常由触发器组成。
  2. 存储电路的状态反馈到组合逻辑电路输入端,与外部输入信号共同决定组合逻辑电路的输出。组合逻辑电路的输出除包括外部输出外,还包含连接到存储电路的内部输出,它将控制存储电路状态的转移。
  • 时序逻辑电路按状态变化的特点,可分为同步时序逻辑电路和异步时序逻辑电路。在同步时序逻辑电路中,电路状态的变化在同一时钟脉冲作用下发生,即各触发器状态的转换同步完成。在异步时序逻辑电路中,没有统一的时钟脉冲信号,即各触发器状态的转换是异步完成的。
  • 对时序逻辑电路功能的描述方式主要有三种:逻辑方程,状态转移表和状态转移图,时序图。
  • 对时序逻辑电路的设计进行描述也有不同的方式,主要有三种:状态转移图描述,基于状态化简的结构性描述,VerilogHDL抽象描述。

触发器

触发器是时序逻辑电路的最基本电路单元,主要有D触发器、JK触发器、T触发器和RS触发器等。根据功能要求的不同,触发器还具有置位、复位、使能、选择等功能。

D触发器

最简D触发器

D触发器的逻辑符号如下所示:
在这里插入图片描述
图中D为信号输入端,clk为时钟控制端,Q为信号输出端。这种触发器的逻辑功能是:不论触发器原来的状态如何,输入端的数据D(无论D=0,还是D=1)都将在时钟clk的上升沿被送入触发器,使得Q=D。其真值表如下所示:
在这里插入图片描述
代码如下:

module DFF (q, clk, data_in);
    output q;
    input clk, data_in;
    reg q;
    always @(posedge clk)   q <= data_in;
endmodule

带复位端的D触发器

在D触发器的实际使用中,有时需要一个复位端(也称清零端)。带有复位端的D触发器的逻辑符号如下所示:
在这里插入图片描述
电路上电时,电路的逻辑处于不定状态,复位脉冲的到来将电路初始化为Q=0的状态。随后,在时钟的控制下,输入端D的数据在每个时钟上升沿被置到输出端Q。同步清0的D触发器的代码如下:

module DFF_rst (q, clk, reset, data_in);
    output q;
    input clk, reset, data_in;
    reg q;
    always @(posedge clk) 
        if (!reset)  q <= 0;
        else         q <= data_in;
endmodule

异步清0的D触发器的代码如下:

module DFF_srst (q, clk, reset, data_in);
    output q;
    input clk, reset, data_in;
    reg q;
    always @(posedge clk or negedge reset)//只要接收到复位信号,立马复位
    	if(!reset)  q <= 0;
    	else        q <= data_in;
endmodule

可以看到,同步清0和异步清0的电路代码只是在always后的敏感向量表上有所不同。对于同步清0,并不是清0信号一变化电路马上就会被置0,清0信号有效后需等待时钟的有效边沿到来后电路才会有动作,因此不应该把清0信号写入敏感向量表中。而异步清0时,只要清0信号有效,电路就会马上更新,输出置0,因此对于异步电路,清0信号有必要写入敏感向量表中。

T触发器

T触发器的逻辑符号如下所示:
在这里插入图片描述
其逻辑功能为:当时钟的有效边沿到来时,如果T=1,则触发器翻转;如果T=0,则触发器的状态保持不变。reset为复位端,异步复位,低电平有效。代码如下:

module TFF (data_out, T, clk, reset);
    output data_out;
    input T, clk, reset;
    reg data_out;
    always @(posedge clk or negedge reset)
   	   if (!reset)     data_out <= 1'b0;
 	   elseif(T)       data_out <= ~data_out;  
endmodule

计数器

计数器是应用最广泛的逻辑部件之一。计数器可以统计输入脉冲的个数,具有计时、计数、分频、定时、产生节拍脉冲等功能、
根据计数器中触发器时钟端的链接方式,分为同步计数器和异步计数器;根据计数方式分为二进制计数器、十进制计数器和任意进制计数器;根据计数器中的状态变化规律,分为加法计数器、减法计数器和加/减计数器。

二进制计数器

采用D触发器实现的二进制计数器的逻辑电路图如下:
在这里插入图片描述
代码如下:

module comp2bit (Q, clk, reset);
    output  q;
    input clk, reset;
    reg Q;
    always @(posedge clk or negedge reset)
    	if (!reset)
   			Q <= 1'b0;
   		else   
  	   	    Q <= ~Q;
endmodule

任意进制计数器

对于M进制的计数器,首先应确定计数器所需触发器的个数。N个触发器对应了2的N次方个状态,其应大于M。
以十一进制计数器为例,最少需要4个触发器。采用反馈清零法设计的十一进制计数器的代码如下:

module comp_11 (count, clk, reset);
    output [3:0]count;
    input clk, reset;
    reg [3:0]count;
    always @(posedge clk)
        if(reset)   count <= 4'b0000;//复位
        else
            if (count == 4'b1010)//一个技术循环结束
                count <= 4'b0000;
            else
                count <= count + 1;
endmodule

移位寄存器

移位寄存器 可以用来实现数据的串并转换,也可以构成移位计数器,进行计数、分频,还可以构成序列码发生器、序列码检测器等。
以环形移位寄存器为例,N位环形寄存器由N个移位寄存器组成,它可以实现环形移位,如下图所示:
在这里插入图片描述
其将每个寄存器的输出作为下一位寄存器的输入,并将高位寄存器的输出作为循环的输入,代码如下:

module shiftregist1 (D, clk, reset);
    parameter shiftregist_width = 4;
    output [shiftregist_width-1:0]D;//[3:0]D
    input clk, reset;
    reg[shiftregist_width-1:0]D;
    always @(posedge clk)
    	if (!reset)
    		D <= 4'b0000;
        else
            D <= {D[shiftregist_width-2:0], D[shiftregist_width-1]};
                //D[2:0], D[3]
endmodule

序列信号发生器

序列信号发生器是能够产生一组或多组序列信号的时序电路,它可以由纯时序电路构成,也可以由包含时序逻辑和组合逻辑的混合电路构成。
以一个产生100111序列的信号发生器为例,可以采用不同的方法:

  1. 由移位寄存器构成
    采用循环移位寄存器,在电路工作前,将所需的序列码置入移位寄存器中,然后循环移位,就可以不断地产生需要的序列。由于移位寄存器输入和输出信号之间没有组合电路,不需要进行组合逻辑的反馈运算,因此所占用的电路的面积很大,结构框图如下:
    在这里插入图片描述
    代码如下:
module signal_maker (out, clk, load, D);
    parameter M = 6;
    output out;
    input clk, load;
    input [M-1:0]D;  
    reg [M-1:0]Q;
    initial     Q = 6'b100111;
    always @(posedge clk)
   		if(load)    Q <= D;
  	    else        Q <= [Q[M-2:0], Q[M-1]];//移位  Q[4:0]+Q[5]
    assign out = Q[M-1]
endmodule

  1. 由移位寄存器和组合逻辑电路构成
    反馈移位寄存器型序列信号发生器的结构框图如下所示:
    在这里插入图片描述
    它由移位寄存器和组合反馈网络组成,从移位寄存器的某一输出端可以得到周期性的序列码。
    代码如下:
module signal_maker2 (out, clk, load, D);
    parameter M = 4;
    output out;
    input clk, load;
    input [M-1:0]D;
    reg [M-1:0]Q;
    wire w1;
    always @(posedge clk)//时序电路部分,移位寄存器
        if(load)        Q <= D;
        else            Q <= {Q[M-2:0], w1};
    assign w1 = (~Q[3])|(~Q[1]&(~Q[0]))|(Q[3]&(~Q[2]));//组合逻辑电路,反馈网络
    assign out = Q[M-1];
endmodule

有限同步状态机

有限状态机是时序电路的通用模型,任何时序电路都可以表示为有限状态机。

  • 根据输出信号的产生方式,有限状态机可以分为米利型(Mealy)和摩尔型(Moore)。Mealy型状态机的输出与当前状态和输入有关,Moore型状态机的输出仅依赖于当前状态,而与输入无关。结构如下所示:
    在这里插入图片描述
  • 状态机的编码方式很多,由此产生的电路也各不相同。常见的编码方式有三种:二进制编码、格雷编码和一位独热编码。
  1. 二进制编码:其状态寄存器是由触发器组成的。N个触发器可以构成2的N次方个状态。二进制编码的优点是使用的触发器个数较少,节省了资源;缺点是状态跳转时可能有多个bit(位)同时变化,引起毛刺,造成逻辑错误。
  2. 格雷编码:与二进制编码类似。格雷编码状态跳转时只有一个bit(位)发生变化,减少了产生毛刺和一些暂态的可能。
  3. 一位独热(One Hot)编码:这是对于n个状态采用n个bit(位)来编码,每个状态编码中只有一个bit(位)为1,如0001、0010、0100、1000。One Hot编码增加了使用触发器的个数,但该种编码方式为以后的译码提供了方便,能有效地节省和简化组合电路。
  • 有限状态机的描述方法有两段式和三段式两种。
    1.两段式描述方法:
//第一个进程,同步时序always块,格式化描述次态寄存器迁移到现态寄存器
always@(posedge clk or negedge rst_n)//异步复位
	if(!rst_n)	current_state <= IDLE;
	else		current_state <= next_state;//非阻塞赋值
//第二个进程,组合逻辑always模块,描述状态转移条件判断
always@(current_state or 输入信号)//电平触发
	begin
		next_state = x;//初始化,使得系统复位后能进入正确的状态
		    case(current_state)
		    	S1:if(...)
		    	next_state = S2;//阻塞赋值
		    	out <= 1'b1;//非阻塞逻辑
		    ...
		    endcase
	 end

2.三段式描述方法:

//第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器
always@(posedge clk or negedge rst_n)//异步复位
	if(!rst_n)	current_state <= IDLE;
	else		current_state <= next_state;//非阻塞赋值
//第二个进程,组合逻辑always模块,描述状态转移条件判断
always@(current_state or 输入信号)//电平触发
	begin
		next_state = x;//初始化,使得系统复位后能进入正确的状态
		    case(current_state)
		    	S1:if(...)
		    	next_state = S2;
		    	...
		    endcase
	 end
//第三个进程,同步时序always模块,格式化描述次态寄存器输出
always@(posedge clk or negedge rst_n)
	begin
	...//
		case(next_state or 输入信号)
			S1: out1 <= 1'b1;
			S2: out1 <= 1'b0;
			default:...   //default免除综合工具综合出锁存器
		endcase
	end		

三段式并不是一定要写三个always块,如果状态机更为复杂,always块也会相应增加。

接下来以两个时序电路来说明有限同步状态机的应用。

顺序脉冲发生器

顺序脉冲发生器又称脉冲分配器,其将高电平脉冲依次分配到不同的输出上,保证在每个时钟周期内只有一路输出高电平,不同时钟上的高电平脉冲依次出现在所有输出端。
以4位顺序脉冲发生器为例,其有4路输出S0、S1、S2、S3,每路输出上高电平脉冲依次出现,输出在1000、0100、0010、0001之间循环。4位顺序脉冲发生器的状态转移图如下所示:
在这里插入图片描述
代码如下:

module state4 (OUT, clk, rst_n);
    output [3:0]OUT;
    input clk;
    input rst_n;
    reg [3:0]OUT;
    reg [1:0]STATE, next_STATE;
    always @(STATE)
        case(STATE)
            2'b00;
                begin
                    OUT <= 4'b1000;
                    next_STATE <= 2'b01;
                end
            2'b01;
                begin
                    OUT <= 4'b0100;
                    next_STATE <= 2'b10;
                end
            2'b10:
                begin
                    OUT <= 4'b0010;
                    next_STATE <= 2'b11;
                end
            2'b11;
                begin
                    OUT <= 4'b0001;
                    next_STATE <= 2'b00;
                end
        endcase
    always @(posedge clk or negedge rst_n)
        if (!rst_n)     STATE <= 2'b00;
        else            STATE <= next_STATE;
endmodule

“11010”序列检测器

序列检测器就是将一个指定的序列从数字码流中检测出来。当输入端出现序列11010时,输出为1,否则输出为0。在此不考虑重复序列,即出现指定序列后就重新开始序列检测,不再考虑以前的数据。该序列检测器的状态转移图如下所示:
在这里插入图片描述
代码如下:

module seqdet (D_out, D_in, rst_n, clk);
    parameter IDLE = 3'd0, A = 3'd1, B = 3'd2, C = 3'd3, D = 3'd4, E = 3'd5;
    output D_out;
    input D_in, rst_n, clk;
    reg [2:0]state, next_state;
    wire D_out;
    assign D_out = (state == E)?1:0;
    always @(state or D_in)
        case(state)
            IDLE:if(D_in)   next_state = A;
                 else       next_state = IDLE;
            A:  if(D_in)    next_state = B;
                else        next_state = IDLE;
            B:  if(D_in)    next_state = B;
                else        next_state = C;
            C:  if(D_in)    next_state = D;
                else        next_state = IDLE;
            D:  if(D_in)    next_state = B;
                else        next_state = E;
            E:  if(D_in)    next_state = IDLE;
                else        next_state = A;
             default:    next_state = IDLE;
		endcase
	always @(posedge clk)
		state <= next_state;
endmodule
举报

相关推荐

0 条评论