Serial.read multiple strings from processing to switch on relays_Arrays

Hi

I am trying to send multiple strings from processing to arduino to turn on and off multiple relays. Ultimately the string / strings sent from processing would be if a line or multiple lines were clicked. Then all of this data sent over to arduino.

The string would be like this

000100 - the first 4 numbers are the reference for the relay to connected to an individual arduino pin
000100 - the 5th number is if the relay is on or off 0 = off 1 = on
000100 - the 6th number is for how long the relay is on for

Having read some posts some initial problems are

1 - the number of lines selected is not known but the maximum number of lines that can be selected is.
2 - Firsts attempts sending just two strings from processing has resulted in unreliable results. Relays do not switch on sometimes etc.

Having read quite a few posts and websites I think the solution is in gathering all of this information in an array and then reading it when arduino knows all of the information has been sent.

One thing that may help if timing / delays are needed when sending lots of strings from processing is that all of the relays do not have to switch on at exactly the same time.

Processing Code

import processing.serial.*;

Serial myPort;

int time;
int wire_01_timer = 1000;
int wire_02_timer = 2000;

boolean wire_01_isOn = true;
boolean wire_02_isOn = true;

void setup() {

  //String portName = Serial.list()[0];
  myPort = new Serial(this, "COM3", 9600);

  time = millis();//store the current time

}

void draw() {

  if (wire_01_isOn && (millis() - time >= wire_01_timer) ) {
    myPort.write("00100,"); //this is ref: 0100 5th number means on or off 0 = off, 1 = on, 2 = on)
//    00100 the first 4 numbers are the reference / pin reference, 
//    the 5th number is to switch it on, off and to a set resistance 
//    0 = off, 1 = on at resistance 5, 2 = on at resistance 200
//    eg - 00101 = wire 1 is on at resistance 5
    wire_01_isOn = false;
    delay(100);
    println("turned wire 1 off");
    //flush();
  }

  if (wire_02_isOn && (millis() - time >= wire_02_timer) ) {
    myPort.write("01000"); //this is ref: 0100 5th number means on or off 0 = off, 1 = on, 2 = on)
    delay(1000);
    wire_02_isOn = false;
    println("turned wire 2 off");
    //flush();
  }
}
void mousePressed() {

  myPort.write("00101"); //this is ref: 0010, 5th number 1 on means switch on at resistance 5
  println("turned wire 1 on");
  delay(1000);
  myPort.write(','); //a break between the strings to separate them
  delay(1000);
  myPort.write("01001"); //this is ref: 0100 and 1 (for "on")
  println("turned wire 2 on");
  delay(1000);

  time = millis();//store the current time

  wire_01_isOn = true;
  wire_02_isOn = true;
}

void serialEvent(Serial myPort)
{
  // read the serial buffer:
  String myString = myPort.readStringUntil('\n');
  println(myString);
}

Arduino Code

# define RELAY_ON 0
# define RELAY_OFF 1

String incomingByte;

void setup() {
 // initialize serial communication:
  Serial.begin(9600);
  digitalWrite (10, RELAY_OFF);
  digitalWrite (8, RELAY_OFF);
  pinMode (10, OUTPUT);
  pinMode (8, OUTPUT);
}

void loop() {

  /*
    listern to the serial port. If anything comes through
    /send the whole string to a wireOperator() method below...
  */

  if (Serial.available() > 0) {
    String s = Serial.readString();
    wireOperator(s);
    Serial.println(s); //write to the serial so can see what arduino received and write this on processing
  }

}

int getPin(String pinRef) {
  //this is the switchboard method. It will take in a
  //pin reference and send back a pin value as an int.
  //This is where pins are referenced relative to string information recieved
  //0010 = relay 1
  if (pinRef == "0010") //Wire ref in from processing specific to that value.
    return (10); //Relay 1 on pin 10
  if (pinRef == "0100") //0100 = relay 2
    return (8);
  else
    return (0);
}

