Probleme bei der Verwendung von I2C auf ESP32 zum Lesen des Temperatur-/Feuchtigkeitssensors (SI7020)

Ich versuche, einen Temperatur- und Feuchtigkeitssensor (SI7020) mit I2C auf dem ESP32 zu lesen.

Ich habe ihren Beispielcode geändert , um nur von einem Slave-Gerät (0x40) zu lesen, aber einige Befehle funktionieren nicht. Ich habe auch versucht, das Gerät mit 0xFE zurückzusetzen.

Ich kann die Geräte-ID (0xFA) lesen:

*******************
TASK[0]  MASTER READ SENSOR( SI7020 )
*******************
data_h: 48
data_l: 52
sensor val: 15428.333333

Geräte-ID lesen

Wenn ich jedoch versuche, die Temperatur (0xE3) abzulesen, erhalte ich:

data_h: 00
data_l: 00

Geben Sie hier die Bildbeschreibung ein

Wenn ich 0xE0 verwende, bekomme ich immer:

data_h: 39
data_l: 9f

Warum kann ich die Temperatur nicht vom SI7020 ablesen?

Der Code, den ich verwende:

#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);
}
In welchem ​​Modus haben Sie den Hold-Master-Modus oder den No-Hold-Master-Modus ausprobiert? Ich weiß nicht, ob es wirklich zusammenhängt, aber bei mir hat mit ESP8266 und SI7021 nur kein Hold-Master-Modus funktioniert. Der Hold-Master-Modus ist nur für Brumm- und Temperaturmessungen verfügbar. Vielleicht funktionieren deshalb andere Befehle für Sie.
Der Befehl funktioniert also E0nicht alleine, da er einen Temperaturwert zurückgibt, der während der vorherigen Feuchtigkeitsmessung gemessen wurde. Vorher E0müssen Sie also immer zuerst E5oder F5-Befehle verwenden. Mit E3verwenden Sie den Hold-Master-Modus, I2C-Clock-Stretching und möglicherweise ESP oder Ihr Code kann damit nicht umgehen. Verwenden Sie den F3Befehl, mit dem Si7020 kein Clockstretching durchführt. Um das Ergebnis zu erhalten, müssen Sie nach dem Senden etwa 9-10 ms warten F3und dann einen I2C-Lesevorgang ausführen, um den Temp-Wert zu erhalten.
@Bence Kaulics F3 gibt mir die gleiche Antwort wie E3 in meinem ursprünglichen Beitrag. Und selbst nach Ausgabe von E5 und F5 gibt E0 die gleiche Antwort wie zuvor. Die Zeilen 43-69 stimmen meines Erachtens mit der im SI7020-Datenblatt gezeigten Sequenz überein .

Antworten (1)

Ihr Oszillogramm zeigt eine isolierte Lesetransaktion, während das Datenblatt eine Schreibtransaktion zeigt, die einem Neustart und der Lesetransaktion vorangestellt ist. Ich habe bereits einige fehlerhafte I2C-Geräte gesehen, die nur eine Teilmenge der möglichen I2C-Transaktionen implementieren, könnte bei diesem der Fall sein. Ich schlage vor, eine Transaktion zu versuchen, die genau so aussieht, wie das Datenblatt zeigt.

Soweit ich weiß, sollten Sie den Befehl 0xF3 mehrmals anstelle eines einzelnen 0xE0 verwenden.