STM32版I²C相亲指南(软件硬件双修版)
一、I²C协议基础:电子世界的鹊桥相会
I²C是什么? 就像牛郎织女需要鹊桥相会,电子元件也需要通信桥梁。I²C(Inter-Integrated Circuit)是飞利浦发明的两线制串行总线,由:
- SCL(Serial Clock)时钟线 —— 心跳节拍器
- SDA(Serial Data)数据线 —— 爱情传声筒 构成。它如同电子世界的"婚介所",支持多主多从通信(最多127个设备),是嵌入式系统最常用的"相亲协议"。
二、I²C工作原理:四步相亲流程
1. 缘分起始(START信号)
如同月老抛出红线,主设备拉低SDA后拉低SCL,生成"心跳起搏器":
______
SDA: __| |______…
SCL: ____|¯¯¯¯|____…
↑ 爱情开始
2. 自我介绍(地址传输)
主设备发送7/10位设备地址 + 1位方向位(0写1读),像递出爱情简历:
// 例如MPU6050地址0x68(二进制01101000)
0 1 1 0 1 0 0 0 | 0 → 写模式
↑_____________↑ ↑
设备身份证 操作意向
3. 双向奔赴(数据传输)
从设备通过ACK(拉低SDA)回应,数据像情书般在时钟高电平时有效:
数据有效区
↗—↘
SDA: __|¯¯|__|¯¯|__…
SCL: ____|¯¯¯|____|¯¯…
4. 缘分暂停/结束(STOP信号)
当SCL高电平时SDA由低变高,如同优雅的告别:
__________
SDA: __| |…
SCL: ____|¯¯¯¯|______…
↑ 曲终人散
三、硬件I²C vs 软件I²C
实现方式 | 专用电路(婚姻登记所) | GPIO模拟(手写情书) |
速度 | 可达400kHz(闪婚) | 通常≤100kHz(慢热型) |
CPU占用 | 自动完成(婚庆公司全包) | 需持续控制(DIY婚礼) |
灵活性 | 引脚固定(包办婚姻) | 任意GPIO(自由恋爱) |
开发难度 | 需配置寄存器(填写结婚申请表) | 时序需精确控制(背诵恋爱守则) |
四、软件I²C登场:GPIO月老手搓红线
/* 像编织中国结一样操作GPIO */
#define SOFT_SCL_PIN GPIO_Pin_8
#define SOFT_SDA_PIN GPIO_Pin_9
#define SOFT_I2C_PORT GPIOB
void Software_I2C_Init() {
GPIO_InitTypeDef GPIO_InitStruct;
// 开启GPIOB的时钟特权
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIO为推挽输出模式(月老模式)
GPIO_InitStruct.GPIO_Pin = SOFT_SCL_PIN | SOFT_SDA_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出,手速要快
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 月老手速50MHz
GPIO_Init(SOFT_I2C_PORT, &GPIO_InitStruct);
// 初始状态:释放总线(高电平)
GPIO_SetBits(SOFT_I2C_PORT, SOFT_SCL_PIN | SOFT_SDA_PIN);
}
/* 起始信号详解 – 电子世界的眉目传情 */
void Software_I2C_Start() {
// 步骤1:SDA先低头示爱(下降沿)
GPIO_ResetBits(SOFT_I2C_PORT, SOFT_SDA_PIN);
Delay_us(5); // 等待心动周期
// 步骤2:SCL紧随其后确认(形成心跳同步)
GPIO_ResetBits(SOFT_I2C_PORT, SOFT_SCL_PIN);
}
void Software_I2C_Stop() {
GPIO_ResetBits(SOFT_I2C_PORT, SOFT_SCL_PIN); // 先按低SCL
Delay_us(2);
GPIO_ResetBits(SOFT_I2C_PORT, SOFT_SDA_PIN); // SDA主动示好
Delay_us(2);
GPIO_SetBits(SOFT_I2C_PORT, SOFT_SCL_PIN); // SCL优雅离场
Delay_us(2);
GPIO_SetBits(SOFT_I2C_PORT, SOFT_SDA_PIN); // SDA最后放手
}
/* ACK检测 – 爱情的回声探测器 */
uint8_t Software_I2C_WaitAck() {
GPIO_SetBits(SOFT_I2C_PORT, SOFT_SDA_PIN); // 松开SDA(给对方回应空间)
GPIO_SetBits(SOFT_I2C_PORT, SOFT_SCL_PIN); // 抬高SCL(准备聆听)
Delay_us(1); // 等待心灵感应
// 读取SDA状态:0=两情相悦,1=一厢情愿
uint8_t ack = GPIO_ReadInputDataBit(SOFT_I2C_PORT, SOFT_SDA_PIN);
GPIO_ResetBits(SOFT_I2C_PORT, SOFT_SCL_PIN); // 结束心跳检测
return ack;
}
四、硬件IIC:标准库里的“包办婚姻”
#include "stm32f10x.h"
#define MPU_ADDR 0xD0 // 陀螺仪工牌号左移一位后的地址
void I2C_Config() {
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
// 开启时钟大人的助攻
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置SDA和SCL为复用开漏模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PB6:SCL, PB7:SDA
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; // 相亲专用通道
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 霸道总裁的相亲参数设置
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 占空比设定
I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 总裁自己不领工牌
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 开启爱的应答
I2C_InitStruct.I2C_ClockSpeed = 100000; // 慢速相亲节奏100kHz
I2C_Init(I2C1, &I2C_InitStruct);
I2C_Cmd(I2C1, ENABLE); // 总裁闪亮登场
}
void MPU6050_Write(uint8_t reg, uint8_t data) {
// 发起相亲邀请
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // 等待前任相亲结束
I2C_GenerateSTART(I2C1, ENABLE); // 总裁打响指
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// 点名陀螺仪
I2C_Send7bitAddress(I2C1, MPU_ADDR, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送情书内容
I2C_SendData(I2C1, reg); // 指定寄存器地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
I2C_SendData(I2C1, data); // 写入数据
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 优雅退场
I2C_GenerateSTOP(I2C1, ENABLE); // 甩披风离开
}
int16_t MPU6050_Read(uint8_t reg) {
uint8_t H, L;
// 第一阶段:写寄存器地址
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, MPU_ADDR, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, reg);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 第二阶段:重新启动读取
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, MPU_ADDR, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// 接收数据(以加速度X轴为例)
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
H = I2C_ReceiveData(I2C1);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
L = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1, ENABLE);
return (int16_t)(H << 8 | L);
}
代码解密:标准库の仪式感
硬件配置就像定做西装:GPIO必须设置成复用开漏模式,别忘了打开APB1和APB2时钟的"水源"
事件检查是防呆设计:每个动作都要用I2C_CheckEvent确认,堪比总裁的贴身秘书反复确认行程
复合式读取玩转回马枪:先写寄存器地址再重启读取,像极了欲擒故纵的恋爱套路
数据拼接讲究门当户对:高低字节结合时记得强制类型转换,避免数据界的"阶级跨越"
来自老派绅士的忠告
虽然标准库的相亲流程稍显繁琐(比起HAL库),但这份寄存器级的仪式感正是电子罗曼史的醍醐味!当你在while循环里等待事件标志时,请把这当作爱情长跑前的必要考验——毕竟美好的婚姻(通信)值得等待!
(调试时若遇I2C死锁,请使出绝招:断电大法好!)
六、I²C调试心法:示波器里的爱情心电图
波形诊断三要素:
- 起始信号:是否出现标准的"低头-同步"序列
- 时钟频率:是否超出设备承受范围(如同恋爱节奏太快)
- 数据对齐:上升沿时数据是否稳定(爱情承诺要坚定)
常见失恋原因:
- 地址错位:7位地址未左移(例如0x68应写作0xD0)
- 时序过急:Delay不足导致设备无法响应
- 总线竞争:多个主设备同时示爱(需仲裁机制)
示波器测量技巧:
#mermaid-svg-X4TAzANSldObQJ7B {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-X4TAzANSldObQJ7B .error-icon{fill:#552222;}#mermaid-svg-X4TAzANSldObQJ7B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X4TAzANSldObQJ7B .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-X4TAzANSldObQJ7B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X4TAzANSldObQJ7B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X4TAzANSldObQJ7B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X4TAzANSldObQJ7B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X4TAzANSldObQJ7B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X4TAzANSldObQJ7B .marker.cross{stroke:#333333;}#mermaid-svg-X4TAzANSldObQJ7B svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X4TAzANSldObQJ7B .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-X4TAzANSldObQJ7B .cluster-label text{fill:#333;}#mermaid-svg-X4TAzANSldObQJ7B .cluster-label span{color:#333;}#mermaid-svg-X4TAzANSldObQJ7B .label text,#mermaid-svg-X4TAzANSldObQJ7B span{fill:#333;color:#333;}#mermaid-svg-X4TAzANSldObQJ7B .node rect,#mermaid-svg-X4TAzANSldObQJ7B .node circle,#mermaid-svg-X4TAzANSldObQJ7B .node ellipse,#mermaid-svg-X4TAzANSldObQJ7B .node polygon,#mermaid-svg-X4TAzANSldObQJ7B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X4TAzANSldObQJ7B .node .label{text-align:center;}#mermaid-svg-X4TAzANSldObQJ7B .node.clickable{cursor:pointer;}#mermaid-svg-X4TAzANSldObQJ7B .arrowheadPath{fill:#333333;}#mermaid-svg-X4TAzANSldObQJ7B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X4TAzANSldObQJ7B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X4TAzANSldObQJ7B .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-X4TAzANSldObQJ7B .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-X4TAzANSldObQJ7B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X4TAzANSldObQJ7B .cluster text{fill:#333;}#mermaid-svg-X4TAzANSldObQJ7B .cluster span{color:#333;}#mermaid-svg-X4TAzANSldObQJ7B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-X4TAzANSldObQJ7B :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
触发模式设置为下降沿
捕捉起始信号
展开时序查看地址位
检查ACK脉冲位置
硬件I²C如交响乐团指挥,精准把控每个节拍;软件I²C如民谣歌手,自由诠释音乐灵魂。理解协议本质后,无论是STM32的I2C外设还是GPIO模拟,都能让设备间谈一场完美的"电子恋爱"!
评论前必须登录!
注册