For the communication of the LEDwork we needed a robust solution. Serial seemed a good way but unfortunately the arduino (both the duemilanove and the pro mini) only has one hardware serial. So we started looking for a solution to overcome this tiny inconvenience. First we looked into a software serial but this didn’t work out, it was a bit too much for the arduino’s little processor to handle up to four software serials (actually it could work with better research but it takes 8 pins which we really need for other stuff). So how about multiplexing?After a crash course in electronics from Rob Luxen from IO StudioLab and some discussion why multiplexing is the way to go or not we decided that it was in fact, the way to go!
We ordered a bunch of CD4052BCN multiplexers and started wiring. The idea is this:
Every LEDwork has one arduino pro mini inside that handles all the communication an lighting and what not. It uses the multiplexer to ‘devide’ its Rx port over four senders. It skips trough them in the program loops. Its Tx port is not multiplexed but simply goes to all four nodes in parallel. Now, how does this multiplexer work? First of the datasheet. As you can see in here the setup is pretty straightforwarded. In our case we only use some of the pins since we only use the multiplexer for receiving.
For us this means that pins INH, Vee and Vss all go to ground, pin OUT/INx goes to Rx, Vdd goes to 5V. A and B are connected to two pins set as output (make sure you do this or it will not work as expected). 0x, 1x, 2x and 3x are connected to the Tx ports of the other LEDWorks. This is almost everything we need before coding the stuff.
We have one more problem though, since we are using a duemilanove for testing. The duemilanove has an onboard usb serial interface which comes with a 10K resistor which distorts the incoming channel. Instead of the 0-5 volt signel we only get a 1-5 volt signal. To get rid of this problem we use a mm74hcu04n hex inverter. Now, don’t ask me how this works exactly, just assume that it does or go to Rob Luxen for more info. For testing we hooked it up as followes: pin 1 is connected to the Tx of the multiplexer, pin 2 is connected to pin 3 (to invert the signal), pin4 is connected to Rx of the arduiono and pin 14 goes to 5V. This means that this comes between the arduino and the multiplexer. If you want to make this a permanent solution make sure that all the other pins of the hex invertor go to ground.
Now, how about some code? I’ve created a very simple test for this. One to put on a sending device and one for a receiving. The code is below. Note that I used a delay() in the sending code. Although you shoul in fact use a delay (calculate the minimum delay based on the baudrate you use), but don’t (really, DON’T) use the function delay() if you want the arduino to do anything else that sending. The dalay function basically shuts the processor down, disallowing it to do anything while the delay is set. Instead, use millis() to check the time since you have been running and base your actions on that. For example, when reading set a var with the currenttime. In the loop check if millis() – [the set time] is larger or equal to your delaytime. Than reset the delaytime and do the rest of the actions needed. An example is the receiving code.
-
byte i = 0;
-
-
void setup()
-
{
-
Serial.begin(9600);
-
}
-
-
void loop()
-
{
-
Serial.print(i++, byte);
-
delay(100);
-
}
This prints the byte-value 0-255 to the serial and starts over. You should be receiving a byte every 100 ms.
-
//define pin constants
-
const int PIN_A = 2;
-
const int PIN_B = 4;
-
-
//define environment vars
-
int PIN_A_value = LOW;
-
int PIN_B_value = LOW;
-
int readFromNeighbour;
-
long timeReadingFromNeighbourStart = 0;
-
long currentTime = 0;
-
-
void setup()
-
{
-
Serial.begin(9600);
-
pinMode(PIN_A, OUTPUT);
-
pinMode(PIN_B, OUTPUT);
-
}
-
-
void loop()
-
{
-
currentTime = millis();
-
if((timeReadingFromNeighbourStart == 0) || (currentTime – timeReadingFromNeighbourStart > 500))
-
{
-
timeReadingFromNeighbourStart = currentTime;
-
readFromNeighbour++;
-
if(readFromNeighbour > 2)
-
{
-
readFromNeighbour = 1;
-
}
-
setReadCommandConditions();
-
}
-
readCommand();
-
}
-
-
void setReadCommandConditions()
-
{
-
switch(readFromNeighbour)
-
{
-
case 1:
-
PIN_A_value = LOW;
-
PIN_B_value = LOW;
-
break;
-
case 2:
-
PIN_A_value = LOW;
-
PIN_B_value = HIGH;
-
break;
-
}
-
digitalWrite(PIN_A, PIN_A_value);
-
digitalWrite(PIN_B, PIN_B_value);
-
}
-
-
void readCommand()
-
{
-
if(Serial.available())
-
{
-
Serial.print(readFromNeighbour);
-
Serial.print("| read: ");
-
Serial.print(Serial.read();
-
Serial.print("\n");
-
}
-
}
This program only looks for two devices. It changes the device it listens to every 500 ms. In the function readCommand() The read character is printed to Serial. You can open a Serial Monitor to check if receiving goes well (connect a usb cable of course). Also, to check whether the multiplexer switches correctly, make both the sender send something different (char instead of byte works also, maybe better for testing). You could also hook leds up to pins A and B to check their states.
While this is mainly a reference to ourselves we hope other benefit from this as well, so if you have any questions, please do not hesitate to ask.