1.I2C总线简介 I2C(Inter-Integrated Circuit ,内部集成电路)总线是一种由飞利浦Philip公司开发的串行总线。是两条串行的总线,它由一根数据线(SDA)和一根 时钟线(SDL)组成。I2C总线上可以接多个I2C设备,每个器件都有一个唯一的地址识别。同一时间只能有一个主设备,其他为从设备。通常MCU作为主设备控制,外设作为从设备。 2.I2C硬件电路 I2C总线为漏极开路结构(OD),因此它们必须接有上拉电阻,阻值常为 4k7 或 10k ;当总线空闲时,两根线均为高电平。OD门与其它任意数量的OD与OC门成"线与"关系,即当总线上的任一器件输出的低电平,都将使总线的信号变低。 3.I2C协议 I2C有三种状态信号:开始信号、结束信号和应答信号 开始信号:SCL为高电平时,SDA由高电平转变为低电平跳变,表示开始通信。 结束信号:SCL为高电平时,SDA由低电平转变为高电平跳变,结束结束通信。 应答信号:接收数据的IC在接收到一个字节数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。 在数据传输过程中,SCL时钟为主设备控制,SCL为高的时候读取数据SDA的数据,SCL为低的时候,主设备改变SDA的数据准备传输下一位。数据从高位开始传输,当传输8位后,主设备会释放SDA总线。如果从设备正确接收到数据,则从设备会拉低SDA总线,则产生一个应答信号。如果从设备出错,不拉低SDA总线,由于上拉电阻的作用,SDA的电平会变为高电平,即为非应答信号。数据传输总是以开始信号开始传输,以结束信号终止传输,中间可以传输多个字节的数据。 4.AT24Cxx AT24C系列为美国ATMEL公司推出的串行COMS型E2PROM。芯片型号后两位表示芯片容量,例如ATC24C02为2K。引脚图中A0、A1、A2为器件地址引脚,GND为地,VCC为正电源,WP为写保护,SCL为串行时钟线,SDA为串行数据线。 AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。A2~A0为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。 写字节操作MCU先发送一个开始信号(START),然后发送器件写操作地址(DEVICE ADDRESS),E2PROM接收到地址后,如果地址和自身的地址一样,E2PROM就会回一个应答信号(ACK)。MCU接收到应答信号后,再发送要操作的内存地址(WORD ADDRESS),得到应答后再传输写入的数据(DATA)。再次等待E2PROM应答后发送结束信号(STOP)结束传输。 E2PROM支持连续写操作,操作和单个字节类似,先发送设备写操作地址(DEVICE ADDRESS),然后发送内存起始地址(WORD ADDRESS),然后不断传输数据。E2PROM的地址指针会自动递增,数据会依次保存在内存中。 E2PROM读字节操作如下,先发送设备写操作地址(DEVICE ADDRESS),然后发送要读取内存的地址(WORD ADDRESS)。然后重新发送开始信号(START),发送设备读操作地址(DEVICE ADDRESS)对E2PROM进行读操作。此时MCU释放SDA数据线,E2PROM控制SDA数据总线,将内存地址中对应的数据发送给MCU。 同理,E2PROM可以连续读操作,在读一个字节后,MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据,不应答发送结束信号后终止传输。 注意:每次操作都是由MCU先发送开始信号,然后发送器件地址,写操作发送写设备地址,读操作发送读设备地址,然后再传输数据。 5.示例程序 本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。I2C1选择I2C模式,PB8,PB9管脚分别配置为I2C1_SDA,I2C2_SCL。 I2C为默认设置不作修改。只需注意一下,I2C为标准模式,I2C传输速率(I2C Speed Frequency)为100KHz。 生成报告以及代码,编译程序。在i2c.c文件中可以看到ADC初始化函数。在stm32f7xx_hal_i2c.h头文件中可以看到I2C的操作函数。分别对应轮询,中断和DMA三种控制方式。 在mian.c文件前面声明两个输出存储读写数据,宏定义E2PROM读写地址以及缓存数据长度。 /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ #define ADDR_24LCxx_Write 0xA0 #define ADDR_24LCxx_Read 0xA1 #define BufferSize 0x100 uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize]; uint16_t i; /* USER CODE END PV */
/* USER CODE BEGIN 2 */ printf("\r\n***************I2C Example*******************************\r\n"); for(i=0; i<256; i++) WriteBuffer[i]=i; /* WriteBuffer init */ /* wrinte date to EEPROM */ if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 0, I2C_MEMADD_SIZE_8BIT,WriteBuffer,BufferSize, 0x10) == HAL_OK) printf("\r\n EEPROM 24C02 Write Test OK \r\n"); else printf("\r\n EEPROM 24C02 Write Test False \r\n"); /* read date from EEPROM */ HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,ReadBuffer,BufferSize, 0x10); for(i=0; i<256; i++) printf("0x%02X ",ReadBuffer[i]); if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */ printf("\r\n EEPROM 24C02 Read Test OK\r\n"); else printf("\r\n EEPROM 24C02 Read Test False\r\n"); /* USER CODE END 2 */ 程序中先初始化写数据缓存。然后调用HAL_I2C_Mem_Write()函数将数据写入E2PROM中。根据函数返回值判断写操作是否正确。在I2C中可以找到内存写函数说明。第一个参数为I2C操作句柄。第二个参数为E2PROM的写操作设备地址。第三个参数为内存地址,第二个参数为内存地址长度,E2PROM内存长度为8bit,第四个参数为数据缓存的起始地址,第五个参数为传输数据的大小,第六个参数为操作超时时间。 /**
* @brief Write an amount of data in blocking mode to a specific memory address
* @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @param DevAddress: Target device address
* @param MemAddress: Internal memory address
* @param MemAddSize: Size of internal memory address
* @param pData: Pointer to data buffer
* @param Size: Amount of data to be sent
* @param Timeout: Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) HAL_I2C_Mem_Read()函数描述如下。第一个参数为I2C操作句柄。第二个参数为E2PROM的读操作设备地址。第三个参数为内存地址,第二个参数为内存地址长度,第四个参数为读取数据存储的起始地址,第五个参数为传输数据的大小,第六个参数为操作超时时间。/** * @brief Read an amount of data in blocking mode from a specific memory address * @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains * the configuration information for the specified I2C. * @param DevAddress: Target device address * @param MemAddress: Internal memory address * @param MemAddSize: Size of internal memory address * @param pData: Pointer to data buffer * @param Size: Amount of data to be sent * @param Timeout: Timeout duration * @retval HAL status */ HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) |
: 总结一下之前的评论 1. 需要修改24c02的写操作,按照前面有个人说的,分成32次写入,延时,写入成功,代码修改如下。 for (i=0; i<32; i++) { if(HAL_I2C_Mem ...
: for (j=0; j<32; j++) { if(HAL_I2C_Mem_Write(&hi2c2, ADDR_24LCxx_Write, 8*j, I2C_MEMADD_SIZE_8BIT,WriteBuffer+8*j,8, 1000) == H ...
: AT24C256读出来也是FF,怎么改啊
: 为什么我读出来都是0XFF呢AT24C256