1.I2C总线简介
I2C(Inter-Integrated Circuit ,内部集成电路)总线是一种由飞利浦Philip公司开发的串行总线。是两条串行的总线,它由一根数据线(SDA)和一根 时钟线(SDL)组成。I2C总线上可以接多个I2C设备,每个器件都有一个唯一的地址识别。同一时间只能有一个主设备,其他为从设备。通常MCU作为主设备控制,外设作为从设备。
2.I2C硬件电路
I2C总线为漏极开路结构(OD),因此它们必须接有上拉电阻,阻值常为 4k7 或 10k ;当总线空闲时,两根线均为高电平。OD门与其它任意数量的OD与OC门成"线与"关系,即当总线上的任一器件输出的低电平,都将使总线的信号变低。
0
|
|
|
|
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为串行数据线。
file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/57ab9950500949099da42d872e4ebde9/clipboard.png
|
|
|
|
|
AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。A2~A0为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。
file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/8fb304ce19184d9584f34784e0cf222b/clipboard.png
|
|
|
|
|
写字节操作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。
file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/7dbd33aef2474eaba675a89616ce9cf8/clipboard.png file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/24e5798ffa454749b7dfe21db7a65370/clipboard.png
|
|
|
|
|
I2C为默认设置不作修改。只需注意一下,I2C为标准模式,I2C传输速率(I2C Speed Frequency)为100KHz。
|
|
|
|
|
生成报告以及代码,编译程序。在i2c.c文件中可以看到ADC初始化函数。在stm32f7xx_hal_i2c.h头文件中可以看到I2C的操作函数。分别对应轮询,中断和DMA三种控制方式。
|
|
|
|
|
在mian.c文件前面声明两个输出存储读写数据,宏定义E2PROM读写地址以及缓存数据长度。
1 | /* USER CODE BEGIN PV */ |
2 | /* Private variables ---------------------------------------------------------*/ |
3 | #define ADDR_24LCxx_Write 0xA0 |
4 | #define ADDR_24LCxx_Read 0xA1 |
5 | #define BufferSize 0x100 |
6 | uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize]; |
|
|
|
|
|
在mian()函数里面添加应用程序读写E2PROM。
01 | /* USER CODE BEGIN 2 */ |
02 | printf("rn***************I2C Example*******************************rn"); |
04 | WriteBuffer=i; /* WriteBuffer init */ |
05 | /* wrinte date to EEPROM */ |
06 | if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 0, I2C_MEMADD_SIZE_8BIT,WriteBuffer,BufferSize, 0x10) == HAL_OK) |
07 | printf("rn EEPROM 24C02 Write Test OK rn"); |
09 | printf("rn EEPROM 24C02 Write Test False rn"); |
11 | /* read date from EEPROM */ |
12 | HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT,ReadBuffer,BufferSize, 0x10); |
14 | printf("0x%02X ",ReadBuffer); |
16 | if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */ |
17 | printf("rn EEPROM 24C02 Read Test OKrn"); |
19 | printf("rn EEPROM 24C02 Read Test Falsern"); |
|
|
|
|
|
程序中先初始化写数据缓存。然后调用HAL_I2C_Mem_Write()函数将数据写入E2PROM中。根据函数返回值判断写操作是否正确。在I2C中可以找到内存写函数说明。第一个参数为I2C操作句柄。第二个参数为E2PROM的写操作设备地址。第三个参数为内存地址,第二个参数为内存地址长度,E2PROM内存长度为8bit,第四个参数为数据缓存的起始地址,第五个参数为传输数据的大小,第六个参数为操作超时时间。
02 | * @brief Write an amount of data in blocking mode to a specific memory address |
03 | * @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains |
04 | * the configuration information for the specified I2C. |
05 | * @param DevAddress: Target device address |
06 | * @param MemAddress: Internal memory address |
07 | * @param MemAddSize: Size of internal memory address |
08 | * @param pData: Pointer to data buffer |
09 | * @param Size: Amount of data to be sent |
10 | * @param Timeout: Timeout duration |
13 | 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()函数读取E2PROM中刚才写入的数据。HAL_I2C_Mem_Read()函数描述如下。第一个参数为I2C操作句柄。第二个参数为E2PROM的读操作设备地址。第三个参数为内存地址,第二个参数为内存地址长度,第四个参数为读取数据存储的起始地址,第五个参数为传输数据的大小,第六个参数为操作超时时间。
02 | * @brief Read an amount of data in blocking mode from a specific memory address |
03 | * @param hi2c : Pointer to a I2C_HandleTypeDef structure that contains |
04 | * the configuration information for the specified I2C. |
05 | * @param DevAddress: Target device address |
06 | * @param MemAddress: Internal memory address |
07 | * @param MemAddSize: Size of internal memory address |
08 | * @param pData: Pointer to data buffer |
09 | * @param Size: Amount of data to be sent |
10 | * @param Timeout: Timeout duration |
13 | HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t |
14 | MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) |
|
|
|
|
|
程序最后调用memcmp()函数判断读写的两个缓存的数据是否一致。memcmp()是比较内存区域是否相等,标准库里面的函数,在main.c前面添加string.h头文件。
1 | /* USER CODE BEGIN Includes */ |
3 | /* USER CODE END Includes */ |
将AT24CXX EEPROM Board模块插入到Open746I开发板I2C1中,编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示如下信息。
|
|
|
|
|