Teensy 3.5: using 2 SHT31 sensors simultaneously

Status
Not open for further replies.

Kedar

Member
Hi,

Is it possible to use two SHT31 with a Teensy 3.5. I know the description says there are just two pins 19 and 18 for SDA and SCL. Please advise. Below is the code I used for a single sensor.


#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <SPI.h>
#include <SoftwareSerial.h>
#if defined(ARDUINO_ARCH_SAMD) || defined(__SAM3X8E__)
#define lcd Serial1
#else
#include <SoftwareSerial.h>
SoftwareSerial lcd = SoftwareSerial(0, 7); //lcd tx pin = 7
#endif
Adafruit_SHT31 sht31 = Adafruit_SHT31();

void setup() {
Serial.begin(9600);
Wire.begin();
Wire.setSDA(A15);// A15 SCL
Wire.setSCL(A14);//A14 SDA
SPI.begin(); // Init SPI bus
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens

Serial.println("SHT31 test");
if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr
Serial.println("Couldn't find SHT31");
while (1) delay(1);
}
lcd.begin(9600); //initializes lcd
lcd.write(0xFE); //screen size
lcd.write(0xD1);
lcd.write(16);
lcd.write(2);
}


void loop() {
float t = sht31.readTemperature();
float h = sht31.readHumidity();

if (! isnan(t)) { // check if 'is not a number'
Serial.print("Temp *C = "); Serial.println(t);
} else {
Serial.println("Failed to read temperature");
}

if (! isnan(h)) { // check if 'is not a number'
Serial.print("Hum. % = "); Serial.println(h);
lcd.write(0xFE);
lcd.write(0x58);
lcd.print("Hum. % = "); lcd.println(h);

} else {
Serial.println("Failed to read humidity");
}
Serial.println();
delay(1000);
}
 
Hi,

Is it possible to use two SHT31 with a Teensy 3.5. I know the description says there are just two pins 19 and 18 for SDA and SCL. Please advise.}

First of all, when you post code, please use the '#' button in the tool bar. It adds the appropriate code before and after the code to make sure the code is properly indented.

Second of all, please don't use Software Serial on Teensy, instead use Seral1 which uses pins 0/1 (or Serial2 which uses pins 9/10, or Serial3 which uses pins 7/8).

The i2c is a shared bus. Each device has an address that it listens on. The Adafruit board has one pin that can select either address #1 (0x44) which is default or address #2 (0x45) if ADDR is connected to a pin with 3.3v voltage.

You would declare two variables:
Code:
Adafruit_SHT31 sht31a = Adafruit_SHT31();
Adafruit_SHT31 sht31b = Adafruit_SHT31();

And in the begin statement use the addresses:

Code:
  if (! sht31a.begin(0x44)) {    // first sensor with default address
    Serial.println("Couldn't find SHT31 #1");
    while (1) delay(1);
  }

  if (! sht31b.begin(0x45)) {    // second sensor with secondary address
    Serial.println("Couldn't find SHT31 #2");
    while (1) delay(1);
  }

Then change your program to read from both sht31a and sht31b.
 
Michael

Thank you, Ill keep that in mind for future note.
Can you tell me how I would go about defining the SDA and SCL pins for each of the seperate SHT31 Sensors?

Code:
 Wire.begin();
  Wire.setSDA(A15);// A15 SCL
  Wire.setSCL(A14);//A14 SDA
A well as defining each variable for readout:

Code:
void loop() {
  float t = sht31.readTemperature();
  float h = sht31.readHumidity();

  if (! isnan(t)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t);
  } else { 
    Serial.println("Failed to read temperature");
  }
  
  if (! isnan(h)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h);
    
  } else { 
    Serial.println("Failed to read humidity");
  }
  Serial.println();
  delay(1000);
}
 
For the bus 'Wire' it uses only one set of shared pins. That is why they need to have unique addresses as those common Teensy pins go to wires common to both devices.
 
In general, i2c acts like an old fashioned party line telephone setup, where everybody can hear all of the conversations on the wire, but each i2c slave device is supposed to only respond to the messages sent to its address. So you send out the first read and say Mr. 0x44, please tell me the temperature and the master waits for the reply. Then it sends out a new message saying Ms. 0x45, please tell me the temperature, and the master waits for the reply. At any one time, there is only one conversation going on, and it is all controlled by the master device.

