一、AT24Cxx芯片引脚
二、新建STM32CubeMX
1.SYS
2.RCC
3.IIC
4.USART
5.Clock Configuration
6.Project Manager
三、添加程序
新建两个文件分别为EEPROM_IIC_AT24CXX.c和EEPROM_IIC_AT24CXX.h
EEPROM_IIC_AT24CXX.c
#include "EEPROM_IIC_AT24CXX.h"
#include <string.h>
/**
* @brief AT24C02任意地址写一个字节数据
* @param addr —— 写数据的地址(0-255)--本次使用AT24C64,写数据的地址(0-8189),不同芯片大小在EEPROM_IIC_AT24CXX.h中有定义
* @param dat —— 存放写入数据的地址
* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat)
{
HAL_StatusTypeDef result;
result = HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, dat, 1, 0xFFFF);
HAL_Delay(5); // 写一个字节,延迟一段时间,不能连续写
return result;
}
/**
* @brief AT24C02任意地址读一个字节数据
* @param addr —— 读数据的地址(0-255)
* @param read_buf —— 存放读取数据的地址
* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf)
{
return HAL_I2C_Mem_Read(&hi2c1, AT24CXX_ADDR_READ, addr, I2C_MEMADD_SIZE, read_buf, 1, 0xFFFF);
}
/**
* @brief AT24C02任意地址连续写多个字节数据
* @param addr —— 写数据的地址(0-255)
* @param dat —— 存放写入数据的地址
* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size)
{
uint8_t i = 0;
uint16_t cnt = 0; // 写入字节计数
HAL_StatusTypeDef result; // 返回是否写入成功
/* 对于起始地址,有两种情况,分别判断 */
if(0 == addr % 8)
{
/* 起始地址刚好是页开始地址 */
/* 对于写入的字节数,有两种情况,分别判断 */
if(size <= 8)
{
// 写入的字节数不大于一页,直接写入
result = HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, dat, size, 0xFFFF);
HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点
return result;
}
else
{
// 写入的字节数大于一页,先将整页循环写入
for(i = 0; i < size/8; i++)
{
HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, &dat[cnt], 8, 0xFFFF);
// 一次写入了八个字节,延迟久一点
HAL_Delay(20); // 写完八个字节,延迟久一点
addr += 8;
cnt += 8;
}
// 将剩余的字节写入
result = HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, &dat[cnt], size - cnt, 0xFFFF);
HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点
return result;
}
}
else
{
/* 起始地址偏离页开始地址 */
/* 对于写入的字节数,有两种情况,分别判断 */
if(size <= (8 - addr%8))
{
/* 在该页可以写完 */
result = HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, dat, size, 0xFFFF);
HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点
return result;
}
else
{
/* 该页写不完 */
// 先将该页写完
cnt += 8 - addr%8;
HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, dat, cnt, 0xFFFF);
HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点
addr += cnt;
// 循环写整页数据
for(i = 0;i < (size - cnt)/8; i++)
{
HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, &dat[cnt], 8, 0xFFFF);
HAL_Delay(20); // 写完八个字节,延迟久一点
addr += 8;
cnt += 8;
}
// 将剩下的字节写入
result = HAL_I2C_Mem_Write(&hi2c1, AT24CXX_ADDR_WRITE, addr, I2C_MEMADD_SIZE, &dat[cnt], size - cnt, 0xFFFF);
HAL_Delay(20); // 写完八个字节(最多八个字节),延迟久一点
return result;
}
}
}
/**
* @brief AT24C02任意地址连续读多个字节数据
* @param addr —— 读数据的地址(0-255)
* @param dat —— 存放读出数据的地址
* @retval 成功 —— HAL_OK
*/
uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size)
{
return HAL_I2C_Mem_Read(&hi2c1, AT24CXX_ADDR_READ, addr, I2C_MEMADD_SIZE, recv_buf, size, 0xFFFF);
}
EEPROM_IIC_AT24CXX.h
#include "main.h"
#include "i2c.h"
#define AT24CXX_ADDR_WRITE 0xA0 // 写命令
#define AT24CXX_ADDR_READ 0xA1 // 读命令
#define AT24C1 127
#define AT24C2 255
#define AT24C4 511
#define AT24C8 1023
#define AT24C16 2047
#define AT24C32 4095
#define AT24C64 8189
#define AT24C128 16383
#define AT24C256 32767
#define BufferSize AT24C64//芯片型号
// 根据BufferSize宏的值来设置I2C_MEMADD_SIZE
#if BufferSize == AT24C64
#define I2C_MEMADD_SIZE I2C_MEMADD_SIZE_16BIT
#elif BufferSize == AT24C02
#define I2C_MEMADD_SIZE I2C_MEMADD_SIZE_8BIT
#endif
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat);
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf);
uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size);
uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size);
printf重定向
参考STM32(keil5)使用printf串口输出(微库法)、usb_printf实现USB虚拟串口输出
修改main.c
添加头文件
#include <stdio.h>
#include "EEPROM_IIC_AT24CXX.h"
main中
printf("\r\n***************I2C EEPROM Example*******************************\r\n");
// uint32_t i;
// uint8_t j;
// for(i = 0; i < 256; i++)
// {
// WriteBuffer[i] = i; /* WriteBuffer init */
// printf("0x%02X ", WriteBuffer[i]);
// if(i % 16 == 15)
// {
// printf("\n\r");
// }
// }
//
///* write date to EEPROM */
// for (j = 0; j < 32; j++)
// {
// if(At24c02_Write_Byte(8*j,WriteBuffer+8*j) == HAL_OK)//根据芯片每页字节大小修改,如AT24C02即为I2C_MEMADD_SIZE_8BIT
// {
// printf("EEPROM 24C64 Write Test OK \r\n");
// }
// else
// {
// printf("\r\n EEPROM 24C64 Write Test False \r\n");
// }
// }
//
// /* read date from EEPROM */
// At24c02_Read_Amount_Byte(0, ReadBuffer, BufferSize); //根据芯片每页字节大小修改,如AT24C02即为I2C_MEMADD_SIZE_8BIT
// for(i = 0; i < 256; i++)
// {
// printf("0x%02X ",ReadBuffer[i]);
// if(i%16 == 15)
// {
// printf("\n\r");
// }
// }
//
// if(memcmp(WriteBuffer,ReadBuffer,255) == 0 ) /* check date */
// {
// printf("EEPROM 24C64 Read Test OK\r\n");
// }
// else
// {
// printf("\r\n EEPROM 24C64 Read Test False\r\n");
// }
// 单个字节 读写测试
uint8_t simple_write_dat = 0xa5; // 一个字节
uint8_t simple_recv_buf = 0;
if(HAL_OK == At24c02_Write_Byte(10, &simple_write_dat))
{printf("Simple data write success \r\n");}
else
{printf("Simple data write fail \r\n");}
HAL_Delay(50);
if(HAL_OK == At24c02_Read_Byte(10, &simple_recv_buf))
{printf("Simple data read success, recv_buf = 0x%02X \r\n", simple_recv_buf);}
else
{printf("Simple data read fail \r\n");}
printf("---------单个字节读写 测试结束------------\r\n");
// 浮点数 读写测试
union float_union
{
float float_write_dat; // 浮点数占4个字节
double double_write_dat; // 双精度浮点数占8个字节
uint8_t buf[8]; // 定义 8个字节 的空间
};
union float_union send_float_data; // 用来发送
union float_union rev_float_data; // 用来接收
// 测试浮点数
send_float_data.float_write_dat = 3.1415f;
if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 4))
{printf("Float data write success \r\n");}
else
{printf("Float data write fail \r\n");}
HAL_Delay(50);
if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 4))
{printf("Float data read success, recv_buf = %f \r\n", rev_float_data.float_write_dat);}// 默认输出六位小数
else
{printf("Float data read fail \r\n");}
// 测试双精度浮点数
send_float_data.double_write_dat = 3.1415f;
if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 8))
{printf("Double data write success \r\n");}
else
{printf("Double data write fail \r\n");}
HAL_Delay(50);
if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 8))
{printf("Double data read success, recv_buf = %.15f \r\n", rev_float_data.double_write_dat);}// 最多15位小数
else
{printf("Double data read fail \r\n");}
printf("----------浮点数读写测试 测试结束----------- \r\n");
// 连续数据读写测试
uint8_t write_dat[22] = {0}; // 22个字节
uint8_t recv_buf[22] = {0};
printf("正在往数组中填充数据... \r\n");
for(int i = 0; i < 22; i++)
{
write_dat[i] = i;
printf("%02X ", write_dat[i]);
}
printf("\r\n 数组中数据填充完毕... \r\n");
if(HAL_OK == At24c02_Write_Amount_Byte(0, write_dat, 22))
{printf("24c02 write success \r\n");}
else
{printf("24c02 write fail \r\n");}
HAL_Delay(50);
if(HAL_OK == At24c02_Read_Amount_Byte(0, recv_buf, 22))
{
printf("read success \r\n");
for(int i = 0; i < 22; i++)
{
printf("0x%02X ", recv_buf[i]);
}
printf("\r\n");
}
else
{printf("read fail\r\n");}
printf("----------连续数据读写 测试结束----------- \r\n");
四、例程
例程1:
CubeMX配置STM32F103C6T6硬件IIC读写EEPROM-AT24C64(HAL库)