#include "IIC.h" #include "driver/i2c.h" #include "esp_log.h" // 日志标签,用于输出日志信息 #define TAG "I2C操作" // 辅助函数:构建 I2C 命令句柄,用于指定设备地址和寄存器地址 static i2c_cmd_handle_t build_i2c_cmd(uint8_t dev_addr, uint8_t reg_addr) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, reg_addr, true); return cmd; } // 辅助函数:执行 I2C 命令句柄并释放资源 static esp_err_t execute_i2c_cmd(i2c_cmd_handle_t cmd) { esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return ret; } /** * @brief 初始化 I2C 主设备 * @return esp_err_t 初始化结果,ESP_OK 表示成功,其他值表示失败 */ esp_err_t i2c_master_init(void) { int i2c_master_port = I2C_MASTER_NUM; i2c_config_t conf = { .mode = I2C_MODE_MASTER, // 设置为 I2C 主设备模式 .sda_io_num = I2C_MASTER_SDA_IO, // 指定 SDA 引脚 .scl_io_num = I2C_MASTER_SCL_IO, // 指定 SCL 引脚 .sda_pullup_en = GPIO_PULLUP_ENABLE, // 启用 SDA 引脚的上拉电阻 .scl_pullup_en = GPIO_PULLUP_ENABLE, // 启用 SCL 引脚的上拉电阻 .master.clk_speed = I2C_MASTER_FREQ_HZ, // 设置 I2C 时钟频率 }; // 配置 I2C 参数 i2c_param_config(i2c_master_port, &conf); // 安装 I2C 驱动 return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); } void i2c_scan(void) { esp_err_t err; i2c_cmd_handle_t cmd; ESP_LOGI(TAG, "开始扫描 I2C 总线..."); for (int addr = 0; addr < 128; addr++) { cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); i2c_master_stop(cmd); err = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); if (err == ESP_OK) { ESP_LOGI(TAG, "在地址 0x%02X 发现设备", addr); } i2c_cmd_link_delete(cmd); } ESP_LOGI(TAG, "扫描完成。"); } /** * @brief 从 I2C 设备读取单个字节数据的函数 * @param dev_addr I2C 设备的 7 位地址 * @param reg_addr 要读取数据的寄存器地址 * @param data 用于存储读取到的单个字节数据的指针 * @return esp_err_t 操作结果,ESP_OK 表示成功,其他值表示失败 */ static esp_err_t my_i2c_master_read_byte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data) { i2c_cmd_handle_t cmd = build_i2c_cmd(dev_addr, reg_addr); i2c_master_start(cmd); i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true); i2c_master_read_byte(cmd, data, I2C_MASTER_NACK); i2c_master_stop(cmd); return execute_i2c_cmd(cmd); } /* * 功能:从 8 位地址的寄存器读取一个字节数据 * 参数: * addr:寄存器的内部地址 * *Data:数据存储地址 * 返回值:(1 = 成功, 0 = 失败) */ unsigned char i2cread(unsigned char addr, unsigned char *Data) { esp_err_t ret = my_i2c_master_read_byte(Device_Address, addr, Data); return (ret == ESP_OK) ? 1 : 0; } /** * @brief 从 Device_Address 的指定寄存器地址开始读取多个字节的数据 * @param addr I2C 设备(Device_Address)内部寄存器的起始地址 * @param length 要读取的数据字节长度 * @param Data 用于存储读取到的数据的缓冲区地址 * @return unsigned char 操作状态,1 表示读取成功,0 表示读取失败 */ unsigned char i2creads(uint8_t addr, uint8_t length, uint8_t *Data) { i2c_cmd_handle_t cmd = build_i2c_cmd(Device_Address, addr); i2c_master_start(cmd); i2c_master_write_byte(cmd, (Device_Address << 1) | I2C_MASTER_READ, true); if (length > 1) { i2c_master_read(cmd, Data, length - 1, I2C_MASTER_ACK); } i2c_master_read_byte(cmd, Data + length - 1, I2C_MASTER_NACK); i2c_master_stop(cmd); esp_err_t ret = execute_i2c_cmd(cmd); return (ret == ESP_OK) ? 1 : 0; } /** * @brief 向 8 位地址的寄存器写入一个字节数据 * @param addr 寄存器的内部地址 * @param Data 要写入的数据 * @return unsigned char 操作结果,1 表示成功,0 表示失败 */ unsigned char i2cwrite(uint8_t addr, uint8_t Data) { i2c_cmd_handle_t cmd = build_i2c_cmd(Device_Address, addr); i2c_master_write_byte(cmd, Data, true); i2c_master_stop(cmd); esp_err_t ret = execute_i2c_cmd(cmd); return (ret == ESP_OK) ? 1 : 0; } /** * @brief 向 Device_Address 的指定寄存器地址开始写入多个字节的数据 * @param addr I2C 设备(Device_Address)内部寄存器的起始地址 * @param length 要写入的数据字节长度 * @param Data 要写入的数据缓冲区地址 * @return unsigned char 操作状态,1 表示写入成功,0 表示写入失败 */ unsigned char i2cwrites(uint8_t addr, uint8_t length, const uint8_t *Data) { i2c_cmd_handle_t cmd = build_i2c_cmd(Device_Address, addr); for (uint8_t i = 0; i < length; i++) { i2c_master_write_byte(cmd, Data[i], true); } i2c_master_stop(cmd); esp_err_t ret = execute_i2c_cmd(cmd); return (ret == ESP_OK) ? 1 : 0; }