STM32驱动AT24C256 EEPROM:I2C通信与数据存储实战

1. 项目背景与核心需求

在嵌入式开发中,非易失性存储是系统设计的关键环节。AT24C256作为一款32KB容量的I2C接口EEPROM芯片,因其稳定的数据保存特性和简单的接口设计,成为STM32项目中常用的外设存储器。这个驱动编写项目的核心目标,是为STM32微控制器建立与AT24C256芯片的可靠通信机制,实现数据的精准读写。

实际开发中,虽然STM32标准外设库或HAL库提供了I2C基础通信函数,但针对AT24C256的特有操作时序、地址编排以及错误处理机制,仍需开发者进行二次封装。特别是在跨页写入、连续读取等场景下,直接使用底层I2C函数会导致代码冗余且易出错。因此,编写专用驱动不仅能提升代码复用性,更能确保存储操作的可靠性。

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。

2. 硬件设计与接口连接

2.1 芯片选型与参数解析

AT24C256是Atmel(现为Microchip)推出的256Kbit(32KB)串行EEPROM,支持标准I2C协议,工作电压范围1.7V至5.5V,兼容绝大多数STM32系列微控制器。其关键特性包括:

  • 页写模式:64字节/页
  • 写周期时间:5ms(最大值)
  • 器件地址:硬件可配置(A2-A0引脚)
  • 数据保存期:100年
  • 读写耐久度:100万次

这些参数直接影响驱动设计,例如写操作后必须插入延时以满足tWR周期要求,连续写入超过64字节需自动执行页切换等。

2.2 硬件连接方案

典型STM32与AT24C256连接方式如下表所示:

STM32引脚 AT24C256引脚 连接说明
PB6(SCL) SCL 时钟线需接上拉电阻(4.7kΩ)
PB7(SDA) SDA 数据线需接上拉电阻(4.7kΩ)
3.3V VCC 电源正极
GND GND 电源地
GND A0-A2 地址引脚接地表示器件地址0x50

注意:上拉电阻值需根据总线速度和线缆长度调整。在标准模式(100kHz)下,4.7kΩ是常用值;快速模式(400kHz)建议使用2.2kΩ。

3. 软件驱动实现

3.1 I2C初始化配置

使用STM32CubeMX生成基础I2C配置后,需手动优化参数

c复制hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;       // 快速模式
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
    Error_Handler();
}

关键点说明:

  • ClockSpeed设置为400kHz需确保硬件布线能支持该速率
  • NoStretchMode禁用时钟延展可提高时序确定性
  • 实际项目中建议添加GPIO初始化代码,将SCL/SDA引脚配置为开漏输出

3.2 基础读写函数实现

单字节写入

c复制HAL_StatusTypeDef EEPROM_WriteByte(uint16_t addr, uint8_t data) {
    uint8_t devAddr = 0xA0 | ((addr >> 8) & 0x0E); // 组合器件地址与高地址位
    uint8_t memAddr = addr & 0xFF;                // 低8位地址
    uint8_t buf[2] = {memAddr, data};
    
    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, devAddr, buf, 2, 100);
    HAL_Delay(5); // 等待写周期完成
    return status;
}

页写入(64字节)

c复制#define PAGE_SIZE 64
HAL_StatusTypeDef EEPROM_WritePage(uint16_t addr, uint8_t *data, uint8_t len) {
    if(len > PAGE_SIZE) return HAL_ERROR;
    
    uint8_t devAddr = 0xA0 | ((addr >> 8) & 0x0E);
    uint8_t memAddr = addr & 0xFF;
    uint8_t buf[PAGE_SIZE + 1];
    
    buf[0] = memAddr;
    memcpy(&buf[1], data, len);
    

内容推荐

已经到底了哦
已经到底了哦