So as defragster says the SDA and SCL wires are common to all devices on the i2c bus (along with ground and 3.3v power). You can hook them up serially (i.e. hook up device #1 to the Teensy, and then chain all 4 wires to the next device) or in parallel (having separate connections to each device). As long as your i2c bus is fairly short, and the devices are well behaved, it doesn't matter. It does matter in larger/longer i2c setups.
 
I cannnot read the data of the second sensor on the same pins even after a delay between measurements


Temp *C = 20.81
Failed to read temperature
Hum. % = 69.81
Failed to read humidity

Temp *C = 20.77
Failed to read temperature
Hum. % = 69.83
Failed to read humidity

Code:
void setup() {
  Serial.begin(9600);
  Wire.begin();
  Wire.setSDA(A15);// A15 SCL
  Wire.setSCL(A14);//A14 SDA
 
  
  SPI.begin(); // Init SPI bus
  while (!Serial)
    delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("SHT31 test");
  if (! sht31a.begin(0x44)) {    // first sensor with default address
    Serial.println("Couldn't find SHT31 #1");
    while (1) delay(1);
  }

  if (! sht31b.begin(0x45)) {    // second sensor with secondary address
    Serial.println("Couldn't find SHT31 #2");
    while (1) delay(1);
  }
  lcd.begin(9600); //initializes lcd
    lcd.write(0xFE); //screen size
  lcd.write(0xD1);
  lcd.write(16);
  lcd.write(2);
}


void loop() {
  float t = sht31a.readTemperature();
  float h = sht31a.readHumidity();
  float t2 = sht31b.readTemperature();
  float h2 = sht31b.readHumidity();

  if (! isnan(t)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t);
  } else { 
    Serial.println("Failed to read temperature");
  }
  delay (100);
   if (! isnan(t2)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t2);
  } else { 
    Serial.println("Failed to read temperature");
  }
  
  if (! isnan(h)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h);
    
  } else { 
    Serial.println("Failed to read humidity");
  }
  delay (100);
    if (! isnan(h2)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h2);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h2);
    
  } else { 
    Serial.println("Failed to read humidity");
  Serial.println();
  delay(1000);
  }
}
 
First of all, when you post code, please use the '#' button in the tool bar. It adds the appropriate code before and after the code to make sure the code is properly indented.

Second of all, please don't use Software Serial on Teensy, instead use Seral1 which uses pins 0/1 (or Serial2 which uses pins 9/10, or Serial3 which uses pins 7/8).

Michael, Serial3 did not work but software serial does. not sure is that is an issue.
 
On Teensy 'software Serial' only works on functional Serial port pins from what Paul has indicated. If that works then there should be no reason using true serial would not function - and work properly with the hardware. Serial3 is not the best choice as hardware has only a 1 byte receive buffer where Serial 1&2 have an 8 byte FIFO buffer. But if it seems to be working now it could be made better later.

There is an example i2c SCANNER that will identify all responsive/functional devices on a given i2c bus, this would help confirm the devices are responding properly on the expected addresses. There is need for attention to PULLUPs on those lines. There needs to be one single set of external pullups on the bus lines - somewhere 2.2K to 4.7K is typical.

<edit>: Is the posted code complete? I don't see where sht31a and sht31b are instantiated? Or #includes that would name any libraries.
Also - does "cannnot read the data of the second sensor" mean it is leaving setup() with both devices 'Found'?
 
@defragster if Im using pin 33 and 34 for one sensor as SCL and SDA pins respectively and 37 and 38 for the other, which ones or all of them need pull ups?
I can read from pins 33 and 34 rign now.

Here's the updated code for your reference:

Code:
#include <Arduino.h>
//#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <SPI.h>
// #define lcd Serial2
#include <SoftwareSerial.h>

  SoftwareSerial lcd = SoftwareSerial(0, 7);  //lcd tx pin = 7
#include <i2c_t3.h>

Adafruit_SHT31 sht31a = Adafruit_SHT31();
Adafruit_SHT31 sht31b = Adafruit_SHT31();

void setup() {
  Serial.begin(9600);
 
Wire.begin(I2C_MASTER, 0x44, 33, 34);
Wire1.begin(I2C_MASTER, 0x45, 37, 38);
 
  SPI.begin(); // Init SPI bus
  while (!Serial)
    delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("SHT31 test");
  if (! sht31a.begin(0x44)) {    // first sensor with default address
    Serial.println("Couldn't find SHT31 #1");
    while (1) delay(1);
  }

  if (! sht31b.begin(0x45)) {    // second sensor with secondary address
    Serial.println("Couldn't find SHT31 #2");
    while (1) delay(1);
  }
  lcd.begin(9600); //initializes lcd
    lcd.write(0xFE); //screen size
  lcd.write(0xD1);
  lcd.write(16);
  lcd.write(2);
}


