首页 » 通讯 » 15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据

15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据

少女玫瑰心 2024-11-26 13:02:27 0

扫一扫用手机浏览

文章目录 [+]

具备多主模式功能,同一接口可以用作主从模式。
7 位/10 位寻址以及广播呼叫的天生和检测。
支持不同的通信速率:— 标准速率(高达 100 kHz)— 快速速率(高达 400 kHz)状态标志:— 发送/吸收模式标志— 字节传输结束标志— I2C 劳碌标志缺点标志:— 主模式下的仲裁丢失情形— 地址/数据传输完成后的应答失落败— 检测误放的起始位和停滞位— 禁止时钟延长后涌现的上溢/下溢带 DMA 功能的 1 字节缓冲(减轻MCU事情)兼容SMBus2.0和PMBus。
详细的功能浸染可参看数据手册(648页中文版)总结:STM32的I2C外设可用作通讯的主机及从机,支持100Kbit/s和400Kbit/s的速率,支持7位、10位设备地址,支持DMA数据传输,并具有数据校验功能。

15.1.2 STM32 IIC构造

IIC通过SCL和SDA两个引脚完成与其他器件进行通信,如下图IIC内部构造图:

15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据 15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据 通讯

IIC引脚对照表:

15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据 15 玩转STM32之IIC通信(芯片硬件篇)_模式_数据 通讯
(图片来自网络侵删)

IIC有四种事情模式:从发送器、从吸收器、主发送器、主吸收器模式四种。
默认情形下,IIC在从模式下事情。
接口在天生起始位后会自动由从模式切换为主模式,并在涌现重在丢失或天生停滞位的时候,从模式切换为从模式,进而实现多主模式功能。

15.1.3 STM32 IIC主模式

在主模式下,I2C接口会启动数据传输(发送起始旗子暗记和器件地址,地址始终在主模式下发送),并天生时钟旗子暗记(SCL),将须要发送的数据写入数据寄存器,并通过数据移位寄存器和数据掌握逻辑(输出),将数据一位位发送到SDA数据线。
通信的时钟由主机的时钟掌握逻理天生,可以在标准速率或快速速率模式下事情。
通信的事情模式由掌握寄存器(CR1和CR2)的不同配置掌握,状态寄存器表示通信过程中产生的一系列状态,根据不同的事情模式和通信状态,掌握逻辑卖力实现完全的通信过程。
串行数据传输始终在涌现起始位时开始,在涌现停滞位时结束。
起始位和停滞位均在主模式下由软件天生。
12C掌握器自动检测从机发送回来的ACK旗子暗记,并置位状态寄存器相应的状态位,程序通过检测状态寄存器(SR1和SR2)的状态位,判断数据是否发送成功。

1-主发送器模式

I2C掌握器产生开始旗子暗记(S),然后通过检测EV5事宜,判断是否启动成功。
在知足EV5事宜后,主机发送器件地址+W,然后通过检测EV6事宜、判断是否发送器件地址成功。
在知足EV6事宜后,主机发送数据,然后通过检测EV8事宜,判断是否发送数据成功。
在发送完末了一个数据后,主机发送结束旗子暗记(P)结束通信过程。
如图:主发送器模式下IIC通信示意图:

EV5:总线正在进行通信(BUSY=1),主/从模式(MSL=1)及起始位是否己经发送(SB=1)。
EV6:处于发送器或吸收器状态(TRA=1),正在进行通信(BUSY=1),主/从模式(MSL=1).数据寄存器是否为空(TXE=1),地址是否已发送(ADDR=1,主模式)。
EV8:处于发送器或吸收器状态(TRA=1),正在进行通信(BUSY=1),主/从模式(MSL=1).数据寄存器是否为空(TXE=l),字节是否传输完成(BTF=1,主模式)。

2-主吸收器模式

I2C掌握器产生开始旗子暗记,然后通过检测EV5事宜,判断是否启动成功。
在知足EV5事宜后,主机发送器件地址,然后通过检测EV6事宜,判断是否发送器件地址成功。
在知足EV6事宜后,主机准备吸收从机发送过来的数据,然后通过检测EV7事宜,判断是否吸收数据成功。
如果吸收的不是末了一个数据的话,则主机发送ACK旗子暗记给从机。
如果吸收的是末了一个数据的话,则主机发送一个NACK旗子暗记,并发送结束旗子暗记,结束通信。
EV7:正在进行通信(BUSY=1),主/从模式(MSL=1),数据寄存器非空(RXNE=1)。
主吸收器模式下I2C通信示意图如图:

