前言
本篇文章介绍触发器
触发器是这样一种电路实现,触发器有一个控制输入端和一个数据输入端,触发器的特点是可以保存数据输入的信息
- 如果控制输入端设置为高电平,数据输入端的数据将会改变输出的数据
- 否则,数据输入端不对输出数据产生影响
SR锁存器
SR锁存器是最简单的一类触发器,通过两个或非门实现,电路图如下:
我们再次给出或非门的输入输出逻辑关系:
输入
A
输入
B
输出
0
0
1
0
1
0
1
0
0
1
1
0
\begin{array}{|c|c|c|} \hline 输入A&输入B&输出\\ \hline 0&0&1\\ \hline 0&1&0\\ \hline 1&0&0\\ \hline 1&1&0\\ \hline \end{array}
输入A0011输入B0101输出1000
SR锁存器的特点如下:
- 默认 S = 0 S=0 S=0, R = 0 R=0 R=0, Q Q Q=0, Q ‾ \overline{Q} Q=1
- 当第一次设置 S S S端为1时, Q Q Q=1, Q ‾ \overline{Q} Q=0
- 然后再次断开 S S S的值不会影响 Q Q Q和 Q ‾ \overline{Q} Q的值
- 如果设置 R R R端为1, Q Q Q=0, Q ‾ \overline{Q} Q=1
- 然后再次断开 R R R的值不会影响 Q Q Q和 Q ‾ \overline{Q} Q的值
SR锁存器有两点需要注意:
- S = 0 S=0 S=0, R = 0 R=0 R=0时, Q Q ‾ Q\overline{Q} QQ维持之前的状态不变
- 不能同时设置 S = 1 S=1 S=1, R = 1 R=1 R=1,因为这个时候状态是不可预测的,这样SR锁存器就没有意义了。
SR锁存器可以简化为带有输入和输出标志的小框图:
SR锁存器最突出的特点在于,它可以记住哪个输入端的最终状态为 1。
触发器
触发器与锁存器的不同在于, 它除了置1、置0输人端以外,又增加了一个触发信号输人端。 只有当触发信号到来时,触发器才能按照输人的置 1、置0信号置成相应的状态,并保持下去。 我们将这个触发信号称为时钟信号(CLOCK),记作CLK。当系统中有多个触发器需要同时动作时,就可以用同一个时钟信号作为同步控制信号了
。
D型触发器
D型触发器由两个或非门组成的SR锁存器加上两个与门组成的逻辑电路
D型触发器有两个输入端:
- 数据控制端,控制端可以看作是CLK
- 数据输入端,数据输入端本来有两个,就是SR锁存器的S端和R端,但是在SR锁存器这一节中我们说过,SR都为0的话保持之前的状态不变,并且SR不能都为1,也就是说SR值一样的时候对我们没什么意义,我们需要的是记住数据输入端的状态,所以我们用一个输入输入端,通过添加一个反相器来引出SR端。参照下面的电路图
D型触发器的特点是:只有当数据控制端为高电平时,数据输入端的状态才会被保存
。
D型触发器比SR触发器复杂一些,电路图如下:
根据D型触发器的特点我们可以想到,D型触发器可以保存数据,就是当我需要保存输入数据的时候,只需要把控制端的时钟置成高位即可。并且时钟变为低位后,输入数据不会改变已经保存的数据。
下面列出D型触发器的状态值:
- 时钟为1,数据端为1, Q Q Q=1, Q ‾ \overline{Q} Q=0
- 时钟为1,数据端为0, Q Q Q=0, Q ‾ \overline{Q} Q=1
- 时钟为0,数据端为1或者0, Q Q Q不变, Q ‾ \overline{Q} Q不变
关于D型触发器的思考:
D型触发器的特点决定了一个可能的情况,就是当时钟为1时,如果数据端的数据发生了改变,每次改变都会产生新的状态。对于某些情况而言,可能需要的仅仅是时钟切换到1时保存数据输入的值,然后不在改变。一个是区间,一个是即时,对于即时的改变,有一种新的触发器,叫做边沿触发器
边沿触发器
边沿触发器的特点:
只有当时钟从0跳变到1时,才会引起输出的改变。边沿触发器与D型触发器的区别在于,在D型触发器中,当时钟输入为0时, 数据端输入的任何改变都不会影响输出;而在边沿触发器中,当时钟输入为1时,数据端输入的改变也不会影响输出。只有在时钟输入从0变到1的瞬间,数据端的输入才会影响边沿触发器的输出
。
边沿触发器是由两个D型触发器连接而成的,电路图如下:
可以推导一下边沿触发器的规则:
- 当CLK=0时,前面的D型触发器能保存数据端的数据,并且会一直保存最新的数据,后面的D型触发器因为CLK=0,不保存数据
- 当CLK从0变成1时,前面的D型触发器关闭,输出的一直是最新的数据,后面的D型触发器打开,将前面的数据保存到 Q Q Q和 Q ‾ \overline{Q} Q
- 当CLK保持1时,因为前面的D型触发器已经关闭,输出的一直是之前的数据,所以后面的D型触发器一直保存的是CLK从0变成1时的数据。
- 当CLK从1变成0时,回到第一步。
最后给出锁存器触发器的C语言实现
可以参考Git地址
/**
* sr锁存器的C语言实现
* s:置位项
* r:重置项
* q:输入Q
* q1:输出Q1
*/
extern void sr_lock(long s, long r,long *q,long *q1);
/**
* D型触发器
* clock:时钟输入
* data:数据输入
* q:输出Q
* q1:输出Q1
*/
extern void d_trigger(long clock, long data,long *q,long *q1);
/**
* 边沿触发器
* clock:时钟输入
* data:数据输入
* q_0:前面的D型触发器的输出数据
* q_1:前面的D型触发器的输出数据
* q:输出Q
* q1:输出Q1
*/
extern void b_trigger(long clock, long data,long *q_0,long *q_1,long *q,long *q1);
void sr_lock(long s, long r,long *q,long *q1)
{
for(int i =0;i<sizeof(long)*8;i++)
{
// 输入都是0,状态不变
if(((1<<i)&s) == 0 && ((1<<i)&r) == 0)
{
continue;
}
// 输入都是1,理论上要避免
if(((1<<i)&s) != 0 && ((1<<i)&r) != 0)
{
continue;
}
// s==1 r==0
if(((1<<i)&s) != 0)
{
(*q) |= 1<<i;
}
else// s==0 r==1
{
(*q) &= ~(1<<i);
}
}
(*q1) = ~(*q);
}
void d_trigger(long clock, long data,long *q,long *q1)
{
long in_1 = alu_and(clock, data, sizeof(long)*8);
long in_2 = alu_and(clock, ~data, sizeof(long)*8);
sr_lock(in_1,in_2,q,q1);
}
void b_trigger(long clock, long data,long *q_0,long *q_1,long *q,long *q1)
{
d_trigger(~clock,data,q_0,q_1);
long in_1 = alu_and(clock, *q_0, sizeof(long)*8);
long in_2 = alu_and(clock, *q_1, sizeof(long)*8);
sr_lock(in_1,in_2,q,q1);
}