您现在的位置是:首页 >技术交流 >STMicroelectronics 系列:STM32F7 系列_(15).STM32F7系列I2C通信网站首页技术交流

STMicroelectronics 系列:STM32F7 系列_(15).STM32F7系列I2C通信

kkchenkx 2026-04-28 00:01:04
简介STMicroelectronics 系列:STM32F7 系列_(15).STM32F7系列I2C通信

STM32F7系列I2C通信

在这里插入图片描述

I2C通信简介

I2C(Inter-Integrated Circuit)是一种简单的双向两线制同步串行总线,用于连接多个低速外设。I2C总线由两根线组成:SCL(串行时钟线)和SDA(串行数据线)。通过这两根线,主设备可以与多个从设备进行通信。I2C总线的特点包括:

  • 简单性:只需要两根线即可实现通信。

  • 多从设备:一条I2C总线上可以连接多个从设备。

  • 双向通信:主设备和从设备可以双向通信。

  • 速度:标准模式下速度为100 kbps,快速模式下为400 kbps,高速模式下为3.4 Mbps。

在STM32F7系列微控制器中,I2C通信通过专用的I2C外设实现。STM32F7系列支持多个I2C通道,每个通道都有独立的配置寄存器和状态寄存器,可以灵活地进行配置和管理。

I2C硬件配置

I2C引脚配置

STM32F7系列微控制器的I2C引脚通常需要配置为复用推挽输出模式。具体步骤如下:

  1. 使能I2C时钟:在RCC时钟控制寄存器中使能I2C外设的时钟。

  2. 配置GPIO引脚:将SCL和SDA引脚配置为复用推挽输出模式,并启用内部上拉电阻。


// 使能I2C时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);



// 配置GPIO引脚

GPIO_InitTypeDef GPIO_InitStructure;



// 使能GPIO时钟

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);



// 配置SCL引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // PB6

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用功能

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50MHz

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 内部上拉

GPIO_Init(GPIOB, &GPIO_InitStructure);



// 配置SDA引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // PB7

GPIO_Init(GPIOB, &GPIO_InitStructure);



// 配置GPIO复用功能

GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);

I2C初始化

I2C外设的初始化主要包括配置时钟频率、模式(主/从)、地址模式等。STM32F7系列提供了丰富的配置选项,确保I2C通信的灵活性和可靠性。


// I2C初始化函数

void I2C_Init(void) {

    I2C_InitTypeDef I2C_InitStructure;



    // 使能I2C外设

    I2C_DeInit(I2C1);

    I2C_StructInit(&I2C_InitStructure);



    // 配置I2C参数

    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; // 使能应答

    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址模式

    I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz



    // 初始化I2C外设

    I2C_Init(I2C1, &I2C_InitStructure);



    // 使能I2C外设

    I2C_Cmd(I2C1, ENABLE);

}

I2C数据传输

主设备发送数据

主设备发送数据的过程包括启动通信、发送从设备地址、发送数据、停止通信。以下是主设备发送数据的示例代码:


// 主设备发送数据函数

void I2C_MasterSendData(uint8_t DeviceAddress, uint8_t *pData, uint16_t Size) {

    // 启动发送

    I2C_GenerateSTART(I2C1, ENABLE);



    // 等待启动条件完成

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}



    // 发送从设备地址

    I2C_Send7bitAddress(I2C1, DeviceAddress, I2C_Direction_Transmitter);



    // 等待从设备应答

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {}



    // 发送数据

    while (Size--) {

        I2C_SendData(I2C1, *pData++);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {}

    }



    // 停止通信

    I2C_GenerateSTOP(I2C1, ENABLE);

}

主设备接收数据

主设备接收数据的过程包括启动通信、发送从设备地址、接收数据、停止通信。以下是主设备接收数据的示例代码:


// 主设备接收数据函数

void I2C_MasterReceiveData(uint8_t DeviceAddress, uint8_t *pData, uint16_t Size) {

    // 启动发送

    I2C_GenerateSTART(I2C1, ENABLE);



    // 等待启动条件完成

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}



    // 发送从设备地址

    I2C_Send7bitAddress(I2C1, DeviceAddress, I2C_Direction_Receiver);



    // 等待从设备应答

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {}



    // 接收数据

    while (Size--) {

        if (Size == 0) {

            // 最后一个字节,发送停止条件

            I2C_GenerateSTOP(I2C1, ENABLE);

        }

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) {}

        *pData++ = I2C_ReceiveData(I2C1);

    }

}

从设备发送数据

从设备发送数据的过程包括等待主设备发送地址、发送数据。以下是从设备发送数据的示例代码:


