Mega to Control 16-Channel Relay Board with Vixen Software

Hi all,

I have scoured the forums and other sites and can’t find a full solution to this issue. In an effort to make things as clear as possible, I may have over-explained some things; I apologize. Thanks in advance for any insight you guys can provide.

Goal: Use Vixen to control Christmas lights. Vixen is ran on my computer and sends info to the Mega 2560, the Mega controls a 16 channel relay board, the relay board switches strings of lights on and off.

Issue: The optocouplers on the relay board are interpreting “LOW” as “HIGH” and “HIGH” as “LOW”. This means when Vixen tells the arduino to switch a relay on, the relay turns off and vice versa. When the board is powered up with the code I have below, all of the relays turn on. When Vixen tells the Mega to turn on a relay, the relay turns off for the duration of the event in Vixen and then the relay turns back on when the event is over.

Attempts at a solution: As far as I can see, I just need the Mega to interpret a 255 from Vixen as a 0 and a 0 from Vixen as a 255. To do this, I just did ‘255-Serial.read()’ I have included this line, commented out in the code below. When I upload the sketch with the ‘255-’, all of the relays turn on. When I get Vixen talking to the Arduino, all of the relays turn off. This is great except when I play events in Vixen, the relay board does nothing.

If making a short video will help anyone understand what is going on I can certainly do so. Thanks!

int A = 2;
int B = 3;
int C = 4;
int D = 5;
int E = 6;
int F = 7;
int G = 8;
int H = 9;
int I = 10;
int J = 11;
int K = 12;
int L = 13;
int M = 14;
int N = 15;
int O = 16;



int i = 0;
int incomingByte[15];

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

  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(H, OUTPUT);
  pinMode(I, OUTPUT);
  pinMode(J, OUTPUT);
  pinMode(K, OUTPUT);
  pinMode(L, OUTPUT);
  pinMode(M, OUTPUT);
  pinMode(N, OUTPUT);
  pinMode(O, OUTPUT);
 


}

void loop()
{
  if (Serial.available() >= 15)
  {
    for (int i=0; i<15;i++)
    {
      incomingByte[i] = Serial.read();

      // incomingByte[i] = 255 - Serial.read(); 
    }                                       // Arduino pins
    digitalWrite(A, incomingByte[0]);  // Pin 2
    digitalWrite(B, incomingByte[1]);  // Pin 3
    digitalWrite(C, incomingByte[2]);  // Pin 4
    digitalWrite(D, incomingByte[3]);  // Pin 5
    digitalWrite(E, incomingByte[4]);  // Pin 6
    digitalWrite(F, incomingByte[5]);  // Pin 7
    digitalWrite(G, incomingByte[6]);  // Pin 8
    digitalWrite(H, incomingByte[7]);  // Pin 9
    digitalWrite(I, incomingByte[8]);  // Pin 10
    digitalWrite(J, incomingByte[9]);  // Pin 11
    digitalWrite(K, incomingByte[10]); // Pin 12
    digitalWrite(L, incomingByte[11]); // Pin 13
    digitalWrite(M, incomingByte[12]); // Pin A0
    digitalWrite(N, incomingByte[13]); // Pin A1
    digitalWrite(O, incomingByte[14]); // Pin A2
    
  }
}

Try

digitalWrite(A, !incomingByte[0]);  // Pin 2

The exclamation mark will invert the data byte.

This will work if the Vixen software sends binary data and not text. If that does not work, I think that you will need to analyse what the Vixen software exactly sends.

Your code will be a lot simpler if you place your pin numbers in an array. In that case you can use a simple loop to control the lights

byte pins[] = {2, 3 ,4, }; // for you to complete

int i = 0;
int incomingByte[15];

void setup()
{
  ...
  ...
}

void loop()
{
  ...
  ...
}

You can use a for-loop to set the pins to output in setup()

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

  for(byte cnt=0;cnt<sizeof(pins); cnt++)
  {
    pinMode(pins[cnt], OUTPUT);
  }
}

And a for-loop to control the pins in loop()

void loop()
{
  if (Serial.available() >= 15)
  {
    for (int i=0; i<15;i++)
    {
      incomingByte[i] = Serial.read();

      // incomingByte[i] = 255 - Serial.read();
    }                                       // Arduino pins

    for(byte cnt=0;cnt<sizeof(pins); cnt++)
    {
      digitalWrite(pins[cnt], !incomingByte[cnt])
    }
  }
}

Code not tested.

Notes on your use of the variable i.

You have that variable declared before setup. In the for-loop to read the serial data, you have a new variable called i; those are not the same variables! The global variable can go as far as I can see.
2)
Do not use single character variable names; it will be a mission to find the use of that variable back when your code gets more complicated. Your current code contains 146 times the character i. Use a sensible name for the global variable, e.g. index if it’s used as an index in an array.

Very nice; that worked great! I haven't taken a look at the loops and shortcuts you posted after the solution but I will take a look and incorporate that into my code as well. Thanks!