From 47f95b9caaddb0c609d17ab4ceb5f7d6426b9392 Mon Sep 17 00:00:00 2001 From: wwhaoww <15849883627@163.com> Date: Fri, 27 Feb 2026 16:31:10 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=B8=BA=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E4=BC=A0=E5=85=A5=E8=AF=BB=E5=86=99=E5=BB=B6=E6=97=B6?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 60 ++++++++++++++--------------------- examples/adapter_template.c | 52 ++++++++++++++----------------- module/Int_EEPROM24xx.c | 62 +++++++++++++++++++++++++++---------- module/Int_EEPROM24xx.h | 60 ++++++++++++++--------------------- 4 files changed, 114 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 0a8c35e..8caaa76 100644 --- a/README.md +++ b/README.md @@ -6,65 +6,51 @@ - 不依赖特定 MCU/SDK(不绑定 STM32 HAL) - 支持页写自动拆分 -- 通过回调适配底层总线 +- 用户传入 I2C 读、I2C 写、毫秒延时三个函数后即可直接使用 ## 目录结构 -- `module/Int_EEPROM24xx.h`:驱动接口定义 +- `module/Int_EEPROM24xx.h`:驱动接口 - `module/Int_EEPROM24xx.c`:驱动实现 -- `examples/adapter_template.c`:适配层模板 +- `examples/adapter_template.c`:移植模板 -## 你需要实现的 3 个函数 +## 使用步骤 -移植时,你只需要实现这三个底层函数,然后在配置结构体里挂接: +1. 将 `module/Int_EEPROM24xx.h/.c` 加入你的工程。 +2. 在你的平台实现三个函数: + - `your_i2c_read(...)` + - `your_i2c_write(...)` + - `your_delay_ms(...)` +3. 调用 `Int_EEPROM24xx_Init(...)` 完成初始化。 +4. 直接调用 `Int_EEPROM24xx_Read/Write` 进行访问。 -1. `bus_read`:从 EEPROM 读数据 -2. `bus_write`:向 EEPROM 写数据 -3. `delay_ms`:毫秒延时 - -> 这也是本仓库提交信息里的重点:**需要自己实现读、写、延时这三个函数**。 - -## 快速接入 - -### 1) 将模块加入工程 - -把以下文件加入你的工程: - -- `module/Int_EEPROM24xx.h` -- `module/Int_EEPROM24xx.c` - -### 2) 实现底层适配函数 - -参考 `examples/adapter_template.c`,按你的平台替换 I2C 读写与延时实现。 - -### 3) 初始化设备描述并调用 API +## 示例 ```c -static const IntEEPROM24xx_t g_eeprom = { - .ctx = your_bus_context, +IntEEPROM24xx_Config_t cfg = { .dev_addr = (0x50u << 1), .page_size = 8u, .mem_addr_size = 1u, .write_cycle_ms = 6u, .timeout_ms = 100u, - .bus_read = your_bus_read, - .bus_write = your_bus_write, - .delay_ms = your_delay_ms, }; -Int_EEPROM24xx_Read(&g_eeprom, 0x00, rx_buf, sizeof(rx_buf)); -Int_EEPROM24xx_Write(&g_eeprom, 0x00, tx_buf, sizeof(tx_buf)); +Int_EEPROM24xx_Init(&cfg, your_i2c_read, your_i2c_write, your_delay_ms); + +Int_EEPROM24xx_Write(0x00, tx_buf, tx_len); +Int_EEPROM24xx_Read(0x00, rx_buf, rx_len); ``` ## 参数说明 -- `dev_addr`:设备地址(7bit 或左移后地址,取决于你的底层驱动规范) +- `dev_addr`:设备地址(7bit 或左移后地址,取决于底层驱动规范) - `page_size`:页大小(必须与芯片手册一致) - `mem_addr_size`:地址字节数(1 或 2) - `write_cycle_ms`:每次页写后的写周期等待 +- `timeout_ms`:底层总线访问超时 -## 常见问题 +## 注意事项 -- 写入失败:优先检查 `page_size` 和 `write_cycle_ms` -- 读写偏移错乱:检查 `mem_addr_size`(1 字节 / 2 字节) -- 跨平台报错:说明底层回调未按目标 SDK 正确实现。 +- 驱动内部会自动按页拆分写入,避免跨页写异常。 +- 若你的器件使用 2 字节地址,请设置 `mem_addr_size = 2`。 +- 若写后立即读失败,请适当增大 `write_cycle_ms`。 diff --git a/examples/adapter_template.c b/examples/adapter_template.c index 9d7bcd5..298200a 100644 --- a/examples/adapter_template.c +++ b/examples/adapter_template.c @@ -1,18 +1,16 @@ #include "Int_EEPROM24xx.h" /* - * 这是移植模板:请把这 3 个函数替换为你的平台实现。 + * 移植模板:你只需要实现这 3 个函数。 */ -static IntEEPROM_Result_t your_bus_read(void *ctx, - uint16_t dev_addr, +static IntEEPROM_Result_t your_i2c_read(uint16_t dev_addr, uint32_t mem_addr, uint8_t mem_addr_size, uint8_t *buf, uint16_t len, uint32_t timeout_ms) { - (void)ctx; (void)dev_addr; (void)mem_addr; (void)mem_addr_size; @@ -20,19 +18,17 @@ static IntEEPROM_Result_t your_bus_read(void *ctx, (void)len; (void)timeout_ms; - /* TODO: 替换为平台 I2C 读函数 */ + /* TODO: 替换为你的平台 I2C 读实现 */ return INT_EEPROM_ERR_IO; } -static IntEEPROM_Result_t your_bus_write(void *ctx, - uint16_t dev_addr, +static IntEEPROM_Result_t your_i2c_write(uint16_t dev_addr, uint32_t mem_addr, uint8_t mem_addr_size, const uint8_t *buf, uint16_t len, uint32_t timeout_ms) { - (void)ctx; (void)dev_addr; (void)mem_addr; (void)mem_addr_size; @@ -40,36 +36,34 @@ static IntEEPROM_Result_t your_bus_write(void *ctx, (void)len; (void)timeout_ms; - /* TODO: 替换为平台 I2C 写函数 */ + /* TODO: 替换为你的平台 I2C 写实现 */ return INT_EEPROM_ERR_IO; } -static void your_delay_ms(void *ctx, uint32_t delay_ms) +static void your_delay_ms(uint32_t delay_ms) { - (void)ctx; (void)delay_ms; - - /* TODO: 替换为平台 delay 实现 */ + /* TODO: 替换为你的平台 delay 实现 */ } -/* 示例:设备描述 */ -static const IntEEPROM24xx_t g_eeprom = { - .ctx = 0, - .dev_addr = (0x50u << 1), - .page_size = 8u, - .mem_addr_size = 1u, - .write_cycle_ms = 6u, - .timeout_ms = 100u, - .bus_read = your_bus_read, - .bus_write = your_bus_write, - .delay_ms = your_delay_ms, -}; - void eeprom_example(void) { - uint8_t tx[8] = {1,2,3,4,5,6,7,8}; + IntEEPROM24xx_Config_t cfg = { + .dev_addr = (0x50u << 1), + .page_size = 8u, + .mem_addr_size = 1u, + .write_cycle_ms = 6u, + .timeout_ms = 100u, + }; + + uint8_t tx[8] = {1, 2, 3, 4, 5, 6, 7, 8}; uint8_t rx[8] = {0}; - (void)Int_EEPROM24xx_Write(&g_eeprom, 0x00, tx, sizeof(tx)); - (void)Int_EEPROM24xx_Read(&g_eeprom, 0x00, rx, sizeof(rx)); + if (Int_EEPROM24xx_Init(&cfg, your_i2c_read, your_i2c_write, your_delay_ms) != INT_EEPROM_OK) + { + return; + } + + (void)Int_EEPROM24xx_Write(0x00, tx, sizeof(tx)); + (void)Int_EEPROM24xx_Read(0x00, rx, sizeof(rx)); } diff --git a/module/Int_EEPROM24xx.c b/module/Int_EEPROM24xx.c index bd178a8..8176faf 100644 --- a/module/Int_EEPROM24xx.c +++ b/module/Int_EEPROM24xx.c @@ -1,18 +1,47 @@ #include "Int_EEPROM24xx.h" -/* 直接透传到用户提供的总线读回调。 */ -IntEEPROM_Result_t Int_EEPROM24xx_Read(const IntEEPROM24xx_t *dev, uint32_t mem_addr, uint8_t *buf, uint16_t len) +static IntEEPROM24xx_Config_t g_cfg; +static IntEEPROM_I2CRead_t g_read_fn; +static IntEEPROM_I2CWrite_t g_write_fn; +static IntEEPROM_DelayMs_t g_delay_fn; +static uint8_t g_inited; + +IntEEPROM_Result_t Int_EEPROM24xx_Init(const IntEEPROM24xx_Config_t *cfg, + IntEEPROM_I2CRead_t read_fn, + IntEEPROM_I2CWrite_t write_fn, + IntEEPROM_DelayMs_t delay_fn) { - if (dev == NULL || buf == NULL || len == 0u || dev->bus_read == NULL) + if (cfg == NULL || read_fn == 0 || write_fn == 0) { return INT_EEPROM_ERR_ARG; } - return dev->bus_read(dev->ctx, dev->dev_addr, mem_addr, dev->mem_addr_size, buf, len, dev->timeout_ms); + if (cfg->page_size == 0u || (cfg->mem_addr_size != 1u && cfg->mem_addr_size != 2u)) + { + return INT_EEPROM_ERR_ARG; + } + + g_cfg = *cfg; + g_read_fn = read_fn; + g_write_fn = write_fn; + g_delay_fn = delay_fn; + g_inited = 1u; + return INT_EEPROM_OK; +} + +/* 直接透传到用户提供的总线读回调。 */ +IntEEPROM_Result_t Int_EEPROM24xx_Read(uint32_t mem_addr, uint8_t *buf, uint16_t len) +{ + if (g_inited == 0u || buf == 0 || len == 0u) + { + return INT_EEPROM_ERR_ARG; + } + + return g_read_fn(g_cfg.dev_addr, mem_addr, g_cfg.mem_addr_size, buf, len, g_cfg.timeout_ms); } /* 按页拆分写入,避免跨页写导致 EEPROM 数据回卷或写失败。 */ -IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem_addr, const uint8_t *buf, uint16_t len) +IntEEPROM_Result_t Int_EEPROM24xx_Write(uint32_t mem_addr, const uint8_t *buf, uint16_t len) { uint16_t written = 0; uint16_t chunk; @@ -21,7 +50,7 @@ IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem uint16_t room; IntEEPROM_Result_t st; - if (dev == NULL || buf == NULL || len == 0u || dev->page_size == 0u || dev->bus_write == NULL) + if (g_inited == 0u || buf == 0 || len == 0u) { return INT_EEPROM_ERR_ARG; } @@ -30,27 +59,26 @@ IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem { /* 计算当前页内偏移和本次最多可写长度。 */ cur_addr = mem_addr + written; - page_off = (uint16_t)(cur_addr % dev->page_size); - room = (uint16_t)(dev->page_size - page_off); + page_off = (uint16_t)(cur_addr % g_cfg.page_size); + room = (uint16_t)(g_cfg.page_size - page_off); chunk = (uint16_t)(((len - written) < room) ? (len - written) : room); /* 实际总线写由平台适配层完成。 */ - st = dev->bus_write(dev->ctx, - dev->dev_addr, - cur_addr, - dev->mem_addr_size, - (const uint8_t *)(buf + written), - chunk, - dev->timeout_ms); + st = g_write_fn(g_cfg.dev_addr, + cur_addr, + g_cfg.mem_addr_size, + (const uint8_t *)(buf + written), + chunk, + g_cfg.timeout_ms); if (st != INT_EEPROM_OK) { return st; } - if (dev->delay_ms != NULL && dev->write_cycle_ms > 0u) + if (g_delay_fn != 0 && g_cfg.write_cycle_ms > 0u) { /* EEPROM 页写后通常需要写周期时间。 */ - dev->delay_ms(dev->ctx, dev->write_cycle_ms); + g_delay_fn(g_cfg.write_cycle_ms); } written = (uint16_t)(written + chunk); } diff --git a/module/Int_EEPROM24xx.h b/module/Int_EEPROM24xx.h index 4bda80d..2206d9c 100644 --- a/module/Int_EEPROM24xx.h +++ b/module/Int_EEPROM24xx.h @@ -2,7 +2,6 @@ #define INT_EEPROM24XX_H #include -#include typedef int32_t IntEEPROM_Result_t; @@ -10,51 +9,38 @@ typedef int32_t IntEEPROM_Result_t; #define INT_EEPROM_ERR_ARG -1 #define INT_EEPROM_ERR_IO -2 -/* 底层总线读回调: - * ctx : 用户上下文(可传 I2C 句柄、驱动实例等) - * dev_addr : 器件地址(格式由你的平台驱动决定) - * mem_addr : EEPROM 内存地址 - * mem_addr_size : 地址字节数(1 或 2) - * timeout_ms : 访问超时(毫秒) - */ -typedef IntEEPROM_Result_t (*IntEEPROM_BusRead_t)(void *ctx, - uint16_t dev_addr, - uint32_t mem_addr, - uint8_t mem_addr_size, - uint8_t *buf, - uint16_t len, - uint32_t timeout_ms); - -/* 底层总线写回调,参数含义同读回调 */ -typedef IntEEPROM_Result_t (*IntEEPROM_BusWrite_t)(void *ctx, - uint16_t dev_addr, +typedef IntEEPROM_Result_t (*IntEEPROM_I2CRead_t)(uint16_t dev_addr, uint32_t mem_addr, uint8_t mem_addr_size, - const uint8_t *buf, + uint8_t *buf, uint16_t len, uint32_t timeout_ms); -typedef void (*IntEEPROM_DelayMs_t)(void *ctx, uint32_t delay_ms); +typedef IntEEPROM_Result_t (*IntEEPROM_I2CWrite_t)(uint16_t dev_addr, + uint32_t mem_addr, + uint8_t mem_addr_size, + const uint8_t *buf, + uint16_t len, + uint32_t timeout_ms); + +typedef void (*IntEEPROM_DelayMs_t)(uint32_t delay_ms); typedef struct { - void *ctx; /* 用户上下文 */ - uint16_t dev_addr; /* 器件地址 */ - uint16_t page_size; /* 页大小(字节) */ - uint8_t mem_addr_size; /* 地址字节数:1 或 2 */ - uint32_t write_cycle_ms; /* 每次页写后等待时间(ms) */ - uint32_t timeout_ms; /* 总线访问超时(ms) */ - IntEEPROM_BusRead_t bus_read; - IntEEPROM_BusWrite_t bus_write; - IntEEPROM_DelayMs_t delay_ms; -} IntEEPROM24xx_t; + uint16_t dev_addr; + uint16_t page_size; + uint8_t mem_addr_size; /* 1 or 2 */ + uint32_t write_cycle_ms; + uint32_t timeout_ms; +} IntEEPROM24xx_Config_t; -/* 读取 EEPROM。 - * 返回 INT_EEPROM_OK 表示成功。 - */ -IntEEPROM_Result_t Int_EEPROM24xx_Read(const IntEEPROM24xx_t *dev, uint32_t mem_addr, uint8_t *buf, uint16_t len); +/* 初始化模块:用户传入 I2C 读、写和毫秒延时函数后,即可直接调用读写 API。 */ +IntEEPROM_Result_t Int_EEPROM24xx_Init(const IntEEPROM24xx_Config_t *cfg, + IntEEPROM_I2CRead_t read_fn, + IntEEPROM_I2CWrite_t write_fn, + IntEEPROM_DelayMs_t delay_fn); -/* 写入 EEPROM(内部会自动按页拆分写入)。 */ -IntEEPROM_Result_t Int_EEPROM24xx_Write(const IntEEPROM24xx_t *dev, uint32_t mem_addr, const uint8_t *buf, uint16_t len); +IntEEPROM_Result_t Int_EEPROM24xx_Read(uint32_t mem_addr, uint8_t *buf, uint16_t len); +IntEEPROM_Result_t Int_EEPROM24xx_Write(uint32_t mem_addr, const uint8_t *buf, uint16_t len); #endif