void wireOperator(String incomingByte) {

  /*
    this method will split the string up using the
    charAt(x) method. This will produce two chunks.
    1. a String "ref" that will hold the 4 digit string ref
    2. an int "state" which will be zero or one for "on" or "off"
  */

  String ref = String( incomingByte.charAt(0)) + "" + String(incomingByte.charAt(1)) + "" + String(incomingByte.charAt(2)) + "" + String(incomingByte.charAt(3) );
  int state = String(incomingByte.charAt(1)).toInt();

  if (state == 1) { //on
    digitalWrite(getPin(ref), RELAY_ON);
    Serial.flush();
  }
  else if (state == 0) {//off
    digitalWrite(getPin(ref), RELAY_OFF);
    Serial.flush();
  }
}

I am using an arduino uno at the moment

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example.

It is not a good idea to use the String (capital S) class as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

000100 - the first 4 numbers are the reference for the relay to connected to an individual arduino pin

So, you want to be able to set the state of pins 0 to 9999. Did I miss something?

    myPort.write("00100,"); //this is ref: 0100 5th number means on or off 0 = off, 1 = on, 2 = on)

That is not in keeping with what you actually send.

Hi Paul and Robin

Really sorry for the extremely slow reply I have only just seen these messages!!!

I have made some progress but think it has not addressed the earlier point that Robin has raised regarding using Strings. I have been through your link today but still a bit confused and unsure on what is the best way to progress using, char array, pointers or strings...

I can currently switch on and off a relay using serial communication from processing.

The next step is sending a string from processing that has the id and a timer value

i.e.
(ID) (Timer)
0001,65.334:

However the timer value is not known or the relay to be switched on until the information is sent from processing.

I can also send an image of what is being sent from processing...?

The code below has descriptions of the problem.

Basically relay 2 turns on because 0002 is all that is sent from processing - how ever would like to have a timer with this like relay 1
relay 1 doesn't as 0001,float value is sent - I don't know how to split this up so the id switches the relay on and the float value turns it off after the defined amount of time.

Any help would be great

Many Thanks

Adam

/* Turning on and off a relay with button clicks from processing using serial communiction
 * Button clicks in processing send string for relay id and a timer float value.
 * The timer value determines how long the relay stays switched on for
 */

//Constants for the relay state - either on or off
# define RELAY_ON 0
# define RELAY_OFF 1

// constants won't change. Used here to set a pin number :
const int R1 =  10; // the number of Relay pin
const int R2 =  9;

// Variables that will change :
int R1State = RELAY_OFF;// Relay State used to set the Relay on or off
int R2State = RELAY_OFF;

// "unsigned long" for variables that hold time as become too large for an int to store
unsigned long R1previousMillis = 0; // will store last time Relay was updated
unsigned long R2previousMillis = 0; //it is unsigned because can swutch it off in processing before it times out

//These are where the string numbers will be assigned to when converted to a float that controls how long the relay is switch on for
//needs to be pulled out from the string sent from processing
//is an "unsigned long" variable the user determines the value in processing
unsigned long R1interval = 5000.150; //interval at which stay on for (millisec). This needs to be set to zero and is defined by the string value
unsigned long R2interval = 1000; //mills will time out after 50days with the unsigned lond variable
unsigned long timeOnStart = 0; //records time when relay switch on - used to determine if interval time reached
unsigned long currentMillis = 0; //records the total time the sketch is ran for


boolean buttonR1 = false; //if the button in processing is switch on or off - R for red so a high resistance is set
boolean buttonB1 = false; //if the button in processing is switch on or off - B for blue so a low resistance is set
boolean stateChange = false; //records the relay state if switched on or off. Used to switch off if relay is on once intercal time is reached
boolean previousState = false;
boolean newdata = false; //determines if all the data is received from processing - was thinking the could be used to split up the whole string

const char startOfNumberDelimiter = ','; //delimiter always used to not where the string of numbers begins
const char endOfNumberDelimiter   = ':'; //delimiter always used to not where the string of numbers ends

//Data for relays and times
String incomingString; // a variable to read all of the incoming serial data - have attached image for data sent from processing
//String TimerVals;// a variable to store the string of numbers which need to be converted to a float - this is the bit that I am confused by. Should it be a char array?
char TimerVals [30]; //An array to hold all of the incoming strings chars - the could have a for loop to run through them all at a certain number ie for int i = 4 ... char 4 in the array is where the numbers start


