Wireless RGB LED and speaker control
AIM
Like the previous experiment, I want to send data from my computer to the Arduino to control a device, using radio frequencies. I'm using XBee transmitters for wireless communication. My model is XBee PRO S2: it uses 2.4GHz frequency at 50mW power, able to reach 3 km on open air. The configuration I'm using is always the same: AT mode, one coordinator (connected to the Arduino) and one router (connected to my computer). The purpose of the experiment is to change the colors of an RGB LED, and the volume and tune of a speaker, using a LabView graphical interface. This is different from the previous project because I need to send analog data now, so one byte is not enough. This time I need to send a string of values. The Arduino IDE includes a very useful command: Serial.parseInt() extract an integer number from a serial string.
ANALOG VOLTAGE
The arduino has some pins that can be used to output an analog voltage with 1023 increments from 0 to 5 V. This is not completely true: the 5 V pins are switched on and off at very high frequency so the average voltage changes. This works well in case of an LED because the human eyes can't see the LED going on and off hundred thousand times a second. What we see is the intensity of the light changing as a result of the time on and off. This tecnique is called PWM (pulse width modulation) and it works well also with motors. But in case of a speaker it's different. A speaker has to vibrate, which means that the power has to go an and off to produce sounds. The Arduino IDE has a function for that: tune() switches a pin on and off at a certain frequency to produce the sound we want in the speaker, always using the 5 V.
As you can see in the following picture, the duty cycle (on/off time ratio) changes and the result average voltage (dotted line) changes as well. But the magnitude of the pulses doesn't change.
Picture from www.bristolwatch.com
DIGIPOTS
DigiPots work as manual potentiometers, but they are IC (Integrated Circuits) controlled with digital signals. Some of them have an SPI communication interface like the MCP4231. The one I'm using is X9C103. It's controlled by 3 main pins: increment, up/down, chip select. The terminals of the variable resistance are High, Low, and Wiper, like in a normal potentiometer.
The digipot X9C103 has 99 increments of 101 Ω each for a maximum resistance of 10 kΩ. Plus the wiper has an internal resistance of 40 Ω. If we use the full scale in series with a speaker we find out that over the 1000 Ω it's really difficult to hear anything. For this reason I'm using only the first 10 increments, up to 1 kΩ. To do this, I made a scale from 0 to 10 in the labview interface and I add 90 in the Arduino sketch, so the resultant variable "vval" is between 90 and 100. I should have bought the digipot X9C102, which has a maximum resistance of 1 kΩ, so I would be able to use all 99 increments (of 10.1 Ω each).
WIRING
I spent many hours with this experiment rewiring the Digipot in different configuration but I only got it to work in this way: the Chip Select, Increment and Up/Down pins are controlled by the Arduino's pins 10, 11 and 12. The High terminal of the DigiPot is connected to pin 2 (the one we are going to "tune"), the Low is connected to ground, and the Wiper is connected to the positive of the speaker. The negative of the speaker is connected to ground. The DigiPot also needs a connection to 5V and ground.
The RGB LED is actually composed by 3 LEDs (red, green and blue) with common cathode (the negative terminal). Each LED needs a resistance: I'm using 220 Ω for the red and 330 Ω for the green and blue, because they have a different voltage drop. Pins 5,6 and 7 control the power to these LEDs (using PWM).
As usual, I connect an LCD screen to show me what's going on in the brain of the Arduino.
LABVIEW INTERFACE
This time it took me few minutes to create this simple page: the configuration of the VISA function for the serial communication is the same as in the previous project. Three colored bars control the intensity of the LEDs (0 to 255), and two horizontal bars control tune and volume of the speaker.
As you can see from the programming diagram, the numbers are converted to strings and then added together in an array, divided by commas. A delay is necessary not to overflow the buffer of the Arduino serial port.
SKETCH
I have rewritten this sketch many times before I got it to work.
After the serial string is read, the single values are extracted by the function parseInt(). The LED pins are set at these values straight away using PWM.
The X9C103 has its own library <DigiPotX9Cxxx.h> (download here) that allows us to use it easily. The variable "vval" (the wanted volume) is compared with the current volume and if it's different, the function pot.increase() and pot.decrease() adjust the value of the DigiPot.
The function "tune" has 2 arguments: the pin we want to tune and the value. This value can be seen in the file "pitches.h" included in the Arduino IDE. I didn't include this library because I'm not interested in playing particular notes, but I just wanna make some noise. Those values are between about 30 to 5000. I've chosen a range between 100 and 4000 to avoid acute or heavy noises.
#include <DigiPotX9Cxxx.h>
DigiPot pot(11,10,12);
#include <LiquidCrystal.h>
LiquidCrystal lcd(26, 27, 28, 29, 30, 31);
const int RED =7;
const int GREEN =6;
const int BLUE =5;
int rval = 0;
int gval = 0;
int bval = 0;
int tval = 0;
int vval = 0;
int currentvolume = 0;
void setup()
{
pot.decrease(100);
Serial.begin(9600);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
lcd.begin(16, 2);
}
void loop()
{
while (Serial.available() > 0)
{
rval = Serial.parseInt();
gval = Serial.parseInt();
bval = Serial.parseInt();
tval = Serial.parseInt();
vval = Serial.parseInt()+90;
if(currentvolume < vval)
{
int diff = vval - currentvolume;
pot.increase(diff);
}
else if(currentvolume > vval)
{
int diff = currentvolume - vval;
pot.decrease(diff);
}
currentvolume = vval;
analogWrite(RED, rval);
analogWrite(GREEN, gval);
analogWrite(BLUE, bval);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(rval);
lcd.setCursor(5,0);
lcd.print(gval);
lcd.setCursor(10,0);
lcd.print(bval);
lcd.setCursor(0,1);
lcd.print(tval);
lcd.setCursor(5,1);
lcd.print(vval);
lcd.setCursor(10,1);
lcd.print(currentvolume);
tone(2, map(tval,0,100,100,4000));
}
}
CONCLUSIONS
It was difficult to wire and program the DigiPot to control the volume of the speaker because it was altering the frequencies of the "tuned" pin and hence the sound was broken. After many hours of trouble rewiring and rewriting it finally works as expected.