Go Down

Topic: Uno (Master Writer)/ Mega (Slave Receiver) I2C Communication (Read 1 time) previous topic - next topic

insultcomicdog

I have a question about parsing data that's being received by a 'slave' Arduino Mega via I2C serial protocol.

I'm sending data from 'master' Arduino UNO which takes the format of any alphabetic character, followed by a delimiting "|", followed by a numeral ranging from 0-255.

An example would be "A|100".

I can format the data any way I want, as long as I send a value between 0-255 and can differentiated with a marker. The int value represents a potentiometer reading and the alphabetic character represents the specific potentiometer that is being read.


Master Code:

Code: [Select]
void updateRedValue(byte val) {
  Wire.beginTransmission(4); // transmit to device #4
  Wire.write("r|");        // sends two bytes
  Wire.write(val);  // sends one byte 
  Wire.endTransmission();    // stop transmitting
}


Slave Code:

Code: [Select]
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
 
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
//    if(c == "r|"){
//      Serial.print("red");
//    } else if (c == "g|"){
//      Serial.print("green");
//    } else if(c == "b|"){
//      Serial.print("blue");
//    }
  }
 int x = Wire.read();    // receive byte as an integer
// Serial.println(x);         // print the integer

  if (x == 0){
     goPreviousAnimation();
  } else if(x == 1) {
     goNextAnimation();
  } else if (x == 2){
    useMic = false;
  } else if(x == 3){
    useMic = true;
  } else if (x == 11 || x == 12 || x == 13 || x == 14 || x == 15){
    earAnimationMode = x;   
  }
}



I tried to do this comparison but it's invalid, as the IDE complains that comparison between a pointer and integer is forbidden:

Code: [Select]
c == "r|"


Can you recommend an optimal way in which I can parse/send this data to determine the prefix?

I need to know the value of the pot and which pot this value is coming from.

Peter_n

I have more questions than answers, because I don't know the sketch.
http://snippets-r-us.com/

It is not needed to send a readable ascii text, the I2C is almost always used with binary integers.
You could use a byte for the potmeter, and a byte for the value.

A value of a pot from 0-255. Is that enough, or do you need an integer ?

The "receiveEvent( int howMany)" is called from an interrupt, it is therefor an interrupt handler.
It is not allowed to use the Serial library, and no delay, and not running animation.
The Wire.available() is not needed, since the "howMany" is the number of bytes.

The global variables that you use in an interrupt should be 'volatile'.

How many potmeters do you have ?

The code that checks the 'x' value and runs a certain animation should be in the loop(). Maybe not, but I like to keep interrupts and normal code seperated.

insultcomicdog

#2
Mar 03, 2015, 07:18 pm Last Edit: Mar 03, 2015, 07:19 pm by insultcomicdog
Hi Peter_n,

Thanks for taking the time to help me.

I have 2 potmeters connected the "master" UNO.

Sending a byte for the sensor and a byte for the value is a great solution that should work.

I will segregate the if statements from the interrupt code.


I've simplified the sketches so you can see the full code for master and slave.

Master:
Code: [Select]
#include <Wire.h>

const long debounceInterval = 100;
unsigned long previousMillis = 0;

// potentiometers
int potent1Pin = A1;                              // select the input pin for the potentiometer
unsigned short potent1Value = 0;                  // variable to store the value coming from the sensor
byte potent1Position = 0;                         // variable to store the rotary switch position
byte potent1Previous = 0;

int potent2Pin = A2;                              // select the input pin for the potentiometer
unsigned short potent2Value = 0;                  // variable to store the value coming from the sensor
byte potent2Position = 0;                         // variable to store the rotary switch position
byte potent2Previous = 0;

byte x = 0;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  Wire.begin(); // join i2c bus (address optional for master)
}

void loop() {
 
  potent1Value = analogRead(potent1Pin);    // read the value from the sensor
  potent2Value = analogRead(potent2Pin);    // read the value from the sensor

  if (millis() - previousMillis >= debounceInterval) {
       
    if (potent1Value < 205) {                          // potentiometer position 1
      potent1Position = 1;
      //Serial.println("potentiometer position = 1");
    }
    if (potent1Value > 205 && potent1Value < 410) {     // potentiometer position 2
      potent1Position = 2;
      //Serial.println("potentiometer position = 2");
    }
    if (potent1Value > 411 && potent1Value < 615) {    // potentiometer position 3
      potent1Position = 3;
      //Serial.println("potentiometer position = 3");
    }
    if (potent1Value > 616 && potent1Value < 820) {    // potentiometer position 4
      potent1Position = 4;
      //Serial.println("potentiometer position = 4");
    }
    if (potent1Value > 821 && potent1Value < 1023) {    // potentiometer position 5
      potent1Position = 5;
      //Serial.println("potentiometer position = 5");
    }
   
    potent2Position = map(potent2Value, 0, 1023, 0, 255);

    previousMillis = millis();
  }
 
  if (potent1Position != potent1Previous) {
      if(potent1Position == 1){
         sendCommand(1, 11);
      } else if(potent1Position == 2){
        sendCommand(1, 12);
      } else if(potent1Position == 3){
         sendCommand(1, 13);
      } else if(potent1Position == 4){
        sendCommand(1, 14);
      } else if(potent1Position == 5){
        sendCommand(1, 15);
      }
     
      potent1Previous = potent1Position;
    }
   
    if (potent2Position != potent2Previous) {
       potent2Previous = potent2Position;
       sendCommand(2, potent2Position );
    }
}

void sendCommand (byte sensorID, byte value) {
   Wire.beginTransmission(4); // transmit to device #4
   Wire.write(sensorID);              // id for sensor
   Wire.write(value);              // sends one byte 
   Wire.endTransmission();    // stop transmitting
}



Slave:
Code: [Select]
#include <Wire.h>

void setup () {
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
 
  Serial.begin(9600);
 
  Serial.println("setup");
}

void loop() {
 
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
 int x = Wire.read();    // receive byte as an integer
 Serial.println(x);         // print the integer
}


With above code I'm run into a new issue, where I only see 1 byte come through on the slave side. When I turn one pot, I see it's ID and no value. Then when I turn the 2nd pot I see nothing. Then when I turn the original pot no new events at all.


If I re add Wire.available() like so:

Code: [Select]
#include <Wire.h>

void setup () {
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
 
  Serial.begin(9600);
 
  Serial.println("setup");
}

void loop() {
 
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    int ID = Wire.read(); // receive byte as a character
    Serial.print("ID");
    Serial.print(ID);         // print the character
  }
 
  int val = Wire.read();    // receive byte as an integer
  Serial.print("val");
  Serial.println(val);         // print the integer
}



I see the IDs and value of my pots. I will set these as global vars and should be good to go. Still not sure why I had to re add Wire.available(). Thanks for pushing me in the right direction.

Peter_n

You have to remove the Serial functions from the receiveEvent.

I think it is easier to use the 'howMany'
Code: [Select]

volatile byte ID;
volatile byte val;
volatile boolean newValue = false;

void receiveEvent( int howMany)
{
  // Two bytes are transmitted, therefor howMany must be 2
  if( howMany == 2)
  {
    ID = Wire.read();
    val = Wire.read();
    newValue = true;
  }
  else
  {
    // something is wrong, illegal number of bytes received.
  }
}

oric_dan

"r|" is a string, and not an ASCII character, so (c == "r|") will never work. Look up the strcmp() and strncmp() functions, they are hidden down in the IDE wherever it keeps the real C compiler.

Go Up