购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第9章
数字逻辑系统的时间规范

在本章的开头,暂时再次回到清单8.1所示的源代码,其中一条“_nop_()”语句的用途可能还在困扰着不少读者。看它的调用形式应该是一个函数,但我们并没有定义呀?它又起到什么作用呢?细心的读者会发现,在清单8.1开头包含了一个头文件intrins.h,它与reg51.h一样是厂商已经定义好的,打开来看看里面有什么吧,如清单9.1所示。

清单9.1 intrins.h头文件内容

从中可以看到,intrins.h头文件中有一些不太熟悉的语句,但我们可以不必理会,重点在于该文件多次使用关键字 extern 引用的一些函数。关键字 extern 的功能可以这样理解: 我后面的这些函数(或变量)在其他文件中已经定义好了,直接就可以使用。 一般系统预定义的变量名或函数名是以下划线开头的,至于具体在哪里定义的我们无需理会,有兴趣读者可以自行研究一下。

intrins.h文件中的常用函数见表9.1。

表9.1 intrins.h文件中的函数

为什么要定义这些函数呢?以“空操作”为例,我们很早就提过,当调用我们自己写的delay_us延时函数时,即使给它传递的参数是0,它还是会延时数微秒。那假设我现在的应用要求非常高,需要精确延时1μs或15μs(延时过长或过短都不行)怎么办?用C51语言可以直接实现吗?当然可以!例如,定义一个专门用来延时的全局变量,然后在需要进行1μs延时的时候就将这个变量自加1或减1。如果觉得使用起来可读性不是很强,还可以定义一个表示延时1μs的宏,如清单9.2所示。

清单9.2 使用全局变量延时1μs

虽然这种方式可以实现延时1μs,如果要延时多个微秒怎么办?使用多个delay_1us宏定义就可以吗?那还真不一定!例如,连续调用52次delay_1us宏定义,本意是想延时52μs,但说不定编译器会“自作聪明”地认为只是想把某个变量累加52次,于是把语句优化成“tmp+=52;”。很明显,优化后的语句执行速度更快,然而这肯定没能达到延时52μs的目标。就算编译器没有对它进行优化(我试着编译后没有优化,但并不代表总不会被优化),还是得考虑这种可能性,对不对?

总之,在C51语言层面实现精确的微秒延时并不太方便,但汇编语言中一条“NOP”指令就代表延时1μs。当然,还有其他一些操作在C51语言层面也不太方便实现。例如,循环移位操作就需要多条C51语句才可以完成,数据运算的效率并不高,但使用汇编语言也只需要一条指令即可完成。

为了方便程序开发者实现一些C51语言不太方便实现的操作,厂商自定义了一些函数,并将它们打包放在intrins.h头文件中,这样调用它们就相当于写汇编指令一样。程序中调用了_nop_()函数,它就是一个空指令(什么也不做),用来延时一个机器周期。对于12MHz的振荡时钟,调用一次_nop()_函数相当于延时1μs,需要多少微秒就调用多少次_nop_()即可,这是一种精确的延时,在要求比较高的场合可以使用。

那为什么需要延时语句呢?为什么是一条延时语句呢?这不得不涉及数字时序逻辑系统中的建立时间(Setup Time, t su )与保持时间(Hold Time, t hd ),前者是指在触发时钟边沿到来前,数据必须保持稳定的最小时间,而后者是指在触发时钟边沿过去后,数据需要再保持稳定的最小的时间,相应的定义如图9.1所示。

图9.1 建立时间与保持时间

图9.1告诉我们:为了保证数据能够被可靠地触发,我们必须在时钟触发边沿(此处为上升沿)时刻提前 至少 一段时间( t su )将数据准备好,并在时钟触发边沿后数据应该保持稳定状态 至少 一段时间( t hd )才行。如果 t su t hd 不满足要求,触发器将进入一种介于状态0与1之间的不确定状态(亚稳定状态),这在数字逻辑系统中是不允许的。

为了进一步理解建立与保持时间,我们先介绍传播延时(Propagation Delay)的概念。它是指输入信号与输出信号在各自50%跳变点之间的时间间隔,通俗来说,它是信号从输入到输出所需要的时间,在数据手册中通常以符号 t PHL t PLH 来标记。例如,非门逻辑的传播延时定义如图9.2所示。

图9.2 传播延时

图9.2中的 t THL 表示输出从高电平的90%下降到10%所需要的转换时间(Transition Time),而 t TLH 输出从高电平的10%上升到90%所需要的时间,它们与 t PHL t PLH 的意义不同。一般输出转换时间要小于传播延时。

不同器件的信号传播路径不尽相同,数据手册中可能会标注多个不同的传播延时,比较典型的是 时钟到数据输出 以及 异步清零或置位端到数据输出 之间传播延迟。下面我们来看看74HC595数据手册中标注的交流参数(AC Characteristics),见表9.2。