void loop() {
  float t = sht31a.readTemperature();
  float h = sht31a.readHumidity();
  float t2 = sht31b.readTemperature();
  float h2 = sht31b.readHumidity();

  if (! isnan(t)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t);
  } else { 
    Serial.println("Failed to read temperature");
  }
  delay (100);
   if (! isnan(t2)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t2);
  } else { 
    Serial.println("Failed to read temperature");
  }
  
  if (! isnan(h)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h);
    
  } else { 
    Serial.println("Failed to read humidity");
  }
  delay (100);
    if (! isnan(h2)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h2);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h2);
    
  } else { 
    Serial.println("Failed to read humidity");
  Serial.println();
  delay(1000);
  }
}
 
Why would one use two different I2C busses for devices with different addresses? They can work very well on one single i2C bus and at the same pins. Using separate i2c busses can theoretically work, too, but it is highly inefficient.

And why do you include SPI.h? I do not see any call to a SPI peripheral in your code...
 
Indeed only one set of pins to set up one common bus for both devices to Teensy is all that is needed.

You can wire to them on unique busses Wire and Wire1, which would require two copies of the driver with one changed to Wire1? - but these are not high throughput devices so I'm not sure of any value in that since you can get them both to have unique addresses and do one set of wires that includes them both from just the Wire pins on SCL0/SDA0.
 
So if I understand it right, I can just use the same pins for SDA0 and SCL0 by defining unique addresses to each sensor using Wire and Wire1 to read the data from the two different sensors?
I tried that, but would I need to create a copy of the library/file Wire named Wire1 so I call them seperately?
But i2c_t3 does that for you so you dont have to define Wire and Wire1 by creating a duplicate file.

That didnt work either btw.
SPI.h was being called for another part of the code which I cut out as I am first trying to just get the teensy to read two sensors simultaneously.
 
... The Adafruit board has one pin that can select either address #1 (0x44) which is default or address #2 (0x45) if ADDR is connected to a pin with 3.3v voltage.
...

@Kedar - please refer to this post above @MM looked at the Adafruit info and the device can have an alternate address set for one of the two devices to they can both run on the same 'Wire' bus.

Using different pin sets would allow them to have the same address - but then a way to adjust the driver for one device to use Wire1 would need to be done.
 
Last edited:
@Kendar - please refer to this post above @MM looked at the Adafruit info and the device can have an alternate address set for one of the two devices to they can both run on the same 'Wire' bus.

Using different pin sets would allow them to have the same address - but then a way to adjust the driver for one device to use Wire1 would need to be done.

Thanks for all the help, tried that first but to no success, also Its KEDAR.
 
Oy vey, since both sensors should be connected to the same I2C pins, you need only Wire and never Wire1 to talk to them, provided you are addressing both correctly with different addresses as was already pointed out. To me, it looks like you do not have fully understood the I2C bus and addressing concept. I suggest that before starting such projects, you acquire first the needed theoretic knowledge.

It's like driving a car: Get a driving license first!
 
Oy vey, since both sensors should be connected to the same I2C pins, you need only Wire and never Wire1 to talk to them, provided you are addressing both correctly with different addresses as was already pointed out. To me, it looks like you do not have fully understood the I2C bus and addressing concept. I suggest that before starting such projects, you acquire first the needed theoretic knowledge.

I learnt that the hard way, thanks for your help. Appreciate it.
 
Looking at assuming it is the right board? :: adafruit-sht31-d-temperature-and-humidity-sensor-breakout

I see:
we spun up a breakout board with the SHT31-D and some supporting circuitry such as pullup resistors

That means using two boards - each will have pullups. Can you try one and then the other and see them work at expected address? They show they are 10K - which is low and that may work at lower speed? I'm not sure when both are online each with pullups.

Putting 3V3 on the adr pin will change the one as note.
 
For anyone looking for how this worked out. Here is the expanation and final code with results:

Connecting the ADR pin to 3.3 Vin changed the address to 0x45. I defined this as per your specifications in the code. But this mean we can read only 2 sensors at a time?

Thanks a ton @MM, @ Defragster!!

Below is the code for you guys to see and the results:







Code:
Code:
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <SPI.h>
// #define lcd Serial2
#include <SoftwareSerial.h>

  SoftwareSerial lcd = SoftwareSerial(0, 7);  //lcd tx pin = 7
//#include <i2c_t3.h>

Adafruit_SHT31 sht31a = Adafruit_SHT31();
Adafruit_SHT31 sht31b = Adafruit_SHT31();

