打印
[其他ST产品]

STM32---I2C

[复制链接]
366|47
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一.I2C协议1.什么是I2C协议?

各个IC之间需要进行数据交流,为了使它们互联互通,I2C出现了。I2C是通用的简单的双向两线制总线协议。在硬件方面,需要的管脚少,连接线和面积小。在软件开发时,可以使用同一个I2C驱动库来驱动不同的器件。



使用特权

评论回复
沙发
王派oo|  楼主 | 2023-7-31 15:01 | 只看该作者
2.物理层特性
SCL:串行时钟总线;时钟用于数据收发同步。

SDA:双向串行数据总线;

(1)主机和从机之间的通讯方式:每个连接到总线的设备都有一个地址,利用这个地址进行访问。(地址就是一个普通的数据);多个主机同时使用总线时,为了防止数据冲突,用仲裁方式决定由哪个设备占用总线。

(2)传输模式:常用的快速模式为400Kbit/s

(3)连接到相同总线的IC数量受到总线的最大电容400pF限制

I2C时,要SCL和SDA管脚配置成开漏输出;添加上拉电阻;在仲裁时利用了线与特性。此时线与逻辑实现不需要与门,在原本上拉电阻和开漏结构及总线基础上就可以实现。

使用特权

评论回复
板凳
王派oo|  楼主 | 2023-7-31 15:02 | 只看该作者
二.协议层
I2C的协议层包括通讯的起始位,停止位,数据有效性,响应,仲裁,时钟同步和地址广播等。

1.I2C读写过程
读过程:从机发送数据给主机

写过程:主机发送数据给从机。

使用特权

评论回复
地板
王派oo|  楼主 | 2023-7-31 15:02 | 只看该作者
复合格式:有两个起始信号。先写,写入数据是从机地址;再读,读入从机内数据。整个过程需要一个地址来找数据,因此有复合格式。

S:表示开始传输信号。1位

SLAVE ADDRESS:通讯的从机地址。7位或10位

R/W-:选择读或写。1位。取1为读。

A:应答信号;               A/A-:应答或非应答信号

P:停止信号

7(或10)位从机地址+1个读写位=8位的读/写地址

当SCL高电平时,SDA信号有效。SDA为高电平则传输数据1,低电平则传输数据0,由高转低则表示起始信号,由低转高表示停止信号。在SCL低电平时,SDA在此时一般进行电平切换,为下一次表示数据做准备。

响应:在SDA线上传输完8位读写地址之后,发送端会释放SDA的控制权,由数据接收端控制SDA。由上拉电阻上拉成高电平(高阻态状态),高电平表示未应答。当从机检测到是自己的地址时,将SDA的电平拉低为0,表示有设备响应。其他设备想在此时传输数据时,无法将SDA的电平拉高后拉低,无法传输数据。

使用特权

评论回复
5
王派oo|  楼主 | 2023-7-31 15:07 | 只看该作者
2.I2C外设
软件模拟协议:控制SDA和SCL的电平->使用CPU直接控制通讯引脚的电平

硬件实现协议:由STM32的I2C片上外设专门负责实现I2C通讯协议,只要配置好该外设,它会自动根据协议要求产生信号,收发数据并缓存起来。CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种硬件外设处理I2C协议的方法使软件设计更加简单。

使用特权

评论回复
6
王派oo|  楼主 | 2023-7-31 15:07 | 只看该作者
1.通讯引脚              SDA,SCL,SMBA(不常用),查表看对应的引脚,I2C有两套通讯线路。
2.时钟控制逻辑      CCR控制I2C时钟频率。具体过程查看CCR寄存器。主模式选项,占空比(低电平时间/高电平时间),CCR写入值的计算。可以使用库函数来便捷计算。
3.数据控制逻辑      数据寄存器(8位有效)
4.整体控制逻辑      控制寄存器start,stop; 状态寄存器TxE,RxNE,AF,ADDR,BUSY

使用特权

评论回复
7
王派oo|  楼主 | 2023-7-31 15:08 | 只看该作者
3.I2C外设通讯过程
STM32作为主发送器:

使用特权

评论回复
8
王派oo|  楼主 | 2023-7-31 15:08 | 只看该作者
I2C通讯时,在通讯的不同阶段,它会对状态寄存器写入不同的数据,通过读取寄存器标志来判断寄存器状态。在发送结束信号之前,需要检测BTF(字节发送结束,表示所有数据都发送出去了)。可使用STM32标准库函数来直接检测这些事件的复合标志。每次读取标志位之后,都要清除。

       上一行是I2C的传输数据,下一行是状态寄存器在不同阶段的动作。

使用特权

评论回复
9
王派oo|  楼主 | 2023-7-31 15:11 | 只看该作者
STM32作为主接收器:

使用特权