表9.2 交流参数(C L =50pF,V CC =4.5V,T A =25℃)

74HC595内部的移位寄存器与锁存器各有一个时钟,所以定义了SH_CP到Q7′以及ST_CP与Q n 之间的传播延时,有些资料也称为时钟输出延迟 t co (Clock to Output Delay),它们表示以时钟有效边沿触发时刻为基准,最大多长时间后输出数据才是有效的,相应的波形如图9.3所示。

图9.3 时钟相关的传播延时

t PHZ t PLZ 也是相同的道理,只不过是以使能的边沿为参考定义的传播延时,相应的参数标记如图9.4所示。

图9.4 使能相关的传播延时

任何走线或电路模块都存在一定的传播延时,对于一个单纯的触发器而言,它本身有效触发数据需要的建立时间与保持时间并不长(一般小于1ns,为区别于电路系统宏观层面的 t su t hd ,我们分别标记为 t su_reg t hd_reg ),但是数字逻辑系统的设计需要考虑更多的因素(例如功能实现、速度、驱动能力等),为此我们很有可能在触发器的数据或时钟输入引脚插入一些必要的逻辑电路。例如,在图8.2所示功能框图中,输入引脚DS、SH_CP、ST_CP、 都串联了两个非门(缓冲器),所以我们应该使用图9.5来描述通用时序逻辑的电路结构。

图9.5 通用的时序逻辑电路结构

图9.5中填充的椭圆代表着走线或(线路上可能存在的)逻辑电路的传播延时,触发器只是整个电路系统的一部分。换句话说,传播延时的存在改变了整个电路系统的时钟建立与保持时间。假设数据延迟( t p_data )、时钟延迟( t p_clk )、触发器本身需要建立时间( t su_reg )与保持时间( t hd_reg )是已知的,则整个电路系统需要的最小建立时间为 t su = t p_data -t p_clk + t su_reg ,需要的最小保持时间为 t hd = t p_data -t p_clk + t hd_reg

这两个计算公式怎么理解呢?以建立时间为例,假设 t p_data t p_clk 均为0,那么电路系统需要的最小建立时间就是触发器本身需要的 t su_reg ,如果仅 t p_data 不为0,说明数据输入线路有传播延迟,为了使触发器能够正常触发数据,输入数据得提前一些时间( t p_data )准备好。也就是说,数据线路存在的传播延迟将导致电路系统需要的建立时间增加。相反, t p_clk 将导致电路系统需要的建立时间减小。

我们来看看74HC595中的时序要求(Timing Requirements),见表9.3。

表9.3 时序要求(V CC =4.5V,T A ≤85℃)

根据不同的测试环境, t su t hd 会在一定的范围内变化,此处仅选择 V CC =4.5V时相应的数据(2.0V低压供电时需要的建立与保持时间会成倍提升),我们需要关注的是 最小值 ,在单片机编程时只要保证建立与保持时间不小于最小值即可。虽然表9.3中的 t su t hd 都没有超过20ns,但为了保证设计裕量,至少应该将其设置为1μs以上,有时为了代码的健壮性还可以多延时数微秒,这样即使碰到一个性能特别差的芯片(例如,老板为了省钱使用便宜的兼容替代芯片)也可以保证电路系统的正常运行,在速度要求不是很高的情况下可以这么做。当然,过多的延时也是没有必要的。

同样我们来看看74HC595数据手册中关于建立与保持时间的定义,如图9.6所示。

图9.6 74HC595的建立与保持时间定义

74HC595中的移位寄存器与锁存器都有各自的时钟,它们都有相应的建立时间与保持时间。图9.6a表达的是:必须在串行数据DS设置好且保持稳定的时间不小于 t su 后,才能在SH_CP引脚产生一个上升沿进行数据触发的移位操作。同样,也必须在SH_CP引脚产生上升沿后,继续保持串行数据DS的稳定时间不小于 t hd 。如果建立时间或保持时间太短,将可能无法正确将数据进行移位操作。

类似地,图9.6b表达的是:当通过SH_CP引脚的上升沿把数据移入移位寄存器后,可以在ST_CP引脚产生上升沿将数据进行锁存,但必须保证两个上升沿之间的间隔不应该小于 t su ,因为时钟触发边沿过后必须经过一定的时间才能得到有效的数据输出,它还得经过线路延时及满足锁存器的建立时间。换句话说,我们必须得保证移位寄存器的数据输出是稳定的。虽然图9.6中并没有给ST_CP上升沿定义 t hd ,但是却定义了一个脉冲宽度最小值 t w ,它们本质上也是为满足保持时间而存在的。

