今年入门嵌入式以来看了很多教程和文档,短时间内接触了很多新知识但是却没有相应的项目经验,所以难免混淆了一些嵌入式技术和知识。最近强化学习了一遍这些概念,看了很多别人写的文章,发现了一些之前遗漏的细节,正好写一篇笔记录整合一下看的资料。仅作为个人后续的翻阅资料。
有的教程中概念很多,比如I2C、UART、SPI、TLL、RS232等等,首先要分清楚什么是电平标准,什么是通信协议。通信协议就是一种规定好的数据格式,用这种规定好的数据格式来传输信息和进行设备之间的通信。比如我规定发送的一帧数据有多少位,第几位表示什么意思,接受设备收到数据后是否应答等等,这就是通信协议。嵌入式设备上用的这些通信协议相比计算机网络那些来讲都比较容易理解。
电平标准通俗来讲就是规定使用什么电气属性来表示“0”和“1”,其实我觉得也可以理解为一种硬件层面的协议。有了电平标准之后就可以来承载通信协议。
常见的电平标准有TTL、CMOS、RS232、RS485等等,电平标准描述转载自这篇博客和这篇博客,稍微做了一些补充后将其贴在下面
TTL电平标准如下:
供电范围在0~5V;如74系列都是5V供电
对输出:大于2.7V是逻辑高电"1";小于0.5V是逻辑低电平"0"
对输入:大于2V是逻辑高电平"1";小于0.8V是逻辑低电平"0"
注意:TTL电平输入脚悬空时内部认为是高电平,且TTL电平输出不能驱动CMOS电平输入。
如果想了解TTL电平的电路实现原理,可以看一下这篇博客
CMOS电平标准如下:
供电范围在3~15V;如4000系列(4011与非门)
假设5V供电
对输出:大于4.6V是逻辑高电平"1";小于0.05V是逻辑低电平"0"
对输入:大于3.5V是逻辑高电平"1";小于1.5V是逻辑低电平"0"
如果想了解CMOS电平的电路实现原理,可以看一下这篇博客
RS232电平标准如下:
对输出:输出“1”时的电平应在-5~-15 V之间,输出“0”时的电平应在+5~+15 V之间
对输入:输入电平在-3~-15 V之间被认为“1”,在+3~+15 V之间被认为“0”
当线路上不传送数据(空闲)时,发送器输出为“1”
可以看得出,RS232与TTL是不兼容的,TTL在输出0v的时候是RS232的非法状态,所以TTL到RS232电平标准需要电平转换芯片。而且RS232传输速率较低,在异步传输时,波特率为20Kbps。
RS485电平标准如下:
RS485 通信采用差分信号传输,通常情况下只需要两根信号线就可以进行正常的通信。
在差分信号中,逻辑0和逻辑1是用两根信号线(A+和B-)的电压差来表示。
逻辑 1:两根信号线(A+和B-)的电压差在 +2V~+6V 之间。
逻辑 0:两根信号线(A+和B-)的电压差在 -2V~-6V 之间。
也与TTL不兼容,通常会使用 485 收发器来转换 TTL 电平和 RS485 电平。RS485的数据最高传输速率为10Mbps,远高于RS232,并且因为采用差分信号传输的方式,所以抗干扰能力强。
首先要了解一些基本的概念,这些概念的解释引自这篇博客和这篇博客:
串行通信:是指计算机与I/O设备之间,同一时刻,只能传输一个bit位的信号。传输数据按顺序依次一bit位接一bit位进行传输,通常数据在一
根数据线或一对差分线上传输。
并行通信:时指计算机与I/O设备之间,通过多条传输线,可以同时传输多个bit位的信号。
同步通信:会利用一根额外的信号线,其实也就是时钟信号线,它往往是发送设备提供的时钟信号,发送设备和接收设备在发送设备提供的同一
时钟频率下完成同步。
异步通信:没有额外的一根信号线用于同步,接收者和发送者使用各自的时钟信号,接收者根据与发送者按事先约定的规来确定数据发送的开始
与结束以及数据单位的持续时间。例如异步串行通信中,一般接收双方会确定一致的停止位,数据位的个数、波特率的大小以及是否采用奇偶校验位。
单工通信:是指数据只按照一个方向传送而不能反方向传送。
半双工通信:是指两个设备之间的数据可以双向通信,但不能同时进行,同一时刻只能我发你收或者你发我收。
全双工通信:对应于半双工通信,就是可以同时双向传输数据。
波特率:指的是信号状态变化的次数或每秒传输的符号数。在通信系统中,携带数据信息的信号单元称为码元,也称为符号。
实际上波特已经是表示速率了,称为波特率只是中文习惯。波特率的单也是Symbol/秒
比特率:指的是每秒钟传输的比特数。
比特率 = 波特率 x 每个符号的比特数
上面的波特率定义是百度百科定义的,但是好像嵌入式领域中的波特率是另一种定义,看下来好像确实是用的下面这种定义:
波特率:描述信道的数据传输速度,单位是bit/s
比特率:指的是每秒钟传输的有效数据的比特数。
比特率 = 波特率 x 单个数据帧有效二进制位数的占比。
比如传输一个字节的数据(8位),再加上起始位和停止位后变成10位构成一个“符号”,每s传输960个符号,那么波特率 = 96 x 100 = 9600(bit/s),比特率 = 960 x 8 = 9600 x (8/10) = 7680(bit/s)
了解了基本的一些概念之后就可以理解常见通信协议的一些细节了。
当使用TTL电平时,发送设备和接收设备一般有三个引脚要接:
UART协议比较简单,其数据帧可由正点原子教程中的图来表示
其各数据位的作用转载自这篇博客,将其贴在下面
同样在这篇博客中还讲了UART接收双方的通信步骤,比较详细,值得一看
没有时钟线,接收方怎么确定是接收到了第几位?
异步通信使以一个字符为传输单位,通信过程中两个字符之间的时间间隔是不固定的,但是在一个字符发送的过程中,一个字符内两个相邻bit的时间间隔是固定的。(这里可以放张图)
所以只要规定好时间间隔是多久,再约定好一个字符有多少个bit(比如规定数据有几个bit,是否带奇偶检验位等等),就可以进行通信了。那怎么保证字符内相bit时间间隔固定呢,就需要在接受和发送双方约定同样的波特率,并且发送设备和接收设备都要有精密时钟振荡器/晶振来支持所设定的波特率。比如约定波特率为9600bit/s,那么一个电平持续时间(时间间隔)就应该是1/9600s
那万一发送设备和接收设备时钟不一致了呢?比如差了0.5个间隔?
这篇博客提到,对于UART来讲,只要保证在接受一个字符的时候主设备和从设备是时钟同步的即可。所以在下一个字符起始位的到来时可以依靠检测起始位来实现发送与接收方的时钟同步。
这篇博客在一篇文章中就对SPI的解释的非常详细和全面了,我也没找到还有什么其他我疑惑的地方,所以这里只是做个传送门。
这篇博客用了一个例子来解释如何根据SPI从设备的手册使用SPI进行主从通信,也写的非常详细,这里放个传送门
在重新看了正点原子的spi教程之后也解决了我一个问题,就是什么时候开始发启动然后传输信息:对于不同的spi芯片有不同的设计方式,可以根据电平手册进行设置。正点原子上使用的spi芯片可以通过设置某个寄存器来设置两种启动传输方式:
这篇博客在一篇文章中就对i2c的解释的非常详细和全面,做个传送门。
I2C 总线内部使用漏极开路输出驱动器,因此 SDA和 SCL 可以被拉低为低电平,但是不能被驱动为高电平,所以每条线上都要使用一个上拉电阻,默认情况下将其保持在高电平。所以,在传输数据的过程中,时钟线SCL为高电平时,SDA线是不能发生变化的,否则会被认为是起始或者停止信号。