Controlling Relays through serial w/ MAX3323 IC

Please checkout my most recent post. Controlling Relays through serial w/ MAX3323 IC - #10 by Divinitous - Programming Questions - Arduino Forum

I have a task where I need to control two relays through serial on my arduino (Uno or Nano). The arduino is connected as the third component in a serial daisy chain. The first two devices are a type of lab equipment that dose a specific amount of liquid when the software commands it. Below is the code I've put together and it works fine with hyperterminal and such, however I need to change the arduinos trigger from the integer to a text command.

Where the problem lies is the two dosing devices operate with an address. For instance the first unit is assigned 01 and the second is 02. When the software sends a command to one of them it will send the address followed by the command (ie. 01RH, 02DA10, 02BF and such). This will create havoc with my arduino as any time it sees a 1 or 2 it will activate a valve. No good. I need the arduino to be triggered by a text command (ie 06VALVE1, 06VALVE2). I only add 06 for conformity, this isn't necessary.

How can I get this accomplished? I have dabbled with the arduino a good bit with making control circuits from sensors/switches, but I admit that this is my first time interacting with serial. I think I need to abandon the switch setup and maybe go with if commands. I'm a bit stumped with the added ignorance with serial interaction.

#define RELAY1 2
#define RELAY2 3

void setup()
{
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT); 
  Serial.begin(4800);
  Serial.println("Type Relay1 or Relay2 to toggle relay on/off");
}
boolean relay1State = false; // Beginning state off
boolean relay2State = false; // Beginning state off
void loop()
{
  static int relayVal = 0;
  int cmd;

  while (Serial.available() > 0)
  {
    cmd = Serial.read();

    switch (cmd)
    {
   case '1':
{
   relay1State = !relay1State; // If true, make false. If false, make true
   digitalWrite(RELAY1, relay1State);
   Serial.print("Relay1 State is now: ");  // Prints the current state
   Serial.println(relay1State);
   break;
} 
   case '2':
{
   relay2State = !relay2State; // If true, make false. If false, make true
   digitalWrite(RELAY2, relay2State);
   Serial.print("Relay2 State is now: ");  // Prints the current state
   Serial.println(relay2State);
   break;
} 
    }
  }
  }

however the arduino I am controlling is at the end of a daisy chain and the other components use numbers in some of their commands.

What does this mean? How is the Arduino's serial port part of a daisy chain?

It sounds like you need a better protocol - one that defines, first and foremost, which Arduino is to use the data. Others just forward it, if that's what you are doing.

PaulS:

however the arduino I am controlling is at the end of a daisy chain and the other components use numbers in some of their commands.

What does this mean? How is the Arduino's serial port part of a daisy chain?

It sounds like you need a better protocol - one that defines, first and foremost, which Arduino is to use the data. Others just forward it, if that's what you are doing.

Paul,
Sorry, guess I didn't explain it well enough. There is only one arduino. Before the arduino are two components with serial in and serial out. The software that interfaces with the components sends a command with the address first. For instance the first component is configured to have the address of 01 and the second is the address of 02. So when the software sends a command to the first component it would send a command such as 01DA20. Second is 02DA20.

With the arduino setup to trigger on any 1 or 2 it would create an issue when the software sends any command with a 1 or 2 in it. So ultimately I need to change arduinos trigger from 1 to "relay1" or a command that is unmistakable as only for the arduino.

-Ryan

You need to read the whole string from Serial, character by character and assemble it into a null terminated string until you receive an end of message marker or a fixed length of message has been received, then parse out the address and command from the string and take action if appropriate.

UKHeliBob:
You need to read the whole string from Serial, character by character and assemble it into a null terminated string until you receive an end of message marker or a fixed length of message has been received, then parse out the address and command from the string and take action if appropriate.

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=11425&page=1

Thank you, I read through the whole post. I'm still not sure as to how I can get this done properly. From what I've read it seems that my best course of action would be to use a start/stop character. But all I've seen there is how to operate with numbers and not with characters.

-Ryan

But all I've seen there is how to operate with numbers and not with characters.

Here is some code that will read and store data between < and >:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

If you send "<02DA10>", the "02DA10" part will be stored in inData. You can then parse inData, to extract data of interest, after where it says "Process the packet".

simple serial code for controlling an arduino pin.

//zoomkat 3-5-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter
//send on, or off, from the serial monitor

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial LED on/off test with , delimiter"); // so I can keep track
}

