I2C communication between 2 Arduinos

Hi

I am using 2 Arduinos in my project as shown in the diagram.

The Slave is basically a sort for PID controller. The POT defines the temperature to set and thermocouple gets temperature from the heater. The slave also sends SET and REAL temperatures to the master over I2C, when called to display on LCD.

The Master performs multitasks including display of temperatures and some other data on LCD.

The reason for 2 separate Arduinos is that the PID controller sketch have some delays() which can have adverse effects on multi-tasking.

The problem is that I could not transmit the temperatures values properly. I tested with fixed values, they transmit fine the LCD displayed correct values. When I transmit POT & thermocouple values the displayed values will keep on changing rapidly and they are far from the actual values.

Here are the codes:

MASTER:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
.
int nowTemp;
int setTemp;
.
.
#define HeaterArduino 5 // Address for I2C Slave Arduino
    

void setup() 
{
  
 .
 .
 .

    Wire.begin(); // Initialize as I2C Master 
 .
.
.
.
  
}

void loop()
{
    .
    getTemperatures();
    .
    .
    updateDisplay();

    .
    .
}

void updateDisplay()
{
    lcd.setCursor(5, 0);
    lcd.print(setTemp);
    lcd.setCursor(16,0);
    lcd.print(nowTemp);
    lcd.setCursor(11,2);
    float sealVal = sealPotVal/1000.0;
    lcd.print(sealVal);
    lcd.setCursor(14,3);
    lcd.print(totalSealed);
   
    lcd.setCursor(11,1);
    float fillVal = fillPotVal/1000.0;
    lcd.print(fillVal);
}

void getTemperatures()
{
  Wire.requestFrom(HeaterArduino, 8); 
  
  nowTemp = Wire.read();
  setTemp = Wire.read();
}

SLAVE:

#include <SPI.h>
#include <Wire.h>
#include <max6675.h>

#define HeaterArduino 5 // Address for I2C Slave Arduino

#define thermoSO 11
#define thermoCS 12
#define thermoCLK 13
.
.
.
.
MAX6675 thermocouple(thermoCLK, thermoCS, thermoSO);
.
.
.
void setup() 
{
  .
  .
  .
  Wire.begin(HeaterArduino);  // Join I2C bus at address 'HeaterArduino' as Slave
  Wire.onRequest(sendTemperatures); 
}

void loop()
{
  readTemperatures();
           
  .
  .
}

void readTemperatures()
{
  realTemperature = thermocouple.readCelsius();
  delay(500);
  potTemperature = analogRead(potentiometer);
  potTemperature = map(potTemperature, 0, 1023, 30, 300);
}

void sendTemperatures()
{
  int realTemp = realTemperature;
  Wire.write(realTemp);
  Wire.write(potTemperature);
}

// Pin 8 (Zero Cross detection) Interrupt routine

ISR(PCINT0_vect)
{
  if(PINB & B00000001)            
  {
    zeroCrossDetected = true; 
  }
}

The code will not compile with the commas between lines. Remove the commas and repost the code, please.

Wire.writes() are usually framed by a Wire.beginTransmission(address) and Wire.endTransmission(). See the Master writer example.

What Arduino boards are you using?

I think that if you were to write non blocking code (NO delay()s) you may be able to use just one Arduino to do the job. These tutorials might help you to get rid of the delays.

Non-blocking timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

This I2C Tutorial may help

...R

groundFungus:
The code will not compile with the commas between lines. Remove the commas and repost the code, please.

I understand that these codes won't compile.
These are part of the actual code, just to show the relevant sketch lines. The dots represent other non-relevant lines of codes.

groundFungus:
Wire.writes() are usually framed by a Wire.beginTransmission(address) and Wire.endTransmission(). See the Master writer example.

Here the SLAVE is sending the data on request from the MASTER.
I am following the example sketches of Slave_Sender and Master_Reader.
As I already mentioned in my 1st post, the transmission is absolutely fine if I use fixed values.
The problem arises when I try to send mapped POT value and the value received from the thermocouple.

groundFungus:
What Arduino boards are you using?

I think that if you were to write non blocking code (NO delay()s) you may be able to use just one Arduino to do the job. These tutorials might help you to get rid of the delays.

Non-blocking timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

The use of delay could not be avoided because the thermocouple MAX6675 is bit slow and need some time to respond.

Anyway, thanks for the links. For this current project, I have already soldered the parts after I found all segment working. But now I am just stuck because the POT value and the thermocouple value won't transmit correctly.

Sorry, you are right. Wire.beginTransmission(address) and Wire.endTransmission() are not to be used in the ISR.

void sendTemperatures()
{
  int realTemp = realTemperature;
  Wire.write(realTemp);
  Wire.write(potTemperature);
}

