SOC-ESP32S3部分:17-I2C驱动实例-EEPROM温湿度传感器
飞书文档https://x509p6c8to.feishu.cn/wiki/KrlCwmlKcikvZ5knxEbcrewwn1c
EEPROM
特别说明,目前ESP32S3由于IO数量少的原因,是没有连接底板的EEPROM的,我们这里只进行代码讲解,这个工程不能在板卡运行的。
我们学习基础课程时,知道底板上是有EEPROM的,就是BL24c02,这里我们不再重新讲解EEPROM的协议时序,如果你不清楚,可以回到51&STM32单片机课程进行了解,我们直接看实现。
原理图部分:
首先,EERPOM未连接到ESP32S3核心板卡,所以这里随便用一组IO进行说明
代码部分,驱动流程如下:
- 初始化I2C总线实例
- 创建I2C设备,添加到总线
- 往某个地址进行写入需要存储的数据
- 读取数据进行打印
需要注意的是:
EEPROM写入数据时,直接往某个地址进行写入即可,直接使用i2c_master_transmit。
EEPROM读取数据时,需要先写入需要读取数据的地址,然后再进行读取,使用先发送再读取函数i2c_master_transmit_receive。
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gptimer.h"
#include "esp_log.h"#include <string.h>
#include "sdkconfig.h"
#include "driver/i2c_master.h"static const char *TAG = "EEPROM"; // 定义日志标签// I2C 引脚和设备配置
#define SCL_IO_PIN 4 // I2C 时钟线引脚编号
#define SDA_IO_PIN 5 // I2C 数据线引脚编号
#define DEVICE_ADDR 0xA0 // I2C 设备地址 (7-bit 地址)
#define MASTER_FREQUENCY 100000 // I2C 总线频率 (100kHz)
#define PORT_NUMBER -1 // I2C 端口号 (-1 表示使用默认端口)// 写入数据到 BL24C02
esp_err_t bl24c02_write(i2c_master_dev_handle_t dev_handle, uint16_t mem_addr, const uint8_t *data, size_t length)
{uint8_t buffer[1 + length];buffer[0] = (mem_addr) & 0xFF; // 写入地址memcpy(buffer + 1, data, length); // 复制数据到缓冲区return i2c_master_transmit(dev_handle, buffer, sizeof(buffer) + length, pdMS_TO_TICKS(1000));
}// 从 BL24C02 读取数据
esp_err_t bl24c02_read(i2c_master_dev_handle_t dev_handle, uint16_t mem_addr, uint8_t *data, size_t length)
{uint8_t addr_buffer[1];addr_buffer[0] = (mem_addr) & 0xFF; // 高字节地址return i2c_master_transmit_receive(dev_handle, addr_buffer, sizeof(addr_buffer), data, length, pdMS_TO_TICKS(1000));
}void app_main(void)
{// 配置 I2C 总线参数i2c_master_bus_config_t i2c_bus_config = {.clk_source = I2C_CLK_SRC_DEFAULT, // 使用默认时钟源.i2c_port = PORT_NUMBER, // 指定 I2C 端口.scl_io_num = SCL_IO_PIN, // SCL 引脚编号.sda_io_num = SDA_IO_PIN, // SDA 引脚编号.glitch_ignore_cnt = 7, // 忽略毛刺计数};// 创建 I2C 总线句柄i2c_master_bus_handle_t bus_handle;ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle)); // 初始化 I2C 总线// 配置 I2C 设备参数i2c_device_config_t dev_cfg = {.dev_addr_length = I2C_ADDR_BIT_LEN_7, // 设备地址长度为 7 位.device_address = DEVICE_ADDR, // 设备地址.scl_speed_hz = MASTER_FREQUENCY, // SCL 时钟频率};// 创建 I2C 设备句柄i2c_master_dev_handle_t dev_handle;ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); // 添加设备到总线// 探测设备esp_err_t ret = i2c_master_probe(bus_handle, DEVICE_ADDR, 1000);if (ret == ESP_OK){ESP_LOGI(TAG, "Device at address 0x%02X found and responsive", DEVICE_ADDR);}else{ESP_LOGE(TAG, "Failed to find device at address 0x%02X", DEVICE_ADDR);}// 写入数据到 BL24C02uint8_t write_data[] = {0xAA, 0xBB, 0xCC, 0xDD};uint8_t mem_addr = 0x00; // 写入起始地址bl24c02_write(dev_handle, mem_addr, write_data, sizeof(write_data));//延时10ms 等待EEPROM写入完成vTaskDelay(pdMS_TO_TICKS(10));// 读取数据从 BL24C02uint8_t read_data[sizeof(write_data)];ret = bl24c02_read(dev_handle, mem_addr, read_data, sizeof(read_data));if (ret == ESP_OK){ESP_LOGI(TAG, "Data read successfully: ");for (int i = 0; i < sizeof(read_data); i++){printf("0x%02X ", read_data[i]);}printf("\n");}else{ESP_LOGE(TAG, "Failed to read data: %d", ret);}ESP_ERROR_CHECK(i2c_master_bus_rm_device(dev_handle));ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle));ESP_LOGI(TAG, "I2C de-initialized successfully");while (1){vTaskDelay(pdMS_TO_TICKS(1000));}}
GXHT3L
温湿度传感器部分也是一样,先查看温湿度传感器连接到ESP32S3核心板的IO
温湿度传感器协议时序,可以查看51/STM32基础课程,驱动的流程如下
- 初始化I2C总线实例
- 创建I2C设备,添加到总线
- 初始化温湿度传感器,设置采样参数
- 轮询间隔读取温湿度数据,进行校验&打印
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gptimer.h"
#include "esp_log.h"#include <string.h>
#include "sdkconfig.h"
#include "driver/i2c_master.h"static const char *TAG = "GXHT3L"; // 定义日志标签// I2C 引脚和设备配置
#define SCL_IO_PIN 8 // I2C 时钟线引脚编号
#define SDA_IO_PIN 4 // I2C 数据线引脚编号
#define DEVICE_ADDR 0x44 // I2C 设备地址 (7-bit 地址)
#define MASTER_FREQUENCY 100000 // I2C 总线频率 (100kHz)
#define PORT_NUMBER -1 // I2C 端口号 (-1 表示使用默认端口)typedef enum
{/* 软件复位命令 */SOFT_RESET_CMD = 0x30A2, /* 加热使能/禁能命令 */PREHEAT_ENABLE_CMD = 0x306D,PREHEAT_DISENABLE_CMD = 0x3066,/* 芯片状态命令 */DEVICE_STATUS_CMD = 0xF32D,/*单次测量模式命名格式:Repeatability_CS_CMDCS:Clock stretching*/HIGH_ENABLED_CMD = 0x2C06,MEDIUM_ENABLED_CMD = 0x2C0D,LOW_ENABLED_CMD = 0x2C10,HIGH_DISABLED_CMD = 0x2400,MEDIUM_DISABLED_CMD = 0x240B,LOW_DISABLED_CMD = 0x2416,/*周期测量模式命名格式:Repeatability_MPS_CMDMPS:measurement per second*/HIGH_0_5_CMD = 0x2032,MEDIUM_0_5_CMD = 0x2024,LOW_0_5_CMD = 0x202F,HIGH_1_CMD = 0x2130,MEDIUM_1_CMD = 0x2126,LOW_1_CMD = 0x212D,HIGH_2_CMD = 0x2236,MEDIUM_2_CMD = 0x2220,LOW_2_CMD = 0x222B,HIGH_4_CMD = 0x2334,MEDIUM_4_CMD = 0x2322,LOW_4_CMD = 0x2329,HIGH_10_CMD = 0x2737,MEDIUM_10_CMD = 0x2721,LOW_10_CMD = 0x272A,/* 周期测量模式读取数据命令 */READOUT_FOR_PERIODIC_MODE = 0xE000,
} GXHT3L_CMD;static esp_err_t gxht3l_send_cmd(i2c_master_dev_handle_t dev_handle,GXHT3L_CMD cmd)
{uint8_t cmd_buffer[2];cmd_buffer[0] = cmd >> 8;cmd_buffer[1] = cmd;return i2c_master_transmit(dev_handle, cmd_buffer, sizeof(cmd_buffer), pdMS_TO_TICKS(1000));
}static void gxht3l_reset(i2c_master_dev_handle_t dev_handle)
{gxht3l_send_cmd(dev_handle,SOFT_RESET_CMD);
}static void gxht3l_init(i2c_master_dev_handle_t dev_handle){gxht3l_send_cmd(dev_handle,MEDIUM_2_CMD);
}static esp_err_t gxht3l_read_data(i2c_master_dev_handle_t dev_handle,uint8_t *data, size_t length)
{gxht3l_send_cmd(dev_handle,READOUT_FOR_PERIODIC_MODE);return i2c_master_receive(dev_handle, data, length, pdMS_TO_TICKS(1000));
}static uint8_t gxht3l_data_to_float(uint8_t* const data, float* temperature, float* humidity)
{uint16_t recv_temperature = 0;uint16_t recv_humidity = 0;/* 校验温度数据和湿度数据是否接收正确 */// if(CheckCrc8(data, 0xFF) != data[2] || CheckCrc8(&data[3], 0xFF) != data[5])// return 1;/* 转换温度数据 */recv_temperature = ((uint16_t)data[0]<<8)|data[1];*temperature = -45 + 175*((float)recv_temperature/65535);/* 转换湿度数据 */recv_humidity = ((uint16_t)data[3]<<8)|data[4];*humidity = 100 * ((float)recv_humidity / 65535);return 0;
}void app_main(void)
{// 配置 I2C 总线参数i2c_master_bus_config_t i2c_bus_config = {.clk_source = I2C_CLK_SRC_DEFAULT, // 使用默认时钟源.i2c_port = PORT_NUMBER, // 指定 I2C 端口.scl_io_num = SCL_IO_PIN, // SCL 引脚编号.sda_io_num = SDA_IO_PIN, // SDA 引脚编号.glitch_ignore_cnt = 7, // 忽略毛刺计数};// 创建 I2C 总线句柄i2c_master_bus_handle_t bus_handle;ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle)); // 初始化 I2C 总线// 配置 I2C 设备参数i2c_device_config_t dev_cfg = {.dev_addr_length = I2C_ADDR_BIT_LEN_7, // 设备地址长度为 7 位.device_address = DEVICE_ADDR, // 设备地址.scl_speed_hz = MASTER_FREQUENCY, // SCL 时钟频率};// 创建 I2C 设备句柄i2c_master_dev_handle_t dev_handle;ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); // 添加设备到总线// 探测设备esp_err_t ret = i2c_master_probe(bus_handle, DEVICE_ADDR, 1000);if (ret == ESP_OK){ESP_LOGI(TAG, "Device at address 0x%02X found and responsive", DEVICE_ADDR);}else{ESP_LOGE(TAG, "Failed to find device at address 0x%02X", DEVICE_ADDR);}gxht3l_init(dev_handle);uint8_t recv_data[6] = {0};float temperature = 0.0;float humidity = 0.0;while (1){vTaskDelay(pdMS_TO_TICKS(2000));gxht3l_read_data(dev_handle,recv_data, sizeof(recv_data));if(gxht3l_data_to_float(recv_data, &temperature, &humidity)==0){ESP_LOGI(TAG,"temperature = %f, humidity = %f\n", temperature, humidity);}}}