AT24C64存储空间大小为64Kbit,也就是65536bit,能存放65536/8 = 8192Byte数据。
写数据
1、按字节写

发送了起始信号后,第一部分要先发送从机地址,第二部分发送访问的存储地址,第三部分发送写入的一字节数据。
从机地址按硬件上EEPROM芯片的A2 A1 A0引脚接线来定义。
存储地址可以看到由13位组成,最左三位是无意义的位,因为按照上面所说,AT24C64可以存储8192个字节的数据,实际以0为起始的话就只有8191个数据,8191换算成二进制为00011111 11111111,可以看出刚好能由13位表示EEPROM内部数据的存储地址。
void AT24C64_W(uint16_t Address, uint8_t Data)
{I2C_Start();I2C_SendByte(AT24C64_Write);uint8_t ack1 = I2C_ReceiveAck();I2C_SendByte(Address>>8);I2C_ReceiveAck();I2C_SendByte(Address);I2C_ReceiveAck();I2C_SendByte(Data);uint8_t ack2 = I2C_ReceiveAck();I2C_Stop();
}
2、按页写

与按字节写入相比,页写入在第一个字节写完后再写了x个数据,因为AT24C64每页32个字节,所以这里的x = 3,也就是再写3byte后结束按页写入。
需要注意的是,每写一个Byte的数据页内地址+1,红线画出来的地方表示当前页写满后会重新覆盖掉这一页前面的数据,而不会自动跳转到下一页。
自己写的简易版按页写数据
void AT24C64_W_Page(uint16_t Address, uint8_t *Data)
{uint8_t i;I2C_Start();I2C_SendByte(AT24C64_Write);uint8_t ack1 = I2C_ReceiveAck();I2C_SendByte(Address>>8);I2C_ReceiveAck();I2C_SendByte(Address);I2C_ReceiveAck();for (i = 0; i < 32; i++){I2C_SendByte(Data[i]);I2C_ReceiveAck();}I2C_Stop();
}
ai升级版按页写数据
- HAL库要求:传入
(7位地址 << 1),即0x50 << 1 = 0xA0。- 底层行为:HAL库会在总线上发出正确的8位地址(
0xA0写,0xA1读)。- 推荐实践:使用
HAL_I2C_Mem_Read/Write简化操作,避免手动处理方向位。
#define AT24C64_ADDR 0x50 // I2C设备地址
/*** @brief 向AT24C64写入一页数据(最多32字节)* @param page_num 页号(0~255,共256页)* @param offset 页内偏移(0~31)* @param data 待写入数据指针* @param len 数据长度(不超过32-offset)* @return HAL_OK成功,其他失败*/
HAL_StatusTypeDef AT24C64_PageWrite(uint8_t page_num, uint8_t offset, uint8_t *data, uint8_t len) {// 参数检查if (page_num > 255 || offset > 31 || len > (32 - offset)) {return HAL_ERROR;}// 计算16位EEPROM地址(高5位为页号,低8位为页内地址)uint16_t mem_addr = (page_num << 5) | offset;uint8_t addr_buffer[2] = { (uint8_t)(mem_addr >> 8), (uint8_t)(mem_addr & 0xFF) };// 组合I2C传输数据:地址 + 数据uint8_t i2c_buffer[2 + 32]; // 地址2字节 + 数据最多32字节memcpy(i2c_buffer, addr_buffer, 2);memcpy(i2c_buffer + 2, data, len);// 启动I2C传输HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, // I2C句柄(需提前初始化)AT24C64_ADDR << 1, // 设备地址(左移1位,HAL库要求)i2c_buffer, // 数据缓冲区2 + len, // 总长度(地址+数据)HAL_MAX_DELAY // 超时时间);// 等待写入完成(AT24C64需要约5ms内部写入周期)if (status == HAL_OK) {HAL_Delay(5);}return status;
}
uint8_t data[32] = {0x01, 0x02, 0x20}; // 3字节数据HAL_StatusTypeDef status = AT24C64_PageWrite(1, 3, data, 3); // 写入第1页,偏移3,地址为:0x35
读数据
1.当前地址读取数据。

2.选定地址读取数据 。

3.连续读取数据。

void AT24C64_R(uint16_t Address, uint8_t *PBUff, uint16_t datalen)
{uint8_t i;I2C_Start();I2C_SendByte(AT24C64_Write);I2C_ReceiveAck();I2C_SendByte(Address>>8);I2C_ReceiveAck();I2C_SendByte(Address);uint8_t ack4 = I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C64_Read);uint8_t ack3 = I2C_ReceiveAck();for (i = 0; i < datalen - 1; i++){PBUff[i] = I2C_ReceiveByte();I2C_Ack();}PBUff[datalen - 1] = I2C_ReceiveByte();I2C_NAck();I2C_Stop();
}
注意:写完数据建议等待5ms,等待数据写入完成
AT24CXXX容量
总容量(Byte容量) = 页数 × 页内字节单元数。
| AT24CXXX | bit容量 | Byte容量 | 页数 | 页内字节单元数 |
| AT24C01 | 1Kbit | 128Byte | 16页 | 8Byte |
| AT24C02 | 2Kbit | 256Byte | 32页 | 8Byte |
| AT24C04 | 4Kbit | 512Byte | 32页 | 16Byte |
| AT24C08 | 8Kbit | 1024Byte | 64页 | 16Byte |
| AT24C16 | 16Kbit | 2048Byte | 128页 | 16Byte |
| AT24C32 | 32Kbit | 4096Byte | 128页 | 32Byte |
| AT24C64 | 64Kbit | 8192Byte | 256页 | 32Byte |
| AT24C128 | 128Kbit | 16384Byte | 256页 | 64Byte |
| AT24C256 | 256Kbit | 32768Byte | 512页 | 64Byte |
参考文章