15.1.4 IIC 从模式

在从模式下,根据写入自身地址寄存器的地址(从模式下的器件地址),l2C掌握器通过比较器能够识主机发送过来的地址是否和其自身地址(7位或10位)同等。
在地址匹配的情形下,根据读写掌握状态,通过数据掌握逻辑可以吸收(写)或发送(读)数据。

1-从发送器模式

在检测到开始旗子暗记后,I2C掌握器通过检测EV1事宜,判断主机发送过来的器件地址是否和本机地址同等。
在知足EV1事宜后,从机发送一个ACK旗子暗记给主机,将数据发送给主机,并通过检测EV3事宜,判断是否发送数据成功。
在发送完末了一个数据后,从机检测到NACK旗子暗记和结束旗子暗记,结束通信。
EV1:正在进行通信(BUSY=1),吸收到的地址匹配(ADDR=1,从模式)。
EV3:处于发送器或吸收器状态(TRA=1),正在进行通信(BUSY=l),数据寄存器是否为空(TXE=1)。
从发送器模式下I2C通信示意图如图:

15.1.5 12C掌握碍中断

I2C掌握器有2个中断向量:一个中新由成功的地址/数期字管传输事宜发另一个中新由银误状态触发。
I2C掌握器支持多种中断事宜的要求,便于实时相应一些紧急事务,为了提高CPU利用率。
选常在I2C掌握器处于从模式时,利用中新办法来相应一系列事务的处理。
例如,从模式下数西的吸收、发送、停滞及缺点等,I2C掌握器中斯事宜如图所示:

15.2 IIC运用步骤和常用库函数15.2.1 IIC运用步骤

以IIC1为例这里,其他的与这是一样的.

(1)使能IIC1时钟和通信线复用引脚端口GPIOB的时钟。

使能IIC通信时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //I2C2时钟使能GPIO时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //GPIO时钟使能(2)初始化引脚

/GPIO引脚复用/GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); //将PB6复用给I2C1GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); //将PB7复用给I2C1/初始化GPIO / GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;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);// 初始化PB6:SCLGPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_Init(GPIOB, &GPIO_InitStructure);// 初始化PB7:SDA(3)初始化IIC事情模式

/ I2C 配置 /I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C模式 /I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // SCL 时钟线的占空比 I2C_InitStructure.I2C_OwnAddress1 =I2C_OWN_ADDRESS7; // 从机时,自身器件地址I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ; // 使能ACK相应//7bit的寻址模式 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = 400000; // 通信速率<=400KI2C_Init(I2C1, &I2C_InitStructure); // I2C2 初始化(4)使能IIC1掌握器

I2C_Cmd(I2C1, ENABLE); // 使能 I2C2(5)使能IIC ACK应答

I2C_AcknowledgeConfig(I2C1, ENABLE); //使能IIC ACK功能(6)中断使能

如果须要利用中断,则须要配置NVIC和使能IIC中断。

15.3.2 想用库函数

与I2C干系的函数和宏都被定义在以下两个文件中。
头文件:stm32f4xx_i2c.h.源文件:stm32f4xx i2c.c。

1-I2C初始化函数

void 12C_Init(12C_TypeDef I2Cx,I2C_InitTypeDef 12C_InitStruct);参数1:I2C_TypeDefI2Cx,I2C运用工具,一个构造体指针,表示形式是I2C1、I2C2和I2C3,以宏定义形式定义在stm32f4xx_.h文件中。
例如:

#define I2C1 ((12C_TypeDef ) I2C1_BASE)#define I2C2 ((12C_TypeDef ) 12C2_BASE)#define I2C3 ((I2C_TypeDef ) I2C3_BASE)

参数2:I2C_InitTypeDef I2C_InitStruct,I2C运用工具初始化构造体指针,以自定义的构造体形式定义在stm32f4xx i2c.h文件中。

