第九章: I²C 模块 —— 给你的芯片装上“微信”!
【摘要】 本文系统讲解I²C通信协议及其应用,通过"微信群聊"类比阐释I²C工作原理:两根总线(SDA/SCL)实现多设备通信,MCU作为"群主"通过地址寻址管理设备。重点解析MCP4017数字电位器的控制方法,提供完整的STM32CubeMX配置指南(引脚设置、时钟配置)和底层驱动代码(含EEPROM读写修复)。内容涵盖硬件设计要点(上拉电阻必须)、地址计
🗣️ I²C 模块 —— 给你的芯片装上“微信”!
✅ 适用对象:嵌入式初学者、电子爱好者
💡 核心目标:理解 I²C 是什么 + 掌握硬件连接 + 学会用 CubeMX 配置 + 能驱动 MCP4017 等设备
🧠 特色:用“微信聊天”比喻通信过程,用“群聊”解释多设备共存,小白秒懂!
🤝 一、什么是 I²C?
I²C 全称 Inter-Integrated Circuit(集成电路互连),是一种芯片之间“聊天”的协议。
📱 生活比喻:
想象你家有个“智能家居群”:
- 微控制器(MCU) = 群主(大脑)
- 温度传感器、EEPROM、电位器 = 群成员
- SDA(数据线)+ SCL(时钟线) = 微信群聊通道
它们只用两根线就能互相发消息、收数据,高效又省线!
🏠 二、举个栗子:智能温控系统
假设你有一个房间温控系统:
-
连接:
MCU 和 温度传感器 通过 SDA(数据线) 和 SCL(时钟线) 连在一起。 -
通信:
MCU 发消息:“@温度传感器,现在多少度?” → 发送 I²C 请求 -
响应:
传感器回复:“25℃!” → 通过同一总线返回数据 -
处理:
MCU 收到后决定:“太热了,开空调!” → 完成闭环控制
✅ 关键点:所有对话都在同一对线上完成,靠“地址”区分谁在说话!
🔌 三、硬件原理图 & 电气特性

1. I²C 总线接线(超简单!)
| 信号 | 引脚 | 说明 |
|---|---|---|
| SCL | MCU 的 I²C_SCL 引脚 | 时钟线,由主机(MCU)控制节奏 |
| SDA | MCU 的 I²C_SDA 引脚 | 数据线,双向传输 |
| 上拉电阻 | 通常 4.7kΩ 接 VCC | 必须加! 因为 I²C 是开漏输出 |
⚠️ 重要提醒:
- SDA/SCL 必须接上拉电阻(否则通信失败!)
- 多个设备可挂在同一总线上(只要地址不同)
2. 实战芯片:MCP4017 数控电位器
📦 芯片简介

MCP4017 是一款通过 I²C 控制的数字电位器,相当于一个“能远程调节的旋钮”。
| 特性 | 说明 |
|---|---|
| 分辨率 | 8 位(256 步) |
| 电阻值 | 有 5kΩ / 10kΩ / 50kΩ / 100kΩ 版本 |
| 引脚 | A(固定端)、B(固定端)、W(滑动端) |
| 供电 | 1.8V ~ 5.5V,超低功耗(1µA) |
| 易失性 | 掉电后位置丢失,上电复位到默认值 |
🎯 典型应用
- 音量调节(代替机械旋钮)
- LED 亮度控制
- 传感器信号增益调节
- 精确分压电路



⚙️ 四、STM32CubeMX 配置步骤