// 从设备发送数据函数

void I2C_SlaveSendData(uint8_t *pData, uint16_t Size) {

    // 等待主设备发送地址

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED)) {}



    // 发送数据

    while (Size--) {

        I2C_SendData(I2C1, *pData++);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_TRANSMITTED)) {}

    }

}

从设备接收数据

从设备接收数据的过程包括等待主设备发送地址、接收数据。以下是从设备接收数据的示例代码:


// 从设备接收数据函数

void I2C_SlaveReceiveData(uint8_t *pData, uint16_t Size) {

    // 等待主设备发送地址

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED)) {}



    // 接收数据

    while (Size--) {

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_RECEIVED)) {}

        *pData++ = I2C_ReceiveData(I2C1);

    }

}

I2C中断和DMA

中断配置

I2C通信可以通过中断方式进行管理,以提高系统的响应速度和效率。中断配置包括使能中断、配置中断优先级、编写中断处理函数等。


// 配置I2C中断

void I2C_ConfigInterrupt(void) {

    NVIC_InitTypeDef NVIC_InitStructure;



    // 使能I2C中断

    I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR | I2C_IT_BUF, ENABLE);



    // 配置NVIC中断

    NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);



    NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;

    NVIC_Init(&NVIC_InitStructure);

}



// I2C事件中断处理函数

void I2C1_EV_IRQHandler(void) {

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET) {

        // 处理发送事件

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) != RESET) {

        // 处理接收事件

    }

}



// I2C错误中断处理函数

void I2C1_ER_IRQHandler(void) {

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_BERR);

        // 处理总线错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_ARLO) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_ARLO);

        // 处理仲裁丢失

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_AF);

        // 处理应答错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_OVR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_OVR);

        // 处理数据溢出

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_PECERR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_PECERR);

        // 处理PEC错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TIMEOUT) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_TIMEOUT);

        // 处理超时错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_SMBALERT) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_SMBALERT);

        // 处理SMBUS警报

    }

}

DMA配置

I2C通信也可以通过DMA方式进行管理,以提高数据传输的效率和减少CPU的负担。DMA配置包括使能DMA、配置DMA通道、编写DMA传输完成和错误处理函数等。


// 配置I2C DMA

void I2C_ConfigDMA(void) {

    DMA_InitTypeDef DMA_InitStructure;



    // 使能DMA时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);



    // 配置DMA通道

    DMA_DeInit(DMA1_Stream6);

    DMA_InitStructure.DMA_Channel = DMA_Channel_1;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(I2C1->DR);

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)TxBuffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

    DMA_InitStructure.DMA_BufferSize = TxBufferSize;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA1_Stream6, &DMA_InitStructure);



    // 使能DMA通道

    DMA_Cmd(DMA1_Stream6, ENABLE);



    // 使能I2C DMA传输

    I2C_DMAEnable(I2C1, ENABLE);

}



// DMA传输完成中断处理函数

void DMA1_Stream6_IRQHandler(void) {

    if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {

        // 传输完成

        DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);

    } else if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TEIF6) != RESET) {

        // 传输错误

        DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TEIF6);

    }

}

I2C通信实例

实例1:主设备向从设备发送数据

在这个实例中,主设备向从设备发送一个简单的数据包。假设从设备的地址是0x50,数据包的内容是"Hello, I2C!"。


#include "stm32f7xx.h"

#include "stm32f7xx_hal.h"



uint8_t TxBuffer[] = "Hello, I2C!";

uint16_t TxBufferSize = sizeof(TxBuffer);



int main(void) {

    // 初始化系统时钟

    SystemInit();



    // 初始化I2C

    I2C_Init();



    // 配置I2C中断

    I2C_ConfigInterrupt();



    // 主设备发送数据

    I2C_MasterSendData(0x50, TxBuffer, TxBufferSize);



    while (1) {

        // 主循环

    }

}

实例2:主设备从从设备接收数据

在这个实例中,主设备从从设备接收一个简单的数据包。假设从设备的地址是0x50,数据包的内容是"Received"。


#include "stm32f7xx.h"

#include "stm32f7xx_hal.h"



uint8_t RxBuffer[10];

uint16_t RxBufferSize = sizeof(RxBuffer);



int main(void) {

    // 初始化系统时钟

    SystemInit();



    // 初始化I2C

    I2C_Init();



    // 配置I2C中断

    I2C_ConfigInterrupt();



    // 主设备接收数据

    I2C_MasterReceiveData(0x50, RxBuffer, RxBufferSize);



    while (1) {

        // 主循环

    }

}

实例3:从设备接收数据并发送回主设备

