Back to the main blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights
In the earlier blog about the Infineon I evaluated the demo and created a library to drive the board from that code which worked out quite well, but it was not complete from the IoT of Holiday Lights perspective
Radio interface to Mrs YUN was missing along with a few commands already demonstrated in various videos
This will provide a quick walk through the current level of the code highlighting a few of the aspects to control the lights attached to the shield
first the need to add in all the libraries for the NRF24L01, the Infineon and support libraries
// Bunch of constants in the form of definitions // 1 = output debug to serial port, 0 = no debug #define debug 1 /* Include needed Lbraries */ #include <SPI.h> #include <Wire.h> #include "nRF24L01.h" #include "RF24.h" #include "printf.h" #include <Infineon.h> #include <avr/pgmspace.h> /* End include libraries */ Infineon RGBLEDS = Infineon();
The Infinion.h is the library I created from the original demo, then added a couple extra features like a colour lookup and an ability to directly set the colour by name
Here is the enum from Infineon.h
typedef enum {White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Aqua, Teal, Blue, Navy, Fuchsia, Purple} Colours;
this allows you to set the colour by a friendly name
and in the main Infineon.c file the actual support code for this
void Infineon::SETCOLOUR(uint8_t Colour) { switch(Colour) { case White: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x800);break; case Silver: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xC00, 0xC00, 0xC00);break; case Gray: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x800);break; case Black: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0x0);break; case Red: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0x0, 0x0);break; case Maroon: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x0, 0x0);break; case Yellow: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0xFFF, 0x0);break; case Olive: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x0);break; case Lime: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0xFFF, 0x0);break; case Green: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x800, 0x0);break; case Aqua: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0xFFF, 0xFFF);break; case Teal: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x800, 0x800);break; case Blue: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0xFFF);break; case Navy: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0x800);break; case Fuchsia: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0x0, 0xFFF);break; case Purple:I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x0, 0x800);break; default: break; }
As you can see this is easy to extend and adjust the colours to get them right, currently some are a bit off when using an LED 12V string as the output., this function can probably be optimized if needed but for now it is easy to follow and update
Back to the main code, skipping the parts related to the radio as there described in the other blog entries
now we come to the variables and enums related to the mode of operation and timing control
enum modes {cSOLID, cFLASH, cRAINBOW}; modes colourMode = cSOLID ; // mode 0 = static, 1 = flash, 2 = rainbow boolean isBright = true; int flashTime = 500; // 500mS int nextFlash ; //enumeration to make accessing the command strings easier enum {hello, SETCOLOUR, RED, GREEN, BLUE, WHITE, FLASH, RAINBOW, OFF }; //Command Strings PROGMEM const char helloCmd[] = "Hello"; PROGMEM const char SETCOLOURCmd[] = "SETCOLOUR"; PROGMEM const char REDCmd[] = "RED"; PROGMEM const char GREENCmd[] = "GREEN"; PROGMEM const char BLUECmd[] = "BLUE"; PROGMEM const char WHITECmd[] = "WHITE"; PROGMEM const char FLASHCmd[] = "FLASH"; PROGMEM const char RAINBOWCmd[] = "RAINBOW"; PROGMEM const char OFFCmd[] = "OFF";
Rainbow has not yet been implemented but Flash has and is described below, the last few parameters re-use some of my tutorial code from this series Fast Track to Arduino Programming, if you want to know the details, please feel free to go look
suffice to say here that it defines the commands that can be received over the serial port of the NRF radio, the SETColourCmd was demonstrated being used from the WEB Page demo utilizing the colour wheel
Skipping down to the setup() loop we see a style of mine that I encourage others to follow. That is to modularize our code right from the start, unless your running out of Flash and really need to get that last byte back, there is no reason not to and you will quickly understand the benefits of seperating the various parts of functionality (Easy of maintenance, Understanding, editing and debugging)
void setup() { // initialize serial: Serial.begin(57600); // do other setup here as needed initialiseNRF(); Wire.begin(); initialiseInfineon(); nextFlash = millis(); // initialise all the digital outputs }
As you can see, the work to initialize the Infineon board and the radio have been abstracted into separate functions and now the setup() function is easy to read and understand without having to know what is happening elsewhere
the same thing goes for the main loop
void loop() { // Notice how the main loop is very simple and the functions // seperate the logic into easily manageable parts if (CheckSerial()) { DoCommand(inputBuffer, "\0"); } if (CheckNRF()) { DoCommand(NRFrdata, "\0"); SendNRFTest(); // echo back command } // Do other stuff switch (colourMode) { case cFLASH: infinionFLASH() ; break; case cRAINBOW: infinionRAINBOW() ;break; } }
for all this code does, there is not a lot in the main loop as it is all extracted into small manageable functions
the first to calls (Check Serial and Check NRF basically do the same thing but with very different hardware, one checks the serial port for a message and if found it puts the message into a buffer, returns it to here and then it is passed to the DoCommand() function to be processed
the CheckNRF function call does the exact same thing except it checks the NRF Radio for data
lastly if a colour mode command has been sent in, the loop will call a function associated with that command. That is all that is required int he main loop to process commands from multiple sources and manage modes etc. yet with all that, just like the setup() method, it is easy to follow and understand without having to know the details of all the functions it uses
that brings me to a tip... Please please name functions something meaningful and the same goes for variables, it makes life so much easier when you go back at a later date to change things or if you share the code
Now skipping past the code described in my tutorials we come to the first specific function to use the RGB shield
void infinionSetRGB(char* RGBColour) { //char printbuf[32]; long number = (long) strtol( RGBColour, NULL, 16); long r = number >> 16; long g = number >> 8 & 0xFF; long b = number & 0xFF; RGBLEDS.I2CWRITE6BYTES (ADDRESS, INTENSITY_RGB, r << 4, g << 4, b << 4); //sprintf(printbuf, "%s - Number: %ld - R: %d, G: %d, B: %d\n", RGBColour, number, r, g, b); //Serial.print(printbuf); }
As you can see again, short, simple and easy to follow, this function allows the colour to be set by passing in the RGB value in HEX
void infinionSetColour(Colours colour) { colourMode = cSOLID; RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0FFF); RGBLEDS.SETCOLOUR(colour ); }
this function on the other hand takes an enumeration value as input and translates this to the RGB value by calling the library function RGBLEDS.SETCOLOUR(colour), I know there is not much here but you have to agree it make the upper code far easier to understand by wrapping the details into a function
void infinionFLASH() { if (millis() >= nextFlash + flashTime) { if (isBright ) { RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0000); isBright = false; } else { RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0FFF); isBright = true; } nextFlash = millis(); } }
lastly the above function shows how the Infineon shield built in functionality can be used to to manipulate the LEDs without having to touch the basic colour settings. This function simply flashes the LEDs in what ever colour they happen to be in (Does not change them or care what it is currently set to) and simply varies the dimming level as a separate and independent value on the shield. The micro controller on the shield takes care of the rest, even adding nice graceful transitions from one intensity to the other if the board has been configured with a FADERATE property.
Thats pretty much it for the code walk through, I hope this helps you to get to grips with your Infineon card and remember, keep your code tidy if you can and modularize often, you will thank yourself later