评论回复
10
王派oo|  楼主 | 2023-7-31 15:13 | 只看该作者
三.I2C库函数
I2C初始化结构体:ClockSpeed,Mode,DutyCycle(占空比), ownAddress(I2C设备地址), Ack(使能,允许应答), AcknowledgeAddress(指定地址长度)

ClockSpeed:支持标准模式100khz,快速模式400khz.
Mode:I2C模式,SMB主模式,SMB从模式
DutyCycle:有2:1和16:9两种。占空比是指低电平和高电平时间的比例。2:1和16:9相差不大,可以随便选用。如果高电平的时间过短,则从SDA线上读取数据的时间短,信息传输不完整。
ownAddress:STM32 I2C自身设备地址,只要在总线上是唯一即可。
AcknowledgeAddress:选择寻址模式是7位还是10位要根据实际连接到I2C总线上的设备的地址进行选择。
GeneratesSRART()产生起始信号

GeneratesSTOP()产生停止信号

FlagStatus I2C_GetFlagStatus()读寄存器位

I2CSend7bitAddress()

I2CSendData()

I2CAcknowledgeConfig()

使用特权

评论回复
11
王派oo|  楼主 | 2023-7-31 15:13 | 只看该作者
四.EEPROM


EEPROM是可重复擦除的存储器 ,掉电可保存。

型号:AT24C02

STM32与EEPROM(AT24C02)通讯时,使用I2C协议。WP写保护,接地不保护。在主机发送开始信号之后,会发送需要通讯的器件地址(EEPROM都要求有8位,包括读写位)。8位器件地址的前四位对于所有串行EEPROM都是一样的1010.接下来的三位是A0,A1,A2为器件地址位,必须与硬件输入引脚保持一致。根据图,此EEPROM的地址为1010,000。

使用特权

评论回复
12
王派oo|  楼主 | 2023-7-31 15:14 | 只看该作者
写操作:
1.字节写:在接受器件地址和ACK应答之后,接收8位的字地址,接到这个地址之后EEPROM应答0,然会主机发送8位数据,EEPROM应答0,主机发送停止信号。此时,EEPROM进入内部写周期TWR,将数据写入非易失性存储器中,在此期间的输入都无效,直到写周期完成。

2.页写:和字节写类似。不同在于,在主机把第一批数据发送出去,EEPROM应答之后,主机不会发送停止信号,而是接着发送7个(AT24C02)数据。EEPROM收到数据之后都会应答0,最后一个数据发送出去且EEPROM应答之后,主机会发送停止信号。接收到每个数据之后,字地址第三位(AT24C02)自动加1,高位不变,维持在当前页。当字地址达到该页边界地址时,随后的数据会写入该页的页首。如果超过8(AT24C02)个,字地址会回转到该页的首字节,将先前的字节覆盖。

3.应答查询:EEPROM进入内部写周期,输入都无效,此时要应答查询,保证输入的数据是有效的。查询ACK状态。

使用特权

评论回复
13
王派oo|  楼主 | 2023-7-31 15:14 | 只看该作者
读操作:
读操作和写操作初始化相同,只有读写位不同。

1.当前地址读:

       内部地址计数器保存上次访问的最后一个地址+1的值。只要芯片有电,该地址就一直保存。当读到最后一页的最后字节,地址会转到0,当写到页尾的最后一个字节,地址会转到该页的首字节。

        主机发送开始信号,发送器件地址,EEPROM应答ACK后,当前地址的数据就随时钟发送出去。主机不用应答,只需要发送停止信号。

2.随机读:主机发送开始信号,先写一个目标字地址,EEPROM接收器件地址并应答。主机发送第二个开始信号,主机再一次发送器件地址,EEPROM应答,并随时钟送出数据。主机不用应答,只需要发送停止信号。

3.顺序读:可以通过当前地址读或者随机读启动。主机接收到一个数据之后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址,随时钟发送后面的数据。主机不需应答,只需发送停止信号。

使用特权

评论回复
14
王派oo|  楼主 | 2023-7-31 15:14 | 只看该作者
五.编程
EEPROM和STM32之间使用I2C通讯。使用硬件实现协议。

I2C和USART的程序相似,可类比学习。

1.初始化I2C相关的GPIO

2.配置I2C外设的工作模式

3.编写I2C写入EEPROM的byte write函数,编写读取的random read函数(简单但效率低);编写page write和seq read函数并校验(提高工作效率)

4.使用两个读写函数进行读写校验,需要写EEPROM内部时序完成的等待函数。

使用特权

评论回复
15
王派oo|  楼主 | 2023-7-31 15:14 | 只看该作者
六.遇到了哪些问题
1.EV5事件while循环卡死:从原理上讲,STM32发送开始信号给EEPROM,检测SR1的SB是否为1来判断信号是否发出。软件读取SR1寄存器后,写数据寄存器的操作将清除该位。GetFlag库函数中,SB宏定义为0x10000001,右移28位得到0x1!=0,则I2C首地址+0x14,找到SR1。SB与上0x00ffffff,表示取低24位,即00000001,与上SR1,表示取SR1的最低位。若结果不为0,return SET。