在这个实例中,从设备接收主设备发送的数据,并将其发送回主设备。假设从设备的地址是0x50,接收缓冲区为RxBuffer,发送缓冲区为TxBuffer

从设备配置

首先,需要配置从设备的I2C参数。从设备的配置与主设备类似,但模式设置为从设备模式。


#include "stm32f7xx.h"

#include "stm32f7xx_hal.h"



uint8_t RxBuffer[10];

uint16_t RxBufferSize = sizeof(RxBuffer);

uint8_t TxBuffer[10];

uint16_t TxBufferSize = sizeof(TxBuffer);



// 从设备配置函数

void I2C_ConfigSlave(void) {

    I2C_InitTypeDef I2C_InitStructure;



    // 使能I2C外设

    I2C_DeInit(I2C1);

    I2C_StructInit(&I2C_InitStructure);



    // 配置I2C参数

    I2C_InitStructure.I2C_Mode = I2C_Mode_Slave; // 从设备模式

    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 2:1占空比

    I2C_InitStructure.I2C_OwnAddress1 = 0x50; // 从设备地址

    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // 使能应答

    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址模式

    I2C_Init(I2C1, &I2C_InitStructure);



    // 使能I2C外设

    I2C_Cmd(I2C1, ENABLE);



    // 配置I2C中断

    I2C_ConfigInterrupt();

}



int main(void) {

    // 初始化系统时钟

    SystemInit();



    // 配置从设备

    I2C_ConfigSlave();



    while (1) {

        // 主循环

    }

}

I2C事件中断处理函数

从设备的事件中断处理函数需要处理接收数据和发送数据的事件。当接收数据完成时,从设备会启动一个新的通信,将接收到的数据发送回主设备。


// I2C事件中断处理函数

void I2C1_EV_IRQHandler(void) {

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) != RESET) {

        // 接收数据

        *RxBuffer++ = I2C_ReceiveData(I2C1);

        RxBufferSize--;



        if (RxBufferSize == 0) {

            // 接收完成,重置指针和大小

            RxBuffer -= sizeof(RxBuffer);

            RxBufferSize = sizeof(RxBuffer);



            // 拷贝接收到的数据到发送缓冲区

            for (uint16_t i = 0; i < sizeof(RxBuffer); i++) {

                TxBuffer[i] = RxBuffer[i];

            }

            TxBufferSize = sizeof(TxBuffer);



            // 启动发送

            I2C_GenerateSTART(I2C1, ENABLE);



            // 等待启动条件完成

            while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}



            // 发送主设备地址

            I2C_Send7bitAddress(I2C1, 0x30, I2C_Direction_Transmitter);



            // 等待主设备应答

            while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {}



            // 发送数据

            while (TxBufferSize--) {

                I2C_SendData(I2C1, *TxBuffer++);

                while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {}

            }



            // 停止通信

            I2C_GenerateSTOP(I2C1, ENABLE);

        }

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TxE) != RESET) {

        // 处理发送事件

        if (TxBufferSize > 0) {

            I2C_SendData(I2C1, *TxBuffer++);

            TxBufferSize--;

        } else {

            // 发送完成

            I2C_GenerateSTOP(I2C1, ENABLE);

        }

    }

}

I2C错误中断处理函数

错误中断处理函数用于处理通信过程中可能出现的各种错误,如总线错误、仲裁丢失、应答错误等。


// I2C错误中断处理函数

void I2C1_ER_IRQHandler(void) {

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_BERR);

        // 处理总线错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_ARLO) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_ARLO);

        // 处理仲裁丢失

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_AF);

        // 处理应答错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_OVR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_OVR);

        // 处理数据溢出

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_PECERR) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_PECERR);

        // 处理PEC错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TIMEOUT) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_TIMEOUT);

        // 处理超时错误

    } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_SMBALERT) != RESET) {

        I2C_ClearFlag(I2C1, I2C_FLAG_SMBALERT);

        // 处理SMBUS警报

    }

}

实例4:使用DMA进行数据传输

使用DMA可以提高数据传输的效率,减少CPU的负担。以下是一个使用DMA进行数据传输的示例。

配置DMA

首先,需要配置DMA通道,使能DMA传输,并配置I2C外设使用DMA。


// 配置I2C DMA

void I2C_ConfigDMA(void) {

    DMA_InitTypeDef DMA_InitStructure;



    // 使能DMA时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);



    // 配置DMA通道

    DMA_DeInit(DMA1_Stream6);

    DMA_InitStructure.DMA_Channel = DMA_Channel_1;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(I2C1->DR);

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)TxBuffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

    DMA_InitStructure.DMA_BufferSize = TxBufferSize;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA1_Stream6, &DMA_InitStructure);



    // 使能DMA通道

    DMA_Cmd(DMA1_Stream6, ENABLE);



    // 使能I2C DMA传输

    I2C_DMAEnable(I2C1, ENABLE);

}

