![](http://img.2748.net/2023/0706/20230706013656466.jpg)
导语“本次 教程使用CubeMx配置I2C进行I2C总线设备的数据读写操作,使用EEPROM作为实验对象”
(资料图片)
•硬件
野火指南者开发板
•软件
CubeMx & MDK & 串口调试助手
•原理图
我们可以从原理图中得到使用的I2C1,AT24C02的设备地址的第三位是000,容量是256个字节。设备地址从下图得到:
不带读写方向的使用左移得到的地址为0b10100000->0xA0, 读地址为:0xA1,写地址为0xA0;
注意:(1) 操作ATC02的时候,多字节写入的时候没写入一个字节,延时最小5ms, 多字节读的时候没有要求,页写入的时候每8个字节为一页,共32页。
我们依然使用之前的USART的项目,在此基础上进行I2C的配置,串口的使用是进行EEPROM读写数据显示在控制台上,使用CubeMx进行I2C的配置:
I2C的配置很简单,完成上述配置后生成代码。
使用MDK打开CubeMx生成的代码进行应用代码编写。
(1)在main.c 中进行AT24C02的相关宏定义和变量定义:
#define ADDR_AT24C_Write0xA0#define ADDR_AT24C_Read 0xA1#define DEV_ADDR_ATC02 0xA0 //0x50 左移得到的。#define ATC02_BufferSize 256 // 256#define I2C_TIMEOUT 0xFF#define AT_I2C hi2c1uint8_t AT24_WriteBuffer[ATC02_BufferSize],AT24_ReadBuffer[ATC02_BufferSize];
( 2 ) 应用函数申明:
HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,uint16_t DevAddress, uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size,uint32_t Timeout);HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,uint16_t DevAddress, uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size,uint32_t Timeout);
I2CWriteBuffer()是自定义的任意字节写入I2C-AT24C02的函数,I2CReadBuffer()是任意字节读写函数。这两个函数的实现采用HAL库的这两个函数:
1)HALStatusTypeDef HALI2CMemWrite(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress, uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout);
参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,写的数据,数据大小,超时时间)
2)HALStatusTypeDef HALI2CMemRead(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress, uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout);
参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,读出数据,数据大小,超时时间)
为什么不直接使用库函数呢?是因为在测试中AT24C02读写不正常,查看AT24C02的手册发现,单个字节写入没问题,多字节的写入需要每个字节延时5ms, 其实多字节的读没有问题,这个从新实现了下。可以连续8个字节的页写入,这个不需要延时。
(3)多字节的读写函数:
/*这里自己实现多字节的ATC02的写操作*/HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,uint16_t DevAddress, uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size,uint32_t Timeout){ uint16_t count=0; for(count=0;count { if(HAL_I2C_Mem_Write(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK) { MemAddress ++; pData ++; HAL_Delay(5); } else { printf("i2c write is error tn"); return HAL_ERROR; } } return HAL_OK;}/*这里自己实现多字节的ATC02的读操作*/HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,uint16_t DevAddress, uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size,uint32_t Timeout){ uint16_t count=0; for(count=0;count< Size;count ++) { if(HAL_I2C_Mem_Read(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK) { MemAddress ++; pData ++; //HAL_Delay(5); } else { printf("i2c read is error n"); return HAL_ERROR; } } return HAL_OK;}
(4)在main函数中添加测试代码:
uint16_t num_atc=0; printf("this is test for I2C device read and write in ATC02rn"); printf("/**--------------------开始I2C-------------------------**/rn"); for( num_atc=0;num_atc { AT24_WriteBuffer[num_atc]=num_atc; printf("0x%xt",AT24_WriteBuffer[num_atc]); } if(I2C_Write_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_WriteBuffer,ATC02_BufferSize, I2C_TIMEOUT) == HAL_OK) { printf("write i2c lots bytes is oktn"); } if(HAL_I2C_Mem_Read(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK) { printf("rn EEPROM 24C02 read data Test OK rn"); } else { printf("rn EEPROM 24C02 read data Test False rn"); }/*这里使用自定义多字节读函数也是正常的*//* if(I2C_Read_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK) { printf("i2c read lots is oktn"); }*/ for(num_atc=0; num_atc< ATC02_BufferSize; num_atc++) { printf("0x%xt",AT24_ReadBuffer[num_atc]); } if(memcmp(AT24_WriteBuffer,AT24_ReadBuffer,ATC02_BufferSize) == 0 ) /* check date */ { printf("rn EEPROM 24C02 Read and write Test OKrn"); } else { printf("rn EEPROM 24C02 Read and write Test Falsern"); } printf("/**--------------------结束I2C-------------------------**/rn");
编译上述程序后下载。
使用串口观察写入的数据和读出的数据是否一致?
可以看到I2C操作EEPROM进行读写都是正常的。
标签: