STM32G030 24C02 多字节读写与页边界处理实验任务书
任务名称: 基于 STM32G030F6P6 的 24C02 多字节读写实验
实验平台: STM32G030F6P6 + 24C02 模块
使用外设: UART、硬件 I²C1、24C02
开发工具: STM32CubeMX + Keil MDK(或现有 IDE)
工程名称: G030_EEPROM_MultiByte_Test
前置任务: 已完成任务 04 的单字节读写和断电保存验证。
任务要求: 独立创建工程,分阶段调试,不直接复制旧工程代码。每阶段通过验收后再继续。每次启动执行有限次写入,不在主循环反复写入。
一、实验目标
- 恢复 UART 输出和 EEPROM ACK 检测。
- 使用数组和缓冲区进行多字节读取。
- 完成页内多字节写入及逐字节校验。
- 封装自动分段的多字节写入接口,避免跨页回卷。
- 验证容量边界、通信失败和断电保持。
最终目标: 从 0x06 开始写入 20 字节递增数据 0x30~0x43,自动分段写入,读回全部数据并逐字节比较。所有必测用例通过后,输出 EEPROM MULTIBYTE TEST PASS。
重要适用条件: 24C02 容量为 256 字节,地址范围为 0x00~0xFF,内部地址使用 8 位。仅有“24C02”名称还不能确定页大小:Microchip AT24C02C 为 8 字节页,ST M24C02 为 16 字节页。器件厂家、完整后缀和最大写入时间尚待根据芯片丝印或模块资料确认。
本任务采用 8 字节软件分段:对已确认采用 8 或 16 字节硬件页的上述器件均不会越过硬件页边界。若实际为 16 字节页,这是保守分段,不代表硬件页只有 8 字节。其他型号先查手册再操作。
二、第一阶段:创建工程与核对硬件
2.1 创建工程
- 在 CubeMX 中选择 STM32G030F6P6,新建独立工程。
- 配置 Serial Wire 和系统时钟,可先使用内部 HSI。
- 配置 UART 和 I²C1,生成代码并编译下载。
- 保存
.ioc,记录实际引脚、EEPROM 丝印、地址引脚和 WP 状态。
2.2 外设配置
| 项目 | 配置 |
|---|---|
| UART | 115200、8 数据位、无校验、1 停止位 |
| UART 实例与 TX 引脚 | 沿用已验证硬件接线,在报告中填写实际值 |
| I²C | I²C1、100 kHz、7 位地址模式 |
| SCL / SDA | 按实际接线和 CubeMX 复用配置 |
| 中断 / DMA | 本实验不启用 |
| 内部存储地址长度 | I2C_MEMADD_SIZE_8BIT |
| 软件分段大小 | 8 字节 |
确认共地、供电和 I/O 电平兼容,上拉电阻接到兼容的电压。核对模块是否已有上拉。WP 应处于允许写入状态。设备地址沿用任务 04 已实测成功的值;只有 A0、A1、A2 均接低电平时,示例才使用 7 位地址 0x50,HAL 地址参数为 0x50 << 1。
本阶段验收标准
- 工程可以编译、下载并运行。
- 保存
.ioc,记录实际接线和地址。 - 确认器件页结构适用,记录厂家、型号和写入时间;无法辨认时在记录中标明待确认,不宣称已核实。
三、第二阶段:UART 与 ACK 基础测试
3.1 实验目标与要求
独立实现 printf() 重定向,在 UART 初始化后输出启动信息,再调用 HAL_I2C_IsDeviceReady() 检测 EEPROM。
理解设备句柄、左移后的设备地址、重试次数、超时及返回值。ACK 只证明设备响应,不证明存储内容正确。
3.2 预期输出
STM32G030 BOOT OK
UART PRINTF OK
EEPROM ACK OK
检测失败时输出 EEPROM ACK FAIL,停止后续写入和正常校验。
本阶段验收标准
- 串口输出无乱码,换行正常,复位后重新输出。
- 正确地址可以检测成功。
- 使用不存在的设备地址进行测试时,能报告失败且不输出 PASS;测试后恢复正确地址。
四、第三阶段:多字节读取
4.1 实验目标
从 0x20 连续读取 8 字节,逐项打印地址和数值。
4.2 学习内容
使用 HAL_I2C_Mem_Read(),理解数组首地址、缓冲区长度和 Size。读取可以跨越写入页边界,但本实验禁止越过容量末端,不依赖地址回卷。
uint8_t read_buf[8] = {0};
4.3 编程任务
- ACK 通过后执行读取,内部地址长度使用 8 位。
- 检查 HAL 返回状态,成功后才使用缓冲区内容。
- 用循环打印
0x20~0x27的地址和数据。
4.4 预期输出与验收
EEPROM READ START ADDR=0x20 LEN=8
ADDR=0x20 DATA=0x..
...
ADDR=0x27 DATA=0x..
EEPROM READ OK
这里的 0x.. 表示原有内容,实际程序必须打印真实数值,不能预设为 0xFF。
- 成功读取并打印 8 字节。
- 能解释为什么读取成功不代表这些内容已经符合某个预期值。
- 读取失败时输出
EEPROM READ FAIL,停止当前测试。
五、第四阶段:页内写入与读回验证
5.1 实验目标
向 0x20~0x27 写入以下 8 字节,再读回校验:
uint8_t write_buf[8] = {0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17};
5.2 学习内容
HAL_I2C_Mem_Write() 返回成功表示总线传输成功,仍需等待 EEPROM 内部写入完成。每次写入后进行有超时上限的 ACK 轮询,设备就绪后才开始下一次操作。等待上限根据实际手册确定,可暂设 20 ms 作为实验预算;轮询单次调用也必须有有限超时,不能无限等待。
5.3 编程要求
- 确认 ACK 通过,打印写入地址、长度和数据。
- 在一次 HAL 写调用中提交 8 字节。
- 检查返回状态,再等待器件就绪。
- 使用独立的读取数组读回 8 字节。
- 逐字节比较;不一致时打印地址、期望值和实际值。
- 任一步失败则停止当前正常验证,不报告成功。
5.4 预期输出
PAGE WRITE ADDR=0x20 LEN=8
EEPROM WRITE OK
EEPROM READY OK
READ DATA: 10 11 12 13 14 15 16 17
PAGE TEST PASS
本阶段验收标准
- 一次页内写入完成,读回 8 字节全部一致。
- 修改数据后再次读回能得到新值。
- 传输失败、就绪超时、读取失败或数据不一致时均不能输出本阶段 PASS。
六、第五阶段:跨页封装与完整验证
6.1 实验目标
封装支持任意合法起始地址与长度的读写接口。建议放在 eeprom.c 和 eeprom.h,由 main.c 调用。
6.2 接口约定
HAL_StatusTypeDef EEPROM_Write(uint16_t addr,
const uint8_t *data,
uint16_t len);
HAL_StatusTypeDef EEPROM_Read(uint16_t addr,
uint8_t *data,
uint16_t len);
本实验约定:空指针、长度为 0、地址不在 0~255 或长度越界时,返回 HAL_ERROR 且不进行总线操作。先检查 addr < 256,再检查 len <= 256 - addr,避免采用容易溢出的相加判定。地址和长度不能只使用 uint8_t,否则无法表达 256 或识别 0x100。
写接口只有在每段传输和就绪检查均成功后才能返回 HAL_OK。中途失败时立即退出;之前已写入的段不会自动回滚,接口不保证整段原子性。
6.3 分段提示
每轮计算:
段内偏移 = 当前地址 % 8
本段可用长度 = 8 - 段内偏移
本次写入长度 = min(剩余长度, 本段可用长度)
完成当前段并确认就绪后,推进地址、数据指针和剩余长度。HAL 不会根据 EEPROM 页大小自动分段;不要直接用一次写调用跨越页边界。
从 0x06 写入 20 字节,采用 8 字节分段时应得到:
| 起始地址 | 长度 | 数据范围 |
|---|---|---|
0x06 |
2 | 0x30~0x31 |
0x08 |
8 | 0x32~0x39 |
0x10 |
8 | 0x3A~0x41 |
0x18 |
2 | 0x42~0x43 |
6.4 必测用例
| 用例 | 操作 | 判据 |
|---|---|---|
| 页内写入 | 0x20,8 字节 |
读回全部一致 |
| 跨页写入 | 0x06,20 字节递增数据 |
四段写入,读回全部一致 |
| 参数变化 | 相同范围改为另一组数据 | 读回为新值 |
| 容量末端 | 0xF8,8 字节 |
成功,最后一个字节位于 0xFF |
| 越界长度 | 0xFE,4 字节 |
操作前拒绝,原数据不变 |
| 越界地址 | 0x100,1 字节 |
操作前拒绝 |
| 非法缓冲区 / 长度 | 空指针;长度为 0 | 按约定拒绝 |
| 通信失败 | 测试配置使用不存在的设备地址 | 返回失败,不误报 PASS |
正常写入还需验证相邻数据未被误改:跨页测试前通过正确接口在 0x05 和 0x1A 写入哨兵值,主测试后再次读取,要求保持不变。越界拒绝测试前后读取末尾合法区域并比较,确认没有部分写入。全部测试会覆盖相应实验区域,不要在其中保存需要保留的其他数据。
6.5 断电保存验证
- 完成跨页写入并读回成功。
- 关闭电源,在程序中选择“只读验证模式”,关闭所有写入和哨兵初始化。
- 下载修改后的程序并重新上电。
- 读取
0x06~0x19,与预期 20 字节比较。 - 全部一致后输出
POWER-OFF RETENTION PASS。
不能通过启动后重新写入再读取来证明断电保存。
6.6 预期输出与最终判据
UART PRINTF OK
EEPROM ACK OK
PAGE TEST PASS
WRITE CHUNK ADDR=0x06 LEN=2
WRITE CHUNK ADDR=0x08 LEN=8
WRITE CHUNK ADDR=0x10 LEN=8
WRITE CHUNK ADDR=0x18 LEN=2
CROSS PAGE TEST PASS
SENTINEL TEST PASS
DATA CHANGE TEST PASS
END OF MEMORY TEST PASS
INVALID REQUEST TEST PASS
COMMUNICATION ERROR TEST PASS
EEPROM MULTIBYTE TEST PASS
异常测试的 PASS 表示“正确拒绝或检测到了异常”,不表示异常请求读写成功。正常测试失败时记录具体状态并停止后续依赖操作。所有本次运行的必测项通过后才输出最终 PASS;断电测试在只读模式中单独输出并提交证据。
本阶段验收标准
- 两个接口可复用,写入能自动分段。
- 跨页数据和相邻哨兵正确。
- 必测边界、非法参数及通信失败均按约定处理。
- 只读启动验证断电保存成功。
七、常见问题与排查
| 现象 | 优先排查 |
|---|---|
| UART 无输出或乱码 | 接线、共地、波特率、时钟、重定向 |
| 无 ACK | 设备地址、供电、SCL / SDA、上拉 |
| 页内正确,跨页错误 | 是否按段边界拆分、数据指针是否推进 |
| 前面数据被后面覆盖 | 单次写入是否越过实际硬件页边界 |
| 第二段写入失败 | 上一段是否完成、ACK 轮询是否超时 |
| 末端数据回到地址 0 | 是否遗漏容量检查,是否发生地址回卷 |
| 返回 OK 但内容错误 | WP、实际型号、数据长度、缓冲区、读回判据 |
| 断电测试总是成功 | 只读模式是否仍执行了写入 |
八、实验完成标准
- 新工程编译、下载、运行正常,保存
.ioc。 - UART 与 ACK 基础测试通过。
- 连续读取与页内 8 字节写入通过。
0x06起始的 20 字节写入自动分段并读回一致。- 相邻哨兵不变,修改数据测试通过。
- 容量末端可正常访问,越界及非法参数操作前拒绝。
- 通信失败正确报告,不误报成功。
- 所有必测项通过后输出最终 PASS。
- 完成独立的断电只读验证。
九、需要提交的实验成果
- 完整工程,包括
.ioc、eeprom.c、eeprom.h和必要源码。 - 实际接线、器件丝印、地址、页大小及写入时间的核对记录。
- 页内与跨页测试日志,包含分段地址、长度和逐字节校验结果。
- 相邻数据、容量边界、参数拒绝和通信失败测试记录。
- 断电只读验证日志和所用模式说明。
- 实验总结:一次典型故障、定位过程、解决方法和学习收获。
十、思考题
- 2 Kbit 为什么对应 256 字节,而不是 2 KB?
- 连续读取与页写入的边界限制有什么不同?
- 为什么从
0x06写入 20 字节不能只按固定 8 字节切分? - 为什么每段写入后都要检查设备就绪?
- 指针推进与地址推进分别改变什么?
- 为什么要在发起总线操作之前检查整个请求的范围?
- 跨页写入第三段失败,前两段的数据会自动恢复吗?
- 为什么需要哨兵测试和只读模式断电测试?
本次实验重点:独立掌握数组与指针、多字节通信、页边界分段、有限等待、错误处理及实际数据验证。
参考资料
- Microchip AT24C01C / AT24C02C 数据手册:容量、8 字节页、读写与就绪机制。
- ST M24C02 数据手册:16 字节页及页内回卷限制,说明不同厂家的页结构可能不同。