Estoy tratando de leer un sensor de temperatura y humedad (SI7020) usando I2C en el ESP32.
Modifiqué su código de ejemplo para leer solo desde un dispositivo esclavo (0x40) pero algunos comandos no funcionan. También intenté restablecer el dispositivo con 0xFE.
Puedo leer el ID del dispositivo (0xFA):
*******************
TASK[0] MASTER READ SENSOR( SI7020 )
*******************
data_h: 48
data_l: 52
sensor val: 15428.333333
Sin embargo, si trato de leer la temperatura (0xE3), obtengo:
data_h: 00
data_l: 00
Si uso 0xE0 siempre obtengo:
data_h: 39
data_l: 9f
¿Por qué no puedo leer la temperatura del SI7020?
El código que estoy usando:
#include <stdio.h>
#include "driver/i2c.h"
#define DATA_LENGTH 512 /*!<Data buffer length for test buffer*/
#define RW_TEST_LENGTH 127 /*!<Data length for r/w test, any value from 0-DATA_LENGTH*/
#define DELAY_TIME_BETWEEN_ITEMS_MS 2000 /*!< delay time between different test items */
#define I2C_EXAMPLE_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */
#define I2C_EXAMPLE_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
#define I2C_EXAMPLE_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */
#define I2C_EXAMPLE_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_EXAMPLE_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_EXAMPLE_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define SI7020_SENSOR_ADDR 0x40 /*!< slave address for SI7020 sensor */
#define SI7020_CMD_READ 0xE0 /*!< Command to set measure mode */
//#define ESP_SLAVE_ADDR 0x28 /*!< ESP32 slave address, you can set any 7bit value */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
xSemaphoreHandle print_mux;
/**
* @brief test code to write esp-i2c-slave
*
* 1. set mode
* _________________________________________________________________
* | start | slave_addr + wr_bit + ack | write 1 byte + ack | stop |
* --------|---------------------------|---------------------|------|
* 2. wait more than 24 ms
* 3. read data
* ______________________________________________________________________________________
* | start | slave_addr + rd_bit + ack | read 1 byte + ack | read 1 byte + nack | stop |
* --------|---------------------------|--------------------|--------------------|------|
*/
static esp_err_t i2c_example_master_sensor_test(i2c_port_t i2c_num, uint8_t* data_h, uint8_t* data_l)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SI7020_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_DIS);
i2c_master_write_byte(cmd, SI7020_CMD_READ, ACK_CHECK_EN);
i2c_master_stop(cmd);
int ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ret;
}
vTaskDelay(1000 / portTICK_RATE_MS);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SI7020_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_DIS);
i2c_master_read_byte(cmd, data_h, ACK_VAL);
i2c_master_read_byte(cmd, data_l, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ESP_FAIL;
}
return ESP_OK;
}
/**
* @brief i2c master initialization
*/
static void i2c_example_master_init()
{
int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_EXAMPLE_MASTER_FREQ_HZ;
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode,
I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
}
static void i2c_test_task(void* arg)
{
int i = 0;
int ret;
uint32_t task_idx = (uint32_t) arg;
uint8_t* data = (uint8_t*) malloc(DATA_LENGTH);
uint8_t sensor_data_h, sensor_data_l;
while (1) {
ret = i2c_example_master_sensor_test( I2C_EXAMPLE_MASTER_NUM, &sensor_data_h, &sensor_data_l);
xSemaphoreTake(print_mux, portMAX_DELAY);
printf("*******************\n");
printf("TASK[%d] MASTER READ SENSOR( SI7020 )\n", task_idx);
printf("*******************\n");
if (ret == ESP_OK) {
printf("data_h: %02x\n", sensor_data_h);
printf("data_l: %02x\n", sensor_data_l);
printf("sensor val: %f\n", ( sensor_data_h << 8 | sensor_data_l ) / 1.2);
} else {
printf("No ack, sensor not connected...skip...\n");
}
xSemaphoreGive(print_mux);
vTaskDelay(( DELAY_TIME_BETWEEN_ITEMS_MS * ( task_idx + 1 ) ) / portTICK_RATE_MS);
//---------------------------------------------------
for (i = 0; i < DATA_LENGTH; i++) {
data[i] = i;
}
}
}
void app_main()
{
print_mux = xSemaphoreCreateMutex();
//i2c_example_slave_init();
i2c_example_master_init();
xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void* ) 0, 10, NULL);
//xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void* ) 1, 10, NULL);
}
Su oscilograma muestra una transacción de lectura aislada, mientras que la hoja de datos muestra una transacción de escritura que precede a un reinicio y la transacción de lectura. Ya he visto algunos dispositivos I2C con errores que solo implementan un subconjunto de las posibles transacciones I2C, podría ser el caso de este. Sugiero probar una transacción que se vea exactamente como se muestra en la hoja de datos.
Según tengo entendido, debe usar el comando 0xF3 varias veces en lugar de un solo 0xE0.
Bence Kaulics
Bence Kaulics
E0
no funcionará solo, ya que devolverá un valor de temperatura medido durante la medición de humedad anterior. Entonces, antesE0
siempre necesitará usarE5
oF5
comandos primero. ConE3
usted está utilizando el modo maestro de retención, el estiramiento del reloj I2C y posiblemente ESP o su código no puede manejar eso. Use elF3
comando, con eso Si7020 no se estirará el reloj. Para obtener el resultado, debe esperar entre 9 y 10 ms después de enviar elF3
y luego debe ejecutar una operación de lectura I2C para obtener el valor temporal.físico