等等,导演,刚刚有个问题忘问了:表9.2中的 f max 是怎么定义的呢?它跟触发器的建立与保持时间密切相关,我们来看图9.7所示电路结构。

图9.7 电路结构

图9.7中的 t p_clk1 t p_clk2 表示不同时钟线路可能存在的传播延时,这将导致不同寄存器的输入时钟边沿相位有所偏移,我们称为 时钟偏斜 (clock skew),它定义为不同时钟线路的传播延时之差(即 t clk_skew = t p_clk2 -t p_clk1 ),那么该电路最小时钟周期为 t clk = t co + t p_data + t su_reg -t clk_skew ,怎么理解呢?也就是说,当第一个时钟边沿到来后,前一个寄存器(U 1 )的输出数据经过一定的传播延时准备给下一个寄存器(U 2 )触发,如果输入的时钟频率太快,U 2 在触发边沿到来时输入数据还没有准备好,因为它还在线路上传播,对不对?所以我们必须限定一个最小时钟周期 t clk ,它对应最大时钟频率 f max =1/ t clk 。假设 t co t p_data t su_reg、 t clk_skew 分别为1ns、50ns、1ns、1ns,则相应的最大时钟频率为1/53ns≈18.87MHz。

图9.8所示时序图将有助于理解 t clk f max )的来源(假设 t clk_skew >0)。

图9.8 时序图

在图9.8中,第一个clk 1 上升沿将输入数据D 1 送到触发器U 1 的输出Q 1 ,第二个CLK 2 的上升沿将D 2 (即经过延时的Q 1 )送到触发器U 2 的输出Q 2 。以第二个CLK 2 上升沿为基准,可以得到U 2 的建立时间 t su = t clk + t clk_skew -t co -t p_data ,保持时间 t hd = t co + t p_data -t clk_skew t hd t clk 之间没有直接的约束关系)。也就是说,如果由我们提供时钟来驱动某个时序逻辑电路,必须保证 t su > t su_reg

那如何进一步提升最大时钟频率呢?从前面的讨论可以知道,限制时钟频率提升的“大头”在于数据线路的传播延时,可以采用插入寄存器的方式将传播延时较大的逻辑电路进行拆分,如图9.9所示。

图9.9 插入寄存器后的电路结构

同样使用前述传播延时数据,插入寄存器(U 3 )后,50ns的线路延时分解成为2个25ns的延时,这样前后两个数据传播延时都下降到了28ns,相应的最大时钟频率约为35.7MHz。如果插入更多寄存器将线路延时进行合理拆分,时钟频率还会进一步提升,这就是很多处理器为提升时钟频率与运算速度而插入“流水线”最基本原理(当然,涉及架构问题会复杂得多,因为提升频率只是一种手段,真正的目的是为了加快数据处理速度)。

74HC595的最大时钟频率也是同样的道理,从图8.2可以看到,移位寄存器的数据输出紧接着下一个移位寄存器的输入,中间并没有连接额外的组合逻辑,所以移位寄存器的最大时钟主要取决于 t co (也就是SH_CP到Q7′的 t PHL / t PLH )与寄存器本身需要的最小建立时间 t su_reg 。从表9.2可以看到, t PHL / t PLH 最大为40ns,建立时间假设为1ns(不是表9.3中的14ns,那是对整个芯片电路而言,而不是触发器本身),则相应的时钟频率约为24MHz。这种计算结果当然并不准确,因为数据手册并没有提供给更多的数据,重点在于给大家介绍时钟频率及相关的时间参数概念,透彻理解它们将会对芯片设计非常有用,即便读者并非有志于此,也有利于深入理解数字逻辑电路的工作原理。

现在回到清单8.1的write_74hc595函数中,把将“byte_data<<=1”语句放在串行数据设置之后,就是为了在SH_CP产生触发上升沿之前进行一定的延时,即使把它放在“SH_CP=1”语句之后,功能上也同样没有发生变化。从编译的结果来看,“byte_data<<=1”语句被分解成了三条汇编语句(即耗时3μs),为了代码的健壮性,我们还加了延时1μs的“_nop_()”语句。

有人可能会问:“SH_CP=1”语句后面是否需要延时呢?因为最后一次产生移位时钟上升沿后,马上就要产生锁存时钟的上升沿,而前面已经提过,这两个边沿之间也有一个最小的建立时间。其实没有必要!因为这两个时钟上升边沿的产生并不是由紧挨着的语句完成的,期间还要执行for语句中的累加与判断指令,也就相当于(至少)延时了2μs。 SmQbrkXOEfAgtn0KdIyPJE3+rbnwXIL8ZWIeT0CEfVBnhgRFUUagFiL9A42cvh3m

点击中间区域
呼出菜单
上一章
目录
下一章
×