主设备发送数据

使用DMA进行数据发送的主设备代码如下:


// 主设备使用DMA发送数据函数

void I2C_MasterSendData_DMA(uint8_t DeviceAddress, uint8_t *pData, uint16_t Size) {

    // 启动发送

    I2C_GenerateSTART(I2C1, ENABLE);



    // 等待启动条件完成

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}



    // 发送从设备地址

    I2C_Send7bitAddress(I2C1, DeviceAddress, I2C_Direction_Transmitter);



    // 等待从设备应答

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {}



    // 配置DMA传输

    DMA_InitStructure.DMA_BufferSize = Size;

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pData;

    DMA_Init(DMA1_Stream6, &DMA_InitStructure);



    // 启动DMA传输

    DMA_Cmd(DMA1_Stream6, ENABLE);



    // 启动I2C DMA传输

    I2C_DMATxRequest(I2C1, ENABLE);

}



int main(void) {

    // 初始化系统时钟

    SystemInit();



    // 初始化I2C

    I2C_Init();



    // 配置I2C DMA

    I2C_ConfigDMA();



    // 主设备发送数据

    I2C_MasterSendData_DMA(0x50, TxBuffer, TxBufferSize);



    while (1) {

        // 主循环

    }

}

主设备接收数据

使用DMA进行数据接收的主设备代码如下:


// 配置DMA接收

void I2C_ConfigDMA_Receive(void) {

    DMA_InitTypeDef DMA_InitStructure;



    // 使能DMA时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);



    // 配置DMA通道

    DMA_DeInit(DMA1_Stream0);

    DMA_InitStructure.DMA_Channel = DMA_Channel_1;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(I2C1->DR);

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RxBuffer;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

    DMA_InitStructure.DMA_BufferSize = RxBufferSize;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA1_Stream0, &DMA_InitStructure);



    // 使能DMA通道

    DMA_Cmd(DMA1_Stream0, ENABLE);



    // 使能I2C DMA传输

    I2C_DMARequestCmd(I2C1, I2C_DMAReq_Enable);

}



// 主设备使用DMA接收数据函数

void I2C_MasterReceiveData_DMA(uint8_t DeviceAddress, uint8_t *pData, uint16_t Size) {

    // 启动发送

    I2C_GenerateSTART(I2C1, ENABLE);



    // 等待启动条件完成

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}



    // 发送从设备地址

    I2C_Send7bitAddress(I2C1, DeviceAddress, I2C_Direction_Receiver);



    // 等待从设备应答

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {}



    // 配置DMA传输

    DMA_InitStructure.DMA_BufferSize = Size;

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pData;

    DMA_Init(DMA1_Stream0, &DMA_InitStructure);



    // 启动DMA传输

    DMA_Cmd(DMA1_Stream0, ENABLE);



    // 启动I2C DMA传输

    I2C_DMARxRequest(I2C1, ENABLE);

}



int main(void) {

    // 初始化系统时钟

    SystemInit();



    // 初始化I2C

    I2C_Init();



    // 配置I2C DMA接收

    I2C_ConfigDMA_Receive();



    // 主设备接收数据

    I2C_MasterReceiveData_DMA(0x50, RxBuffer, RxBufferSize);



    while (1) {

        // 主循环

    }

}

DMA传输完成和错误处理函数

处理DMA传输完成和错误的中断函数如下:


// DMA传输完成中断处理函数

void DMA1_Stream6_IRQHandler(void) {

    if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {

        // 传输完成

        DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);

        // 停止I2C通信

        I2C_GenerateSTOP(I2C1, ENABLE);

    } else if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TEIF6) != RESET) {

        // 传输错误

        DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TEIF6);

    }

}



// DMA接收完成中断处理函数

void DMA1_Stream0_IRQHandler(void) {

    if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_TCIF0) != RESET) {

        // 接收完成

        DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TCIF0);

        // 停止I2C通信

        I2C_GenerateSTOP(I2C1, ENABLE);

    } else if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_TEIF0) != RESET) {

        // 接收错误

        DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TEIF0);

    }

}

总结

通过上述示例,我们可以看到STM32F7系列微控制器在I2C通信中的灵活性和高效性。无论是简单的轮询方式,还是更高级的中断和DMA方式,STM32F7都能提供强大的支持,确保数据传输的可靠性和高效性。希望这些示例代码能帮助你更好地理解和实现I2C通信。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。