Uno/Mega2560 I2C AND OneWire temp sensor reading (DS18b20)

I am trying to use the I2C protocol with an Arduino Uno as a Master reader requesting data from a Mega 2560 as a slave writer/responder. AND on the mega-slave, I am also trying to use the “OneWire and DallasTemperature” libs to pull off the 1-wire 4 temperature sensor values (temperature probe DS18b20).

Both work fine independently: uno master request to slave and reading the data response from the mega slave; and separately, periodically reading the 4 temperature sensor values over the one line by the mega. But both enabled in the mega2560 slave, the sketch hangs up when requesting the sensor readings: “ sensors.requestTemperatures(); ”

I am thinking that it has to do with the issuance of the temperature sensor read request AND the mega slave’s request-for-data event handler. But I do not know enough about the core to fix this, or even to know if this is the real root of my problem.

Any help would be appreciated. Thank you.

Greg

But I do not know enough about the core to fix this, or even to know if this is the real root of my problem.

Nor do you seem to know enough to post the code you are asking questions about. Sorry, we can't help you.

@PaulS - Thank you, I think. And you are correct; I can be very stupid at times. But that I can fix - I can add the Master/Slave sketches and even a picture and outputs. But even if I add all that, as I should have, it sounds like you still can not help - "Sorry, we can't help you."

I am a sixty seven years old man that has not worked in sixteen years with serious memory problems. Micro-electronics, circuit boards, even resistors are all new to me and I find that I can forget most of what I learned yesterday overnight. Not an excuse, just a problem I have to manage. But I am pursuing this path as an activity to keep my brain active, learning and [need] to remind myself of what's going on and what needs doing in the Aquaponics system I am building.

I apologize for wasting your time with my inadequate original post. I will post a sequel here later today in hopes that you or another may help in this matter.

BTW: My thinking was simple: Is there any known reason that this dual software serial bus configuration, I2C and 1-wire, will not work due to know issues. And I still do not know that.

But Thank You for your time and I hope to provide better posts in the future.

Greg

"A day without learning something new is a wasted day."

But even if I add all that, as I should have, it sounds like you still can not help - "Sorry, we can't help you."

No. If you did add the sketches and schematics, there is a very good likelihood that we could help you.

My thinking was simple: Is there any known reason that this dual software serial bus configuration, I2C and 1-wire, will not work due to know issues. And I still do not know that.

If the code is written correctly, and the devices are wired correctly, there is no reason that you can not use I2C, Serial, and Wire together in the same sketch.

@PaulS. Again, Thank you for your time.

I plan to attach here my code - uno as master and mega as slave. The mega's initial configuration is with the offending (???) code, the following three lines, commented out:

  // This seems to force a local event call this routine again ( see setup )
  // forcing an event handler loop ( I2C from Master - onRequest ) until 
  // the stack overflows. It seems that I need to better differentiate the
  // Wire.requestFrom( ... ) and the sensors.requestTemperatures( ) interrupts

  /* --- Uncomment this section to realize the problem looping. ---
  Serial.println( "Request Handler Looping..." );
  sensors.requestTemperatures( ); // This causes looping, or so I think.
  temp0 = sensors.getTempFByIndex( 0 ) * 10; // Only one sensor attached.
  */

Serial debug for two cases is also included - I2C only with just random data returned from the sensors module showing both the Master and Slave outputs. Then one sample with the slave enabling the one-wire temperature sensor polling and reading. This is where the troubled "event handler" looping plays in.

So here goes. UnoMaster I2C sketch - simply loops polling the MegaSlave for data - random samples or temperature readings, printing them as a formatted debug string to the Serial Monitor.

#define NAME "sensors_unoMaster"

#include <Wire.h>

#define LEDpin 13
#define loopDelay  2000
#define setupPause 1000

#define MASTER 11  // device ID #11
#define SLAVE  10  // device ID #10

void setup( ) {
  
  pinMode( LEDpin, OUTPUT );
  Wire.begin( );
  Serial.begin( 9600 );

  delay( setupPause ); // Pause for a second...

  Serial.print( NAME );
  Serial.print( " set up complete. Master polling mode.\n" );

  return;
}

