STM32学习笔记-----I2C协议

STM32的I2C(Inter-Integrated Circuit)是一个串行通信协议,用于微控制器和其他外部设备之间的数据交换。STM32的I2C外设支持多种模式,能够方便地进行设备之间的低速、低功耗数据传输。以下是STM32使用标准库的I2C配置和使用方法的详细介绍

I2C基础概念

I2C总线是一个双线制协议,包含两条信号线:

  • SCL:时钟线(Clock),由主设备提供时钟信号。
  • SDA:数据线(Data),用于传输数据,支持双向传输。

I2C设备分为:

  • 主设备:负责启动和停止通信,并生成时钟信号。STM32通常作为主设备。
  • 从设备:接收或发送数据,响应主设备的命令。

STM32 I2C标准库配置

STM32的I2C功能可以通过标准库(STM32固件库)进行配置。主要的配置步骤包括:

  1. 初始化I2C外设:设置I2C的工作模式、时钟、地址模式、波特率等。
  2. 配置GPIO:I2C的SCL和SDA信号线需要进行相应的GPIO配置。
  3. 数据传输:进行I2C通信,包括写数据、读数据、地址设置等。

1. I2C初始化

首先,需要初始化I2C外设并配置相关参数。以下是一个基于标准库的I2C初始化例子:

cpp 复制代码
#include "stm32f4xx.h"

void I2C_Init_Config(void)
{
    // 使能I2C时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    // 使能GPIO时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    // 配置GPIO(SCL和SDA)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_9;  // SCL为PB6,SDA为PB9
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;            // 复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;          // 开漏输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;            // 上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 设置I2C复用功能(PB6为SCL,PB9为SDA)
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

    // 配置I2C
    I2C_InitTypeDef I2C_InitStructure;
    I2C_InitStructure.I2C_ClockSpeed = 100000;      // I2C时钟频率100kHz
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;      // 工作模式I2C
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  // 占空比2:1
    I2C_InitStructure.I2C_OwnAddress1 = 0x30;        // 设置设备的地址
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;      // 使能ACK应答
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址模式
    I2C_Init(I2C1, &I2C_InitStructure);

    // 使能I2C1外设
    I2C_Cmd(I2C1, ENABLE);
}

在上面的代码中:

  • I2C_ClockSpeed:设置I2C的时钟频率。常见的I2C时钟频率有100kHz(标准模式)和400kHz(快速模式)。
  • I2C_OwnAddress1:设置STM32的I2C从地址。
  • I2C_Ack:使能应答功能,允许设备进行数据确认。
  • I2C_AcknowledgedAddress:选择7位或10位地址模式。

2. 数据传输

I2C通信一般包括两种操作:写数据 和读数据。

写数据到I2C设备

在写数据时,首先发送设备地址,然后发送数据。以下是通过I2C写数据的例子:

cpp 复制代码
void I2C_Write(uint8_t slaveAddress, uint8_t regAddress, uint8_t data)
{
    // 等待I2C总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    // 发送启动信号
    I2C_GenerateSTART(I2C1, ENABLE);

    // 等待START信号发送完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    // 发送从设备地址
    I2C_Send7bitAddress(I2C1, slaveAddress, I2C_Direction_Transmitter);

    // 等待地址传输完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    // 发送寄存器地址
    I2C_SendData(I2C1, regAddress);

    // 等待数据传输完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    // 发送数据
    I2C_SendData(I2C1, data);

    // 等待数据传输完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
}
从I2C设备读取数据

读取数据时,首先发送设备地址和寄存器地址,然后进行数据读取。以下是读取数据的代码:

cpp 复制代码
uint8_t I2C_Read(uint8_t slaveAddress, uint8_t regAddress)
{
    uint8_t receivedData;

    // 等待I2C总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    // 发送启动信号
    I2C_GenerateSTART(I2C1, ENABLE);

    // 等待START信号发送完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    // 发送从设备地址
    I2C_Send7bitAddress(I2C1, slaveAddress, I2C_Direction_Transmitter);

    // 等待地址传输完成
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    // 发送寄存器地址
    I2C_SendData(I2C1, regAddress);

    // 等待数据传输完成
    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, slaveAddress, I2C_Direction_Receiver);

    // 等待数据接收
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    // 接收数据
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    receivedData = I2C_ReceiveData(I2C1);

    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);

    return receivedData;
}

3. 错误处理与常见问题

I2C通信中常见的问题包括:

  • 总线忙碌 :通过检查I2C_FLAG_BUSY标志位来确认I2C是否处于忙碌状态。
  • 超时错误:如果操作时间过长,可能会引发超时错误。可以设置一个超时计数器,并定期检查。

4. 总结

使用STM32的标准库配置和使用I2C外设涉及初始化I2C外设、配置GPIO、进行数据传输等步骤。理解I2C的工作原理和每个步骤的细节是保证通信稳定性的关键。

通过标准库的I2C功能,STM32可以高效地与外部设备(如传感器、EEPROM等)进行数据交换,适用于各种嵌入式应用。

相关推荐
夕除14 分钟前
Redis 过期策略
redis·笔记·面试
Nuanyt2 小时前
Agent 学习笔记(下篇三):上线工程、进阶选择与操作界面(Stage 7 / 7.5 / 8 + 延伸路线)
笔记·python·学习·memory·aiagent·harness
szxinmai主板定制专家2 小时前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x
叼烟扛炮3 小时前
Linux 学习笔记(四十一):TCP 并发演进——从单进程到多线程服务器
linux·运维·服务器·网络·笔记·学习·tcp/ip
叼烟扛炮3 小时前
Linux 学习笔记(四十四):HTTP 协议解析与极简 Web 服务器实战
linux·服务器·学习
叼烟扛炮3 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
songyuc4 小时前
【Manskill3】TableSceneBuilder学习笔记
pytorch·笔记·学习
外收内放5 小时前
Python基础语法练习题(75)
开发语言·python·学习
HQB20265 小时前
屹晶微电子 EG1130|2‑24V 输入 / 最高 28V 输出 内置 MOS 异步升压 DC‑DC|SOT23‑6|摄像头 / 车充 / 电池充电电源
嵌入式硬件·硬件工程
゛凌乱的记忆づ6 小时前
好用的md文件编辑器——TyporaS与Typora
笔记·git·typora·markdown