I2C外设简介
STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担;软件只需要写入控制寄存器CR和数据寄存器DR,当然,为了实时监控时序的状态,软件还需要读取状态寄存器SR,来了解外设电路当前处于什么状态。
支持多主机模型。
支持7位/10位地址模式。
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)。
支持DMA。
兼容SMBus协议。
STM32F103C8T6 硬件I2C资源:I2C1、I2C2。(软件I2C,想开几路就可以开几路,而硬件I2C需要考虑资源问题,这算是软件I2C的优势)
I2C框图

SDA和SCL是两个通信引脚,而SMBALERT是SMBus使用的,I2C不需要管他。
查询引脚定义表,可以看到引脚所复用的GPIO口引脚标号:


SDA部分

上面这一块是SDA,也就是数据控制部分,数据收发的核心部分是数据寄存器和数据移位寄存器
。
当我们需要发送数据时,可以把一个字节数据写到数据寄存器DR,当移位寄存器没有数据移位时,这个数据寄存器的值,就会进一步转到移位寄存器里,在移位的过程中,我们就可以直接把下一个数据放到数据寄存器里等着了,一旦前一个数据移位完成,下一个数据就可以无缝衔接,继续发送,当数据由数据寄存器转到移位寄存器时,就会置状态寄存器的TXE位为1,表示发送寄存器为空。
当我们需要接收数据时,输入的数据一位一位的从引脚移入到移位寄存器里,当一个字节的数据收齐之后,数据就整体从移位寄存器转到数据寄存器,同时置标志位RXNE,表示接收寄存器非空,这时我们就可以把数据从数据寄存器读出来了。
SCL部分

时钟控制是用来控制SCL线的,在这个时钟控制寄存器写对应的位,电路就会执行对应的功能。
控制逻辑电路,写入控制寄存器,可以对整个电路进行控制,读取状态寄存器,可以得知电路的工作状态。
I2C基本结构

因为I2C是高位先行,所以移位寄存器是向左移位。
在发送的时候,最高位先移位出去,在发送的时候,最高位先移位出去,然后是次高位,一个SCL时钟,移位一次,移位8次,这样就能把一个字节,由高位到低位,依次放到SDA线上了。
在接收的时候,数据通过GPIO口从右边依次移进来,最终移8次,一个字节就接收完成了。
GPIO口这里,使用硬件I2C时,这两个对应的GPIO口,都要配置成复用开漏输出的模式。
开关控制也就是I2C_Cmd,配置好了就使能外设就行了。
硬件I2C操作流程
主机发送

当STM32想要指定地址写的时候,就要按照主发送器传送序列图来进行,有7位地址的主发送和10位地址的主发送,它们的区别就是:
7位地址,起始条件后的一个字节是寻址。
10位地址,起始条件后的两个字节都是寻址;其中前一个字节,这里写的是帧头,内容是5位的标志位11110+2位地址+1位读写位,后一个是纯粹的8位地址。(知道就行,不需要太深入)
起始条件之后,会发生EV5事件,这个EV5事件,可以把它看成是标志位,手册中都是用EV(Event)X事件来代替标志位的,那为什么不直接用标志位呢?那是因为有的状态会产生多个标志位,所以就用事件来代替了。EV5事件:就是SB(Start Bit)标志位为1,SB是状态寄存器的一个位,表示了硬件的状态,SB置1,代表起始条件已发送。当软件读取了SR1寄存器后,也就是查看了SB这一位,然后写数据寄存器会将该位清零。所以SB不需要手动清除。
当EV5事件产生后,就可以发送一个字节的从机地址了,从机地址需要写到数据寄存器DR中,写入DR之后,硬件电路就会自动把这一个字节转到移位寄存器里,再把这个字节发送到I2C总线上,之后硬件会自动接收应答并判断。如果没有应答,硬件就会置应答失败的标志位,然后这个标志位可以申请中断来提醒我们。
当寻址完成之后,会发生EV6事件,即ADDR标志位为1,ADDR标志位在主模式状态下代表地址发送结束。
EV6结束后,是EV8_1事件,即TxE标志位为1,移位寄存器非空,数据寄存器空,这时需要我们需要写入数据寄存器DR进行数据发送了。DR会立刻转移到移位寄存器进行发送。
把所有数据都发送后,会产生EV8_2事件,即移位寄存器空,数据寄存器空。
主机接收

软件/硬件I2C对比
