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
Wenn ich jedoch versuche, die Temperatur (0xE3) abzulesen, erhalte ich:
data_h: 00
data_l: 00
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);
}
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.
Bence Kaulics
Bence Kaulics
E0
nicht alleine, da er einen Temperaturwert zurückgibt, der während der vorherigen Feuchtigkeitsmessung gemessen wurde. VorherE0
müssen Sie also immer zuerstE5
oderF5
-Befehle verwenden. MitE3
verwenden Sie den Hold-Master-Modus, I2C-Clock-Stretching und möglicherweise ESP oder Ihr Code kann damit nicht umgehen. Verwenden Sie denF3
Befehl, mit dem Si7020 kein Clockstretching durchführt. Um das Ergebnis zu erhalten, müssen Sie nach dem Senden etwa 9-10 ms wartenF3
und dann einen I2C-Lesevorgang ausführen, um den Temp-Wert zu erhalten.physiii