0

I am interfacing the HTU21D sensor with my nodeMCU v3. All good! I managed to get some readings etc. But when I re-upload my code the device does not respond. If I remove the power supply from the pin and hard reset it, it works again. I have exactly the same problem using the Sparkfun library, so it seems more of a hardware problem. Anyone else had the same problem? link to the sparkfun library https://github.com/sparkfun/SparkFun_HTU21D_Breakout_Arduino_Library for reference, here is my code

   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;//variables to store temp and humidity
int8_t TmpCrc, HumCrC;

void setup() {// put your setup code here, to run once:
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(HTU21_ADDR);
  Wire.write(0xFE);
  Wire.endTransmission(true);

}

void loop() {// put your main code here, to run repeatedly:
  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);


}```


  • Are you also resetting the slave device together with the nodeMCU? When you disrupt the I2C communication at the wrong time, the slave might be in a bad state, blocking the bus. Also you might not want to spam the I2C and Serial bus (because you don't have any delay or such in your loop()) – chrisl May 17 at 17:57
  • Well If I press reset it would run through the setup loop which would reset the device. This would indeed NOT work if the I2C bus is in a bad state. What could be a solution to reset the bus? – sanrays10 May 17 at 21:25
  • Does the setup really run completely? How do you know that? With reset I mean a real hard reset, not a command reset. Only a hard reset would reset the I2C bus – chrisl May 18 at 8:34
  • Yes the setup runs completely. I found out that the bus hangs if I terminate communication by uploading new code to the board. I found a piece of code that releases the bus which works. – sanrays10 May 18 at 16:24
0

Yes the setup runs completely. I found out that the bus hangs if I terminate communication by uploading new code to the board. I found a piece of code that releases the bus which works. See below:

#if defined(TWCR) && defined(TWEN)
  TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
#endif

  pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup.
  pinMode(SCL, INPUT_PULLUP);


  boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low.
  if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master.
    return 1; //I2C bus error. Could not clear SCL clock line held low
  }

  boolean SDA_LOW = (digitalRead(SDA) == LOW);  // vi. Check SDA input.
  int clockCount = 20; // > 2x9 clock

  while (SDA_LOW && (clockCount > 0)) { //  vii. If SDA is Low,
    clockCount--;
    // Note: I2C bus is open collector so do NOT drive SCL or SDA high.
    pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW
    pinMode(SCL, OUTPUT); // then clock SCL Low
    delayMicroseconds(10); //  for >5uS
    pinMode(SCL, INPUT); // release SCL LOW
    pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again
    // do not force high as slave may be holding it low for clock stretching.
    delayMicroseconds(10); //  for >5uS
    // The >5uS is so that even the slowest I2C devices are handled.
    SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low.
    int counter = 20;
    while (SCL_LOW && (counter > 0)) {  //  loop waiting for SCL to become High only wait 2sec.
      counter--;
      delay(100);
      SCL_LOW = (digitalRead(SCL) == LOW);
    }
    if (SCL_LOW) { // still low after 2 sec error
      return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
    }
    SDA_LOW = (digitalRead(SDA) == LOW); //   and check SDA input again and loop
  }
  if (SDA_LOW) { // still low
    return 3; // I2C bus error. Could not clear. SDA data line held low
  }

  // else pull SDA line low for Start or Repeated Start
  pinMode(SDA, INPUT); // remove pullup.
  pinMode(SDA, OUTPUT);  // and then make it LOW i.e. send an I2C Start or Repeated start control.
  // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus.
  /// A Repeat Start is a Start occurring after a Start with no intervening Stop.
  delayMicroseconds(10); // wait >5uS
  pinMode(SDA, INPUT); // remove output low
  pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
  delayMicroseconds(10); // x. wait >5uS
  pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset
  pinMode(SCL, INPUT);
  return 0; // all ok
}

Thanks for pointing me in the right direction!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.