STM32软件I2C读写AT24C64 - 指南

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容量) = 页数 × 页内字节单元数。

AT24CXXXbit容量Byte容量页数页内字节单元数
AT24C01    1Kbit128Byte16页 8Byte
AT24C02    2Kbit    256Byte32页 8Byte
AT24C04    4Kbit    512Byte32页16Byte
AT24C08    8Kbit    1024Byte64页 16Byte
AT24C16    16Kbit2048Byte128页  16Byte
AT24C32    32Kbit    4096Byte128页  32Byte
AT24C6464Kbit8192Byte256页32Byte
AT24C128    128Kbit    16384Byte256页64Byte
AT24C256    256Kbit    32768Byte512页 64Byte

参考文章

posted @ 2025-10-24 17:01  wzzkaifa  阅读(12)  评论(0)    收藏  举报