什么是IIC通信协议?
IIC(Inter-Integrated Circuit)通信协议,又称为I2C(Inter-Integrated Circuit 2)协议,是一种广泛使用的串行通信协议。它由飞利浦半导体公司(现NXP Semiconductors)开发,用于连接微控制器和其他设备,实现数据的串行传输。
IIC协议的基本原理
I2C协议使用两条线进行通信:数据线(SDA)和时钟线(SCL)。这两条线通过上拉电阻连接到电源,确保在空闲状态下保持高电平。I2C协议支持多主设备和多个从设备,通过每个设备的地址来区分通信目标。
IIC协议的关键特性
- 双向通信:I2C协议支持双向数据传输,即主设备可以发送数据给从设备,也可以从从设备接收数据。
- 多主模式:允许多个主设备连接到同一条总线上,通过仲裁机制来选择唯一的主设备进行通信。
- 多从模式:I2C总线可以连接多个从设备,每个从设备都有唯一的地址,主设备通过地址来选择要通信的从设备。
- 速率灵活:I2C总线的速率可以根据应用需求进行调整,常见的速率有100 kHz(标准模式)、400 kHz(快速模式)和3.4 MHz(高速模式)。
- 低成本:I2C总线只需要两根线进行通信,降低了硬件成本和复杂性。
IIC协议的应用场景
I2C协议被广泛应用于各种数字芯片间的通信,例如:
- 传感器与微控制器之间的通信:如温度传感器、湿度传感器、加速度计等。
- 存储器芯片:如EEPROM和RTC芯片,用于数据的读写和时钟管理。
- 控制外设设备:如LED驱动器、LCD控制器、扩展IO芯片等。
- 显示器控制器:如OLED显示屏、液晶显示模块等。
- 工业自动化领域:如工业传感器、PLC等。
IIC协议的通信过程
I2C通信过程包括以下几个步骤:
- 起始信号:主设备发送一个起始信号,表示开始通信。
- 发送从设备地址:主设备发送从设备的地址和读/写位。
- 应答信号:从设备确认收到地址并发送应答信号。
- 数据传输:主设备和从设备之间进行数据的发送和接收。
- 停止信号:通信完成后,主设备发送停止信号,表示通信结束。
IIC协议的代码示例
以下是一个简单的I2C通信的代码示例,展示了如何使用STM32微控制器通过软件模拟I2C协议来读取AT24C02 EEPROM的数据。
#include "stm32f10x.h"
#include "delay.h"
#define I2C_SCL_PIN GPIO_Pin_6 // 定义SCL引脚
#define I2C_SDA_PIN GPIO_Pin_7 // 定义SDA引脚
#define I2C_SCL_PORT GPIOB // 定义SCL引脚所在的端口
#define I2C_SDA_PORT GPIOB // 定义SDA引脚所在的端口
// I2C延时函数
void I2C_Delay(void) {
delay_us(5);
}
// I2C初始化函数
void I2C_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_SCL_PORT, &GPIO_InitStructure);
// 释放总线
I2C_SCL_PORT->BSRR = I2C_SCL_PIN;
I2C_SDA_PORT->BSRR = I2C_SDA_PIN;
}
// I2C起始信号
void I2C_Start(void) {
I2C_SDA_PORT->BSRR = I2C_SDA_PIN; // SDA高电平
I2C_Delay();
I2C_SCL_PORT->BSRR = I2C_SCL_PIN; // SCL高电平
I2C_Delay();
I2C_SDA_PORT->BRR = I2C_SDA_PIN; // SDA低电平,开始信号
I2C_Delay();
I2C_SCL_PORT->BRR = I2C_SCL_PIN; // SCL低电平
}
// I2C停止信号
void I2C_Stop(void) {
I2C_SDA_PORT->BRR = I2C_SDA_PIN; // SDA低电平
I2C_Delay();
I2C_SCL_PORT->BSRR = I2C_SCL_PIN; // SCL高电平
I2C_Delay();
I2C_SDA_PORT->BSRR = I2C_SDA_PIN; // SDA高电平,停止信号
}
// I2C发送一个字节
void I2C_SendByte(uint8_t byte) {
uint8_t i;
for (i = 0; i < 8; i++) {
I2C_SDA_PORT->BRR = I2C_SDA_PIN; // SDA低电平
if (byte & 0x80) {
I2C_SDA_PORT->BSRR = I2C_SDA_PIN; // SDA高电平
}
I2C_Delay();
I2C_SCL_PORT->BSRR = I2C_SCL_PIN; // SCL高电平
I2C_Delay();
I2C_SCL_PORT->BRR = I2C_SCL_PIN; // SCL低电平
byte <<= 1;
}
I2C_SDA_PORT->BSRR = I2C_SDA_PIN; // SDA释放,准备接收应答
I2C_Delay();
I2C_SCL_PORT->BSRR = I2C_SCL_PIN; // SCL高电平
I2C_Delay();
I2C_SCL_PORT->BRR = I2C_SCL_PIN; // SCL低电平
}
// I2C读取一个字节
uint8_t I2C_ReadByte() {
uint8_t i, byte = 0;
I2C_SDA_PORT->ODR &= ~I2C_SDA_PIN; // SDA输入模式
for (i = 0; i < 8; i++) {
byte <<= 1;
I2C_SCL_PORT->BSRR = I2C_SCL_PIN; // SCL高电平
I2C_Delay();
if (I2C_SDA_PORT->IDR & I2C_SDA_PIN) {
byte |= 0x01;
}
I2C_SCL_PORT->BRR = I2C_SCL_PIN; // SCL低电平
I2C_Delay();
}
return byte;
}
// 从AT24C02读取一个字节数据
uint8_t AT24C02_ReadByte(uint16_t addr) {
uint8_t data;
I2C_Start();
I2C_SendByte(0xA0 << 1); // 发送设备地址和写命令
I2C_WaitAck();
I2C_SendByte(addr >> 8); // 发送高地址字节
I2C_WaitAck();
I2C_SendByte(addr & 0xFF); // 发送低地址字节
I2C_WaitAck();
I2C_Start();
I2C_SendByte(0xA1 << 1); // 发送设备地址和读命令
I2C_WaitAck();
data = I2C_ReadByte();
I2C_Stop();
return data;
}
int main(void) {
I2C_Init();
uint8_t data = AT24C02_ReadByte(0x00); // 从地址0x00读取数据
// ... 其他操作
while (1) {
// ... 主循环
}
}
以上代码展示了如何初始化I2C接口,发送起始和停止信号,以及如何发送和接收数据。在实际应用中,可能需要根据具体的硬件连接和设备地址进行适当的调整。通过理解和掌握I2C协议的原理和编程方法,可以实现微控制器与其他设备的高效通信。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
点击领取更多详细资料