您现在的位置是:首页 >技术交流 >STMicroelectronics 系列:STM32F7 系列_(15).STM32F7系列I2C通信网站首页技术交流
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引脚通常需要配置为复用推挽输出模式。具体步骤如下:
-
使能I2C时钟:在RCC时钟控制寄存器中使能I2C外设的时钟。
-
配置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通信。




QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结