HTU21 на GY-21 breakout board I2C проблема

Я соединяю датчик HTU21D с моим NodeMCU v3. Все хорошо! Мне удалось получить кое-какие показания и так далее. Но когда я повторно загружаю свой код, устройство не отвечает. Если я выну блок питания из контакта и сброшу его, он снова заработает. У меня точно такая же проблема с использованием библиотеки Sparkfun, так что это скорее аппаратная проблема. У кого-нибудь еще была такая же проблема? ссылка на библиотеку sparkfun https://github.com/sparkfun/SparkFun_HTU21D_Breakout_Arduino_Library для справки, вот мой код

   This program interfaces the HTU21 temp/humidity sensor via I2C
*/

#include <Wire.h>
#include <Math.h>

const int HTU21_ADDR = 0x40;
const int Trigger_Temp_Measurement = 0xE3;// hold master
const int Trigger_Hum_Measurement = 0xE5; // hold master
const int Trigger_Temp = 0xF3; //No Hold Master
const int Trigger_Hum = 0xF5; //No Hold Master

int16_t Temp, Hum;//переменные для хранения температуры и влажности
int8_t TmpCrc, HumCrC;

void setup() {// поместите свой установочный код здесь, чтобы запустить один раз:
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(0xFE);
  Wire.endTransmission(true);

}

void loop() {// поместите свой основной код здесь, чтобы запускать его повторно:
  TempReading();
  HumReading();

}

void TempReading() {

  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(Trigger_Temp_Measurement);
  Wire.endTransmission();

  Wire.requestFrom(HTU21_ADDR, 3, true);
  if (Wire.available() <= 3) {
    Temp = (Wire.read() << 8) | (Wire.read() );
    TmpCrc = Wire.read();
  }
  float TempCalc = -46.85 + (175.72 * ((float)Temp / (pow(2, 16))));
  Serial.print("Temperature \t");
  Serial.print(TempCalc);
  //Serial.println(TmpCrc, HEX);

}

void HumReading() {
  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(Trigger_Hum_Measurement);
  Wire.endTransmission();

  Wire.requestFrom(HTU21_ADDR, 3, true);
  if (Wire.available() <= 3) {
    Hum = (Wire.read() << 8) | (Wire.read());
    HumCrC = Wire.read();
  }

  float HumCalc = -6 + 125 * (Hum / (pow(2, 16)));
  Serial.print("\t Humidity \t");
  Serial.println(HumCalc);
  //Serial.println(HumCrC, HEX);


}```


, 👍1

Обсуждение

Вы также сбрасываете ведомое устройство вместе с NodeMCU? Когда вы нарушаете связь I2C в неподходящее время, ведомое устройство может находиться в плохом состоянии, блокируя шину. Кроме того, вы можете не захотеть спамить I2C и последовательную шину (потому что у вас нет никакой задержки или чего-то подобного в вашем " loop ()")., @chrisl

Ну, если я нажму reset, он пройдет через цикл настройки, который сбросит устройство. Это действительно НЕ сработает, если шина I2C находится в плохом состоянии. Каким может быть решение для сброса шины?, @sanrays10

Действительно ли установка работает полностью? Откуда ты это знаешь? Под сбросом я подразумеваю настоящий жесткий сброс, а не сброс команды. Только жесткий сброс приведет к сбросу шины I2C, @chrisl

Да, установка выполняется полностью. Я обнаружил, что шина зависает, если я прекращаю связь, загружая новый код на плату. Я нашел фрагмент кода, который освобождает шину, которая работает., @sanrays10


1 ответ


1

Да, установка выполняется полностью. Я обнаружил, что шина зависает, если я прекращаю связь, загружая новый код на плату. Я нашел фрагмент кода, который освобождает шину, которая работает. См. ниже:

#if defined(TWCR) && defined(TWEN)
  TWCR &= ~(_BV(TWEN)); //Отключите 2-проводной интерфейс Atmel, чтобы мы могли напрямую управлять контактами SDA и SCL
#endif

  pinMode(SDA, INPUT_PULLUP); // Сделайте входы контактов SDA (data) и SCL (clock) с помощью pullup.
  pinMode(SCL, INPUT_PULLUP);


  boolean SCL_LOW = (digitalRead(SCL) == LOW); // Проверьте, что SCL низкий.
  if (SCL_LOW) { //Если он удерживается на низком уровне, Arduno не может стать мастером I2C.
    return 1; //Ошибка шины I2C. Не удалось очистить линию часов SCL, удерживаемую на низком уровне
  }

  boolean SDA_LOW = (digitalRead(SDA) == LOW);  // vi. Проверьте вход SDA.
  int clockCount = 20; // > 2x9 часов

  while (SDA_LOW && (clockCount > 0)) { // vii. Если SDA низкий,
    clockCount--;
    // Примечание: шина I2C является открытым коллектором, поэтому НЕ приводите SCL или SDA высоко.
    pinMode(SCL, INPUT); // отпустите подтягивание SCL так, чтобы при выводе оно было НИЗКИМ
    pinMode(SCL, OUTPUT); // затем clock SCL Low
    delayMicroseconds(10); // для >5uS
    pinMode(SCL, INPUT); // release SCL LOW
    pinMode(SCL, INPUT_PULLUP); // снова включите подтягивающие резисторы
    // не форсируйте высоко, так как ведомый может удерживать его низко для растягивания часов.
    delayMicroseconds(10); // для >5uS
    // >5uS предназначен для обработки даже самых медленных устройств I2C.
    SCL_LOW = (digitalRead(SCL) == LOW); // Проверьте, является ли SCL низким.
    int counter = 20;
    while (SCL_LOW && (counter > 0)) {  // цикл, ожидающий, пока SCL станет высоким, ждет только 2 секунды.
      counter--;
      delay(100);
      SCL_LOW = (digitalRead(SCL) == LOW);
    }
    if (SCL_LOW) { // все еще низкий уровень после ошибки 2 сек
      return 2; // Ошибка шины I2C. Не мог очистить. Линия часов SCL удерживается низко подчиненными часами stretch for >2sec
    }
    SDA_LOW = (digitalRead(SDA) == LOW); // и снова проверьте вход SDA и цикл
  }
  if (SDA_LOW) { // все еще низкий
    return 3; // Ошибка шины I2C. Не мог очистить. Линия передачи данных SDA удерживается на низком уровне
  }

  // else pull SDA line low for Start or Repeated Start
  pinMode(SDA, INPUT); // удалить подтягивание.
  pinMode(SDA, OUTPUT);  // а затем сделайте его НИЗКИМ, т. е. отправьте I2C Start или повторное управление запуском.
  // Когда есть только один мастер I2C, запуск или повторный запуск имеет ту же функцию, что и Остановка, и очищает шину.
  /// Повторный старт-это Старт, происходящий после Старта без промежуточной Остановки.
  delayMicroseconds(10); // wait >5uS
  pinMode(SDA, INPUT); // удалить выходной низкий
  pinMode(SDA, INPUT_PULLUP); // и сделать SDA высоким, т. е. отправить I2C STOP control.
  delayMicroseconds(10); // x. wait >5uS
  pinMode(SDA, INPUT); // и сбросить контакты в качестве трехфазных входов, что является состоянием по умолчанию при сбросе
  pinMode(SCL, INPUT);
  return 0; // все ок
}

Спасибо, что указали мне правильное направление!

,