void setup() {
  Serial.begin(9600);
 Wire.begin();
Wire.setSDA(A15);// A15 SCL
Wire.setSCL(A14);//A14 SDA

 
  SPI.begin(); // Init SPI bus
  while (!Serial)
    delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("SHT31 test");
  if (! sht31a.begin(0x44)) {    // first sensor with default address
    Serial.println("Couldn't find SHT31 #1");
    while (1) delay(1);
  }

  if (! sht31b.begin(0x45)) {    // second sensor with secondary address
    Serial.println("Couldn't find SHT31 #2");
    while (1) delay(1);
  }
  lcd.begin(9600); //initializes lcd
    lcd.write(0xFE); //screen size
  lcd.write(0xD1);
  lcd.write(16);
  lcd.write(2);
}


void loop() {
  float t = sht31a.readTemperature();
  float h = sht31a.readHumidity();
  float t2 = sht31b.readTemperature();
  float h2 = sht31b.readHumidity();

  if (! isnan(t)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.println(t);
  } else { 
    Serial.println("Failed to read temperature");
  }
  delay (100);
   if (! isnan(t2)) {  // check if 'is not a number'
    Serial.print("Temp 2*C = "); Serial.println(t2);
  } else { 
    Serial.println("Failed to read temperature");
  }
  
  if (! isnan(h)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(h);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum. % = "); lcd.println(h);
    
  } else { 
    Serial.println("Failed to read humidity");
  }
  delay (100);
    if (! isnan(h2)) {  // check if 'is not a number'
    Serial.print("Hum.2 % = "); Serial.println(h2);
 lcd.write(0xFE);
      lcd.write(0x58);
         lcd.print("Hum.2 % = "); lcd.println(h2);
    
  } else { 
    Serial.println("Failed to read humidity");
  Serial.println();
  delay(1000);
  }
}
SHT31 test
Temp *C = 21.22
Temp 2*C = 21.90
Hum. % = 65.46
Hum.2 % = 37.07
Temp *C = 21.22
Temp 2*C = 21.89
Hum. % = 65.46
Hum.2 % = 37.70
Temp *C = 21.20
Temp 2*C = 21.90
Hum. % = 65.48
Hum.2 % = 37.75
Temp *C = 21.22
Temp 2*C = 21.90
Hum. % = 65.50
Hum.2 % = 37.47
Temp *C = 21.20
Temp 2*C = 21.90
Hum. % = 65.52
Hum.2 % = 37.06
 
Very cool it worked out. A shame there wasn't a bit more detail on the Adafruit device page that might have gotten you off to a better start … i.e showing wiring with two devices - then people would buy twice as many :)

If your wiring looks clear and you could get a nice picture it might help others.

I'm wondering if you could get the open address #44 device online alone and powered up - then have the code WAIT while you put 3.3V power on the addr pin to change it to #45 - then RESUME the code with .begin(0x45) - and if the device responds with the address changed after power up.
 
Very cool it worked out. A shame there wasn't a bit more detail on the Adafruit device page that might have gotten you off to a better start … i.e showing wiring with two devices - then people would buy twice as many

In the mid eighties of last century already, a short time after bringing I2C to the market for the first time, Philips sent out engineers and technicians to offer free I2C courses in universities, engineer and technician schools. That’s how I learnt about it, btw. There was even a free meal afterwards offered by Philips.

Thus, I’d expect that now, more than 30 years later, I2C/SMBus has in the meantime become common knowledge and virtually everybody in the electronic and embedded domain should perfectly know how it works and how things have to be wired up.
 
Another thing I wished was more of these libraries were setup, to allow users to easily use a different Wire object, like Wire1 ore Wire2

Again it would not be hard to do it here, just add an optional parameter to the begin method, which defaults to Wire, and then save that variable away as a member variable (pointer to which one), and then change all of the Wire.... calls to pwire->.... calls. I have done it on on a few libraries, and have tried to get them accepted, but ...

Alternative: maybe @Paul and others, if we have difficulty getting all of these libraries updated, wonder if it would make sense to try a different approach.

That is we create objects like today except instead of Wire object always meaning logically Wire0, we actually create Wire0 and in the case of T3.5, probably still Wire1 and Wire2.

But we still have a Wire object, which is a forwarder to one of the physical Wire objects, defaults to Wire0.

Then maybe the Wire object has a method, something like: Wire.setWireObject(Wire0);

So you could change it on the fly around calls that use Wire...

So you could do some of the above, like:
Code:
  Wire.setWireObject(Wire0);
  float t = sht31a.readTemperature();
  float h = sht31a.readHumidity();
  Wire.setWireObject(Wire1);
  float t2 = sht31b.readTemperature();
  float h2 = sht31b.readHumidity();

Again just a random idea...
 
Status
Not open for further replies.
Back
Top