最近又用到了iic,但是原理又有些忘记了,刚好就趁这个机会整理一下一些常用的通信协议,主要是针对协议层和寄存器的整理,均以32为例,32有关内容大部分来自《STM32中文参考手册V10》,方便日后查阅温习。
串口协议
因为也不是初学,同步异步和各种标准就不赘述了,主要讲异步
协议层内容
串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯 的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据
以32为例,每一帧数据由:
- 起始位,为1位逻辑0
- 数据内容,8或9位
- 校验位,奇偶校验,准确来说包含在数据内容里,如果需要使用校验,则其为数据内容的最后1位
- 停止位,常为1or2位逻辑1
组成,通信的双方对数据帧格式约定一致才可正常收发数据
奇偶校验
奇偶校验位分为奇校验和偶校验两种,是一种简单的数据误码校验方法。奇校验是指每帧数据中,包括数据位和奇偶校验位的全部位中1的个数必须为奇数;偶校验是指每帧数据中,包括数据位和奇偶校验位的全部位中1的个数必须为偶数。
波特率
波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。而比特率指单位时间内传输的比特数,单位 bit/s(bps)。对于 USART 波特率与比特率相等,波特率越大,传输速率越快。
而STM32的USART的发送器和接收器使用相同的波特率,计算公式为:
其中:
- fck为USART的时钟,而不同的USART挂载在不同的时钟总线上,例如USART1就是挂载在APB2总线上
- USARTDIV是一个存放在波特率寄存器(USART_BRR)中的一个无符号定点数:
其中, DIV_Mantissa[15:4] 位定义 USARTDIV 的整数部分,DIV_Fraction[3:0] 位定义 USARTDIV 的小数部分
对于小数部分,寄存器中存储的值为实际小数*16,若不为整数则取近似值;整数部分则直接取16进制
例如,假设USARTDIV值为39.0625,则:DIV_Mantissa=39=0x27,DIV_Fraction=0.062516=1=0x01=0x1,最终USART_BRR存储的值为:0x0271,*此结果是当fck为72MHz时比特率为115200bps的配置值。
通信的起始和停止
- 空闲帧:在双方没有发送或接收数据时,此时数据帧可以被视作1个完全由1组成的完整数据帧
- 断开帧:被视作全为0的帧
相关寄存器
一些比较常用的就不写了
功能引脚
SW_RX:只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚
nRTS:请求以发送 (Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当 USART 接 收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高 电平。该引脚只适用于硬件流控制
nCTS:清除以发送 (Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下 一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送(也就是下一帧不会被发送)。该引脚只适用于硬件流控制。
| STM32F10x | USART1 | USART2 | USART3 |
| :———-: | :——: | :——: | :——: |
| nCTS | PA11 | PA0 | PB13 |
| nRTS | PA12 | PA1 | PB14 |
数据寄存器DR
USART 数据寄存器 (USART_DR) 只有低 9 位有效,并且第 9 位数据是否有效要取决于 USART 控制寄存器 1(USART_CR1) 的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M 位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。
USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一 个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR 读取数据会自动提取 RDR 数据。
TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR
控制器CR、SR
发送器
USART_CR1分为两部分,一部分为上面一排,用于配置串口的有唤醒单元、中断控制等等,另一部分为图中下面一排,用于控制USART的发送器
- UE:首先,若要激活该USART,需要先将USART_CR1寄存器上的UE位置位
- M:M用于定义字长,8or9
- STOP[1:0] :若要控制帧的停止位长度,可以通过 USART 控制寄存器 2(USART_CR2) 的 STOP[1:0] 位控制
- TE:当USART_CR1发送使能位 TE 置 1 之后(发送使能),发送器开始会先发送一个空闲帧 (一个数据帧长度的高电平),接下 来就可以往 USART_DR 寄存器写入要发送的数据。
- TC:在写入最后一个数据后,需要等待 USART 状态寄存器 (USART_SR) 的 TC 位为 1,表示数据传输完成
- TCIE:如果 USART_CR1 寄存器的 TCIE 位置 1,TC置位后将产生中断。
- TXE:由硬件设置,置位则表明:数据已经从TDR移送到移位寄存器,且TDR已清空,数据发送已经开始,下一个数据可以被写进TDR。
- TXEIE:如果被设置,TXE的置位会产生一个中断
其他的位不太常用,需要的话再下来查
接收器
- RE:USART接收使能,使能后开始等待接收数据帧起始位,对于起始位的侦测有一套严格的侦测方法,但是我没怎么看懂/吹口哨,STM32中文参考手册中有详细讲,感兴趣可以去看下
- RXNE:与接收器的TXE相似,表示当前数据已被读取(包括有关的错误标志),数据已经进入RDR,随时可以被读取
- RXNEIE:RXNE对应中断
有关一些错误标志我也不整理了,感觉基本比较少遇到
校验控制
将 USART_CR1 寄存器的 PCE 位置 1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启 动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收 数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校验中断。
偶校验PS位为0,奇校验为1
中断事件
| 中断事件 | 事件标志位(该位引起中断) | 中断使能控制位 |
|---|---|---|
| 发送数据寄存器TDR为空 | TXE | IXEIE |
| CTS 标志 | CTS | CTSIE |
| 发送完成 | TC | TCIE |
| 准备好读取接收到的数据(接收移位寄存器为空) | RXNE | RXNEIE |
| 检测到上溢错误 | ORE | RXNEIE |
| 测到空闲线路 | IDLE | IDLEIE |
| 奇偶校验错误 | PE | PEIE |
| 断路标志 | LBD | LBDIE |
| 多缓冲通信中的噪声标志、上溢错误和帧错误 | NF/ORE/FE | EIE |
IIC协议
I2C 通讯协议 (Inter - Integrated Circuit) 是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单, 可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多 个集成电路 (IC) 间的通讯
物理层
物理层不是本篇重点,就简单讲一下。
IIC是一个支持多设备的总线,在一个IIC通讯总线中,可以连接多个通讯设备,它们都可以是主机或从机(主机可以简单理解为发送数据的一端,从机则为接收一端)
一个 IIC总线只使用两条总线线路,一条双向串行数据线 (SDA) ,一条串行时钟线 (SCL)。 数据线即用来表示数据,时钟线用于数据收发同步,且每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
协议层
初始化
在IIC总线空闲(初始)时,SCL和SDA都为高电平
特殊信号
I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号
起始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
停止信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的设备在接收到8位数据后,向发送数据的设备发出特定的低电平脉冲,表示已收到数据。应答信号的出现次数与数据长度有关,每接收8位数据后接收端都会向发送端发出一个应答信号
- 有效应答位:SCL为高电平时,SDA为低电平
- 非应答位:~,SDA为高电平
当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个数据帧真正地被传输完成
为确保稳定性,每次电平转换的时间要>4.7us
数据有效性
为了不将刚刚讲到的起始、停止信号误识别为数据内容,IIC协议规定了在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,而起始、停止信号则刚好是在SCL=1高电平时在SDA上发生电平跳变,这样起始、停止信号就和数据传输很好的区分开了。并且当SCL=1时,数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号而不是数据内容。只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化,因为SCL为低时,SDA的数据是无效的,不读取的。
这样就可以理解为,当SCL=1高电平时为读取SDA也就是数据的过程,每一次SCL的高电平读取1位SDA数据,在SCL=0低电平时,SDA可以改变,为下一次SCL高电平的读取做准备
地址
多数IIC设备的地址为7位或10位,通常位7位。在地址最后还要加上1位的读/写地址,所以设备地址为8位
对于读/写地址位:
- 0表示主设备向从设备写数据
- 1表示主设备从从设备读数据
例如,对于手势识别模块PAJ7620,当我们要向模块发送数据时,就要先向该模块的地址发送指定数据内容将其读/写地址位设置为0.次数该设备才可以接收主设备写来的数据
整体流程
- 主机先产生起始信号
- 紧接着发送一个设备地址,该设备地址由7位从机地址+1位数据方向位组成,此时方向位为0
- 主机将地址发送到总线上的过程中,总线上的其他设备会同时将地址逐位与自己的地址相比较,当7位从机地址匹配成功后,根据第八位数据方向位将该设备确定为发送/接收器。
- 由于地址数据也算作一帧数据,所以在设备匹配成功后,从机将会发送1个应答信号
- 对于PAJ7620,此时需要对其寄存器进行初始化,初始化成功后从机会返回1个应答信号
- 此后主机、从机之间便可正常通讯
- 若要停止该通信,需要主机发送1个停止信号
- 若要改变数据传输方向,在从机初始化完成后,主机需要再重新产生1个起始信号;之后发送设备地址,此时方向位应为1;最后主机将自身SDA的IO口设置为输入模式;
STM32的IIC硬件
STM32 的 I2C 外设可用作通讯的主机及从机,支持 100Kbit/s 和 400Kbit/s 的速率,支持 7 位、10 位设备地址,支持 DMA 数据传输,并具有数据校验功能
| STM32F10x | IIC1 | IIC2 |
|---|---|---|
| SCL | PB6/PB8(重映射) | PB10 |
| SDA | PB7/PB9(重映射) | PB11 |
时钟逻辑
STM32 的I2C外设都挂载在APB1总线上,使用APB1的时钟源 PCLK1,具体的SCL时钟计算不细讲了
数据控制逻辑
I2C 的 SDA 信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是数据寄存器 (DR)、地址寄存器 (OAR)、PEC 寄存器以及 SDA 数据线。
数据寄存器DR
当向外发送数据的时候,数据移位寄存器以DR为数据源,把数据一位一位地通过 SDA 信号线发送出去;当从外部接收数据的时候,数据移位寄存器把 SDA 信号线采样到的数据一位一位地存储到DR中。
帧错误校验计算PEC
若使能了数据校验,接收到的数据会经过 PCE 计算器运算,运算结果存储在“PEC 寄存器”中。
比较器
当 STM32 的 I2C 工作在从机模式的时候,接收到设备地址信号时,数据移位寄存器会把接收到 的地址与 STM32 的自身的“I2C 地址寄存器”的值作比较,以便响应主机的寻址。STM32 的自 身 I2C 地址可通过修改“自身地址寄存器”修改,支持同时使用两个 I2C 设备地址,两个地址分别存储在 OAR1 和 OAR2 中
整体控制逻辑
整体控制逻辑负责协调整个 I2C 外设,控制逻辑的工作模式根据我们配置的“控制寄存器 (CR1/CR2)”的参数而改变。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器 (SR1 和 SR2)”,我们只要读取这些寄存器相关的寄存器位,就可以了解 I2C 的工作状态。除此之外,控制逻辑还根据要求,负责控制产生 I2C 中断信号、DMA 请求及各种 I2C 的通讯信号 (起始、停止、响应信号等)。
硬件通讯过程
发送器
发送流程:
- 当发生起始信号后,它产生事件“EV5”,并会对 SR1 寄存器的“SB” 位置 1,表示起始信号已经发送
- 紧接着发送设备地址并等待应答信号,若有从机应答,则产生事件“EV6”及“EV8”,这 时 SR1 寄存器的“ADDR”位及“TXE”位被置 1,ADDR 为 1 表示地址已经发送,TXE 为 1 表示数据寄存器为空
- 以上步骤正常执行并对 ADDR 位清零后,我们往 I2C 的“数据寄存器 DR”写入要发送的数据,这时 TXE 位会被重置 0,表示数据寄存器非空,I2C 外设通过 SDA 信号线一位位把数据发送 出去后,又会产生“EV8”事件,即 TXE 位被置 1,重复这个过程,就可以发送多个字节数据了
- 发送数据完成后,控制 I2C 设备产生一个停止信号 (P),这个时候会产生 EV8_2 事件,SR1 的 TXE 位及 BTF 位都被置 1,表示通讯结束
接收器
可以参考发送器,应该可以推测出来
软件IIC和硬件IIC的选择
由硬件处理IIC可以减轻CPU的负担,但是配置和使用起来都较为复杂;软件模拟IIC由于是由CPU控制整个通讯时序和引脚状态,CPU占用会更多,但是相对的使用起来会比较方便,且便于移植。
SPI协议
SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface),即串行外围设备接口,是 一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率 较高的场合。
物理层
SPI使用3条总线和片选线,3 条总线分别为 SCK、MOSI、MISO;片选线(也称为 NSS、CS)用于主机片选设备:
片选信号线:当有多个 SPI 从设备与 SPI 主机相连时,设备的其它信号线 SCK、MOSI 及 MIS O 同时并联到相同的 SPI 总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就 有多少条片选信号线。
当主机要选择从设备时, 把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以 SPI 通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。
SCK时钟线:用于通讯数据同步。它由通讯主机产生,决定了通讯的速率
MOSI:主设备输出/从设备输入引脚。
MISO:主设备输入/从设备输出引脚。
需要注意的是,不同于串口中,主机的TX对应从机的RX,SPI中主机和从机的MOSI和MISO是一一对应的
协议层
时钟极性与相位
对于STM32,SPI_CR寄存器中有CPOL和CPHA位,其中CPOL位控制时钟极性,CPHA控制时钟相位。
- CPOL时钟极性:
- 置0:SCK在空闲时为低电平
- 置1:SCK在空闲时为高电平
- CPHA时钟相位:
- 置0:将SCK时钟第一边沿用作数据位采样
- 置1:将SCK时钟第二边沿用作数据采样
因此,基于不同配置的CPOL和CPHA,SPI一共有四种通讯时序:
| CPOL \ CPHA | 0 | 1 |
|---|---|---|
| 0 | 检测上升沿 | 检测下降沿 |
| 1 | 检测下降沿 | 检测上升沿 |
起始信号和停止信号
通讯的开始与结束由片选信号线控制,当主机要选择从设备时, 把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以 SPI 通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。
数据位切换
由上图可以观察出,数据位根据时钟配置不同,采样点也不同
- 当CPHA时钟相位为0时,SCK第一个信号边沿用于采集数据,第二个信号边沿用于切换数据位,为下一次采样做准备
- 当CPHA时钟相位为1时,SCK第一个信号边沿用于数据位切换,第二个信号边沿用于采集数据
同时,每个数据帧根据寄存器SPI_CR1寄存器的DFF的配置可以配置为8位或16位
STM32的SPI硬件
具体的寄存器每一位的功能请参考STM32SPI协议通信详解_rivencode的博客-CSDN博客_stm32spi通信,讲的很详细,这里我主要讲一下主机模式下的发送流程:
NSS片选线产生信号,选择设备
第一次发送时,发送缓冲区为空,因此表示其为空的TXE标志在最开始会一直为高电平
第一次发送时,第一帧数据0xF1在时钟信号产生的同时被存入发送缓冲区中,等待被发出,此时TXE为0,表示发送缓冲区非空
1个时钟周期之后,0xF1从发送缓冲区被移入移位寄存器,同时把第0位数据从移位寄存器发出,此时发送寄存器被清空,TXE硬件置1
与此同时,从机端也发送了1位数据至接收缓冲区中
在这之后,第二帧数据(不是第二位!)在1个时钟周期后被存入发送缓冲区中等待下一次的转移。发送缓冲区非空,TXE置0
与此同时,每过1个时钟周期,主机端移位寄存器发送出1位数据,接收缓冲区存入1位数据,1帧数据在8个时钟周期后被完全发送出。同时主机也收到1帧完整数据,此时RXNE标志置位,此时第一帧数据正式发送完毕
此后数据从上述第四点开始循环
假如我们使能了 TXE 或 RXNE 中断,TXE 或 RXNE 置 1 时会产生 SPI 中断信号,进入同一个中断服务函数,到 SPI 中断服务程序后,可通过检查寄存器位来了解是哪一个事件,再分别进行处理。也可以使用 DMA 方式来收发接收缓冲区中的数据。