void loop( ) {

  digitalWrite( LEDpin, ( digitalRead( LEDpin ) != HIGH ? HIGH : LOW ) );

  // Request from MegaSlave 4 temperature sensor readings @ 2 bytes ints each.
  int count = Wire.requestFrom( SLAVE, 8, true );

  while ( 8 < Wire.available( ) ) { } // Wait until all 8 bytes are available.
  if ( count >= 8 ) {
    float temp0 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    float temp1 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    float temp2 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    float temp3 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;

    // Build and print a serial debug output string of the data.
    String print_string = "Temperature data:  "
           + String( temp0 ) + ", "
           + String( temp1 ) + ", "
           + String( temp2 ) + ", "
           + String( temp3 );
    Serial.println( print_string );

  } else {
    Serial.print( "Bad sensor data.  count = " );
    Serial.println( count );
  }

  delay( loopDelay );

  return;
}

...and the MegaSlave sketch is set into a waiting mode, awaiting a request from the Master for new data, at which time it will respond with: 1) randomly generated sample data to example the I2C, or 2) real sensor probe readings (only one for the post) with three random samples to fill out the Master's request for 8-bytes. (Ultimately, there will be six temperature probes attached.)

#define NAME "sensors_megaSlave"
#define NAME "sensors_megaSlave"

#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 12 // DS18B20 1-wire temperature data pin [digital]
#define LEDpin 13
#define loopDelay  2000
#define idleDelay  100
#define setupPause 1000

#define MASTER 11  // device ID #11
#define SLAVE  10  // device ID #10

// Setup oneWire instance to communicate with Temperature sensor
OneWire oneWire( ONE_WIRE_BUS );

// Initialize Dallas Temperature setup with the oneWire reference
DallasTemperature sensors( &oneWire );

void setup( ) {
  
  pinMode( LEDpin, OUTPUT );
  randomSeed( analogRead( 0 ) );
  Serial.begin( 9600 );

  Wire.begin( SLAVE );
  Wire.onRequest( requestEvent ); // register I2C request event handler

  sensors.begin( );
  discoverOneWireDevices( ); // Optional

  delay( setupPause ); // ...pause a sec

  Serial.print( NAME ); // Serial debug commenting.
  Serial.print( " set up complete. Slave wait mode.\n" );

  return;
}

void loop( ) {

  delay( idleDelay );

  return;
}

void requestEvent( ) {

  digitalWrite( LEDpin, ( digitalRead( LEDpin ) != HIGH ? HIGH : LOW ) );

  unsigned int temp0, temp1, temp2, temp3; // Typed for I2C as 2-bytes each.

  // No sensors when testing the I2C bus only.
  temp0 = random( 1000 ); // round( sensors.getTempFByIndex( 0 )*10 );
  temp1 = random( 1000 ); // round( sensors.getTempFByIndex( 1 )*10 );
  temp2 = random( 1000 ); // round( sensors.getTempFByIndex( 2 )*10 );
  temp3 = random( 1000 ); // round( sensors.getTempFByIndex( 3 )*10 );


  // This seems to force a local event call this routine again ( see setup )
  // forcing an event handler loop ( I2C from Master - onRequest ) until 
  // the stack overflows. It seems that I need to better differentiate the
  // Wire.requestFrom( ... ) and the sensors.requestTemperatures( ) interrupts

  /* --- Uncomment this section to realize the problem looping. ---
  Serial.println( "Request Handler Looping..." );
  sensors.requestTemperatures( ); // This causes looping, or so I think.
  
  temp0 = sensors.getTempFByIndex( 0 ) * 10; // Only one sensor attached.
  */

  // Build a serial degug output string and print it.
  String print_string = "Temperature sensors:  "
        + String( temp0 / 10.0 ) + ", "
        + String( temp1 / 10.0 ) + ", "
        + String( temp2 / 10.0 ) + ", "
        + String( temp3 / 10.0 );
  Serial.println( print_string );

  // I2C data setup and transmission
  while ( Wire.available( ) ) { }
  uint8_t tempData[8] = {
        uint8_t( ( temp0 >> 8 ) ), uint8_t( ( temp0 << 8 ) >> 8 ), 
        uint8_t( ( temp1 >> 8 ) ), uint8_t( ( temp1 << 8 ) >> 8 ), 
        uint8_t( ( temp2 >> 8 ) ), uint8_t( ( temp2 << 8 ) >> 8 ), 
        uint8_t( ( temp3 >> 8 ) ), uint8_t( ( temp3 << 8 ) >> 8 ) };
  Wire.write( tempData, 8 );

  return;
}

