exporting a variable from i2c to void loop

Hi everybody,

i'm trying to use a variable that's being read from the i2c bus (so it's being obtained in the receiveevent void) to do a certain job in the void loop.

void loop() {
 for (int thisNote=0; thisNote<26; thisNote){
 //   while (Wire.available()) { // loop through all but the last
  
  int start = 0; 
  int thisLed=0;
  while (start==0){
  int leds[] = {ledPin3, ledPin4, ledPin5, ledPin3, ledPin4, ledPin3, ledPin4, ledPin3, ledPin4, ledPin5, ledPin3, ledPin4, ledPin3,
                ledPin5, ledPin3, ledPin4, ledPin3, ledPin3, ledPin4, ledPin5, ledPin3, ledPin5, ledPin4, ledPin4, ledPin3};
   digitalWrite(leds[thisLed], HIGH); 
  int noteDuration = 1000 / noteDurations[thisNote];  
  delay(100);
   
  if (sensor==1){
     digitalWrite(leds[thisLed], LOW);
     thisNote++;
     thisLed=thisLed+1;
     tone(8, melody[thisNote], noteDuration);
     int pauseBetweenNotes = noteDuration * 1.30;
     delay(pauseBetweenNotes);
    }  
  Serial.print("SENSORON:");
  Serial.print(sensor);                    // presenta sensor output 1 
  Serial.println("\t"); 
  delay(500);  
}
} 
//}                          
}


// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent (int HowMany) {

   int sensor = Wire.read(); // receive byte as a character
     Serial.println(sensor); 
 
}

The thing is the value i'm obtaining in the void receiveEvent it's not the one i get on the void loop (the var sensor in the void loop is always zero)

I guess it's a var declaring problem but i don't get to solve it.

You have posted a snippet showing only two functions, please read the how to use this forum post, don't post snippets, post complete code.

loop and receiveEvent are functions, they are not "voids". They are functions that return void (ie, nothing).

When you declare sensor within receiveEvent, it is a local variable. So you have a local variable named "sensor" only in scope within receiveEvent and presumably (I say presumably because you haven't posted your global variable declarations, but you say it compiles successfully, and you don't declare "sensor" within loop) also a global one. So in loop it's using the global, but in receiveEvent it's using the local variable.

The solution is to use the global variable in receiveEvent - remove the "int" from the first line.

You must also declare the global sensor variable as volatile, since you are changing it within an ISR.

(deleted)

thank you very much,

i really have to start programming from the beginning because there are some basics concepts that i still don't have

DrAzzy:
You must also declare the global sensor variable as volatile, since you are changing it within an ISR.

Don't think receiveEvent() is an ISR, they don't take arguments.

gfvalvo:
Don't think receiveEvent() is an ISR, they don't take arguments.

Good point - we don't know if it is being called from one BECAUSE OP DID NOT POST THE WHOLE PROGRAM!

This is why we hate snippets here.

DrAzzy:
You have posted a snippet showing only two functions, please read the how to use this forum post, don't post snippets, post complete code.

loop and receiveEvent are functions, they are not "voids". They are functions that return void (ie, nothing).

When you declare sensor within receiveEvent, it is a local variable. So you have a local variable named "sensor" only in scope within receiveEvent and presumably (I say presumably because you haven't posted your global variable declarations, but you say it compiles successfully, and you don't declare "sensor" within loop) also a global one. So in loop it's using the global, but in receiveEvent it's using the local variable.

The solution is to use the global variable in receiveEvent - remove the "int" from the first line.

You must also declare the global sensor variable as volatile, since you are changing it within an ISR.

Here's my complete code:

#include <Wire.h>
#include "Pitches.h"
int sensor=0;
int ledPin3 = 3;
int ledPin4 = 4;
int ledPin5 = 5;
//melody array, it shows the order the notes are gonna be played when you touch the corresponding array position in the sensors array
int melody[] = {NOTE_E4, NOTE_F4, NOTE_G4, NOTE_E4, NOTE_C4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_D4, NOTE_D4, NOTE_E4, NOTE_C4, 
                NOTE_E4, NOTE_F4, NOTE_G4, NOTE_E4, NOTE_C4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_C4};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {4, 4, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 
                       4, 4, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4};

void setup() {
   pinMode(ledPin3, OUTPUT); // configura el pin 13 como salida
   pinMode(ledPin4, OUTPUT); // configura el pin 13 como salida
   pinMode(ledPin5, OUTPUT); // configura el pin 13 como salida
   Wire.begin(8);                // join i2c bus with address #8
   Wire.onReceive(receiveEvent); // what to do when receiving data
// Wire.onRequest(requestEvent); //function to run when asking for data
   Serial.begin(9600);           // start serial for output
  
}

void loop() {
 for (int thisNote=0; thisNote<26; thisNote){
 //   while (Wire.available()) { // loop through all but the last
  
  int start = 0; 
  int thisLed=0;
  while (start==0){
  int leds[] = {ledPin3, ledPin4, ledPin5, ledPin3, ledPin4, ledPin3, ledPin4, ledPin3, ledPin4, ledPin5, ledPin3, ledPin4, ledPin3,
                ledPin5, ledPin3, ledPin4, ledPin3, ledPin3, ledPin4, ledPin5, ledPin3, ledPin5, ledPin4, ledPin4, ledPin3};
   digitalWrite(leds[thisLed], HIGH); 
  int noteDuration = 1000 / noteDurations[thisNote];  
  delay(100);
   
  if (sensor==1){
     digitalWrite(leds[thisLed], LOW);
     thisNote++;
     thisLed=thisLed+1;
     tone(8, melody[thisNote], noteDuration);
     int pauseBetweenNotes = noteDuration * 1.30;
     delay(pauseBetweenNotes);
    }  
  Serial.print("SENSORON:");
  Serial.print(sensor);                    // presenta sensor output 1 
  Serial.println("\t"); 
  delay(200);  
}
} 
//}                          
}


// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent (int HowMany) {

    sensor = Wire.read(); // receive byte as a character
     Serial.println(sensor); 
 
}

The problem I had was actually the declaration in the function receiveEvent, and not in the global as you said.

Before that i tried to put all the function i had in loop inside the receiveEvent.

What do you think is better?

Having it separetely in two functions or having it all in the receiveEvent function?

The code is a mess. The receiveEvent() function is called from an ISR. You can’t do Serial.println() inside it. You also must keep it as short as possible. Variables shared between loop() and ISR must be volatile. And, accesses to them in loop() must be protected from interrupts. It also looks like your loop() function will get stuck in an infinite ‘while’ loop. See below for a possible framework to build on. Make the code in your loop() function non-blocking.

EDIT: Simplified the Code:

#include <Wire.h>

volatile int sensor;
volatile boolean newFlag = false;

void setup() {
  Wire.onReceive(receiveEvent); // what to do when receiving data
  Serial.begin(9600);           // start serial for output
}

void loop() {
  int localSensor;

  if (newFlag) {
    noInterrupts();
    localSensor = sensor;
    newFlag = false;
    interrupts();
    
    /*
     ******* Process new localSensor value here. Only use NON-BLOCKING code *******
    */
  }
}

void receiveEvent(int HowMany) {
  sensor = Wire.read();    // read the first byte
  while (Wire.available()) {
    (void)(Wire.read());  // flush the rest (if any)
  }
  newFlag = true;
}