typedef struct{uint32_t I2C_ClockSpeed;//时钟速率uint16_t I2C_Mode;//事情模式uint16 t I2C_DutyCycle;//时钟旗子暗记低电平/高电平的占空比uint16_t I2C_OwnAddressl;//自身器件地址,从机时利用uintl6_t 12C_Ack;//ACK应答使能uint16_t I2C_AcknowledgedAddress;/12C寻址模式}12C_InitTypeDef;成员1:uint32_tI2C_ClockSpced,时钟速率,根据自定义的通信速率,库程序会将I2C配置为标准模式(≤100kHz)或快速模式。
成员2: uintl6_tI2C_Mode,事情模式,可以是12C模式或SMBus模式,有如下定义:#define I2C_Mode_12C ((uintl6_t)0x0000) //I2C模式#define 12C_Mode_SMBusDevice ((uint16_t)0x0002)//SMBus设备模式#define I2C_Mode_SMBusHost ((uint16_t)0x000A) //SMBus 主机模式成员3:12C DutyCycle,定义时钟旗子暗记低电平/高电平的占空比,有如下定义:#define I2C_DutyCycle_16_9 ((uintl6_t)0x4000)//时钟旗子暗记低电干/高电干=16/9#define I2C_DutyCycle_2 ((uintl6_t)0xBFFF)//时钟旗子暗记低电平/高电平=2成员4:I2C_OwnAddress1,定义从机通信时的自身器件地址。
成员5:I2C_ Ack,定义ACK应答使能,有如下定义。
#define l2C_Ack_Enable ((uint16_t)0x0400)//使能ACK应答使能#define l2C Ack Disable ((uintl6_t1)0x0000)//禁止使能ACK应答使能成员6:I2C_AcknowledgedAddress,定义I2C寻址模式,有如下定义。
#define l2C_AcknowledgedAddress_7bi t ((uint16_t)0x4000)//7 (位地址寻址模式#define I2C_AcknowledgedAddress_10bit ((uint16_1)0xC000)//10位地址寻址模式
2-IIC 使能函数

void 12C_Cmd(I2C_TypeDef 12Cx,FunctionalState NewState);参数2:FunctionalState NewState,使能或禁止12CACK应答功能。
ENABLE:使能I2C ACK应答功能。
DISABLE:禁止I2CACK应答功能。
例如,使能I2C1 ACK应答功能:I2C_Cmd (12C1,ENABLE);参数1:I2C运用工具,同I2C初始化函数参数1。
4-I2C检测通信事宜函数

ErrorStatus I2C_CheckEvent(12C_TypeDef 12Cx,uint32_t I2C EVENT);参数1:I2C运用工具,同12C初始化参数1。
参数2:uint32t I2C EVENT,定义通信事宜,有EVI~EV9事宜,它D分国定 不同的I2C通信状态。
例如,EV8为主机吸收到字节数据事宜。
#deline I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint)2_1Cx00070084其他的定义拜会头文件stm32f4xx_i2c.h文件中的定义。
例如,等待I2C2主机发送完一个字节(EV8)。
while(!12C_CheckEvent(I2C2,12C_EVENT_MASTER_BVTE_ TRANSMITTED)返回:成功或失落败、ErorSiuatus是一个列举类型,定义如下:typedef enum {ERROR=0,SUCCESS=!ERROR}ErrorStatus;
5-I2C开始值号

/ @brief Generates I2Cx communication START condition. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @param NewState: new state of the I2C START condition generation. This parameter can be: ENABLE or DISABLE. @retval None./void I2C_GenerateSTART(I2C_TypeDef I2Cx, FunctionalState NewState)6-I2C掌握器产生结束旗子暗记函数

/ @brief Generates I2Cx communication STOP condition. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @param NewState: new state of the I2C STOP condition generation. This parameter can be: ENABLE or DISABLE. @retval None./void I2C_GenerateSTOP(I2C_TypeDef I2Cx, FunctionalState NewState)7-I2C掌握器发送7位寻址地址函数

/ @brief Transmits the address byte to select the slave device. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @param Address: specifies the slave address which will be transmitted @param I2C_Direction: specifies whether the I2C device will be a Transmitter or a Receiver. This parameter can be one of the following values @arg I2C_Direction_Transmitter: Transmitter mode @arg I2C_Direction_Receiver: Receiver mode @retval None./void I2C_Send7bitAddress(I2C_TypeDef I2Cx, uint8_t Address, uint8_t I2C_Direction)8-I2C掌握器发送一个字节的数据函数

/ @brief Sends a data byte through the I2Cx peripheral. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @param Data: Byte to be transmitted.. @retval None/void I2C_SendData(I2C_TypeDef I2Cx, uint8_t Data)9-I2C掌握器吸收一个字节的数据函数

/ @brief Returns the most recent received data by the I2Cx peripheral. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @retval The value of the received data./uint8_t I2C_ReceiveData(I2C_TypeDef I2Cx)10-I2C掌握器获取最新的通信事宜涵数

/ @brief Returns the last I2Cx Event. @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. @note For detailed description of Events, please refer to section I2C_Events in stm32f4xx_i2c.h file. @retval The last event/uint32_t I2C_GetLastEvent(I2C_TypeDef I2Cx)以上便是这些部分,详细的其他部分请查看干系.c以及.h文件和数据手册。
15.3 运用

#include "bsp_i2c_ee.h"#include "bsp_usart.h"uint16_t EEPROM_ADDRESS;static __IO uint32_t I2CTimeout = I2CT_LONG_TIMEOUT; static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);/ @brief I2C 事情模式配置 @param 无 @retval 无/void I2C_Config(void){I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /-------------------第1步--------------------/ /时钟使能/RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); //I2C2时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE); //GPIO时钟使能/-------------------第2步--------------------/ /GPIO引脚复用/GPIO_PinAFConfig(GPIOH, GPIO_PinSource4, GPIO_AF_I2C2); //将PH4复用给I2C2GPIO_PinAFConfig(GPIOH, GPIO_PinSource5, GPIO_AF_I2C2); //将PH5复用给I2C2/初始化GPIO / GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;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(GPIOH, &GPIO_InitStructure);// 初始化PH4:SCLGPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_Init(GPIOH, &GPIO_InitStructure);// 初始化PH5:SDA/-------------------第3步--------------------// I2C 配置 /I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C模式 /I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // SCL 时钟线的占空比 I2C_InitStructure.I2C_OwnAddress1 =I2C_OWN_ADDRESS7; // 从机时,自身器件地址I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ; // 使能ACK相应//7bit的寻址模式 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = 400000; // 通信速率<=400KI2C_Init(I2C2, &I2C_InitStructure); // I2C2 初始化 /-------------------第4步--------------------/I2C_Cmd(I2C2, ENABLE); // 使能 I2C2 /-------------------第5步--------------------/I2C_AcknowledgeConfig(I2C2, ENABLE); //使能IIC ACK功能EEPROM_ADDRESS = 0xA0;//EEPROM器件地址}/ @brief 将缓冲区中的数据写到I2C EEPROM中 @param @arg pBuffer:缓冲区指针 @arg WriteAddr:写地址 @arg NumByteToWrite:写的字节数 @retval 无/void I2C_Buffer_Write(u8 pBuffer, u8 WriteAddr, u16 NumByteToWrite){u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;Addr = WriteAddr % I2C_PageSize;count = I2C_PageSize - Addr;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;/ If WriteAddr is I2C_PageSize aligned /if(Addr == 0) {/ If NumByteToWrite < I2C_PageSize /if(NumOfPage == 0) {I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);I2C_WaitEepromStandbyState();}/ If NumByteToWrite > I2C_PageSize /else {while(NumOfPage--){I2C_Page_Write(pBuffer, WriteAddr, I2C_PageSize); I2C_WaitEepromStandbyState();WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}if(NumOfSingle!=0){I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);I2C_WaitEepromStandbyState();}}}/ If WriteAddr is not I2C_PageSize aligned /else {/ If NumByteToWrite < I2C_PageSize /if(NumOfPage== 0) {I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle);I2C_WaitEepromStandbyState();}/ If NumByteToWrite > I2C_PageSize /else{NumByteToWrite -= count;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize; if(count != 0){ I2C_Page_Write(pBuffer, WriteAddr, count);I2C_WaitEepromStandbyState();WriteAddr += count;pBuffer += count;} while(NumOfPage--){I2C_Page_Write(pBuffer, WriteAddr, I2C_PageSize);I2C_WaitEepromStandbyState();WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize; }if(NumOfSingle != 0){I2C_Page_Write(pBuffer, WriteAddr, NumOfSingle); I2C_WaitEepromStandbyState();}}} }/ @brief 写一个字节到I2C EEPROM中 @param @arg pBuffer:缓冲区指针 @arg WriteAddr:写地址 @retval 无/uint32_t I2C_Byte_Write(u8 pBuffer, u8 WriteAddr){/ Send STRAT condition 启动操作/I2C_GenerateSTART(I2C2, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV5 and clear it 检测总线是否忙/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);} / Send EEPROM address for write 发送器件地址 写操作 /I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV6 and clear it 等待ACK/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);} / Send the EEPROM's internal address to write to 发送器件内写地址 /I2C_SendData(I2C2, WriteAddr);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV8 and clear it 等待ACK/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);} / Send the byte to be written 写数据/I2C_SendData(I2C2, pBuffer); I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV8 and clear it 等待ACK/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);} / Send STOP condition 停滞操作/I2C_GenerateSTOP(I2C2, ENABLE);return 1;}/ @brief 在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数 不能超过EEPROM页的大小,AT24C02每页有8个字节 @param @arg pBuffer:缓冲区指针 @arg WriteAddr:写地址 @arg NumByteToWrite:写的字节数 @retval 无/uint32_t I2C_Page_Write(u8 pBuffer, u8 WriteAddr, u8 NumByteToWrite){I2CTimeout = I2CT_LONG_TIMEOUT;while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) //检测IIC掌握器是否忙 确认没有总线上没有通信{if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);} / Send START condition 启动操作/I2C_GenerateSTART(I2C2, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);} / Send EEPROM address for write 写器件地址 写操作/I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV6 ((uint32_t)0x00070082) and clear it 等待ACK 确认以下信息: TRA-发送器/吸收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);} / Send the EEPROM's internal address to write to 发送器件内写地址/ I2C_SendData(I2C2, WriteAddr); I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器/吸收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成 /while(! I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);} / While there is data to be written /while(NumByteToWrite--) {/ Send the current byte 写数据/I2C_SendData(I2C2, pBuffer); / Point to the next byte to be written /pBuffer++; I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器/吸收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成/while (!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);} }/ Send STOP condition 停滞操作/I2C_GenerateSTOP(I2C2, ENABLE);return 1;}/ @brief 从EEPROM里面读取一块数据 @param @arg pBuffer:存放从EEPROM读取的数据的缓冲区指针 @arg WriteAddr:吸收数据的EEPROM的地址 @arg NumByteToWrite:要从EEPROM读取的字节数 @retval 无/uint32_t I2C_Buffer_Read(u8 pBuffer, u8 ReadAddr, u16 NumByteToRead){ I2CTimeout = I2CT_LONG_TIMEOUT;//((u8 )0x4001080c) |=0x80; while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) //检测IIC掌握器是否忙{if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);}/ Send START condition 启动操作/I2C_GenerateSTART(I2C2, ENABLE);//((u8 )0x4001080c) &=~0x80;I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);}/ Send EEPROM address for write 写器件地址 写操作/I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV6 ((uint32_t)0x00070082) and clear it 等待ACK 确认以下信息: TRA-发送器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);}// / Clear EV6 by setting again the PE bit 打消事宜6 实际测试去掉也没有出错/// I2C_Cmd(I2C2, ENABLE);/ Send the EEPROM's internal address to write to 发送器件内读地址/I2C_SendData(I2C2, ReadAddr); I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV8 and clear it 等待ACK ((uint32_t)0x00070084) 确认以下信息: TRA-发送器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空 and BTF-字节传输完成 /while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);}/ Send STRAT condition a second time 重亲启动操作/ I2C_GenerateSTART(I2C2, ENABLE);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV5 ((uint32_t)0x00030001) and clear it 确认以下信息: BUSY-总线正在进行通信, MSL-主/从模式, and SB-起始位已经发送/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);}/ Send EEPROM address for read 发送器件地址+1 读操作/I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Receiver);I2CTimeout = I2CT_FLAG_TIMEOUT;/ Test on EV6 ((uint32_t)0x00030002) and clear it 等待ACK 确认以下信息: TRA-吸收器, BUSY-总线正在进行通信, MSL-主/从模式, TXE-数据寄存器为空, ADDR-地址已发送(主模式)/while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);}/ While there is data to be read /while(NumByteToRead) { I2CTimeout = I2CT_LONG_TIMEOUT;if(NumByteToRead == 1)//末了一个数据的话{/ Disable Acknowledgement 禁止ACK 结束数据吸收/I2C_AcknowledgeConfig(I2C2, DISABLE);/ Send STOP Condition 停滞操作/I2C_GenerateSTOP(I2C2, ENABLE);}else/ Enable Acknowledgement to be ready for another reception 使能ACK 重复数据吸收/I2C_AcknowledgeConfig(I2C2, ENABLE); while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)==0) //等待数据吸收结束 ((uint32_t)0x00030040) BUSY-总线正在进行通信, MSL-主/从模式, and RXNE-数据寄存器非空 flags{if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);} {/ Read a byte from the device 读取数据/pBuffer = I2C_ReceiveData(I2C2);/ Point to the next location where the byte read will be saved /pBuffer++; / Decrement the read bytes counter /NumByteToRead--;} }return 1;}/ @brief Wait for EEPROM Standby state @param 无 @retval 无/void I2C_WaitEepromStandbyState(void) {vu16 SR1_Tmp = 0;do{/ Send START condition /I2C_GenerateSTART(I2C2, ENABLE);/ Read I2C2 SR1 register /SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);/ Send EEPROM address for write /I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);}while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));/ Clear AF flag /I2C_ClearFlag(I2C2, I2C_FLAG_AF);/ STOP condition / I2C_GenerateSTOP(I2C2, ENABLE); }/ @brief Basic management of the timeout situation. @param errorCode:缺点代码,可以用来定位是哪个环节出错. @retval 返回0,表示IIC读取失落败./static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode){/ Block communication and all processes /return 0;}/END OF FILE/

#ifndef __I2C_EE_H#define __I2C_EE_H#include "stm32f4xx.h"/ AT24C01/02每页有8个字节 ///#define I2C_PageSize 8/ AT24C04/08A/16A每页有16个字节 /#define I2C_PageSize 16 / STM32 I2C 快速模式 /#define I2C_Speed 400000/ 这个地址只要与STM32外挂的I2C器件地址不一样即可 /#define I2C_OWN_ADDRESS7 0X0A /I2C接口/#define EEPROM_I2C I2C2#define EEPROM_I2C_CLK RCC_APB1Periph_I2C2#define EEPROM_I2C_CLK_INIT RCC_APB1PeriphClockCmd#define EEPROM_I2C_SCL_PIN GPIO_Pin_4 #define EEPROM_I2C_SCL_GPIO_PORT GPIOH #define EEPROM_I2C_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH#define EEPROM_I2C_SCL_SOURCE GPIO_PinSource4#define EEPROM_I2C_SCL_AF GPIO_AF_I2C2#define EEPROM_I2C_SDA_PIN GPIO_Pin_5 #define EEPROM_I2C_SDA_GPIO_PORT GPIOH #define EEPROM_I2C_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH#define EEPROM_I2C_SDA_SOURCE GPIO_PinSource5#define EEPROM_I2C_SDA_AF GPIO_AF_I2C2/等待超时时间/#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)#define I2CT_LONG_TIMEOUT ((uint32_t)(10 I2CT_FLAG_TIMEOUT))/ AT24C02 2kb = 256 B , 1个块 32 页, 8 字节/页,Block0 AT24C04 4kb = 512 B , 2个块232 页,16 字节/页,Block0~1 AT24C08 8kb = 1K B , 4个块432 页,16 字节/页,Block0~3 AT24C16 16kb = 2K B , 8个块832 页,16 字节/页,Block0~7 Device Address 1 0 1 0 A2 A1 A0 R/W 1 0 1 0 0 0 0 0 = 0XA0 1 0 1 0 0 0 0 1 = 0XA1 // EEPROM Addresses defines / #define EEPROM_Block0_ADDRESS 0xA0 / 块0 AT24C02 AT24C04 AT24C08 AT24C16/#define EEPROM_Block1_ADDRESS 0xA2 /块1 AT24C04 AT24C08 AT24C16/#define EEPROM_Block2_ADDRESS 0xA4 /块2 AT24C08 AT24C16/#define EEPROM_Block3_ADDRESS 0xA6 /块3 AT24C08 AT24C16/#define EEPROM_Block4_ADDRESS 0xA8 / 块4 AT24C16/ #define EEPROM_Block5_ADDRESS 0xAA /块5 AT24C16/#define EEPROM_Block6_ADDRESS 0xAC /块6 AT24C16/#define EEPROM_Block7_ADDRESS 0xAE /块7 AT24C16/void I2C_Config(void);void I2C_Buffer_Write(u8 pBuffer, u8 WriteAddr, u16 NumByteToWrite);uint32_t I2C_Byte_Write(u8 pBuffer, u8 WriteAddr);uint32_t I2C_Page_Write(u8 pBuffer, u8 WriteAddr, u8 NumByteToWrite);uint32_t I2C_Buffer_Read(u8 pBuffer, u8 ReadAddr, u16 NumByteToRead);void I2C_WaitEepromStandbyState(void);#endif / __I2C_EE_H /

标签:

相关文章

技能|电脑无法通电怎么解决_戴尔_电脑

如果按下电源按钮后戴尔打算机无法打开,不通电,请按照以下步骤打消故障。视频加载中...01检讨电源线、互换适配器与外设首先检讨电源...

通讯 2025-01-24 阅读1 评论0