void discoverOneWireDevices( void ) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];

  delay( 500 );

  Serial.println( "\nLooking for 1-Wire devices..." ); 

  while( oneWire.search( addr ) ) {
    Serial.print( "Found \'1-Wire\' device with address:  " );

    for( i = 0; i < 8; i++ ) {
      Serial.print( "0x" );
      if ( addr[i] < 16 ) {
        Serial.print( '0' );
      }
      Serial.print( addr[i], HEX );
      if ( i < 7 ) {
        Serial.print( ", " );
      }
    }
    Serial.println( ); 

    if ( OneWire::crc8( addr, 7 ) != addr[7] ) {
      Serial.println( "*** CRC is not valid! ***\n" );
      return;
    }
  }
  Serial.println( );

  oneWire.reset_search( );

  return;
}

This is the sample obtained from the serial monitor for the base test case:

sensors_unoMaster set up complete. Master polling mode.
Temperature data:  53.60, 95.70, 40.50, 64.00
Temperature data:  17.20, 17.30, 46.90, 98.90
Temperature data:  38.20, 3.10, 86.40, 50.60
Temperature data:  65.20, 28.10, 76.50, 89.80
Temperature data:  78.10, 30.50, 24.20, 44.60
...

*** And the slave: ***

Looking for 1-Wire devices...
Found '1-Wire' device with address:  0x28, 0xEE, 0xDE, 0xEE, 0x12, 0x16, 0x01, 0x99

sensors_megaSlave set up complete. Slave wait mode.
Temperature sensors:  39.60, 34.00, 26.30, 81.20
Temperature sensors:  52.40, 24.50, 89.20, 15.40
Temperature sensors:  41.40, 65.20, 21.20, 98.60
Temperature sensors:  89.10, 91.80, 20.20, 6.20
Temperature sensors:  26.70, 7.10, 41.20, 82.00
...

Do not worry about the absolute numbers.

Finally, a serial monitor sample of the Mega slave module trying to poll and read the 1-wire temperature probe sensors.

Looking for 1-Wire devices...
Found '1-Wire' device with address:  0x28, 0xEE, 0xDE, 0xEE, 0x12, 0x16, 0x01, 0x99

Request Handler Looping...
Request Handler Looping...
Request Handler Looping...
Request Handler Looping...
Request Handler Looping...
...

Only thing that I have left is an image of the wiring - I am not good at the schematics yet, no drawing tools. But stuff to learn I guess.

The right side of the mini bread board is the I2C connections using two 1K pull-ups to 5V - hard to see. It includes a Vin to Vin (Mega to Uno) parasitic power for the uno for I have but one power cord and one usb connector. So, parasitic power it is for now.

The left side is the 1-wire temperature setup w/ a 4.7K pull-up and bus connection to digital pin #12.

Well at this point, I do not know what else to supply. If more is needed, please let me know.

Thank you,

Greg

In the MegaSlave sketch, on line 71, try:

delay(800);

The requestEvent() method is an interrupt service routine. Interrupts are disabled when an ISR is running.

Reading from the sensors is not possible in the ISR. Using Serial.print() is not a good idea.

When the master requests temperatures, that is NOT the time to collect the data for the response. The slave should be continually (or on some reasonable schedule, driven by millis(), not a timer interrupt) collecting data. When the master requests data, the slave should return the newest data that it has.

In the future, please use quote tags for data and code tags for code. Scrolling back and forth, trying to find the code when your post has 4 code windows is a pain in the ass.

There really is no excuse for using the String class to make one print possible. Call print() 4 or 8 or 10 times, instead.

  // I2C data setup and transmission
  while ( Wire.available( ) ) { }

God help you if there ever IS data available to read. The data is never read, so the amount of data never goes down. If the condition is ever true, you enter an infinite loop.

So, taking the advice offered I cleaned up my sketches and moved the Master code from the uno to an uno-wifi. Serial output on the Slave is removed, adding it back in only when testing the introduction of new functionality. On the Master, instead of Serial (not really available) I use the Caio library to print over the internet to the WiFi Monitor on my Mac for debugging. The collected temperature results are posted from the Master to the ThingSpeak IoT website every 30-seconds and can be seen here.

#define NAME "sensors_unoWiFiMaster"

#include <Wire.h>
#include <Ciao.h>

// ThingSpeak Data Store Channels access:
// ChannelID  "165824"
#define SERVER_ADDR  "api.thingspeak.com"
#define CONNECTOR  "rest" 
#define API_WRITE_KEY  “…XXX…” // <— supply your own.

