# sf_i2c **Repository Path**: tiantao1240/sf_i2c ## Basic Information - **Project Name**: sf_i2c - **Description**: sf_i2c是一个可移植性高的软件模拟i2c驱动库,可以移植到任何单片机代码中,基于多驱动设计,底层驱动与接口完全分离,可在一个单片机软件中创建多个i2c接口,每个i2c接口用名称来进行区分,可通过名称查找i2c接口的指针,只需要实现一些简单的接口就可以使用。 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 19 - **Forks**: 16 - **Created**: 2021-10-06 - **Last Updated**: 2025-11-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SF_I2C - 轻量级软件模拟I2C驱动库 [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![C Standard](https://img.shields.io/badge/C-99-blue.svg)](https://en.wikipedia.org/wiki/C99) [![Platform](https://img.shields.io/badge/Platform-Embedded%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)]() ## 📖 项目简介 SF_I2C 是一个完全使用软件模拟实现的轻量级I2C驱动库,专为嵌入式系统设计。通过GPIO模拟I2C时序,可在任何支持GPIO操作的MCU上使用,摆脱硬件I2C外设的限制。 ## ✨ 核心特性 - 🚀 **纯软件实现** - 不依赖硬件I2C外设,通用性强 - 📏 **极简设计** - 代码精简,资源占用极小 - 🔧 **高度可移植** - 通过接口抽象,轻松适配不同MCU平台 - 🔍 **设备发现** - 支持设备名称查找和链表管理 - ⚡ **可调时序** - 灵活控制通信速度 - 🛡️ **稳定可靠** - 完善的超时和错误处理机制 ## 🏗️ 系统架构 ``` 应用层 (Application) ↓ SF_I2C 驱动层 (sf_i2c.c/h) ↓ 硬件抽象层 (i2c_ops_t 接口) ↓ 物理层 (GPIO 操作) ``` ## 📁 文件结构 ``` sf_i2c/ ├── sf_i2c.c # 核心驱动实现 ├── sf_i2c.h # 驱动头文件 ├── bsp_i2c.c # STM32平台适配 ├── bsp_i2c.h # 板级支持包头文件 └── README.md # 说明文档 ``` ## 🔰 快速开始 ### 1. 硬件接口配置 首先实现硬件操作接口: ```c // 在 bsp_i2c.c 中实现硬件操作函数 static void i2c0_sda_pin_low(void) { GPIO_ResetBits(I2C0_PORT, I2C0_SDA_PIN); } static void i2c0_sda_pin_high(void) { GPIO_SetBits(I2C0_PORT, I2C0_SDA_PIN); } static uint8_t i2c0_sda_pin_read(void) { return GPIO_ReadInputDataBit(I2C0_PORT, I2C0_SDA_PIN); } // ... 其他接口函数 ``` ### 2. 定义I2C设备实例 ```c static struct sf_i2c_dev i2c0_dev = { .name = "i2c0", // 设备名称 .speed = 2, // 时序延迟控制 .delay_us = i2c_delay, // 微秒延时函数 .ops.sda_low = i2c0_sda_pin_low, .ops.sda_high = i2c0_sda_pin_high, .ops.scl_low = i2c0_scl_pin_low, .ops.scl_high = i2c0_scl_pin_high, .ops.sda_read_level = i2c0_sda_pin_read, .ops.sda_set_input = i2c0_sda_pin_dir_input, .ops.sda_set_output = i2c0_sda_pin_dir_output, }; ``` ### 3. 初始化I2C总线 ```c void bsp_i2c_init(void) { /* 硬件GPIO初始化 */ i2c0_port_init(); /* 软件驱动初始化 */ sf_i2c_init(&i2c0_dev); } ``` ### 4. 基本数据读写 ```c // 准备传输消息 struct sf_i2c_msg msgs[2]; uint8_t write_data[2] = {0x00, 0x55}; uint8_t read_data[4]; // 写操作消息 msgs[0].addr = 0xA0; // 设备地址 msgs[0].flags = SF_I2C_FLAG_WR; // 写标志 msgs[0].len = 2; msgs[0].buf = write_data; // 读操作消息 msgs[1].addr = 0xA0; msgs[1].flags = SF_I2C_FLAG_RD; // 读标志 msgs[1].len = 4; msgs[1].buf = read_data; // 执行传输 I2C_Error_t ret = sf_i2c_transfer(&i2c0_dev, msgs, 2); if (ret == I2C_SUCCESS) { // 传输成功 } ``` ## 📚 API 参考 ### 设备管理 | 函数 | 描述 | | ------------------- | ---------------- | | `sf_i2c_init()` | 初始化I2C设备 | | `sf_i2c_dev_find()` | 通过名称查找设备 | ### 数据传输 | 函数 | 描述 | | -------------------- | ------------ | | `sf_i2c_transfer()` | 执行I2C传输 | | `sf_i2c_send_byte()` | 发送单个字节 | ### 底层操作 | 函数 | 描述 | | ------------------- | ------------ | | `sf_i2c_start()` | 产生起始信号 | | `sf_i2c_stop()` | 产生停止信号 | | `sf_i2c_ack()` | 产生应答信号 | | `sf_i2c_wait_ack()` | 等待应答信号 | ## 🎯 使用示例 ### 设备扫描 ```c void i2c_scan_devices(void) { struct sf_i2c_dev *dev = sf_i2c_dev_find("i2c0"); if (dev == NULL) return; for (uint8_t addr = 0x08; addr <= 0x77; addr++) { struct sf_i2c_msg msg = { .addr = addr, .flags = SF_I2C_FLAG_WR, .len = 0, .buf = NULL }; if (sf_i2c_transfer(dev, &msg, 1) == I2C_SUCCESS) { printf("发现设备: 0x%02X\n", addr); } } } ``` ### EEPROM读写 ```c // 写入EEPROM uint8_t eeprom_write(struct sf_i2c_dev *dev, uint16_t mem_addr, uint8_t *data, uint8_t len) { uint8_t buffer[256 + 2]; buffer[0] = (mem_addr >> 8) & 0xFF; // 地址高字节 buffer[1] = mem_addr & 0xFF; // 地址低字节 memcpy(&buffer[2], data, len); struct sf_i2c_msg msg = { .addr = 0xA0, .flags = SF_I2C_FLAG_WR, .len = len + 2, .buf = buffer }; return sf_i2c_transfer(dev, &msg, 1); } // 读取EEPROM uint8_t eeprom_read(struct sf_i2c_dev *dev, uint16_t mem_addr, uint8_t *data, uint8_t len) { uint8_t addr_buf[2] = {(mem_addr >> 8) & 0xFF, mem_addr & 0xFF}; struct sf_i2c_msg msgs[2] = { { // 发送内存地址 .addr = 0xA0, .flags = SF_I2C_FLAG_WR, .len = 2, .buf = addr_buf }, { // 读取数据 .addr = 0xA0, .flags = SF_I2C_FLAG_RD, .len = len, .buf = data } }; return sf_i2c_transfer(dev, msgs, 2); } ``` ## 🔧 移植指南 ### 1. 实现硬件操作接口 ```c // 定义硬件操作结构体 i2c_ops_t my_i2c_ops = { .sda_low = my_sda_low, .sda_high = my_sda_high, .scl_low = my_scl_low, .scl_high = my_scl_high, .sda_read_level = my_sda_read, .sda_set_input = my_sda_input, .sda_set_output = my_sda_output }; ``` ### 2. 实现延时函数 ```c void my_delay_us(uint32_t us) { // 根据目标平台实现微秒级延时 for (volatile uint32_t i = 0; i < us * 100; i++); } ``` ### 3. 创建设备实例 ```c struct sf_i2c_dev my_i2c = { .ops = my_i2c_ops, .speed = 5, // 调整此值控制通信速度 .delay_us = my_delay_us, .name = "my_i2c" }; ``` ## ⚙️ 配置选项 在 `sf_i2c.h` 中可配置: ```c #define I2C_DEV_FIND 1u // 启用设备查找功能 ``` ## 🐛 故障排除 ### 常见问题 1. **通信超时** - 检查SCL/SDA线连接 - 调整`speed`参数增加延时 - 确认上拉电阻正确连接 2. **无设备响应** - 验证设备地址是否正确 - 检查电源和地线连接 - 确认设备是否正常工作 3. **数据错误** - 降低通信速度 - 检查时序是否符合设备要求 - 验证延时函数精度 ### 调试技巧 ```c // 添加调试输出 #define I2C_DEBUG 1 #if I2C_DEBUG #define I2C_LOG(fmt, ...) printf("[I2C] " fmt, ##__VA_ARGS__) #else #define I2C_LOG(fmt, ...) #endif ``` ## 🤝 贡献指南 欢迎提交 Issue 和 Pull Request! 1. Fork 本仓库 2. 创建功能分支: `git checkout -b feature/NewFeature` 3. 提交更改: `git commit -am 'Add NewFeature'` 4. 推送分支: `git push origin feature/NewFeature` 5. 提交 Pull Request ## 📄 许可证 本项目采用 MIT 许可证,详见 [LICENSE](LICENSE) 文件。 --- **如果这个项目对你有帮助,请给它一个 ⭐ !**