嵌入式笔记:常用接口之详解I2C总线

 I2C (Inter-Integrated Circuit)

1. 简介

I2C (也称为 IIC) 是一种同步、多主、低速的串行通信协议,只需要两根线即可实现设备之间的数据传输,广泛应用于各种嵌入式设备中,这点在下文原理部分会进一步介绍。

2. 原理与特性

1. 双线通信
I2C 总线由两根信号线组成:

SCL:即时钟线,由主设备(Master)产生时钟信号,用于同步数据传输。
SDA:即数据线,用于主设备与从设备(Slave)之间的双向数据传输。
2. 主从结构
主设备(Master):控制总线的时钟和启动/停止数据传输。
从设备(Slave):响应主设备的请求。

I2C 支持主设备和从设备之间的双向数据传输。
3. 多设备通信
I2C 总线支持多个主设备和从设备连接到同一条总线,通过地址区分不同的从设备。

4. 硬件连接
I2C 总线通过上拉电阻连接到电源,且上拉电阻通常为 4.7 kΩ,确保空闲状态下 SDA 和 SCL 线为高电平,所有设备的 SDA 和 SCL 线分别连接到同一条总线。

3. I2C 特性

1.  多主设备:I2C 支持多个主设备,但需要仲裁机制来避免总线冲突。
2.  速度支持:I2C 支持不同的传输速度,包括标准模式 (100kbps)、快速模式 (400kbps) 和快速模式增强版 (1Mbps)。
3.  硬件简单:I2C 的硬件实现相对简单,只需要少量的外部元件。
4.  地址区分:每个 I2C 设备都有一个唯一的地址,主设备通过地址选择要通信的从设备。

4. I2C协议

1.  起始条件 (Start Condition):SCL 为高电平时,SDA 从高电平变为低电平,表示通信开始。
2.  地址传输:主设备发送 7 位或 10 位从设备地址,紧接着发送一位读/写标志位 (R/W bit)。
3.  数据传输:主设备或从设备根据读/写标志位进行数据传输,每次传输一个字节。
4.  应答信号 (ACK/NACK):从设备在接收到每个字节后,发送一个应答信号 (ACK) 表示成功接收,如果没有应答,则发送非应答信号 (NACK)。
5.  停止条件 (Stop Condition):SCL 为高电平时,SDA 从低电平变为高电平,表示通信结束。

5. 配置与使用

1.  配置 I2C 外设:
    a. 使能 I2C 外设时钟。
    b. 配置 GPIO 为 I2C 功能 (通常是 Alternate Function, Open-Drain, Pull-up)。
    c. 配置 I2C 参数(如时钟速度、地址模式等)。
2.  发送数据:主设备发送从设备地址和写标志位,然后发送要写入的数据。
3.  接收数据: 主设备发送从设备地址和读标志位,然后从从设备接收数据。

6. 示例代码 (基于STM32 HAL 库)

// 初始化 I2C
void I2C1_Init(void) {
  // 1. 使能 I2C 时钟
  __HAL_RCC_I2C1_CLK_ENABLE();
  // 2. 配置 I2C 引脚 (SCL, SDA)
  //    配置为 Alternate Function, Open-Drain, Pull-up
  // 3. 配置 I2C 参数
  I2C_HandleTypeDef hi2c1;
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000; // 100kHz
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

  HAL_I2C_Init(&hi2c1);
}

// I2C 发送数据
HAL_StatusTypeDef I2C1_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size) {
  return HAL_I2C_Mem_Write(&hi2c1, DevAddress << 1, MemAddress, I2C_MEMADD_SIZE_8BIT, pData, Size, 100);
}

// I2C 接收数据
HAL_StatusTypeDef I2C1_Read(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size) {
  return HAL_I2C_Mem_Read(&hi2c1, DevAddress << 1, MemAddress, I2C_MEMADD_SIZE_8BIT, pData, Size, 100);
}

7. 常见问题

1.  总线冲突: 当多个主设备同时尝试控制总线时,可能会发生总线冲突。需要合理的仲裁机制来解决。
2.  上拉电阻配置:SDA 和 SCL 线上拉电阻的值需要根据总线电容和传输速度进行选择。
3.  从设备应答丢失: 如果从设备没有正确应答,可能是地址错误、设备故障或其他原因。
4.  时钟速度设置: I2C 的时钟速度需要根据设备的规格和总线电容进行选择。

8. 应用场景

1.  传感器数据采集:读取温湿度传感器、气压传感器等的数据。(好吧参加过蓝桥杯单片机比赛的同学应该比较清楚,毕竟I2C的代码肯定都背过)
2.  EEPROM 存储:存储配置参数、用户数据等。(蓝桥杯一样讲过EEPROM)
3.  显示屏控制:控制 OLED、LCD 等显示屏的显示内容。
4.  电机控制:控制电机的驱动芯片。
5.  无线模块:与无线模块进行通信。

更多学习链接推荐

1. keysking视频课:I2C与温湿度测量

2. 时序图及原理讲解:https://www.bilibili.com/video/BV1RzxJeMEdy/?spm_id_from=333.337.search-card.all.click&vd_source=f68e12cdc3f47e1bbc4e154a7f74c517
 

各大学习平台都有不少对于I2C的讲解,同时包括蓝桥杯,STM32系列视频课等等,本文仅仅根据自己的理解进行简要概括总结,各位可以当作学习笔记,更多实例开发建议大家根据B站视频课进行更直观的学习。了解到许多嵌入式岗位对于I2C,SPI,UART等接口有着具体的要求,后续也会进一步学习整理其他嵌入式常用接口系列博客,欢迎各位关注学习,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值