STM32——IIC(I2C)通信详解
通过本文的介绍,我们了解了 I2C 协议的基本原理、STM32 的 I2C 硬件连接和软件实现。利用 STM32 的 I2C 接口,我们可以方便地与各种 I2C 从设备进行通信。在实际应用中,需要根据具体的需求和从设备的特性进行适当的调整和优化,以确保通信的稳定性和可靠性。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、引言
在嵌入式系统开发中,设备之间的通信至关重要。I2C(Inter - Integrated Circuit),也称为 IIC,是一种广泛应用的串行通信协议,由飞利浦公司开发。它具有接口线少、控制简单、通信速率较高等优点,被大量应用于各种设备之间的数据传输。STM32 系列微控制器内置了 I2C 接口,能够方便地实现与其他 I2C 设备的通信。本文将详细介绍 STM32 的 I2C 通信原理、硬件连接和软件实现,并给出相应的代码示例。
二、I2C 协议原理
2.1 基本概念
I2C 总线由两根线组成:串行数据线(SDA)和串行时钟线(SCL)。所有连接到 I2C 总线上的设备都通过这两根线进行通信。每个设备都有一个唯一的 7 位或 10 位地址,主设备通过地址来选择与之通信的从设备。
2.2 通信过程
- 起始条件:当 SCL 为高电平时,SDA 由高电平变为低电平,标志着一次通信的开始。
- 地址帧:主设备发送从设备的地址,同时包含读写位(0 表示写,1 表示读)。
- 应答位:从设备接收到地址后,在第 9 个时钟周期拉低 SDA 表示应答。
- 数据传输:主设备和从设备之间进行数据的读写操作,每个字节传输后都有一个应答位。
- 停止条件:当 SCL 为高电平时,SDA 由低电平变为高电平,标志着一次通信的结束。
三、STM32 的 I2C 硬件连接
3.1 引脚选择
不同型号的 STM32 微控制器的 I2C 引脚位置可能不同。以 STM32F103 为例,I2C1 的 SCL 引脚为 PB6,SDA 引脚为 PB7;I2C2 的 SCL 引脚为 PB10,SDA 引脚为 PB11。
3.2 上拉电阻
SDA 和 SCL 线需要外接上拉电阻,一般取值为 4.7KΩ - 10KΩ,以确保在空闲状态下两根线为高电平。
3.3 硬件连接示例
假设我们要将 STM32 与一个 I2C 从设备(如 EEPROM)连接,只需将 STM32 的 SDA 和 SCL 引脚分别连接到从设备的 SDA 和 SCL 引脚,并接上拉电阻到 VCC。
四、STM32 的 I2C 软件实现
4.1 初始化 I2C 接口
以下是使用 STM32 HAL 库初始化 I2C1 接口的代码:
#include "stm32f1xx_hal.h"
I2C_HandleTypeDef hi2c1;
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
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;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(i2cHandle->Instance==I2C1)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_RCC_I2C1_CLK_ENABLE();
}
}
4.2 向从设备写入数据
#define SLAVE_ADDRESS 0xA0
void I2C_WriteData(uint8_t *pData, uint16_t Size)
{
if (HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS, pData, Size, 1000) != HAL_OK)
{
Error_Handler();
}
}
4.3 从从设备读取数据
void I2C_ReadData(uint8_t *pData, uint16_t Size)
{
if (HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDRESS, pData, Size, 1000) != HAL_OK)
{
Error_Handler();
}
}
4.4 主函数示例
int main(void)
{
HAL_Init();
MX_I2C1_Init();
uint8_t writeData[] = {0x01, 0x02, 0x03};
uint8_t readData[3];
// 向从设备写入数据
I2C_WriteData(writeData, sizeof(writeData));
// 从从设备读取数据
I2C_ReadData(readData, sizeof(readData));
while (1)
{
// 主循环
}
}
五、代码解释
5.1 初始化部分
MX_I2C1_Init 函数用于初始化 I2C1 接口,设置时钟速度、占空比、寻址模式等参数。HAL_I2C_MspInit 函数用于初始化 I2C1 的 GPIO 引脚,并使能 I2C1 的时钟。
5.2 数据写入部分
I2C_WriteData 函数使用 HAL_I2C_Master_Transmit 函数将数据发送到从设备。HAL_I2C_Master_Transmit 函数的参数包括 I2C 句柄、从设备地址、要发送的数据指针和数据长度,以及超时时间。
5.3 数据读取部分
I2C_ReadData 函数使用 HAL_I2C_Master_Receive 函数从从设备读取数据。HAL_I2C_Master_Receive 函数的参数与 HAL_I2C_Master_Transmit 类似。
5.4 主函数部分
在主函数中,首先进行系统初始化和 I2C 接口初始化,然后定义要写入的数据和用于存储读取数据的数组,调用写入和读取函数进行数据传输,最后进入主循环。
六、注意事项
6.1 时钟速度
I2C 的时钟速度需要根据从设备的支持范围进行设置,常见的时钟速度有 100KHz(标准模式)和 400KHz(快速模式)。
6.2 应答机制
在数据传输过程中,要注意应答位的处理。如果从设备没有正确应答,可能会导致通信失败。
6.3 错误处理
在代码中要添加错误处理机制,当 I2C 通信出现错误时,及时进行相应的处理,如重试或报错。
七、总结
通过本文的介绍,我们了解了 I2C 协议的基本原理、STM32 的 I2C 硬件连接和软件实现。利用 STM32 的 I2C 接口,我们可以方便地与各种 I2C 从设备进行通信。在实际应用中,需要根据具体的需求和从设备的特性进行适当的调整和优化,以确保通信的稳定性和可靠性。
更多推荐



所有评论(0)