本文使用STM32FI03RCT6型号的单片机, 基于正点原子的函数库进行总结讲解
复制
想来单片机这块儿除了USART串口通信外,常见的便是I2C通信了,因为I2C通信 硬件连接简单,可扩展性强,但是这种硬件连线的简洁,是以协议的复杂来弥补的。I2C通信是一种半双工通信,也就是可以双向传输数据但不能同时进行。
STM32单片机是可以进行硬件I2C通信或者软件模拟进行I2C通信的,硬件I2C通信只需要对I2C引脚以及通信模式这两个结构体进行初始化即可,但I2C硬件通信由于硬件原因并不稳定(原子哥说的),不过在STM32F4系列有所改善,但我都没试过(寒假在家手头硬件条件不足)。
下面我们基于软件I2C模拟进行说明。
I2C通信物理层原理
1:二线传输:I2C通信除了地线GND和电源线VCC外,只需要两条线,一条双向串行数据线(SDA),一条时钟线(SCL)。
2:无中心主机:可以多个设备并联到总线上,每一个设备都可以做为主机(或者从机)来发送,接受设备。但每一时刻只能有一个主机。
3:软件寻址:总线上的每一个设备都有一个唯一地址供识别,地址可以是7位或10位。
I2C通信协议层:传输过程
以STM32作为主设备发送数据为例:
步1:主机产生传输启示信号S,并联在总线上的所有设备都可以接收到
步2:所有从机开始准备接收接下来主机广播的从机地址,被选中设备(从设备)开始待命接收数据。其他设备便不再接收接下来的信息。
步3:主机开始向从设备发送数据,数据被拆分为数据包发送,每个数据包大小为8位(也就是一个字节一个字节的打包发送),从设备每接收到一个字节,便返回一个应答信号,主机再继续发送。
步4:如此传输N个数据后,主设备发送停止信号,数据传输停止
当主机读数据时:
主机广播完地址,接收到应答信号后,从机开始向主机返回数据包,大小也为8位。从机每发送一个包,等待主机的应答信号。如此反复发送N个字节后,当主机想要停止接收数据时,便向从机返回一个非应答信号,则从机停止数据发送。
到此我们了解了I2C通信的基本过程,但正点原子并没有直接操纵这些过程的库函数,所以我们需要需要更接近底层一步的时序问题;
1:空闲状态
总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。空闲状态就是没有数据传输的状态啦。我们需要在每次数据传输之前将总线置为空闲状态
代码如下图:
图中代码为IIC初始化代码,先开启时钟,再设置引脚PC11,PC12模式。最后红框内为将时钟线SCL和数据线SDA均置高,即初始化为空闲状态。
2:起始信号与停止信号
在上面的IIC通信流程分析中,我们在通信开始时要由主机先发一个起始信号start,停止时要发一个停止信号stop:
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
时序图如下:
ST32的代码实现:
在上面两图开头的SDA_OUT()为宏定义;含义如下图:
3:应答信号
主机每接收到一个数据包,都需要给从机返回一个应答信号A,应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
但这只是在过程上是如此,在时序上是如何进行的呢?我们知道每一个数据包都是八位,所以传输一个数据包在占据数据线SDA的同时,遵循时钟线SCL的脉冲时序(也就是一个脉冲发送一位,传输一个包需要占用8个时钟脉冲信号),而我们便在第九个时钟脉冲信号时释放数据线SDA(也就是拉低),然后空闲出来发送应答信号A。
不过我们只需要控制在该发送应答信号的第九个脉冲时序就可以了。
下面我们看代码:
上图是STM32做为主机发送数据等待从机的应答信号。
当STM32需要做出应答或者非应答信号时,便比较简单了:
在熟悉了上述过程以后,我们便可以进行写一个过程层面的函数,进行发送一整个字节或者接收一整个字节了(当然,是原子哥写的):
I2C的硬件实现:
据此我们便将I2C软件模拟的一些基本操作说完了,硬件I2C便是将上述这些我们手写的代码(原子哥手写的)作为硬件封装起来,我们只需要配置I2C模式结构体就可以了,就是下面这个结构体(注意啊,这个结构体是使用硬件I2C时使用的,别搞混了):
1:I2C_ClockSpeed设置的是I2C的传输速率
2:I2C_Mode设置的是I2C的使用模式,有I2C模式(I2C_Mode_I2C)和SMBus模式(I2C_Mode_SMBusDevice,I2C_Mode_SMBusHost)。
3:I2C_DutyCycle设置的是I2C的时钟线的占空比,可以设置高电平与时间之比为16:9(I2C_DutyCycle_16_9)或者2:1(I2C_DutyCycle_2)。
4:I2C_OwnAddress1设置的为STM32自己的I2C设备地址,每个连接在I2C总线上的设备都有一个自己的地址,作为主机也不例外。该地址可以自行设置,可以选择7位或者10位。
5:I2C_Ack设置的位I2C的应答,若为I2C_Ack_Enable,则允许应答;若为I2C_Ack_Disable,则不许应答。往往设为允许应答。
6:I2C_AcknowledgedAddress设置的为I2C寻址模式,需要根据通信对方的地址进行设置。对方地址为7位,则设置为7位寻址。