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);