The write() function writes 1 byte. An int (realTemp) is 2 bytes. Same with potTemperature if it is an int (do not know the data type, that is left off in the code that you did not post). So, if both are int data type you need to request and send 4 bytes. To send an int one byte at a time see the highByte and lowByte functions.

We would like to know which Arduino boards that you use, because then we would know the size of a integer.

Do you understand these hints:

volatile int myData[2];

void getTemperatures()
{
  int n = Wire.requestFrom(HeaterArduino, sizeof( myData));
  if( n == sizeof( myData))
  {
    Wire.readBytes( (byte *)myData, sizeof( myData));
  }
}

void sendTemperatures()
{
  Wire.write( (byte *) myData, sizeof( myData));
}

Then it is only a small stap to the I2C Tutorial by Robin2. So if you need to add a float or byte, then you can switch to a 'struct' as in that tutorial.

[Edit]Removed wrong ';'

if( n == sizeof( myData);

Should there be a semicolon at the end of the if statement?

groundFungus:
Should there be a semicolon at the end of the if statement?

O no :-[ I'm going to stand in the corner for a while. Thanks.

:slight_smile:

groundFungus:
The write() function writes 1 byte. An int (realTemp) is 2 bytes. Same with potTemperature if it is an int (do not know the data type, that is left off in the code that you did not post). So, if both are int data type you need to request and send 4 bytes. To send an int one byte at a time see the highByte and lowByte functions.

Both are int
realTemp is declared int
potTemperature is mapped integer value between 30 - 300

Do you mean

void getTemperatures()
{
  Wire.requestFrom(HeaterArduino, 4); // INSTEAD OF Wire.requestFrom(HeaterArduino, 8);
 
  nowTemp = Wire.read();
  setTemp = Wire.read();
}

Koepel:
We would like to know which Arduino boards that you use, because then we would know the size of a integer.

I am using two Arduino Pro Mini 5v - 328P

Do you understand these hints:

volatile int myData[2];

void getTemperatures()
{
  int n = Wire.requestFrom(HeaterArduino, sizeof( myData));
  if( n == sizeof( myData))
  {
    Wire.readBytes( (byte *)myData, sizeof( myData));
  }
}

void sendTemperatures()
{
  Wire.write( (byte *) myData, sizeof( myData));
}




Then it is only a small stap to the I2C Tutorial by Robin2. So if you need to add a float or byte, then you can switch to a 'struct' as in that tutorial.

[Edit]Removed wrong ';'

I can partially understand the hints but I am not fully clear.

myData contains both the integers - right?
How will I store both values in myData, sorry I am bit confused.

How will I store both values in myData, sorry I am bit confused.

Here is a way. The array, myData has 2 int elements.

void sendTemperatures()
{
  myData[0] = realTemperature;  
  myData[1] = potTemperature);
  Wire.write( (byte *) myData, sizeof( myData));
}
void getTemperatures()
{
  int n = Wire.requestFrom(HeaterArduino, sizeof( myData));
  if( n == sizeof( myData))
  {
    Wire.readBytes( (byte *)myData, sizeof( myData));
    realTemperature = myData[0];  
    potTemperature = myData[1];
  }
}

abuhafss:
How will I store both values in myData, sorry I am bit confused.

Have you studied the code in the link in Reply #4? - I believe it has all you need.

...R

Yes, I have got it now.

Actually, my experience with C is limited. I could not grasp the usage of array in the first instant.

Thanks all.

I got my project working.

Bundle of thanks to all of you for your contribution.

I am having a new issue.

Here is the void setup() for the Heater Controller:

void setup() 
{
  pinMode(potentiometer,       INPUT);      // To set temperature
  pinMode(zerocrossing, INPUT_PULLUP);  // To detect zerocrossing
  pinMode(firePin,            OUTPUT);        // To fire TRIAC
  pinMode(heaterReady,        OUTPUT);   // HIGH when heater reached SET temperature
  pinMode(greenLED,           OUTPUT);
  pinMode(redLED,             OUTPUT);
  pinMode(heaterBoard,        OUTPUT);

  digitalWrite(heaterBoard,     HIGH); // Send signal to Sealer Board that Heater Board is ON
  digitalWrite(redLED,          HIGH);
  digitalWrite(heaterReady,      LOW);
  
  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D8 (zero cross input) trigger an interrupt on state change.

  Wire.begin(HeaterArduino);  // Join I2C bus at address 'HeaterArduino' as Slave
  Wire.onRequest(sendTemperatures); 
}

The issue is that now the heater is not working. A few hours ago it was working fine.

I am concerned if the "Wire.onRequest(sendTemperatures)" interrupt is conflicting with "PCMSK0 |= (1 << PCINT0)" interrupt. Is there such possibility?

The interrupt attached to pin D8 is to detect zero crossing of the AC cycle (50Hz x 2 = 100Hz). I can measure 100Hz on pin D8 but no voltage on pin D9 which has to trigger the TRIAC. That means that the Zero-Cross-Detection routine is not activating.