iic通讯基础知识
I2C(Inter-Integrated Circuit)协议是一种串行通信协议,它允许多个设备通过两条线(一个串行数据线SDA和一个串行时钟线SCL)进行通信。这种协议由飞利浦半导体(现在的恩智浦半导体)开发,广泛应用于集成电路之间的数据传输。
以下是STM32微控制器中I2C协议的一些主要特性和概念:
1. **多主模式功能**:STM32F429微控制器支持多主模式,意味着同一接口可以用作主设备或从设备。
2. **寻址方式**:支持7位或10位设备地址,以及广播呼叫的生成和检测。
3. **通信速度**:支持不同的通信速度,包括标准速度(高达100 kHz)和快速速度(高达400 kHz)。
4. **状态标志**:包括发送/接收模式标志、字节传输结束标志和I2C忙碌标志。
5. **错误标志**:包括主模式下的仲裁丢失、地址/数据传输完成后的应答失败、检测误放的起始位和停止位、禁止时钟延长后出现的上溢/下溢等。
6. **DMA功能**:带DMA功能的1字节缓冲,可以减轻微控制器(MCU)的工作负担。
7. **兼容性**:兼容SMBus2.0和PMBus协议。
在STM32微控制器中,I2C协议的物理层特点包括:
- 支持设备的总线,允许多个I2C设备共享同一总线。
- 仅使用两条总线线路:SDA和SCL。
- 每个设备都有一个独立的地址,用于主机访问。
- 总线通过上拉电阻接到电源,当所有设备空闲时,总线保持高电平。
- 多个主机同时使用总线时,会通过仲裁方式决定哪个设备占用总线。
- 具有三种传输模式:标准模式、快速模式和高速模式。
协议层定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。I2C的通讯过程包括起始信号、发送设备地址、传输方向选择位、数据传输、应答信号、停止信号等步骤。
STM32的I2C外设可以作为通讯的主机和从机,支持100Kbit/s和400Kbit/s的速率,支持7位和10位设备地址,支持DMA数据传输,并具有数据校验功能。此外,STM32的I2C外设还支持SMBus2.0协议。
在实际应用中,STM32的I2C硬件结构包括通讯引脚、时钟控制逻辑、数据控制逻辑和整体控制逻辑。通过配置相应的寄存器,可以控制I2C的通讯速率、地址、数据传输方向等参数。
在STM32F407微控制器上使用I2C接口驱动EEPROM设备,通常涉及以下步骤:
1. **硬件连接**:确保EEPROM的SDA(数据线)和SCL(时钟线)分别连接到STM32F407的对应I2C引脚上。同时,需要为SDA线配置上拉电阻。
2. **I2C初始化**:配置STM32F407的I2C接口,设置正确的时钟速率、地址模式(7位或10位地址)、主从模式等。
3. **EEPROM地址配置**:根据EEPROM的数据手册,配置EEPROM的设备地址。例如,如果使用的是AT24C64,并且其A0、A1、A2引脚都接地,则设备地址为0xA0(写操作)或0xA1(读操作)。
4. **读写函数实现**:
- **写入数据**:首先发送起始信号,然后发送EEPROM的写地址,接着发送要写入的数据,最后发送停止信号。
- **读取数据**:发送起始信号,发送EEPROM的读地址,然后接收数据,最后发送非应答信号(NACK)和停止信号。
5. **错误处理**:在读写操作中,需要检查EEPROM的应答信号(ACK),如果没有收到ACK,可能需要重新尝试操作或处理错误。
6. **等待EEPROM就绪**:在进行写操作后,EEPROM可能需要一段时间来完成写入。在这段时间内,对EEPROM的任何操作都会失败。因此,通常需要实现一个等待EEPROM就绪的函数。
以下是一个简单的代码示例,展示了如何使用STM32F407的I2C接口向EEPROM写入和读取数据:
```c
#include "stm32f4xx_hal.h"
// 假设使用I2C1接口,EEPROM地址为0xA0(写)和0xA1(读)
#define EEPROM_I2C_ADDR_WRITE 0xA0
#define EEPROM_I2C_ADDR_READ 0xA1
// I2C初始化函数(需要根据实际情况配置)
void EEPROM_I2C_Init(void) {
// 初始化I2C接口,设置时钟速率等
// ...
}
// 向EEPROM写入一个字节的数据
HAL_StatusTypeDef EEPROM_WriteByte(uint8_t address, uint8_t data) {
HAL_StatusTypeDef status;
uint8_t tx_data[2] = {address, data};
status = HAL_I2C_Mem_Write(&hi2c1, EEPROM_I2C_ADDR_WRITE, tx_data, 2, 100);
return status;
}
// 从EEPROM读取一个字节的数据
HAL_StatusTypeDef EEPROM_ReadByte(uint8_t address, uint8_t *data) {
HAL_StatusTypeDef status;
uint8_t rx_data;
status = HAL_I2C_Mem_Read(&hi2c1, EEPROM_I2C_ADDR_READ, address, I2C_MEMADD_SIZE_8BIT, &rx_data, 1, 100);
*data = rx_data;
return status;
}
// 等待EEPROM就绪
uint8_t EEPROM_WaitReady(void) {
// 实现等待EEPROM就绪的逻辑
// ...
return 1; // 返回1表示就绪,0表示未就绪
}
// 示例:向EEPROM写入数据,然后读取回来
int main(void) {
uint8_t write_data = 0x55; // 要写入的数据
uint8_t read_data;
EEPROM_I2C_Init(); // 初始化I2C接口
// 写入数据
if (EEPROM_WriteByte(0x00, write_data) == HAL_OK) {
// 等待EEPROM完成写入
while (!EEPROM_WaitReady());
// 读取数据
if (EEPROM_ReadByte(0x00, &read_data) == HAL_OK) {
// 检查读取的数据是否正确
if (read_data == write_data) {
// 数据正确
} else {
// 数据错误
}
}
}
// 其他代码...
}
```
请注意,上述代码仅为示例,实际使用时需要根据具体的硬件配置和EEPROM型号进行相应的调整。特别是在实现`EEPROM_WaitReady`函数时,需要根据EEPROM的数据手册来正确处理写入后的等待时间。此外,HAL库函数`HAL_I2C_Mem_Write`和`HAL_I2C_Mem_Read`是STM32 HAL库提供的I2C内存读写函数,它们简化了I2C通信的复杂性。