void setup() {
  Serial.begin(9600);

  // set the digital pin as output:
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);

  digitalWrite(R1, RELAY_OFF);// the initial state of the relays is off - stop large current draws
  digitalWrite(R2, RELAY_OFF);

  R1State = RELAY_OFF;
}

/*
 * Making it modular so could have a function here to get the whole string that is coming in
 * the split it up into two parts - an id part to determine which relay and a string with to  
 * numbers for the relays interval timer. This would = relay1timer.
 * strings are split by , and end with :
 */

void splitting() {

}

void timevals() {
//convert the string numbers to a float
// R1interval = TimerVals.toFloat();
}

void serialEvent() {
  String incomingString = ""; //this clears the string for new input
  if (Serial.available()) {
    delay(100); //Wait for all data to be received
    while (Serial.available()) {
      incomingString = incomingString + char(Serial.read());
      newdata = true;
    }
  }
//could get rid of the new data part but thought it may be useful as a condition to split the strings
  if (newdata == true & incomingString == "0001") { //"Relay 1 ON" is the id - need to separate this from the numbers sent with it. Use the numbers for the interval timer
    Serial.println(incomingString);
//    Serial.write(incomingString);
    digitalWrite(R1, RELAY_ON);
    buttonR1 = !buttonR1; //button 1 Red
    R1State = RELAY_ON; //when incoming string comes in and something happens the relay state updates
    Serial.flush();
  } else if (newdata == true & incomingString == "0002") {
    Serial.println(incomingString);
    digitalWrite(R2, RELAY_ON);
    buttonB1 = !buttonB1; //button 1 blue
    Serial.flush();
  } else if (newdata == true & incomingString == "1&2Off") {
    Serial.println(incomingString);
    digitalWrite(R1, RELAY_OFF);
    digitalWrite(R2, RELAY_OFF);
    R1State = RELAY_OFF;
    buttonR1 = buttonR1;
    buttonB1 = buttonB1;
    Serial.flush();
  } else {
    Serial.println (incomingString);
    Serial.flush();
  }
}

/*
 * Define a timer here for how long relays stay on for. The time depends on the value sent from processign
 * 
 */
void Relay1Time () {
  currentMillis = millis ();
  //check if the relay has changed state
  if ((previousState == false && R1State == RELAY_ON) || (previousState == true && R1State == RELAY_OFF)) {
    stateChange = true;
  }
  //if you notice a state change in the relays, reset the timer to the current time.
  if (stateChange) {
    timeOnStart = millis();
    stateChange = false;
  }
  //Only send serial data if the current time minus the start time is equal to the interval.
  //The == is exactly the time interval. >= leads to time being slipped / it runs over
  if (currentMillis - timeOnStart == R1interval) { //R1interval here should be the value split from the string received from processing
    if (R1State == RELAY_OFF) {
      digitalWrite(R1, RELAY_OFF); //not printing info if the relay is off
      //Serial.println(timeOnStart / 1000); //printing the value every 5s
      //Serial.println(currentMillis / 1000);
    }
    if (R1State == RELAY_ON) {
      digitalWrite(R1, RELAY_OFF);
      Serial.println(timeOnStart / 1000);//Print the times - this can be read in processing to check they are working
      Serial.println(currentMillis / 1000);// / 1000 turns the data to seconds
    }
  }
  //set previous state
  if (R1State == RELAY_ON) {
    previousState = true;
  } else {
    previousState = false;
  }
}

void loop() {
  Relay1Time (); //constanly check the time and state to turn off the relay if it is on and the interval time is reached
}

ajb12:
unsure on what is the best way to progress using, char array, pointers or strings...

Don't use the String class as it is only laying up trouble for the future when it causes memory corruption.

If you send the data like "<1, 1, 334>" then it will be easy to receive and to parse using the third example and the parse example in my link.

...R

@ajb12, do no hijack. @ajb12, do not cross-post. Other thread removed.

Hi Robin

Thanks for the heads up and potential pitfalls. Will go over your link.

Sorry for the cross-post.

Thank you for removing

Cheers

Adam