void loop() {

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      //if (readString.length() >0) {
        Serial.println(readString); //prints string to serial port out
        //do stuff with the captured readString
        if(readString.indexOf("on") >=0)
        {
          digitalWrite(ledPin, HIGH);
          Serial.println("LED ON");
        }
        if(readString.indexOf("off") >=0)
        {
          digitalWrite(ledPin, LOW);
          Serial.println("LED OFF");
        }       
        readString=""; //clears variable for new input
      //}
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Another example, this is basically the code I use and it never failed

const uint16_t INPUT_LEN = 128;

void checkSerialCommands( HardwareSerial serial );

void setup()
{
  Serial.begin( 57600 );
  Serial1.begin( 57600 );
}

void loop()
{  
  checkSerialCommands( Serial );
  checkSerialCommands( Serial1 );
}

void checkSerialCommands( HardwareSerial serial )
{
  if ( serial.available() > 0 ) 
  {
    static char input[INPUT_LEN];
    static uint8_t i;
    char c = serial.read();

    if ( c != '\r' && i < INPUT_LEN-1)
      input[i++] = c;

    else
    {
      input[i] = '\0';
      i = 0;
      
      uint8_t var1;
      uint8_t var2;
      char output[128];

      if ( sscanf( input, "relay %hhu %hhu", &var1, &var2 ) > 0 )
      {
        sprintf( output, "relay: %hhu state:%hhu\r\n", var1, (bool)var2 );
        serial.print( output );
        setRelayState( var1, (bool)var2 );
      }
    }
  }
}

Line Ending setting must be Carriage Return. Then you type in Serial monitor "relay 1 0" to turn relay 1 OFF (or maybe ON if your relays are active low ;))

Of course you need to replace the setRelayState by your own function.

zoomkat:
simple serial code for controlling an arduino pin.

//zoomkat 3-5-12 simple delimited ',' string parse 

//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter
//send on, or off, from the serial monitor
...

Zoomkat,
Perfect, simple enough for me to understand! Many thanks.
-Ryan

Alright folks, I seem to have mastered the coding and get the expected results through the serial monitor. Send command 01V11| from monitor, relay turns on, arduino sends 01Y back confirming operation took place. Send command 01V10| from monitor, relay turns off, arduino sends 01Y back confirming operation took place. Bellissimo!! Should be smooth sailing from here.

Doh, there's an issue. Now comes the part where I communicate through the serial port alone without USB. I have my arduino interfacing with the serial through a MAX3323EEPE IC. The arduino receives the command, activates the relay, but does not send a response back to terminal. It seems as if the TX isn't happy with something.

Rather than doing softwareserial I'm using the RX/TX pins as I have no need for a second serial interface or the extra coding.

A how to on wiring the MAX3323 is here. (picture attached is current configuration) Sorry no multisim on this PC, mspaint skills at work here. All capacitors are 1uf.

Note: I found that the guide suggests pin 1 to ground, but have read that this should be 2 to ground. Tried both.

At first I figured I might have fubar'd up my Nano3.0, so I swapped it out with another. No luck. I then tried a Uno. Nada. I then swapped out the MAX3323 with another. Nada still. So I'm unsure as to where to point now. When I plug the same serial cable into my dosing device I can send and receive, so the cable is good. The serial going to the arduino shares the same ground as the arduino and MAX3323.

It's vital that the arduino sends the confirmation code as the software I am using will not proceed until it gets this confirmation.

Below is my code.

int Relay1 = 2;
int Relay2 = 3;
String readString;

void setup() {
  Serial.begin(4800);
  pinMode(Relay1, OUTPUT);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Relay1, LOW);
  digitalWrite(Relay2, LOW);
}

boolean relay1State = false; // Assume off to start with
boolean relay2State = false;

void loop() {
  static int relayVal = 0;
  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '|') {          //Ending of command
//      if (readString.length() >0) {
//        //Serial.Println(readString); //prints string to serial port out
//Valve1 Control
        //Valve1 ON
        if(readString.indexOf("01V11") >=0)
          {
          digitalWrite(Relay1, HIGH);
          relay1State = true;
          delay(50);
          Serial.println("01Y");
          }
        //Valve1 OFF
        if(readString.indexOf("01V10") >=0)
          {
          digitalWrite(Relay1, LOW);
          relay1State = false;
          delay(50);
          Serial.println("01Y");
          }
       readString=""; //clears variable for new input
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
//  }
}

max3323_pins.jpg

Alright, I'm digging deeper here. I see that the MAX3323 IC TX output voltage swing is ±5.4v. The RS232 IC (ICL232CBEZ) on the component that I am communicating through has a TX output swing of ±9v. The ICL232CBEZ is able to communicate both RX/TX with my PC. Whereas the MAX3323 is only able to RX but not TX to my PC. Unfortunately I have no oscilloscope here and cannot check voltages. Am I going in the right direction? I see so many people having success with the MAX3323, why am I having this problem. Is there a different model that I should be using?

I have been using a serial adapter in my express card slot of my laptop, but have also tried a usb to serial adapter in this computer and an older PC with a serial port. All resulting in the same scenario...
ICL232CBEZ good RX/TX
MAX3323 good RX, no TX

MAX3323

ICL232CBEZ

Hope everyone enjoyed the holiday and managed to walk away without any missing fingers.

Still a bit lost about my lack of TX from this MAX chip.