1. 启用 I²C 外设
- 在 Pinout 图中找到 I2C1(或其他)
- 设置 SDA → PB7,SCL → PB6(以 STM32F103C8T6 为例)
2. 配置参数
| 参数 | 推荐值 |
|---|---|
| Mode | I2C |
| Speed Mode | Standard Speed (100 kHz) |
| Own Address 1 | 0(主机模式无需地址) |
| Pull-up Resistors | External(外部已接) |
3. 生成代码
- 勾选 Generate peripheral initialization as a pair of '.c/.h' files
- 生成后即可调用 HAL 库函数(如
HAL_I2C_Master_Transmit)
💡 提示:若使用自定义底层(如你提供的
I2CStart()),可关闭 HAL 初始化,直接操作 GPIO 模拟 I²C。
💻 五、底层代码详解(含修复)
🛠️ 注意:你提供的代码是软件模拟 I²C(Bit-Banging),非 HAL 库。以下已修复语法错误并添加注释。
1. EEPROM 读写(通用模板)
/**
* @brief 向EEPROM写入数据
* @param EEPROM_String 指向要写入数据的指针
* @param addr 起始地址
* @param num 字节数
*/
void eeprom_write(uint8_t *EEPROM_String, uint8_t addr, uint8_t num) {
I2CStart(); // 启动I2C
I2CSendByte(0xA0); // 器件地址 + 写位(0xA0 = 10100000)
I2CWaitAck();
I2CSendByte(addr); // 写入地址
I2CWaitAck();
while (num--) { // 修复:num-- → num--
I2CSendByte(*EEPROM_String++);
I2CWaitAck();
delay1(200); // 写入延时(EEPROM需要时间)
}
I2CStop();
HAL_Delay(5); // 确保写入完成
}
/**
* @brief 从EEPROM读取数据
*/
void eeprom_read(uint8_t *EEPROM_String, uint8_t addr, uint8_t num) {
// 第一步:发送要读的地址(写模式)
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
// 第二步:重新启动,切换到读模式
I2CStart();
I2CSendByte(0xA1); // 读命令(0xA1 = 10100001)
I2CWaitAck();
while (num--) { // 修复:num-- → num--
*EEPROM_String++ = I2CReceiveByte();
if (num)
I2CSendAck(); // 还要读,发ACK
else
I2CSendNotAck(); // 最后一字节,发NACK
}
I2CStop();
}
2. MCP4017 控制(重点!)
/**
* @brief 向MCP4017写入滑动端位置(0~127)
* @note MCO4017 是 7 位数据(0x00~0x7F),不是 8 位!
*/
void mcp4017_write(uint8_t data) {
// 限制输入范围(安全第一!)
if (data > 0x7F) data = 0x7F;
I2CStart();
I2CSendByte(0x5E); // 写地址:0x2F << 1 | 0 = 0x5E
I2CWaitAck();
I2CSendByte(data); // 发送滑动端位置
I2CWaitAck();
I2CStop();
}
/**
* @brief 从MCP4017读取当前滑动端值
*/
void mcp4017_read(uint8_t *data) {
I2CStart();
I2CSendByte(0x5F); // 读地址:0x2F << 1 | 1 = 0x5F
I2CWaitAck();
*data = I2CReceiveByte();
I2CSendNotAck(); // 单字节读,直接 NACK
I2CStop();
}
🔍 地址说明:
- MCP4017 默认 I²C 地址为 0x2F(由 A0/A1/A2 引脚决定)
- 写地址 =
0x2F << 1 | 0 = 0x5E- 读地址 =
0x2F << 1 | 1 = 0x5F
✅ 六、I²C 的核心优势
| 优势 | 说明 |
|---|---|
| 省线 | 仅需 SDA + SCL 两根线,可挂多个设备 |
| 简单 | 协议清晰,易于软件/硬件实现 |
| 灵活 | 支持多主多从(虽常用单主) |
| 低速够用 | 100kHz / 400kHz,适合传感器、EEPROM 等 |
❌ 局限:不适合高速大数据传输(如摄像头),此时用 SPI 更合适。
🧠 本章口诀(背下来!)
🗣️ I²C 就像微信群,两根线搞定所有芯!
🔗 SDA 传数据,SCL 打节拍!
📬 地址来区分,谁在发消息!
🔌 上拉电阻不能忘,通信稳定有保障!
🎚️ MCP4017 是旋钮,远程调阻真轻松!
💾 EEPROM 存数据,掉电不丢记得住!
📺 推荐学习资源
- 【4分钟看懂!I2C通讯协议 最简单的总线通讯!】
👉 4分钟看懂!I2C通讯协议 最简单的总线通讯!
这份笔记完整覆盖了IIC所有内容,包括:
- I²C 基本概念与生活类比
- MCP4017 芯片详解
- 硬件连接要点
- CubeMX 配置建议
- EEPROM 与 MCP4017 的底层代码(含修复)
- 地址计算、数据范围、上拉电阻等关键细节
现在,你的开发板不仅能“说话”(UART)、有“慧眼”(ADC)、会“表情”(LED),还能通过 I²C 组建芯片朋友圈,协同工作,打造真正的智能系统!✨
更多推荐


所有评论(0)