ST单片机的I2C总线操作分为主机模式与从机模式。做主机时,由主机提供时钟驱动。在通讯的过程中相关的硬件寄存器会根据某些事件的发生而置位。这样通信的双方就可以根据这些事件标志来控制通信的过程。在实际程序中有两种用法,一种是阻塞式的等待查询法。这种方式下通信过程是在不停地检查各种特定事件的过程中完成的。还有一种是中断处理法,I2C硬件在工作时会产生中断,应用程序在中断处理程序里检查各种硬件中断标志来完成通信过程。下文主要来源于ST的官方标准库文件stm8l10x_i2c.h
I2C主机模式下的事件(按通信流程顺序描述)
通讯开始时的EV5
在主机发送开始信号START(I2C_GenerateSTART()函数)之后必须等待EV5事件。此事件出现意味着可以在I2C总线上开始通讯(总线是空闲状态)该时间完成标志在库文件中被定义为:
I2C_EVENT_MASTER_MODE_SELECT = (uint16_t)0x0301
从机确认地址的EV6
在检查EV5后,主机发送从机地址(使用I2C_Send7bitAddress()函数),这个函数还确定本次通信的方向:做发送端或是接收端
然后主机必须等待从机设备发出确认信号ACK。
如果确认信号出现,那么:
1)如果是主机作接收端(7位地址)
那么会是I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED标志被触发。
2)如果是主机作发送端(7位地址)
那么会是I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED标志被触发。
3)在10位寻址模式下,主机在发出SRART信号并且检查EV5事件后必须发送10位寻址模式的地址头部分(使用I2C_SendData())
然后主机应该等待EV9事件。EV9事件出现意味着10位寻址模式下的地址头部已经被正确地发送到了总线上。然后,主机应当发送10位地址模式下的地址尾部LSB(使用I2C_Send7bitAddress()).然后主机等待EV6事件;
EV6
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED = (uint16_t)0x0782
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED = (uint16_t)0x0302
EV9(10位地址模式下才会出现)
I2C_EVENT_MASTER_MODE_ADDRESS10 = (uint16_t)0x0308
通信过程中的事件:
如果通信已经建立,主机就要开始检查以下事件
1)如果是主机接收模式:主机必须要等待EV7事件,然后接收从机发来的数据(I2C_ReceiveData() function)
2)如果是主机发送模式:主机要马上发送数据(I2C_SendData()),然后等待事件EV8或EV8_2
EV8和EV8_2事件非常相似,但有以下不同:
-EV8事件意味着要发送的数据已经被写入到了数据寄存器,正在逐次进入物理发送器。
-EV8_2事件意味着数据已经确实进入了物理发送器,并且出现在了总线上。
在大多数情况下,使用EV8已经足够了。如果同时还要检查EV8_2事件会导致通信过程变慢,但是这样可以使通信过程有更高的可信度。EV8_2也比EV8更合适用来检查最后一部分数据是否已经成功发送(在STOP信号前的最后数据)
要注意的是,如果我们的软件不能确认最后的字节结尾已经被发送。那我们可以通过同时检查EV7事件和BTF标志(比如. (I2C_EVENT_MASTER_BYTE_RECEIVED | I2C_FLAG_BTF))来确认这一点。不过在这种情况下通信会变慢。
EV7:
I2C_EVENT_MASTER_BYTE_RECEIVED = (uint16_t)0x0340
主机发送模式:
EV8:
I2C_EVENT_MASTER_BYTE_TRANSMITTING = (uint16_t)0x0780
EV8_2
I2C_EVENT_MASTER_BYTE_TRANSMITTED = (uint16_t)0x0784
*********************************************************************************************************************************
I2C从机模式下的事件(按照通信过程描述)
通信开始时的事件
首先,单片机作从机时要通过I2C_AcknowledgeConfig()函数使能自己的应答模式。另外要设置自己的通信地址。这个地址在I2C_OwnAddress1字段中。
主机发送了开始信号START并跟随发送了从器件地址后,从机会检查地址是否与自己匹配。如果匹配则会发送一个ACK信号:
1)在一般情况下当主机发送的地址和自己的地址匹配时会出现EV1事件
I2C_EVENT_SLAVE_XXX_ADDRESS_MATCHED
xxx会是TRANSMITTER或RECEIVER:
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED
I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED
2)如果主机发送的是统一呼叫(发送地址是0x00),并且从机使用函数I2C_GeneralCallCmd()使能了统一呼叫应答。那么也会出现EV1事件
I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED
EV1:
一般情况下:
I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED = (uint16_t)0x0202
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED = (uint16_t)0x0682
统一呼叫情况下:
I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED = (uint16_t)0x1200
在EV1事件出现后:
如果是从机接收模式:
EV2: 收到字节数据.
I2C_EVENT_SLAVE_BYTE_RECEIVED = (uint16_t)0x0240
EV4:通信结束(主机发送一个停止信号STOP终止通信).
I2C_EVENT_SLAVE_STOP_DETECTED = (uint16_t)0x0010
从机发送模式下:
EV3:从机发送完毕一个字节数据:
I2C_EVENT_SLAVE_BYTE_TRANSMITTED = (uint16_t)0x0684
I2C_EVENT_SLAVE_BYTE_TRANSMITTING = (uint16_t)0x0680
EV3_2:主机发送了NACK信号,之后从机就等待主机发送STOP信号也就是EV4事件;
I2C_EVENT_SLAVE_ACK_FAILURE = (uint16_t)0x0004
接收模式下事件I2C_EVENT_SLAVE_BYTE_TRANSMITTED和I2C_EVENT_SLAVE_BYTE_TRANSMITTING功能很接近.I2C_EVENT_SLAVE_BYTE_TRANSMITTING事件检测是可选的。用于确认EV3事件发生时数据传输正确完成。
正常通信时的时序: