一、串行数据的时钟同步问题
串行数据的发送(如USB,UART,I2C, SPI等)是通过一条数据总线发送,于是就有如果通过一条数据总线连续发送连续的01信号给接收设备,由于发送者和接受者的时钟频率不同,信号的同步是个问题,举个例子,接受者接收到一段连续时间的低电平,无法得知这究竟代表3个0还是10个0。
二、I2C和SPI数据的时钟同步
解决上面的问题的办法I2C和SPI是在传输数据信号的同时,附加一个时钟信号,用来同步两端的数据传输,接受者可以在时钟信号的辅助下进行数据采样,就能正确得到发送过来的数据了;例如I2C的SDA用来传输数据,SCL来传输同步时钟;
这样做的可以解决时钟同步的问题,但是会附加一条额外的时钟信号线;
三、USB的数据时钟同步
USB的数据通信就不需要添加时钟信号线,也能保持两端的同步,其采用的NRZi(Non-Return-to-Zero InvertedCode)编码进行数据通信;在这之前,先解释下什么是RZ(Return-Zero code)编码。
在RZ编码中,正电平代表逻辑1,负电平代表逻辑0,每传输完一位数据,信号返回0电平,也就是信号线上会出现3种电平:正电平、负电平、零电平
从上面的图形来看,接受者只需要在信号归零后进行数据采样,就可以得到数据线上传输的实际的数据即可;这样做的有点就是相当于把时钟信号用归零编码到了数据之内,也就是实现了I数据的自同步。但是虽然省略了时钟线,当时会在实际数据传输中加入了归零操作,那么会有一半的数据带宽用来做归零操作,这其实是很大的浪费;
而使用的非归零编码(NRZ)则把归零操作取掉,很好的解决了带宽浪费的问题,但是由下图又可以知道,虽然解决了带宽问题,但是时钟同步问题又回来了
同理USB采用的NRZI编码,改编码就是用信号翻转表示一个逻辑,在USB传输中,电平翻转代表0,电平不变表示1;翻转的信号本身可以作为一种通知机制,而且可以看到,即使把 NRZI 的波形完全翻转,所代表的数据序列还是一样的,对于像 USB 这种通过差分线来传输的信号尤其方便;同该编码同样具有时钟同步的问题;
在USB可以使用一个同步域来解决时钟同步的问题,每个USB的数据包,最好都有个同步域,固定值为0000 0001,这个值经过NRZI编码之后就是一串方波,由此接受者可以确定数据的时钟频率,从而可以解析到正确的数据;
但是,这样还是会有一个问题,就是虽然接收者可以主动和发送者的频率匹配,但是两者之间总会有误差。
假如数据信号是 1000个逻辑1,经过 USB 的 NRZI 编码之后,就是很长一段没有变化的电平,在这种情况下,即使接受者的频率和发送者相差千分之一,就会造成把数据采样成 1001个或者 999个了。
USB对这个问题的解决办法,就是强制插0,也就是传说中的bit-stuffing,如果要传输的数据中有6个连续的1,发送前就会在第6个1后面强制插入一个0,让发送的信号强制出现翻转,从而强制接受者进行频率调整。这就使得接收器,逻辑上每7个位至少会出现一次电平转换,用来保证数据和时钟同步。接受者只要删除6个连续 1 之后的0,就可以恢复原始的数据了。
四、UART
UART是异步通信,异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的);
UART的数据传输格式
其中各位的意义如下:
起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。