Email Print

No image

Here is a post about what you can do in an afternoon or two with a whole load of electronics stuff lying around.

I have had an red-green-blue (RGB) board from Big Clive or Phenoptix lying around for a while. I had developed an RGB LED controller for it, so I also had one of those attached to it.

It is designed to fit in to those 150W halogen light holders and I had managed to find one of those as well.

I wanted to do something fun with it so decided to make a wirelessly controlled LED lamp which can be used to change the room ambiance, or to signify some form of data (anything from room temperature to number of emails to read).

Demonstration

Here is the completed lamp and a short demo video:

alt

Concept

The light contains an RGB LED board which is controlled using serial data from a microcontroller.

The microcontroller will read command sent to it via its serial lines and act on those accordingly.

The serial data is sent wirelessly using an XRF radio UART serial module. Any data sent to the device in the correct format will cause it to change colour.

Data will be sent using another XRF module from elsewhere (the XRF has a great range).

Parts required

If you would like to follow this build then you will need:

There are loads of different options for all of these parts, this was just what I had lying around.

Hardware

I wired two of the Minimus outputs (PD0 and PD1) to the Serial Data and Serial Clock lines of the RGB LED controller. The RGB controller was wired up to the 12V input and contains an on-board 5V regulator, which powers all the logic level equipment.

The XRF was wired to the Rx and Tx lines of the Minimus (PD2 and PD3). The wires were swapped over, so the XRF Tx connected to the Rx of the Minimus and vice versa. This is due to the flow of data from the XRF to the Minimus.

The XRF is a 3V3 device so I also needed a 3V3 converter board, the active version of this break out board.

A push switch was also wired to a digital input on the Minimus (on PD4). This has not bee used for anything yet, but the idea is that it will be used to locally switch the light output on and off.

Here are some photos of the guts of the it:

alt

All the parts before fitting into the halogen floodlight base.

alt

The minimus AVR.

alt

The RGB LED controller.

alt

The XRF and XBBO 3v3 breakout board.

alt

The RGB LED floodlight board.

alt

The empty halogen floodlight holder. This has holes for the 12V DC power, the push switch and the aerial of the XRF.

alt

alt

The RGB board was screwed into place with some 3mm machine screws and a couple of tapped holes I drilled.

alt

The finished, closed unit with glass front and power.

Software

The software was written using the Arduino IDE. It was uploaded to the Minimus AVR using the flow mentioned in this previous blog post. The code is available to download here or is written out here. Hopefully the comments help with the code flow. It uses the substring command which (as noted here) might be too memory intensive, which could cause an issue (but this code works as it is).

/********************************************************
/****** Colour Change using RGB shield with Minimus ****
/****** by Matt Little **********************************
/****** Date: 18/3/14 ***********************************
/****** This email address is being protected from spambots. You need JavaScript enabled to view it.
  ************************
/****** www.re-innovation.co.uk *************************
/********************************************************

This will read serial commands via a software serial.
It will update the colour of the LED board depending upon those commands.

Data is sent to the board serially in the format aXXXXXXX
Where XXXXXXX is an integer which relates to the hex FFFFFF
FF0000 hex = 16711680 int = RED ON
00FF00 hex = 65280 int = GREEN ON
0000FF hex = 255 int = BLUE ON

This can be created from the RGB (0-255) values with
R  x 65280
G x 255
B x 1

This will be read by an XRF or wireless device from a sending unit.

The minimus pin outputs are:
Minimus:    Arduino Equivalent:  Connection to:
PC2          20                   
PD0          0                    SDI
PD1          1                    CKI
PD2          2                    Rx
PD3          3                    Tx
PD4          4                    SWITCH 1
PD5          5
PD6          6
PD7          7
PB0          8  
PB1          9
GND

PB2          10
PB3          11
PB4          12                  LED 1
PB5          13                  LED 2
PB6          14                  LED 3
PB7          15
PC7          16                  
PC6          17
RESET    
PC5          18
PC4          19
Vcc



see www.re-innovation.co.uk for more details
Modified:
18/3/14  Initial code written - Matt Little

*/

