导语“本次 教程使用CubeMx配置I2C进行I2C总线设备的数据读写操作,使用EEPROM作为实验对象”
01第一节 系统要求
•硬件
野火指南者开发板
•软件
CubeMx & MDK & 串口调试助手
•原理图
我们可以从原理图中得到使用的I2C1,AT24C02的设备地址的第三位是000,容量是256个字节。设备地址从下图得到:
不带读写方向的使用左移得到的地址为0b10100000->0xA0, 读地址为:0xA1,写地址为0xA0;
注意:(1) 操作ATC02的时候,多字节写入的时候没写入一个字节,延时最小5ms, 多字节读的时候没有要求,页写入的时候每8个字节为一页,共32页。
02第二节 CubeMx的配置
我们依然使用之前的USART的项目,在此基础上进行I2C的配置,串口的使用是进行EEPROM读写数据显示在控制台上,使用CubeMx进行I2C的配置:
I2C的配置很简单,完成上述配置后生成代码。
03第三节MDK的代码编写
使用MDK打开CubeMx生成的代码进行应用代码编写。
(1)在main.c 中进行AT24C02的相关宏定义和变量定义:
#define ADDR_AT24C_Write 0xA0
#define ADDR_AT24C_Read 0xA1
#define DEV_ADDR_ATC02 0xA0 //0x50 左移得到的。
#define ATC02_BufferSize 256 // 256
#define I2C_TIMEOUT 0xFF
#define AT_I2C hi2c1
uint8_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");
编译上述程序后下载。
04第四节效果演示
使用串口观察写入的数据和读出的数据是否一致?
可以看到I2C操作EEPROM进行读写都是正常的。
评论
查看更多