#define LEDpin 13
#define loopDelay  30000 // Important:: ThinkSpeak update policy!
#define setupPause 1000

#define MASTER 11  // device ID #11
#define SLAVE 10  // device ID #10

float temp0 = 0.0, temp1 = 0.0, temp2 = 0.0, temp3 = 0.0;

void setup( ) {
  
  pinMode( LEDpin, OUTPUT );
  Wire.begin( );

  Ciao.begin();

  delay( setupPause ); // Pause for a second...

  Ciao.print( NAME );
  Ciao.print( " set up complete. Master polling mode.\n" );

  return;
}

void loop( ) {

  digitalWrite( LEDpin, ( digitalRead( LEDpin ) != HIGH ? HIGH : LOW ) );

  // Request from MegaSlave 4 temperature sensor readings @ 2 bytes ints each.
  int count = Wire.requestFrom( SLAVE, 8, true );
  if ( count == 8 ) {
    temp0 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    temp1 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    temp2 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
    temp3 = ( Wire.read( ) << 8 | Wire.read( ) ) / 10.0;
  } else {
    Ciao.print( "Bad sensor data returned.  count = " );
    Ciao.println( count );
  }

  // Build a ThingSpeak channel update request with new/last valid data.
  if ( count == 8 || (temp0 + temp1 + temp2 + temp3) > 0 ) {
    
    String uri= "/update?api_key=";
    uri += API_WRITE_KEY;
    uri += "&field1=";
    uri += temp0;
    uri += "&field2=";
    uri += temp1;
    uri += "&field3=";
    uri += temp2;
    uri += "&field4=";
    uri += temp3;
    
    Ciao.println(uri); // Send URI to WiFi debug console (optional)

    Ciao.println("Sending temperature data to ThingSpeak Channel"); 
    CiaoData data = Ciao.write(CONNECTOR, SERVER_ADDR, uri);
    if ( !data.isEmpty() ) {
      Ciao.print( "State: " );
      Ciao.print( data.get(1) );
      Ciao.print( "  Response: " );
      Ciao.println( data.get(2) );
    } else { 
      Ciao.print( "ThingSpeak temperature write Error: " );
      Ciao.println( data.get(1) );
    }
  }

  delay( loopDelay );

  return;
}


#define NAME "sensors_megaSlave"

#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 12 // DS18B20 1-wire temperature data pin [digital]
#define LEDpin 13
#define loopDelay  500
#define setupPause 1000

#define MASTER 11  // device ID #11
#define SLAVE  10  // device ID #10

// Typed for I2C as 2-bytes each to transmit when requested.
unsigned int temp0, temp1, temp2, temp3;

// Setup oneWire instance to communicate with Temperature sensor
OneWire oneWire( ONE_WIRE_BUS );

// Initialize Dallas Temperature setup with the oneWire reference
DallasTemperature sensors( &oneWire );

void setup( ) {
  
  pinMode( LEDpin, OUTPUT );

  Wire.begin( SLAVE );
  Wire.onRequest( requestEvent ); // register I2C request event handler

  sensors.begin( );

  delay( setupPause );

  return;
}

void loop( ) {

  digitalWrite( LEDpin, ( digitalRead( LEDpin ) != HIGH ? HIGH : LOW ) );

  sensors.requestTemperatures( );
  
  // Save temperature values for transmission on demand
  temp0 = round( sensors.getTempFByIndex( 0 ) * 10 );
  temp1 = round( sensors.getTempFByIndex( 1 ) * 10 );
  temp2 = round( sensors.getTempFByIndex( 2 ) * 10 );
  temp3 = round( sensors.getTempFByIndex( 3 ) * 10 );

  delay( loopDelay );

  return;
}

void requestEvent( ) {

  // I2C temperature data setup and transmission
  while ( Wire.available( ) ) { }
  uint8_t tempData[8] = {
        uint8_t( ( temp0 >> 8 ) ), uint8_t( ( temp0 << 8 ) >> 8 ), 
        uint8_t( ( temp1 >> 8 ) ), uint8_t( ( temp1 << 8 ) >> 8 ), 
        uint8_t( ( temp2 >> 8 ) ), uint8_t( ( temp2 << 8 ) >> 8 ), 
        uint8_t( ( temp3 >> 8 ) ), uint8_t( ( temp3 << 8 ) >> 8 ) };
  Wire.write( tempData, 8 );

  return;
}

Much more to be added, but all in due time.

Thanks again.

Greg