2026/2/21 3:36:45
网站建设
项目流程
个人帮忙做网站吗,程序员为什么35岁就不能干?,百度站长社区,网站系统管理u32 device_addr 和 u32 WriteAddr 的核心区别在于 “定位层级” 和 “作用场景” 完全不同—— 前者是 I2C 总线上的 “设备级地址”#xff08;找外部哪个 EEPROM#xff09;#xff0c;后者是 EEPROM 内部的 “存储单元地址”#xff08;找设备里哪个位置#xff09;找外部哪个 EEPROM后者是 EEPROM 内部的 “存储单元地址”找设备里哪个位置可以用 “快递地址” 的逻辑快速理解对比维度u32 device_addrI2C 从机地址u32 WriteAddrEEPROM 内部地址核心作用定位I2C 总线上的某个 EEPROM 设备区分多个外部设备定位该 EEPROM 内部的某个存储单元区分设备内不同位置定位层级外部总线级“找哪栋楼”设备内部级“找楼里哪个房间”来源 / 依据I2C 协议标准 EEPROM 芯片规格 硬件接线A0/A1/A2 引脚EEPROM 芯片容量地址位数由容量决定如 24C02 是 8 位地址格式规则8 位有效7 位基础地址 1 位读写位写操作时读写位 08/16/24 位有效取决于容量如 24C64 是 16 位地址取值范围示例24C02 默认0xA00x501最多 8 个设备0xA0~0xAE24C02256 字节0x00~0xFF24C648KB0x0000~0x1FFF通信阶段I2C 起始信号后第一个发送的地址用于 “呼叫” 从机设备地址确认后发送的地址用于 “指定存储位置”错误影响错误则 I2C 总线无响应找不到设备错误则数据写入错误位置如覆盖其他数据或超出容量失败举个实际场景例子帮你彻底理解假设你有一个 I2C 总线上面挂了两个 EEPROM 芯片24C02 和 24C64现在要把0x12这个数据写入 “24C02 的第 0x10 个存储单元”你需要先通过device_addr告诉 I2C 总线“我要找 24C02 这个设备”—— 所以device_addr 0xA024C02 的默认写地址24C02 收到0xA0后回复 ACK表示 “我在找我有事”接着你通过WriteAddr 0x10告诉 24C02“我要把数据写到你内部的第 0x10 个位置”最后发送数据0x1224C02 就会把数据存到自己的 0x10 地址处。如果此时你把device_addr写成 24C64 的地址0xA0 也是 24C64 的默认地址不若两个芯片 A0 引脚不同24C64 可设为 0xA2就会呼叫到 24C64 而不是 24C02如果WriteAddr写成 0x20数据就会写到 24C02 的 0x20 地址而不是目标 0x10。总结关键区别device_addr管 “外部选设备”解决 “和谁通信” 的问题WriteAddr管 “内部选位置”解决 “数据存在设备的哪里” 的问题两者是 “先选设备再选位置” 的递进关系缺一不可且格式、作用、取值范围完全独立。在 I2C EEPROM 的读写函数中u32 WriteAddr、u32 device_addr、u32 reg_addr是三个核心地址参数作用层级和定位目标完全不同—— 简单说device_addr找 “外部哪个 EEPROM 设备”WriteAddr/reg_addr找 “设备内哪个存储位置”两者本质是同一类地址仅命名场景不同。以下是全维度解析、对比和实操示例一、三个参数的核心定义与本质参数名核心作用本质定位通俗类比u32 device_addr定位 I2C 总线上的目标 EEPROM 设备总线级地址设备身份证图书馆的 “书架编号”找哪排u32 WriteAddr定位 EEPROM 内部的写入起始存储单元设备内存储地址写场景书架上的 “写入起始格编号”u32 reg_addr定位 EEPROM 内部的读取起始存储单元设备内存储地址读场景书架上的 “读取起始格编号”二、关键区别与关联重点1.device_addrvsWriteAddr/reg_addr层级完全不同device_addr解决 “和谁通信”I2C 总线可挂多个设备如 24C02 24C64device_addr是 EEPROM 的唯一识别码只有地址匹配的设备才会响应主机MCU。格式7位基础地址 1位读写位bit00 写bit01 读示例24C02 写地址0xA0、读地址0xA1。WriteAddr/reg_addr解决 “通信设备内的哪个位置”两者都是 EEPROM 内部存储单元的 “偏移地址”仅命名对应读写场景写函数中叫WriteAddr指定 “从哪个单元开始写入数据”读函数中叫reg_addr指定 “从哪个单元开始读取数据”本质完全一致 —— 若要 “先写后读验证”需让WriteAddr reg_addr写入和读取的内部位置相同。2.WriteAddr与reg_addr完全等价仅命名差异对比维度u32 WriteAddr写场景u32 reg_addr读场景本质设备内存储单元偏移地址设备内存储单元偏移地址地址位数由 EEPROM 容量决定8/16/24 位由 EEPROM 容量决定8/16/24 位取值范围0 ~EEPROM 总容量 - 10 ~EEPROM 总容量 - 1发送方式写模式下跟随device_addr后发送高位→低位读模式下先以写模式发送告知读取起始位置关联用法写入后需用相同值作为reg_addr读取验证读取前需与之前的WriteAddr一致才能读到对应数据示例写函数向 24C64 的WriteAddr0x0100写入数据 → 数据存在 0x0100 单元读函数需用reg_addr0x0100读取 → 才能拿到刚才写入的数据。三、格式规范与取值示例以 24C02/24C64 为例1.device_addr格式8 位有效u32 仅为兼容EEPROM 型号硬件接线A0/A1/A27 位基础地址写模式device_addrbit00读模式device_addrbit0124C02均接 GND0x500x50 1 0xA00xA00x01 0xA124C64均接 GND0x500x50 1 0xA00xA00x01 0xA124C02A0 接 VCCA1/A2 接地0x510x51 1 0xA20xA20x01 0xA32.WriteAddr/reg_addr格式地址位数由容量决定EEPROM 型号容量地址位数取值范围发送方式示例0x010024C02256B8 位0x00 ~ 0xFF直接发 1 字节(u8) 0x00仅低 8 位有效24C648KB16 位0x0000 ~ 0x1FFF分 2 字节发高位 0x01 → 低位 0x0024C1024128KB24 位0x000000 ~ 0x1FFFFF分 3 字节发0x00 → 0x01 → 0x00四、通信流程中的协作关系先写后读示例以 “向 24C64 的 0x0100 地址写入 3 字节再读取验证” 为例看三个参数的协作1. 写入流程用device_addr0xA0WriteAddr0x0100主机发 I2C 起始信号主机发device_addr0xA0写模式→ 24C64 地址匹配响应 ACK主机发WriteAddr0x0100分高位 0x01、低位 0x00 发送→ 24C64 地址指针指向 0x0100主机发 3 字节数据如 0x11、0x22、0x33→ 24C64 存储到 0x0100~0x0102主机发停止信号等待 5ms 写入周期完成。2. 读取流程用device_addr0xA0reg_addr0x0100主机发 I2C 起始信号主机发device_addr0xA0写模式用于告知读取起始地址→ 24C64 响应 ACK主机发reg_addr0x0100与 WriteAddr 相同分高位 0x01、低位 0x00 发送→ 地址指针指向 0x0100主机发重复起始信号不停止总线主机发device_addr0xA1读模式→ 24C64 响应 ACK24C64 连续发 3 字节数据0x11、0x22、0x33→ 主机接收存入缓冲区主机发停止信号读取完成。→ 核心协作逻辑device_addr负责 “锁定目标 EEPROM”WriteAddr/reg_addr负责 “锁定设备内的存储位置”三者配合实现 “精准读写”。五、常见误区与避坑指南混淆device_addr和WriteAddr/reg_addr错误把WriteAddr0x0100当作device_addr发送 → 总线无响应地址不匹配避坑记住 “device_addr是 8 位如 0xA0/A1WriteAddr/reg_addr是 8/16/24 位如 0x00~0x1FFF”作用层级完全不同。WriteAddr与reg_addr不一致错误写WriteAddr0x0100读reg_addr0x0200→ 读不到写入的数据避坑读写验证时必须保证WriteAddr reg_addr起始地址相同。device_addr未区分读写模式错误读取时用写模式地址0xA0→ 24C64 不响应读取全为 0xFF避坑读取时device_addr需置 bit01如 0xA0→0xA1写入时 bit00。WriteAddr/reg_addr超出 EEPROM 容量错误24C02最大地址 0xFF写WriteAddr0x100→ 数据写入无效位置避坑读写前检查WriteAddr 写写字节数 ≤ 总容量、reg_addr 读取字节数 ≤ 总容量。地址位数发送错误错误24C6416 位地址仅发送WriteAddr0x0100的低 8 位0x00→ 写入地址错误避坑根据 EEPROM 容量拆分地址16 位分 2 字节、24 位分 3 字节按 “高位→低位” 发送。六、完整实操代码示例24C64 先写后读c#include xt_i2c.h #include delay.h #include stdio.h // 配置参数24C64 #define EEPROM_DEV_ADDR_TX 0xA0 // device_addr写模式 #define EEPROM_DEV_ADDR_RX 0xA1 // device_addr读模式 #define EEPROM_WRITE_ADDR 0x0100 // WriteAddr写入起始地址 #define EEPROM_REG_ADDR 0x0100 // reg_addr读取起始地址与WriteAddr一致 #define WRITE_NUM 3 // 写入字节数 #define READ_NUM 3 // 读取字节数 #define EEPROM_TOTAL_SIZE 8192 // 24C64 总容量 8KB #define EEPROM_ADDR_BITS 16 // 24C64 是 16 位地址 // 单页写入函数基础依赖 static void IIC_E2P_PageWrite(XT_I2C_TypeDef *i2c_no, u8* pBuf, u32 len, u32 dev_addr, u32 write_addr) { if (pBuf NULL || len 0 || (write_addr len) EEPROM_TOTAL_SIZE) return; while (XT_I2C_GetFlagStatus(i2c_no, XT_I2C_FLAG_BUSY) ! RESET); XT_I2C_GenerateSTART(i2c_no, ENABLE); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_MODE_SELECT)); XT_I2C_Send7bitAddress(i2c_no, dev_addr, XT_I2C_DIRECTION_TX); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // 发送 16 位 WriteAddr高位→低位 XT_I2C_SendData(i2c_no, (u8)(write_addr 8)); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); XT_I2C_SendData(i2c_no, (u8)write_addr); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); for (u32 i 0; i len; i) { XT_I2C_SendData(i2c_no, pBuf[i]); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); } XT_I2C_GenerateSTOP(i2c_no, ENABLE); delay_ms(5); // 等待写入周期完成 } // 多字节读取函数基础依赖 static void IIC_E2P_ReadBytes(XT_I2C_TypeDef *i2c_no, u8* pBuf, u32 len, u32 dev_addr, u32 reg_addr) { if (pBuf NULL || len 0 || (reg_addr len) EEPROM_TOTAL_SIZE) return; while (XT_I2C_GetFlagStatus(i2c_no, XT_I2C_FLAG_BUSY) ! RESET); XT_I2C_GenerateSTART(i2c_no, ENABLE); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_MODE_SELECT)); // 发送 device_addr写模式和 reg_addr XT_I2C_Send7bitAddress(i2c_no, dev_addr, XT_I2C_DIRECTION_TX); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); XT_I2C_SendData(i2c_no, (u8)(reg_addr 8)); // 16 位地址高位 while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); XT_I2C_SendData(i2c_no, (u8)reg_addr); // 16 位地址低位 while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // 重复起始切换为读模式 XT_I2C_GenerateSTART(i2c_no, ENABLE); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_MODE_SELECT)); XT_I2C_Send7bitAddress(i2c_no, dev_addr | 0x01, XT_I2C_DIRECTION_RX); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); // 接收数据最后1字节发NACK for (u32 i 0; i len; i) { XT_I2C_AcknowledgeConfig(i2c_no, (i len-1) ? DISABLE : ENABLE); while (!XT_I2C_CheckEvent(i2c_no, XT_I2C_EVENT_MASTER_BYTE_RECEIVED)); pBuf[i] XT_I2C_ReceiveData(i2c_no); } XT_I2C_GenerateSTOP(i2c_no, ENABLE); XT_I2C_AcknowledgeConfig(i2c_no, ENABLE); // 恢复ACK } int main(void) { u8 write_buf[WRITE_NUM] {0x11, 0x22, 0x33}; // 待写入数据 u8 read_buf[READ_NUM] {0}; // 接收缓冲区 I2C1_Init(); // 初始化 I2C1配置引脚、时钟、速率 100KHz // 1. 写入数据device_addr0xA0WriteAddr0x0100 IIC_E2P_PageWrite(XT_I2C1, write_buf, WRITE_NUM, EEPROM_DEV_ADDR_TX, EEPROM_WRITE_ADDR); // 2. 读取数据device_addr0xA0先写reg_addrreg_addr0x0100 IIC_E2P_ReadBytes(XT_I2C1, read_buf, READ_NUM, EEPROM_DEV_ADDR_TX, EEPROM_REG_ADDR); // 3. 打印结果验证是否一致 printf(写入数据0x%02X 0x%02X 0x%02X\n, write_buf[0], write_buf[1], write_buf[2]); printf(读取数据0x%02X 0x%02X 0x%02X\n, read_buf[0], read_buf[1], read_buf[2]); while(1); }预期输出plaintext写入数据0x11 0x22 0x33 读取数据0x11 0x22 0x33总结三个参数的核心关系device_addr管 “找哪个 EEPROM”总线级定位WriteAddr/reg_addr管 “找设备内哪个位置”存储级定位两者完全等价仅命名对应读写场景正确用法先通过device_addr锁定设备再通过WriteAddr/reg_addr锁定存储位置三者配合实现精准读写。记住 “先选设备再选位置” 的逻辑就能避免绝大多数地址配置错误。