解决办法:当GPIO管脚设置为10KHZ,且在各个EVn事件中全都使用I2C_CheckEvent库函数来检测,程序执行正常。

为什么使用GetFlag库函数来检测各个EVn事件会卡死在while循环里?GetFlag库函数和I2C_CheckEvent库函数有什么区别?

EV5检测位宏定义为0x00030001,I2C的SR2寄存器数据左移16位或上SR1数据后与上0x00ffffff,表示取SR2低8位和SR1全16位。得到的数据如果和EV5宏定义相同即成功。只要SR2低两位(BUSY总线忙,MSL处于主模式)和SR1低1位(SB发送起始信号完成)是1,则成功。                          GetFlag库函数只检测SR1->SB位是否置一,不关心其他位。在检测SB位的效果上,I2C_CheckEvent库函数和GetFlag库函数是一样的。在检测EV6时,I2C_CheckEvent库函数检测SR1低三位,SR2的1和7位,GetFlag库函数检测SR2的1位。理论上说,在检测EV6时,I2C_CheckEvent库函数和GetFlag库函数效果是一样的。但是程序下载进去后,无法实现。

接下来的EVn事件,同样地,也是使用I2C_CheckEvent库函数才能正确执行。

2.在EEPROM的等待内部时序结束的函数中,使用GetFlag库函数检测,否则卡死。

3.EEPROM写入和读出函数:PageWrite(uint8_t BYTE_WRITE_ADDR, uint8_t* Data, uint8_t numtowrite )

RandomRead( uint8_t BYTE_READ_ADDR,uint8_t *data,uint8_t numByteToRead )

表示data是uint_8t*类型的指针,指向data的首地址,在数据读写时,指针移动一次,跳过uint_8的内存大小,将data的内容逐一读写。

使用特权

评论回复
16
王派oo|  楼主 | 2023-7-31 15:15 | 只看该作者
七.软件模拟I2C
软件模拟I2C是使用板上任意两个引脚作为I2C接口SDA,SCL。将这两个引脚拉低拉高来模拟实现SDA,SCL的高低变化,从而达到模拟I2C通讯的效果。

软件模拟I2C时,两个引脚一样地配置为开漏输出。使用开漏输出的原因同样是要实现线与。当一个设备把总线拉低时,如果有其它设备读取,则不会损坏电路。开漏输出需要在外部连接上拉电阻。如果在此处中采用推挽输出,那么,可想而知,在有多个设备的时候,无法线与,会出现电流倒灌,电路短路的问题。但是,当只有一个从设备的时候,我们不需要担心是否有线与的功能,所以,在这个时候,按理来说,是可以使用推挽输出的。但是,要特别注意的是,使用推挽输出的时候,我们需要配置输入和输出模式。这是为什么呢?因为配置为推挽输出,这个引脚只能作为输出,无法读取电平。所以,在接收数据的时候,我们需要把模式改为上拉输入模式。那为什么开漏输出不需要改变输入输出模式呢?因为开漏输出的内部电路结构:引脚处电平完全由外部电平决定。而推挽输出的内部电路的特点是强上拉,强下拉,完全由内部电平决定,无论外部电平是什么。

使用特权

评论回复
17
王派oo|  楼主 | 2023-7-31 15:15 | 只看该作者
因此,只需要配置好GPIO,编写两个引脚高低电平变化的I2C开始函数,应答和非应答函数,停止函数,发送和接收函数就可以实现I2C读写操作。那么,在这个过程中,按照SDA和SCL的电平变化来编写函数是至关重要的。首先,要熟悉SDA和SCL配合工作的过程。(不再需要打开IIC的时钟,不用再配置IIC的结构体)

数据的有效性:SDA的数据必须在SCL的高电平周期保持稳定。数据线的高低变化只有在SCL是低电平时才能进行。

起始:SCL为高时,SDA由高变低。

停止:SCL为高时,SDA由低变高。

传输数据的字节格式:发送到SDA线上的字节必须是8位,字节数不受限制。每个字节后要有一个响应位。首先传输数据的最高位。

响应:数据传输必须带响应。响应期间,发送器释放SDA(高),接收器将SDA拉低

使用特权

评论回复
18
tifmill| | 2023-8-7 07:31 | 只看该作者
STM32 硬件I2C 到底怎么样?

使用特权

评论回复
19
burgessmaggie| | 2023-8-7 17:56 | 只看该作者
stm32硬件i2c缺陷解决方法

使用特权

评论回复
20
eefas| | 2023-8-7 19:50 | 只看该作者
使用STM32的I2C功能, 可以与各种外设进行通信,如传感器、存储器、显示屏等。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

247

帖子

0

粉丝