基于STM32的AT24C系列EEPROM通用驱动与分页写实现

📅 发布时间:2026/9/2 9:27:23
基于STM32的AT24C系列EEPROM通用驱动与分页写实现
简介面向STM32开发者的AT24C系列EEPROM驱动代码包覆盖AT24C32、AT24C64与AT24C128三种常规容量适用于物联网终端、智能家居、工业控制等需要掉电保存配置信息或用户数据的项目。压缩包内共有两个文件一个C源文件负责I²C读写时序与命令封装另一个头文件提供函数声明和地址定义整体不足四KB移植时只需复制源码并调整引脚即可快速接入现有工程。驱动编写过程中重点考虑了I²C总线初始化、STM32复用功能配置、七位设备地址与读写控制位组合、字节寻址和连续写操作等关键环节同时给出超时与校验出错时的基础处理思路便于理解硬件I²C与软件模拟I²C两种实现方式的差别。代码结构简洁注释清晰适合学习与二次开发。目前已有四千二百四十二人学习下载对正在学习AT24C系列驱动编写或需要在嵌入式项目中增加外部存储功能的工程师具有直接参考价值。 做嵌入式这几年EEPROM基本是绕不开的存储器件。ST芯片、各家电控板、传感器模块上都能看到AT24系列我在STM32项目里前后用过AT24C02、AT24C32、AT24C64后来做设备日志存储又换到AT24C128。坦白说从AT24C02换到AT24C32时挺折腾——字地址从1字节变成2字节读写出参完全变了。但AT24C32、AT24C64、AT24C128这三颗协议基本一致只是容量、页大小、从机地址引脚数有差异。用宏把这些差异参数化后我从三份驱动瘦身成一份通用驱动后续换型号只改一行宏。这篇文章就把这套驱动程序的设计思路、完整代码和实际调试中踩过的坑一次性讲清楚。1. 三个型号到底差在哪容量、页大小与I2C从机地址1.1 容量与字地址先说最基础的单位换算。AT24C32的32指的是32Kbit换算成字节要除以8也就是4KBAT24C64是8KBAT24C128是16KB。很多新手在这里直接被坑按32KB去规划存储结构写到一半发现地址越界。这三颗芯片内部存储地址都用2字节表示数据手册里叫Word Address。也就是说一次I2C写操作要先发内存地址高字节再发低字节然后才发数据。这和AT24C01/02/04/08/16这系只用1字节地址的老芯片完全不同。在STM32 HAL库里对应参数是I2C_MEMADD_SIZE_16BIT写驱动时千万别选成8位。型号容量字节地址范围页大小可配置从机地址AT24C3240960x000~0xFFF32字节0x50~0x57AT24C6481920x000~0x1FFF32字节0x50~0x57AT24C128163840x000~0x3FFF64字节0x50~0x511.2 从机地址AT24C128 只有 A2 有效I2C设备地址是硬件引脚决定的AT24C32/64有A2、A1、A0三个地址引脚7位设备地址格式是1010 A2 A1 A0基地址0x50三根引脚排列组合后可以挂8片。AT24C128就不一样了它只引出A2引脚A1和A0在芯片内部被固定为0所以同一总线上最多挂2片地址只能是0x50或0x51。这个差异在换型号时最容易翻车。我见过一个同事把板子上的AT24C64直接换成AT24C128驱动地址没改I2C扫描死活找不到设备。一查原来AT24C64的A1、A0接了IO口拉高设备地址是0x53AT24C128根本没有A1、A0引脚实际地址变成0x50不查手册根本想不到。1.3 页大小影响写入策略EEPROM的页写入机制决定了驱动怎么写。AT24C32/64的页大小是32字节AT24C128是64字节。在一个页写周期内连续写入的数据不能超过页大小一旦越过页末尾地址会回卷到本页开头把刚才写的数据覆盖掉。所以驱动的写函数核心就一句话按页拆分写入。先算当前地址距离本页末尾还剩多少字节本次最多写这么多写完了再推进地址直到所有数据写完。这个逻辑我会在第三节详细展开它是整个驱动最重要的部分。2. 为什么值得抽一套通用驱动而不是三份驱动2.1 三颗芯片的协议几乎相同AT24C32/64/128的操作时序完全一致START - 从机地址写位 - 内存地址高字节 - 内存地址低字节 - 数据 - STOP。读操作就是随机读前面加一个重复START再切到读模式。差异只有三个参数容量上限、页大小、设备地址位宽。如果给每颗芯片单独写一份驱动读函数、写函数的主体结构几乎一样只是宏定义不同。后果就是维护成本翻三倍——修一个跨页bug要改三处。我把差异点抽成宏用条件编译选择型号一份驱动走天下。产品线从AT24C64升到AT24C128时只需要改AT24C_DEVICE这个宏其他代码一概不动。2.2 硬件接线与I2C初始化通用驱动要跑稳硬件基础必须对。SDA和SCL都是开漏引脚必须接上拉电阻到VCC。STM32的I2C引脚在CubeMX里要配置为开漏复用模式上拉电阻一般选4.7k如果总线上设备多、走线长或者频率用到400kHz以上换成2.2k更稳。上拉电阻太大信号上升沿变缓通信容易丢数据太小灌电流偏大长期可靠性受影响。EEPROM的VCC范围通常是1.8V~5.5V和STM32同电源供电最省事。WP写保护引脚必须处理最简单粗暴的做法是直接接地让芯片永远可写。A2/A1/A0根据你规划的设备地址接VCC或GND不要悬空。CubeMX里选择I2C1或I2C2时钟配置到400kHz快速模式即可。AT24C系列最高支持1MHz但MCU端I2C外设在400kHz以上时对板上走线和上拉很敏感不是必须的话没必要冒险。3. 驱动实现宏配置、分页写、ACK轮询3.1 头文件把差异全部收敛成宏先来看头文件的关键部分。型号选择、页大小、最大地址、设备地址都在这里定义驱动源文件只跟这些宏打交道。#ifndef __AT24CXX_H #define __AT24CXX_H #include main.h /* 型号选择 */ #define AT24C32 0 #define AT24C64 1 #define AT24C128 2 #define AT24C_DEVICE AT24C128 /* 硬件地址引脚电平根据实际接线修改 */ #define AT24C_A2_LEVEL 0 #define AT24C_A1_LEVEL 0 #define AT24C_A0_LEVEL 0 #if (AT24C_DEVICE AT24C32) #define AT24C_PAGE_SIZE 32 #define AT24C_MAX_ADDR 0x0FFF /* 4096B */ #elif (AT24C_DEVICE AT24C64) #define AT24C_PAGE_SIZE 32 #define AT24C_MAX_ADDR 0x1FFF /* 8192B */ #elif (AT24C_DEVICE AT24C128) #define AT24C_PAGE_SIZE 64 #define AT24C_MAX_ADDR 0x3FFF /* 16384B */ #else #error Unknown AT24C device #endif /* HAL库要求7位地址左移1位0x50 1 0xA0 */ #define AT24C_BASE_ADDR (0x50 1) #if (AT24C_DEVICE AT24C128) #define AT24C_DEV_ADDR (AT24C_BASE_ADDR | (AT24C_A2_LEVEL 2)) #else #define AT24C_DEV_ADDR (AT24C_BASE_ADDR | (AT24C_A2_LEVEL 2) | \ (AT24C_A1_LEVEL 1) | AT24C_A0_LEVEL) #endif uint8_t at24cxx_Init(void); uint8_t at24cxx_WriteBytes(uint16_t addr, uint8_t *pData, uint16_t len); uint8_t at24cxx_ReadBytes(uint16_t addr, uint8_t *pData, uint16_t len); #endifAT24C_DEV_ADDR这个宏要注意HAL库的DevAddress参数要求填7位地址左移1位的8位格式也就是0x50要写成0xA0。bit0由HAL内部根据读写操作自动设置用户不要自己拼读写位。3.2 写函数先算页剩余空间再下笔写函数是整个驱动的核心分页逻辑就在这里#include at24cxx.h extern I2C_HandleTypeDef hi2c1; #define AT24C_I2C_TIMEOUT 100 static void at24cxx_WaitReady(void) { while (HAL_I2C_IsDeviceReady(hi2c1, AT24C_DEV_ADDR, 1, AT24C_I2C_TIMEOUT) ! HAL_OK) { /* 继续轮询直到EEPROM内部写周期结束 */ } } static uint8_t at24cxx_IsAddrValid(uint16_t addr, uint16_t len) { if ((addr len) (AT24C_MAX_ADDR 1)) { return 0; } return 1; } uint8_t at24cxx_WriteBytes(uint16_t addr, uint8_t *pData, uint16_t len) { uint16_t offset 0; uint16_t chunk; if (pData NULL || len 0) { return 2; } if (!at24cxx_IsAddrValid(addr, len)) { return 3; } while (offset len) { /* 当前地址距离本页末尾还剩多少字节 */ chunk AT24C_PAGE_SIZE - (addr % AT24C_PAGE_SIZE); /* 本次实际写入长度不能超过剩余数据长度 */ if (chunk (len - offset)) { chunk len - offset; } if (HAL_I2C_Mem_Write(hi2c1, AT24C_DEV_ADDR, addr, I2C_MEMADD_SIZE_16BIT, pData offset, p a hrefhttps://download.csdn.net/download/qq_35731693/20387665 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p