#include <stdlib.h>
#include <string.h> // This is for the serial shifted output data const int SDI = 0; //PD0 of the Minimus is used as the SDI (Serial Data) const int CKI = 1; //PD1 of the Minimus is used as the CKI (Data clock) const int led = 6; //LED of Minimus const int led1 = 12; //LED const int led2 = 13; //LED const int led3 = 14; //LED const int sw1 = 16; // Input switch // This line defines a "Uart" object to access the serial port HardwareSerial Uart = HardwareSerial(); // Variables for the RGB shield #define STRIP_LENGTH 1 //This is to use more than one RGB LED board. In this case only one board connected long strip_colors[STRIP_LENGTH]; long fade = 0x000000; // A long integer for the fade function long fade_change = 0x000000; // A long int to do bitwise shifting on the fade value long colour = 0x000000; // This holds the colour to display boolean dataAvailable=LOW; // Flag to show data is available // ****** Serial Data Read*********** // Variables for the serial data read char inByte; // incoming serial char String str_buffer = ""; // This is the holder for the string which we will display #define MAX_STRING 20 // Sets the maximum length of string probably could be lower char stringBuffer[MAX_STRING]; // A buffer to hold the string when pulled from program memory void setup() { Uart.begin(9600); // Set up a serial output for data display and changing parameters //set pins to output so you can control the shift register pinMode(SDI, OUTPUT); pinMode(CKI, OUTPUT); pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(sw1, INPUT); digitalWrite(led1, LOW); digitalWrite(led2, LOW); digitalWrite(led3, LOW); strip_colors[0] = 0xFF0000; //Set the data to Bright Red post_frame(); //Push the current color frame to the strip delay(200); strip_colors[0] = 0x00FF00; //Set the data to Bright Red post_frame(); //Push the current color frame to the strip delay(200); strip_colors[0] = 0x0000FF; //Set the data to Bright Red post_frame(); //Push the current color frame to the strip delay(200); strip_colors[0] = 0x000000; //Set the data to Bright Red post_frame(); //Push the current color frame to the strip } void loop() { getData(); // Check the serial port for data if(dataAvailable==HIGH) { strip_colors[0] = colour; //Set the data to Bright Red post_frame(); //Push the current color frame to the strip } delay(50); // Just slow everything down } // **********************GET DATA SUBROUTINE***************************************** // This sub-routine picks up and serial string sent to the device and sorts out a power string if there is one // All values are global, hence nothing is sent/returned void getData() { // **********GET DATA******************************************* // We want to find the bit of interesting data in the serial data stream // As mentioned above, we are using LLAP for the data. // All the data arrives as serial commands via the serial interface. // All data is in format aXXDDDDDDDDD where XX is the device ID if (Uart.available() > 0) { dataAvailable=HIGH; // Tell the rest of the program there is data available inByte = Uart.read(); // Read whatever is happening on the serial port if(inByte=='a') // If we see an 'a' then read in the next 11 chars into a buffer. { str_buffer+=inByte; for(int i = 0; i<11;i++) // Read in the next 11 chars - this is the data { inByte = Uart.read(); str_buffer+=inByte; } //Uart.println(str_buffer); // TEST - print the str_buffer data (if it has arrived) sortData(); Uart.print("OK"); // Receive info back to say its updated str_buffer=""; // Reset the buffer to be filled again } } else { dataAvailable=LOW; // Tell the rest of the program there is data available } } // **********************SORT DATA SUBROUTINE***************************************** // This sub-routine takes the read-in data string (12 char, starting with a) and does what is required with it // The str-buffer is global so we do not need to send it to the routine void sortData() { // We first want to check if the device ID matches. // If it does not then we disregard the command (as it was not meant for this device if(str_buffer.substring(1,4)=="OFF") { colour = 0; } else { String colourString = str_buffer.substring(1,9); colour = colourString.toInt(); } } //Takes the current strip color array and pushes it out void post_frame (void) { //Each LED requires 24 bits of data //MSB: R7, R6, R5..., G7, G6..., B7, B6... B0 //Once the 24 bits have been delivered, the IC immediately relays these bits to its neighbor //Pulling the clock low for 500us or more causes the IC to post the data. for(int LED_number = 0 ; LED_number < STRIP_LENGTH ; LED_number++) { long this_led_color = strip_colors[LED_number]; //24 bits of color data for(byte color_bit = 23 ; color_bit != 255 ; color_bit--) { //Feed color bit 23 first (red data MSB) digitalWrite(CKI, LOW); //Only change data when clock is low long mask = 1L << color_bit; //The 1'L' forces the 1 to start as a 32 bit number, otherwise it defaults to 16-bit. if(this_led_color & mask) digitalWrite(SDI, HIGH); else digitalWrite(SDI, LOW); digitalWrite(CKI, HIGH); //Data is latched when clock goes high } } //Pull clock low to put strip into reset/post mode digitalWrite(CKI, LOW); delayMicroseconds(500); //Wait for 500us to go into reset }

Further work