Ghidini & Guerrini

The Color Machine (La macchina dei colori, in Italian language) is a tool to teach children about the use and the operation of RGB color coding, which is used in all digital devices (TVs, smartphones, computers, etc.). Using 3 knobs you can increase the percentages of red, green and blue separately, and the LED strip at the top of the machine lights up consistently with the color mix choosen. In this way approximately 16 million of colors can be generated.

The Color Machine has 4 different operating modes: "letís create colors", "guess the color", "the names of the colors" and "demo". Under the guidance of a teacher, children can play and learn at the same time to recreate colors with additive synthesis. This device is currently used in the educational workshops of Musil - Museum of Industry and Labour of Rodengo Saiano (Italy).





How it works

With additive synthesis, you can obtain a wide range of colors mixing the 3 primary colors: Red, Green and Blue (hence the acronym RGB). For instance, mixing red and green in equal parts you get the yellow, mixing red and blue you get the magenta, and so on. With all the 3 colors at maximum values you get the white, with all 3 at minimum you get the black.

The input interface of the Color Machine consists of 3 knobs, each of which controls one of each primary color. For example rotating clockwise the red knob, you increase the percentage of red: the LED strip begins to light up with red and the selected value for red appears in the RGB led display. The value for each color can vary from 0 to 255 (where 0 is the minimum, that is the complete lack of red, and 255 is the maximum, that is the red at its brightest level). Rotating the 3 knobs involves the variation of the value for each color: the 3 values are shown in the LCD display, and the LED strip lights of the color obtained by the mixing of those values.

in the first operating mode (Letís create colors!) the user is free to try to generate colors. In the second one (Guess the color!) the machine proposes a randomly generated color, and the user must operate on the 3 knobs to obtain the same color. In the third mode (Colors' names), the device shows in the display the name of famous colors and in the LED strip the corresponding colors. The last mode (Demo) is a demonstration of the deviceís ability to create colors.



ALL THE MATERIAL OF THIS PROJECT (SOFTWARE, PCBs DESIGN, ETC.) IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIAL OR THE USE OR OTHER DEALINGS IN THE MATERIAL.

Production

The device was built using an Arduino Mega 2560 as basic element. Each of the 3 knobs controls 1 incremental encoders, mounted on a LED ring breakout board (see Mayhew Labs rotary encoder LED ring). The output is made through a RGB backlight positive LCD display and a strip with 16 RGB LEDs (controlled through shift registers). Some custom-designed PCBs have been developed and printed to build the LED strip and to make wire connections easier. The electronics are housed in an aluminium box, suitably modified. A custom aluminium front panel was also designed and built.


The custom-designed PCB LED strip.

Parts List


1Hammond 1550NBK black aluminium box 250mm x 250mm x 101mm
1Custom-designed front panel, aluminium 2,5mm
4Rubber feet 19mm x 8mm
1Rocket switch
1Panel mount 2.1mm DC barrel jack
1USB cable 30cm (to program the Arduino)
1Wall adapter power supply 12V 1A
1Arduino Mega 2560 R3
3Incremental encoder 24 detents 24 pulses Bourns
3Clear plastic knob
3Rotary Encoder LED Ring Breakout Board
1RGB backlight positive LCD display 20x4
3Panel mount momentary push button switch
3Button Quick-Connect Wire
165mm RGB clear LEDs 10000 mcd
6Shift Registers 8-Bit - 74HC595
1Custom-designed PCB for Arduino Mega
1Custom-designed PCB for the LED strip
1Custom-designed PCB for the RGB backlight positive LCD display
3Custom-designed PCB for the rotary encoder LED ring breakout board
1Trimmer 300mW 100KOhm
SomeSteel hex skt csk head screw M3x20mm
SomeSteel nut M3
SomeM/screw Sltd C/s M2.5x12
SomeSteel nut M2.5
ManyBreak-away pin strip male header 2,54 mm
SomeElectrolytic capacitors
ManyResistors (various values)
Some4 / 3 / 2 pin jumper cables
SomeHeat shrink
The first prototype on breadboards.
The custom-designed PCB (shield for Arduino Mega).
The custom-designed PCB mounted on the Arduino Mega.
The custom-designed PCB for RGB backlight positive LCD display.
The backside of the front panel: at the bottom you can see the 3 rotary encoder led ring breakout boards with the custom-made PCBs mounted on them. At the top you can see the back of the LCD shield with the custom-designed PCB mounted on it. At left and right the back of the 2 panel mount momentary push button switchs.
PCB design for Arduino Mega.
PCB design for the LED strip.
PCB design for the RGB backlight positive LCD display.
PCB design for the rotary encoder LED ring breakout board.
Download
"Custom-designed PCB for Arduino Mega"
Fritzing source file
Download
"Custom-designed PCB for LED strip"
Fritzing source file
Download
"Custom-designed PCB for RGB LCD display"
Fritzing source file
Download
"Custom-designed PCB for rotary encoder
LED ring breakout board"
Fritzing source file

Software

The main software routine, which is still being finalized, has been developed in-house.
The LED strip control is performed with PWM through ShiftPWM library by Elco Jacobs.
Reading the rotary encoder is performed with Oleg's "Reading rotary encoder on Arduino".

We are not software developers, so do not assume that the following code is correct, clean and/or (well) commented.
/*

****************************** THE COLOR MACHINE ******************************

  http://www.ghidiniguerrini.it/projects/color_machine

        Copyright (c) 2013 Ghidini-Guerrini
        
The Color Machine by Ghidini-Guerrini is licensed under a 
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
Based on a work at http://www.ghidiniguerrini.it/projects/color_machine      

*******************************************************************************
      
      
THIRD PARTY CREDITS:

Reading the rotary encoder is performed with Oleg's example code:
http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
    
Using PWM with LED strip is performed with Elco Jacobs' ShiftPWM Library
http://www.elcojacobs.com/shiftpwm/

*/
  

// LCD
#include 
LiquidCrystal lcd(13, 7, 8, 5, 4, 2);
const int RED_LED_PIN = 6; 
const int GREEN_LED_PIN = 9; 
const int BLUE_LED_PIN = 3;
unsigned long int freqLCD = 500;
unsigned long int timeLCD = 0;
unsigned long int time = 0;

// LED STRIPE
const int ShiftPWM_latchPin=10;
#define SHIFTPWM_NOSPI
const int ShiftPWM_dataPin = 11;
const int ShiftPWM_clockPin = 12;
const bool ShiftPWM_invertOutputs = false; 
const bool ShiftPWM_balanceLoad = false;
#include    // include ShiftPWM.h after setting the pins!
unsigned char maxBrightness = 220;
unsigned char pwmFrequency = 75;
int numRegisters = 6;
int numRGBleds = numRegisters*8/3;

//These are the pins that will talk to the shift register through SPI
#define SDI    A0    //Data
#define CLK    A1    //Clock
#define LE     A2    //Latch

//These are the rotary encoder pins A, B, and switch
#define ENC_A_RED   22 // 8 -> 2
#define ENC_B_RED   23 // 9 -> 3
#define ENC_SW_RED  30 
#define ENC_A_GREEN 24 //   10 -> 4
#define ENC_B_GREEN 25 //    11 -> 5
#define ENC_SW_GREEN  31 
#define ENC_A_BLUE  26 //   12 -> 6
#define ENC_B_BLUE  27 //  13  -> 7
#define ENC_SW_BLUE  32 
#define ENC_PORT PINA //PINB -> PIND //The port that the rotary encoder is on (see http://www.arduino.cc/en/Reference/PortManipulation)
int PASSO_RED = 5;
int PASSO_GREEN = 5;
int PASSO_BLUE = 5;
int PASSO_RED_TRIVIA = 5;
int PASSO_GREEN_TRIVIA = 5;
int PASSO_BLUE_TRIVIA = 5;
unsigned long int ledInterval = 0;
int valueEncRed = 0;
int valueEncGreen = 0;
int valueEncBlue = 0;
int cont = 0;

// Global variables
int scaledCounterRed = 0;  
int counterOldRed = 0;
int counterFinalRed = 0;
int passaggioRed = 0;
int scaledCounterGreen = 0; 
int counterOldGreen = 0;
int counterFinalGreen = 0;
int scaledCounterBlue = 0;  
int counterOldBlue = 0;
int counterFinalBlue = 0;

// Buttons
const int BUTTON_RESET = A3; // ANOTHER WAY TO CALL PIN A1
const int BUTTON_MODE = A4; // ANOTHER WAY TO CALL PIN A2
const int BUTTON_SCROLL = A5; // ANOTHER WAY TO CALL PIN A2
int buttonResetState = 0;
int buttonModeState = 0; // variable for reading the pushbutton status
int buttonScrollState = 0;

int modalita = 0;
char* modalitaArray[]={"COLORS","COLORTRIVIA","COLORNAMES","DEMO"};
int numModalita = 4;
boolean colors = true;
boolean colorTrivia = true;
boolean colorNames = true;
int coloreScelto = 0;
int coloreSceltoOld = -1;
const int numColori = 23;

char* coloriArray[numColori][7]={
                          {"Acquamarina","127","255","212","50","100","14"},
                          {"Amaranto","229","43","80","190","6","4"},
                          {"Arancione","255","165","0","170","30","0"},
                          {"Azzurro","0","127","255","0","50","100"},
                          {"Blu","0","0","255","0","0","240"},
                          {"Bordeaux","128","0","0","40","0","0"},
                          {"Ciano","0","255","255","0","100","90"},
                          {"Ciliegia","222","49","99","255","11","6"},
                          {"Fucsia","244","175","238","140","0","16"},
                          {"Giada","0","168","107","0","134","8"},
                          {"Giallo","255","255","0","158","130","0"},
                          {"Lavanda","230","230","250","45","30","35"},
                          {"Lime","204","255","0","70","150","0"},
                          {"Magenta","255","0","255","230","0","200"},
                          {"Mandarino","255","204","0","176","74","0"},
                          {"Pervinca","204","204","255","70","54","140"},
                          {"Pesca","255","229","180","172","64","8"},  
                          {"Rosa","255","192","203","200","55","45"},
                          {"Rosso","255","0","0","225","0","0"},
                          {"Salmone","255","140","105","214","54","6"},
                          {"Turchese","48","213","200","38","100","24"}, 
                          {"Verde","0","255","0","0","200","0"}, 
                          {"Viola","143","0","255","70","0","154"}   
                        };


byte aaccentata[8] = {B01000, B00100, B01110, B00001, B01111, B10001, B01111, B00000};
 
const int BUTTON_DELAY = 500  ; 
unsigned long int BUTTON_RESET_TIME = 0; 
unsigned long int BUTTON_MODE_TIME = 0; 
unsigned long int BUTTON_SCROLL_TIME = 0; 

boolean SerialMonitor = false;

unsigned int sequence[16] = {0x8000,0x8001,0x8003,0x8007,0x800f,0x801f,0x803f,0x807f,0x80ff,0x81ff,0x83ff,0x87ff,0x8fff,0x9fff,0xbfff,0xffff};

void resetRings() {
   digitalWrite(LE,LOW);
   shiftOut(SDI,CLK,MSBFIRST,(0x8000 >> 8));    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x8000);           //Low byte second - I PRIMI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,(0x8000 >> 8));    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,(0x8000 >> 0));    //Low byte second - I PRIMI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,(0x8000 >> 8));    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);            //Low byte second - I PRIMI 8 LED
   digitalWrite(LE,HIGH);
}

void resetToZeroRings() {
   digitalWrite(LE,LOW);
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //Low byte second - I PRIMI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //Low byte second - I PRIMI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //High byte first -I SECONDI 8 LED
   shiftOut(SDI,CLK,MSBFIRST,0x000);    //Low byte second - I PRIMI 8 LED
   digitalWrite(LE,HIGH);
}

// STARTUP SCREEN
void schermateStart() {
  
  analogWrite(RED_LED_PIN, 0);
  analogWrite(GREEN_LED_PIN, 0);
  analogWrite(BLUE_LED_PIN, 0);
     
  lcd.setCursor(0, 0);
  lcd.print("MUSIL RODENGO SAIANO"); 
 
  lcd.setCursor(0, 1);
  lcd.print("L A  M A C C H I N A");
  lcd.setCursor(1, 2);
  lcd.print("D E I  C O L O R I");
  
  
  lcd.setCursor(7, 3);
  lcd.print("Vers. 1");
  delay(5000);
  
  lcd.clear();

}


void setup()
{
  
  time=millis();
  timeLCD=millis();
  
  resetToZeroRings();
  
  lcd.begin(20, 4);
  schermateStart();
  lcd.createChar(0, aaccentata);
   
  //Set SPI pins to output
  pinMode(SDI, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(LE,OUTPUT);
  
  pinMode(ENC_SW_RED, INPUT);
  digitalWrite(ENC_SW_RED, HIGH);
  pinMode(ENC_SW_GREEN, INPUT);
  digitalWrite(ENC_SW_GREEN, HIGH);
  pinMode(ENC_SW_BLUE, INPUT);
  digitalWrite(ENC_SW_BLUE, HIGH);
  
  //Set encoder pins to input, turn internal pull-ups on
  pinMode(ENC_A_RED, INPUT);
  digitalWrite(ENC_A_RED, HIGH);
  pinMode(ENC_B_RED, INPUT);
  digitalWrite(ENC_B_RED, HIGH);
  pinMode(ENC_A_GREEN, INPUT);
  digitalWrite(ENC_A_GREEN, HIGH);
  pinMode(ENC_B_GREEN, INPUT);
  digitalWrite(ENC_B_GREEN, HIGH);
  pinMode(ENC_A_BLUE, INPUT);
  digitalWrite(ENC_A_BLUE, HIGH);
  pinMode(ENC_B_BLUE, INPUT);
  digitalWrite(ENC_B_BLUE, HIGH);
  
  //Set serial rate, prompt for desired sequence
  if (SerialMonitor) Serial.begin(9600);
  
  // BUTTONS
  pinMode(BUTTON_RESET, INPUT);
  pinMode(BUTTON_MODE, INPUT);
  pinMode(BUTTON_SCROLL, INPUT);
  
  resetRings();
  
  // LED STRIPE 
  ShiftPWM.SetAmountOfRegisters(numRegisters);
  ShiftPWM.SetPinGrouping(1); 
  ShiftPWM.Start(pwmFrequency,maxBrightness);
  ShiftPWM.SetAll(0);  
  
  randomSeed(analogRead(5));
}




void loop()
{ 
  
  time = millis();
  
  buttonModeState = digitalRead(BUTTON_MODE);
  if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
        modalita++;
        if (modalita == numModalita) modalita = 0;
       
        BUTTON_MODE_TIME = millis();    
        
        coloreScelto = 0;
        coloreSceltoOld=numColori-1;
        ShiftPWM.SetAll(0);
        analogWrite(RED_LED_PIN, 255);
        analogWrite(GREEN_LED_PIN, 255);
        analogWrite(BLUE_LED_PIN, 255);
        resetToZeroRings();
        colors = true;
        colorTrivia = true;
        colorNames = true;
        lcd.clear();
  }  


  
  // START "COLORS"
  
  if (modalitaArray[modalita] == "COLORS") { 
    //Local Variables
    static uint16_t counterRed = 0;      //this variable will be changed by encoder input
    int16_t tmpdataRed;
   
    static uint16_t counterGreen = 0;    //this variable will be changed by encoder input
    int16_t tmpdataGreen;
   
    static uint16_t counterBlue = 0;     //this variable will be changed by encoder input
    int16_t tmpdataBlue;  
    
    boolean variazioneEncSwitch = false;
    
    if (colors) {
    
         colors = false;
         resetRings();
         lcd.clear();        
         lcd.setCursor(3, 0);
         lcd.print("CREA I COLORI!");
         analogWrite(RED_LED_PIN, 225);
         analogWrite(GREEN_LED_PIN, 225);
         analogWrite(BLUE_LED_PIN, 225);
         int16_t tmpdataRed = 0;
         int16_t tmpdataGreen = 0;
         int16_t tmpdataBlue = 0;
         counterOldRed = 0;
         counterOldGreen = 0;
         counterOldBlue = 0; 
         counterFinalRed = 0;
         counterFinalGreen = 0;    
         counterFinalBlue = 0;
         counterRed = 0;
         counterGreen = 0;    
         counterBlue = 0;
        
    }
    
    tmpdataRed = read_encoder_RED();
    tmpdataGreen = read_encoder_GREEN();
    tmpdataBlue = read_encoder_BLUE();
    
    counterOldRed = counterFinalRed;
    counterOldGreen = counterGreen;
    counterOldBlue = counterBlue;
    
    // ROTARY ENCODER'S BUTTON
    int buttonEncRed = digitalRead(ENC_SW_RED);                                     // Read button state
    if ((buttonEncRed == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {      // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncRed == 0) { 
         counterFinalRed = 255;
         counterRed = 210;
         valueEncRed = 1; 
       } else { 
         counterFinalRed = 0;
         counterRed = 0;
         valueEncRed = 0;
       }
       variazioneEncSwitch = true;
    }
    
    int buttonEncGreen = digitalRead(ENC_SW_GREEN);                                 // Read button state
    if ((buttonEncGreen == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {    // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncGreen == 0) { 
         counterFinalGreen = 255;
         counterGreen = 210;
         valueEncGreen = 1; 
       } else { 
         counterFinalGreen = 0;
         counterGreen = 0;
         valueEncGreen = 0;
       }
       variazioneEncSwitch = true;
    }
    
    int buttonEncBlue = digitalRead(ENC_SW_BLUE);                                   // Read button state
    if ((buttonEncBlue == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {     // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncBlue == 0) { 
         counterFinalBlue = 255;
         counterBlue = 210;
         valueEncBlue = 1; 
       } else { 
         counterFinalBlue = 0;
         counterBlue = 0;
         valueEncBlue = 0;
       }
       variazioneEncSwitch = true;
    }
    
   buttonResetState = digitalRead(BUTTON_RESET);
   if ((buttonResetState == HIGH) &&  (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
       BUTTON_SCROLL_TIME = millis(); 
       tmpdataRed = 0;
       tmpdataGreen = 0;
       tmpdataBlue = 0;
       counterRed = 0;
       counterGreen = 0;
       counterBlue = 0;
       counterFinalRed = 0;
       counterFinalGreen = 0;
       counterFinalBlue = 0;
       scaledCounterRed = 0;
       scaledCounterGreen = 0;
       scaledCounterBlue = 0;
       variazioneEncSwitch = true;
   }  
    
   //if the encoder has moved
   if(tmpdataRed) {
       counterRed += tmpdataRed;  
       if (counterRed > 60000) counterRed = 0; 
       if ((counterRed >= 210) & (PASSO_RED == 5)) counterRed = 210; 
       if ((counterRed > 1020) & (PASSO_RED == 1)) counterRed = 1020; 
       counterFinalRed = map(counterRed,0,1020,0,255) * PASSO_RED;
       if ((counterFinalRed > 255) & (counterFinalRed < 800)) counterFinalRed = 255;
       if (counterFinalRed > 800) counterFinalRed = 0;
   }
   
   //if the encoder has moved
   if(tmpdataGreen) {
       counterGreen += tmpdataGreen;  
       if (counterGreen > 60000) counterGreen = 0; 
       if ((counterGreen >= 210) & (PASSO_GREEN == 5)) counterGreen = 210; 
       if ((counterGreen > 1020) & (PASSO_GREEN == 1)) counterGreen = 1020; 
       counterFinalGreen = map(counterGreen,0,1020,0,255) * PASSO_GREEN;
       if ((counterFinalGreen > 255) & (counterFinalGreen < 800)) counterFinalGreen = 255;
       if (counterFinalGreen > 800) counterFinalGreen = 0;
   }
   
   //if the encoder has moved
   if(tmpdataBlue) {
       counterBlue += tmpdataBlue;  
       if (counterBlue > 60000) counterBlue = 0; 
       if ((counterBlue >= 210) & (PASSO_BLUE == 5)) counterBlue = 210; 
       if ((counterBlue > 1020) & (PASSO_BLUE == 1)) counterBlue = 1020; 
       counterFinalBlue = map(counterBlue,0,1020,0,255) * PASSO_BLUE;
       if ((counterFinalBlue > 255) & (counterFinalBlue < 800)) counterFinalBlue = 255;
       if (counterFinalBlue > 800) counterFinalBlue = 0; 
   }
   
   if ((tmpdataRed) | (tmpdataGreen) | (tmpdataBlue) | variazioneEncSwitch) {
       //Send the LED output to the shift register 
       variazioneEncSwitch = false;
       scaledCounterRed = map(counterFinalRed,0,255,0,15);
       scaledCounterGreen = map(counterFinalGreen,0,255,0,15);
       scaledCounterBlue = map(counterFinalBlue,0,255,0,15);
       digitalWrite(LE,LOW);
       shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterBlue] >> 8));    //High byte first
       shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterBlue]);           //Low byte second
       shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterGreen] >> 8));    //High byte first
       shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterGreen]);           //Low byte second
       shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterRed] >> 8));    //High byte first
       shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterRed]);           //Low byte second
       digitalWrite(LE,HIGH);
       
       // LED STRIPE  
       for(int led=0; led timeLCD + freqLCD) {
       timeLCD = millis();
       lcd.setCursor(0, 2);
       lcd.print("Rosso   Verde    Blu");
       lcd.setCursor(0, 3);
       lcd.print(" ");
       if ((counterFinalRed<100) & (counterFinalRed>=10)) lcd.print(" ");
       if (counterFinalRed<10) lcd.print("  ");
       lcd.print(counterFinalRed);
       lcd.print("     ");
       if ((counterFinalGreen<100) & (counterFinalGreen>=10)) lcd.print(" ");
       if (counterFinalGreen<10) lcd.print("  ");
       lcd.print(counterFinalGreen);
       lcd.print("     ");
       if ((counterFinalBlue<100) & (counterFinalBlue>=10)) lcd.print(" ");
       if (counterFinalBlue<10) lcd.print("  ");
       lcd.print(counterFinalBlue);  
   }   
 
  }
  // COLORS END
    
  
  
  // "COLORTRIVIA" START
  if (modalitaArray[modalita] == "COLORTRIVIA") { 
   
    static uint16_t counterRed = 0;      //this variable will be changed by encoder input
    int16_t tmpdataRed;
    static uint16_t counterGreen = 0;      //this variable will be changed by encoder input
    int16_t tmpdataGreen;
    static uint16_t counterBlue = 0;      //this variable will be changed by encoder input
    int16_t tmpdataBlue;  
  
    static int randRedDef;
    static int randGreenDef;
    static int randBlueDef;
    static int randRed;
    static int randGreen;
    static int randBlue;
    
    if (colorTrivia) {
    
       colorTrivia = false;
       resetRings();
       lcd.clear(); 
       lcd.setCursor(1, 0);
       lcd.print("INDOVINA IL COLORE!");
       int sommacolori = 1000;
       byte rgb[3] = { 1, 1, 1};
       int randHue = 0;
       while ((rgb[0]%5 != 0) | (rgb[1]%5 != 0) | (rgb[2]%5 != 0)) {
         randHue = random(0,360);
         double HSVridotto = map2(randHue,0,359,0,1);
         hsvToRgb(HSVridotto,1,1,rgb);
       }
       randRedDef = rgb[0];
       randGreenDef = rgb[1];
       randBlueDef = rgb[2];
       int16_t tmpdataRed = 0;
       int16_t tmpdataGreen = 0;
       int16_t tmpdataBlue = 0;
       counterOldRed = 0;
       counterOldGreen = 0;
       counterOldBlue = 0; 
       counterFinalRed = 0;
       counterFinalGreen = 0;    
       counterFinalBlue = 0;
       counterRed = 0;
       counterGreen = 0;    
       counterBlue = 0;
       for(int led=0; led BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
        BUTTON_SCROLL_TIME = millis();  
        ShiftPWM.SetAll(0);
        resetRings();
        colorTrivia = true;
        counterFinalRed = 0;
        counterFinalGreen = 0;    
        counterFinalBlue = 0;
     } 
 
    //Call read_encoder() function    
    tmpdataRed = read_encoder_RED();
    tmpdataGreen = read_encoder_GREEN();
    tmpdataBlue = read_encoder_BLUE();
    counterOldRed = counterFinalRed;
    counterOldGreen = counterGreen;
    counterOldBlue = counterBlue; 
    boolean variazioneEncSwitch = false;
  
    int buttonEncRed = digitalRead(ENC_SW_RED);                                    // Read button state
    if ((buttonEncRed == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {     // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncRed == 0) { 
         counterFinalRed = 255;
         counterRed = 210;
         valueEncRed = 1; 
       } else { 
         counterFinalRed = 0;
         counterRed = 0;
         valueEncRed = 0;
       }
       variazioneEncSwitch = true;
     }
    
    int buttonEncGreen = digitalRead(ENC_SW_GREEN);                                  // Read button state
    if ((buttonEncGreen == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {     // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncGreen == 0) { 
         counterFinalGreen = 255;
         counterGreen = 210;
         valueEncGreen = 1; 
       } else { 
         counterFinalGreen = 0;
         counterGreen = 0;
         valueEncGreen = 0;
       }
       variazioneEncSwitch = true;
    }
    
    int buttonEncBlue = digitalRead(ENC_SW_BLUE);                                   // Read button state
    if ((buttonEncBlue == LOW) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {     // Check if the button has changed and debounce button input
       BUTTON_SCROLL_TIME = millis(); 
       if (valueEncBlue == 0) { 
         counterFinalBlue = 255;
         counterBlue = 210;
         valueEncBlue = 1; 
       } else { 
         counterFinalBlue = 0;
         counterBlue = 0;
         valueEncBlue = 0;
       }
       variazioneEncSwitch = true;
    }
    
   buttonResetState = digitalRead(BUTTON_RESET);
   if ((buttonResetState == HIGH) &&  (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
      BUTTON_SCROLL_TIME = millis(); 
      tmpdataRed = 0;
      tmpdataGreen = 0;
      tmpdataBlue = 0;
      counterRed = 0;
      counterGreen = 0;
      counterBlue = 0;
      counterFinalRed = 0;
      counterFinalGreen = 0;
      counterFinalBlue = 0;
      scaledCounterRed = 0;
      scaledCounterGreen = 0;
      scaledCounterBlue = 0;
      variazioneEncSwitch = true;
   }   


  
   //if the encoder has moved
   if(tmpdataRed) {
      counterRed += tmpdataRed;  
      if (counterRed > 60000) counterRed = 0; 
      if ((counterRed >= 210) & (PASSO_RED_TRIVIA == 5)) counterRed = 210; 
      if ((counterRed > 1020) & (PASSO_RED_TRIVIA == 1)) counterRed = 1020; 
      counterFinalRed = map(counterRed,0,1020,0,255) * PASSO_RED_TRIVIA;
      if ((counterFinalRed > 255) & (counterFinalRed < 800)) counterFinalRed = 255;
      if (counterFinalRed > 800) counterFinalRed = 0;
   }
   
   //if the encoder has moved
   if(tmpdataGreen) {
      counterGreen += tmpdataGreen;  
      if (counterGreen > 60000) counterGreen = 0; 
      if ((counterGreen >= 210) & (PASSO_GREEN_TRIVIA == 5)) counterGreen = 210; 
      if ((counterGreen > 1020) & (PASSO_GREEN_TRIVIA == 1)) counterGreen = 1020; 
      counterFinalGreen = map(counterGreen,0,1020,0,255) * PASSO_GREEN_TRIVIA;
      if ((counterFinalGreen > 255) & (counterFinalGreen < 800)) counterFinalGreen = 255;
      if (counterFinalGreen > 800) counterFinalGreen = 0;
   }
   
   //if the encoder has moved
   if(tmpdataBlue) {
      counterBlue += tmpdataBlue;  
      if (counterBlue > 60000) counterBlue = 0; 
      if ((counterBlue >= 210) & (PASSO_BLUE_TRIVIA == 5)) counterBlue = 210; 
      if ((counterBlue > 1020) & (PASSO_BLUE_TRIVIA == 1)) counterBlue = 1020; 
      counterFinalBlue = map(counterBlue,0,1020,0,255) * PASSO_BLUE_TRIVIA;
      if ((counterFinalBlue > 255) & (counterFinalBlue < 800)) counterFinalBlue = 255;
      if (counterFinalBlue > 800) counterFinalBlue = 0;
   }
   
   if ((tmpdataRed) | (tmpdataGreen) | (tmpdataBlue) | (variazioneEncSwitch)) {
   
      //Send the LED output to the shift register 
      variazioneEncSwitch = false;
      scaledCounterRed = map(counterFinalRed,0,255,0,15);
      scaledCounterGreen = map(counterFinalGreen,0,255,0,15);
      scaledCounterBlue = map(counterFinalBlue,0,255,0,15);
      digitalWrite(LE,LOW);
      shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterBlue] >> 8));    //High byte first
      shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterBlue]);           //Low byte second
      shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterGreen] >> 8));   //High byte first
      shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterGreen]);          //Low byte second
      shiftOut(SDI,CLK,MSBFIRST,(sequence[scaledCounterRed] >> 8));     //High byte first
      shiftOut(SDI,CLK,MSBFIRST,sequence[scaledCounterRed]);            //Low byte second
      digitalWrite(LE,HIGH);
   
      // LED STRIPE  
      for(int led=numRGBleds/2; led timeLCD + freqLCD) {
      timeLCD = millis();
      lcd.setCursor(0, 2);
      lcd.print("Rosso   Verde    Blu");
      int distanza = abs(randRedDef-counterFinalRed)+abs(randGreenDef-counterFinalGreen)+abs(randBlueDef-counterFinalBlue);
      int distanzaGreen = 0;
    
      // NEAR TO SOLUTION
      if (distanza <= 150) {
         distanzaGreen = map(distanza,150,0,255,0);
         analogWrite(GREEN_LED_PIN, distanzaGreen);
      } else  {
         analogWrite(GREEN_LED_PIN, 255);
      }
      analogWrite(RED_LED_PIN, map(distanza,510,0,0,255));

      //YOU WIN!
      if (distanza == 0) {
         analogWrite(RED_LED_PIN, random(50,255));
         analogWrite(GREEN_LED_PIN, random(50,255));
         analogWrite(BLUE_LED_PIN, random(50,255));
         lcd.setCursor(0,0);
         lcd.print("                    ");
         lcd.setCursor(3,0);
         lcd.print("HAI INDOVINATO!");  
         lcd.setCursor(0, 2);
         lcd.print("Rosso   Verde    Blu");
      } 
          
      lcd.setCursor(0, 3);
      lcd.print(" ");
      if ((counterFinalRed<100) & (counterFinalRed>=10)) lcd.print(" ");
      if (counterFinalRed<10) lcd.print("  ");
      lcd.print(counterFinalRed);
      lcd.print("     ");
      if ((counterFinalGreen<100) & (counterFinalGreen>=10)) lcd.print(" ");
      if (counterFinalGreen<10) lcd.print("  ");
      lcd.print(counterFinalGreen);
      lcd.print("     ");
      if ((counterFinalBlue<100) & (counterFinalBlue>=10)) lcd.print(" ");
      if (counterFinalBlue<10) lcd.print("  ");
      lcd.print(counterFinalBlue);  
   }

  } 
  // COLORTRIVIA END
    
    
    
    
    
  
  // "COLORNAMES" START
  if (modalitaArray[modalita] == "COLORNAMES") { 
   
   if (colorNames) {
      colorNames = false;
      resetToZeroRings();
      lcd.clear(); 
      lcd.setCursor(0, 0);
      lcd.print("I  NOMI  DEI  COLORI");
   } 
 
   buttonResetState = digitalRead(BUTTON_RESET);
   if ((buttonResetState == HIGH) &&  (time > BUTTON_RESET_TIME + BUTTON_DELAY)) {
      BUTTON_RESET_TIME = millis();
      if (coloreScelto == numColori-1) coloreScelto=-1;
      coloreScelto++;  
      lcd.setCursor(0,2);
      lcd.print("<                  >");
   }
 
   buttonScrollState = digitalRead(BUTTON_SCROLL);
   if ((buttonScrollState == HIGH) &&  (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
      BUTTON_SCROLL_TIME = millis();
      coloreScelto--;  
      if (coloreScelto == -1) coloreScelto=numColori-1;
         lcd.setCursor(0,2);
         lcd.print("<                  >");
      } 
        
      if (coloreScelto != coloreSceltoOld)  { 
         String testo = coloriArray[coloreScelto][0];
         int lunghezza = (20-testo.length())/2+1;
         lcd.setCursor(0, 2);
         lcd.print("<                  >");
         lcd.setCursor(lunghezza, 2);
         lcd.print(coloriArray[coloreScelto][0]); 
                   
         int risultatoRedMap = atoi(coloriArray[coloreScelto][4]);
         int risultatoGreenMap = atoi(coloriArray[coloreScelto][5]);
         int risultatoBlueMap = atoi(coloriArray[coloreScelto][6]);
         for(int led=0; led> 2);  //add current state
   return ( enc_states[( old_AB_GREEN & 0x0f )]);
}

int8_t read_encoder_BLUE() {
   int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
   static uint16_t old_AB_BLUE = 0;
   old_AB_BLUE <<= 2;                           //remember previous state
   old_AB_BLUE |= (( ENC_PORT & 0x30 ) >> 4);   //add current state
   return ( enc_states[( old_AB_BLUE & 0x0f )]);
}



// ********************** DEMO FUNCTIONS **********************

boolean rgbLedRainbow(int numRGBLeds, int delayVal, int numCycles, int rainbowWidth){
  
   if (modalitaArray[modalita] == "DEMO") {
      ShiftPWM.SetAll(0);
      resetToZeroRings();
      lcd.clear();
      lcd.clear();
      lcd.setCursor(1, 0);
      lcd.print("LA MACCHINA      ");
      lcd.setCursor(1, 1);
      lcd.print("        DEI COLORI      ");
      lcd.setCursor(1, 2);
      lcd.print("    D  E  M  O       ");
      lcd.setCursor(3, 3);
      lcd.print("  Arcobaleno ");
  
      int i = 0;
      int aus = 0;
      int colore = 0;
      for(int cycle=0;cycle BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
                  BUTTON_SCROLL_TIME = millis();  
                  ShiftPWM.SetAll(0);
                  resetRings();
                  return true;
               } 
              
               buttonModeState = digitalRead(BUTTON_MODE);  
               if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
                  BUTTON_MODE_TIME = millis();  
                  ShiftPWM.SetAll(0);
                  resetRings();
                  modalita = 0;
                  resetRings();  
                  return true;
                }     
                
          
            }
       
            byte rgb[3];
            double HSVridotto = map2(colore+135,0,359,0,1);
            hsvToRgb(HSVridotto,1,1,rgb);
            analogWrite(RED_LED_PIN, 255-rgb[0]);
            analogWrite(GREEN_LED_PIN, 255-rgb[1]);
            analogWrite(BLUE_LED_PIN, 255-rgb[2]);
            colore++;
            if (colore > 359) colore = 0;
               i++;
               if (i%6 == 0) {
                  digitalWrite(LE,LOW);
                  shiftOut(SDI,CLK,MSBFIRST,(sequence[aus] >> 8));    //High byte first
                  shiftOut(SDI,CLK,MSBFIRST,sequence[aus]);           //Low byte second
                  shiftOut(SDI,CLK,MSBFIRST,(sequence[aus] >> 8));    //High byte first
                  shiftOut(SDI,CLK,MSBFIRST,sequence[aus]);           //Low byte second
                  shiftOut(SDI,CLK,MSBFIRST,(sequence[aus] >> 8));    //High byte first
                  shiftOut(SDI,CLK,MSBFIRST,sequence[aus]);           //Low byte second
                  digitalWrite(LE,HIGH);
                  aus++; 
                  if (aus >= 16) aus = 0;
               }
              delay(5); // this delay value determines the speed of hue shift
            } 
    
        } 

    }
  }




boolean rgbLedPolice(int numRGBLeds, int numCicli, int durata){
 
   if (modalitaArray[modalita] == "DEMO") {
   resetToZeroRings();
   lcd.clear();
   lcd.clear();
   lcd.setCursor(1, 0);
   lcd.print("LA MACCHINA      ");
   lcd.setCursor(1, 1);
   lcd.print("        DEI COLORI      ");
   lcd.setCursor(1, 2);
   lcd.print("    D  E  M  O       ");
   lcd.setCursor(3, 3);
   lcd.print("    Allarme");
  
   for (int x=0;x BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
           BUTTON_SCROLL_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           return true;
        } 
        
        buttonModeState = digitalRead(BUTTON_MODE);  
        if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
           BUTTON_MODE_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           modalita = 0;
           resetRings();  
           lcd.setCursor(3, 3);
           lcd.print("                    ");
           return true;
        }      
    
        for(int led=0;led> 8));    //High byte first
        shiftOut(SDI,CLK,MSBFIRST,sequence[15]);           //Low byte second
        digitalWrite(LE,HIGH);  
        analogWrite(RED_LED_PIN, 0);
        analogWrite(GREEN_LED_PIN, 255);
        analogWrite(BLUE_LED_PIN, 255);
        delay(durata);
   
        buttonScrollState = digitalRead(BUTTON_SCROLL);  
        if ((buttonScrollState == HIGH) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
           BUTTON_SCROLL_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           return true;
        } 
        
        buttonModeState = digitalRead(BUTTON_MODE);  
        if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
           BUTTON_MODE_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           modalita = 0;
           resetRings();  
           lcd.setCursor(3, 3);
           lcd.print("                    ");
           return true;
        }      
            
     }
 
     for (int x=0;x<5;x++) {
        time = millis();
        ShiftPWM.SetAll(0);
        digitalWrite(LE,LOW);
        shiftOut(SDI,CLK,MSBFIRST,0x000);    
        shiftOut(SDI,CLK,MSBFIRST,0x000);
        shiftOut(SDI,CLK,MSBFIRST,0x000); 
        shiftOut(SDI,CLK,MSBFIRST,0x000);  
        shiftOut(SDI,CLK,MSBFIRST,0x000);   
        shiftOut(SDI,CLK,MSBFIRST,0x000);  
        digitalWrite(LE,HIGH);
     
        analogWrite(BLUE_LED_PIN, 255);
        analogWrite(GREEN_LED_PIN, 255);
        analogWrite(RED_LED_PIN, 255);
        delay(durata);
        
        buttonScrollState = digitalRead(BUTTON_SCROLL);  
        if ((buttonScrollState == HIGH) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
           BUTTON_SCROLL_TIME = millis();  
           ShiftPWM.SetAll(0);
            resetRings();
           return true;
        } 
        
        buttonModeState = digitalRead(BUTTON_MODE);  
        if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
           BUTTON_MODE_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           modalita = 0;
           resetRings();  
           return true;
        }      
     
        for(int led=numRGBLeds/2;led> 8));    //High byte first
        shiftOut(SDI,CLK,MSBFIRST,sequence[15]);           //Low byte second
        shiftOut(SDI,CLK,MSBFIRST,0x000); 
        shiftOut(SDI,CLK,MSBFIRST,0x000);  
        shiftOut(SDI,CLK,MSBFIRST,0x000);   
        shiftOut(SDI,CLK,MSBFIRST,0x000);  
        digitalWrite(LE,HIGH); 
   
        analogWrite(BLUE_LED_PIN, 0);
        analogWrite(GREEN_LED_PIN, 255);
        analogWrite(RED_LED_PIN, 255); 
        delay(durata);
   
        buttonScrollState = digitalRead(BUTTON_SCROLL);  
        if ((buttonScrollState == HIGH) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
           BUTTON_SCROLL_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           return true;
        } 
        
        buttonModeState = digitalRead(BUTTON_MODE);  
        if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
           BUTTON_MODE_TIME = millis();  
           ShiftPWM.SetAll(0);
           resetRings();
           modalita = 0;
           resetRings();  
           return true;
        }     
     }
   } 
   return false;
  }
}



void hsvToRgb(double h, double s, double v, byte rgb[3]) {
   double r, g, b;
   int i = int(h * 6);
   double f = h * 6 - i;
   double p = v * (1 - s);
   double q = v * (1 - f * s);
   double t = v * (1 - (1 - f) * s);

   switch(i % 6){
      case 0: r = v, g = t, b = p; break;
      case 1: r = q, g = v, b = p; break;
      case 2: r = p, g = v, b = t; break;
      case 3: r = p, g = q, b = v; break;
      case 4: r = t, g = p, b = v; break;
      case 5: r = v, g = p, b = q; break;
   }

   rgb[0] = r * 255;
   rgb[1] = g * 255;
   rgb[2] = b * 255;
}


double map2(double value, float x_min, float x_max, float y_min, float y_max) {                                
    return (y_min + (((y_max - y_min)/(x_max - x_min)) * (value - x_min))); 
} 


boolean rgbLedColors(int numRGBLeds, int numCicli, int durata){

   if (modalitaArray[modalita] == "DEMO"){
      int valoreRed = 0;
      int valoreGreen = 0;
      int valoreBlue = 0;
      ShiftPWM.SetAll(0);
      resetToZeroRings();
      lcd.clear();
      lcd.setCursor(1, 0);
      lcd.print("LA MACCHINA      ");
      lcd.setCursor(1, 1);
      lcd.print("        DEI COLORI      ");
      lcd.setCursor(1, 2);
      lcd.print("    D  E  M  O       ");
      lcd.setCursor(3, 3);
      lcd.print("   Tonalit");
      lcd.write(byte(0)); 
      for (int x=0;x BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
               BUTTON_SCROLL_TIME = millis();  
               ShiftPWM.SetAll(0);
               resetRings();
               lcd.setCursor(3, 3);
               lcd.print("                      ");
               return true;
            } 
            
            buttonModeState = digitalRead(BUTTON_MODE);  
            if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
               BUTTON_MODE_TIME = millis();  
               ShiftPWM.SetAll(0);
               resetRings();
               modalita = 0;
               lcd.setCursor(3, 3);
               lcd.print("                      ");
               resetRings();  
               return true;
            }      
            
         delay(durata);
      } 
   
    }
    return false;
  }
}



boolean rgbLedKnightRider(int numRGBLeds, int numCicli, int durataacceso, int steps){

   if (modalitaArray[modalita] == "DEMO") {
   ShiftPWM.SetAll(0);
   resetToZeroRings();
   lcd.clear();
   lcd.setCursor(1, 0);
   lcd.print("LA MACCHINA      ");
   lcd.setCursor(1, 1);
   lcd.print("        DEI COLORI      ");
   lcd.setCursor(1, 2);
   lcd.print("    D  E  M  O       ");
   lcd.setCursor(3, 3);
   lcd.print(" Knight Rider");
   
   for (int x=0;x BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
               BUTTON_SCROLL_TIME = millis();  
               ShiftPWM.SetAll(0);
               resetRings();
               return true;
            } 
            
            buttonModeState = digitalRead(BUTTON_MODE);  
            if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
               BUTTON_MODE_TIME = millis();  
               ShiftPWM.SetAll(0);
               resetRings();
               modalita = 0;
               resetRings();  
               return true;
            }       
            
     
         } 
        for (int acceso=numRGBLeds-1;acceso>=0;acceso--) { 
           for(int led=numRGBLeds-1;led>=0;led--){ 
              if (led == acceso) { 
                ShiftPWM.SetHSV(led, HSV, 255, 255);
              } else { 
                ShiftPWM.SetHSV(led, HSV, 0, 0);   
              }   
         
           }
           byte rgb[3];
           double HSVridotto = map2(HSV,0,359,0,1);
           hsvToRgb(HSVridotto,1,1,rgb);
           analogWrite(RED_LED_PIN, 255-rgb[0]);
           analogWrite(GREEN_LED_PIN, 255-rgb[1]);
           analogWrite(BLUE_LED_PIN, 255-rgb[2]); 
           delay(durataacceso);
        
           buttonScrollState = digitalRead(BUTTON_SCROLL);  
           if ((buttonScrollState == HIGH) && (time > BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
              BUTTON_SCROLL_TIME = millis();  
              ShiftPWM.SetAll(0);
              resetRings();
              return true;
           } 
           
           buttonModeState = digitalRead(BUTTON_MODE);  
           if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
              BUTTON_MODE_TIME = millis();  
              ShiftPWM.SetAll(0);
              resetRings();
              modalita = 0;
              resetRings();  
              return true;
           }     
            
         } 
       
      }    
 
    } 
    return false;
  }
}



boolean rgbLedCarnival(int numRGBLeds, int delayVal, int numCycles, int rainbowWidth){
  
  if (modalitaArray[modalita] == "DEMO") {
     int i = 0;
     ShiftPWM.SetAll(0);
     resetToZeroRings();
     lcd.clear();
     lcd.clear();
     lcd.setCursor(1, 0);
     lcd.print("LA MACCHINA      ");
     lcd.setCursor(1, 1);
     lcd.print("        DEI COLORI      ");
     lcd.setCursor(1, 2);
     lcd.print("    D  E  M  O       ");
     lcd.setCursor(3, 3);
     lcd.print("   Carnevale");
     
     for(int cycle=0;cycle BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
                 BUTTON_SCROLL_TIME = millis();  
                 ShiftPWM.SetAll(0);
                 resetRings();
                 return true;
              } 
            
              buttonModeState = digitalRead(BUTTON_MODE);  
              if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
                 BUTTON_MODE_TIME = millis();  
                 ShiftPWM.SetAll(0);
                 resetRings();
                 modalita = 0;
                 resetRings();  
                 return true;
              }     
           }
     
           // LED RINGS
           i++;
           if (i%2 == 0) {
              digitalWrite(LE,LOW);
              shiftOut(SDI,CLK,MSBFIRST,(0xAAAA >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0xAAAA);           //Low byte second
              shiftOut(SDI,CLK,MSBFIRST,(0xAAAA >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0xAAAA);           //Low byte second
              shiftOut(SDI,CLK,MSBFIRST,(0xAAAA >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0xAAAA);           //Low byte second
              digitalWrite(LE,HIGH);
           } else {
              digitalWrite(LE,LOW);
              shiftOut(SDI,CLK,MSBFIRST,(0x5555 >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0x5555);           //Low byte second
              shiftOut(SDI,CLK,MSBFIRST,(0x5555 >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0x5555);           //Low byte second
              shiftOut(SDI,CLK,MSBFIRST,(0x5555 >> 8));    //High byte first
              shiftOut(SDI,CLK,MSBFIRST,0x5555);           //Low byte second
              digitalWrite(LE,HIGH);
           }
        
           int randRed = random(0,200);
           int randGreen = random(0,200);
           int randBlue = random(0,200);
           analogWrite(RED_LED_PIN, 255-randRed);
           analogWrite(GREEN_LED_PIN, 255-randGreen);
           analogWrite(BLUE_LED_PIN, 255-randBlue);
           delay(75); // this delay value determines the speed of hue shift
       } 
    
    } 

    return false;
    }
}





boolean whiteBright(int numRGBLeds, int numCycles, int rainbowWidth){
  
   if (modalitaArray[modalita] == "DEMO") {
      int i = 0;
      ShiftPWM.SetAll(0);
      resetToZeroRings();
      analogWrite(RED_LED_PIN, 255-50);
      analogWrite(GREEN_LED_PIN, 255-50);
      analogWrite(BLUE_LED_PIN, 255-50);
      lcd.clear();
      lcd.setCursor(1, 0);
      lcd.print("LA MACCHINA      ");
      lcd.setCursor(1, 1);
      lcd.print("        DEI COLORI      ");
      lcd.setCursor(1, 2);
      lcd.print("    D  E  M  O       ");
      lcd.setCursor(3, 3);
      lcd.print("   Shining");
 
      for (int i = 50;i<500;i++) {
         time = millis();
         for(int led=0;led BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
            BUTTON_SCROLL_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            return true;
         } 
         
         buttonModeState = digitalRead(BUTTON_MODE);  
         if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
            BUTTON_MODE_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            modalita = 0;
            resetRings();  
            return true;
         }    
   
      }
 
      for (int aus = 0; aus <= 230; aus++) {
         time = millis();
         for(int led=0;led BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
            BUTTON_SCROLL_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            return true;
         } 
         
         buttonModeState = digitalRead(BUTTON_MODE);  
         if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
            BUTTON_MODE_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            modalita = 0;
            resetRings();  
            return true;
         }       

      } 
 
      unsigned long int FLICKER_TIME = 0;
      unsigned long int FLICKER_FREQ = 1500;
      int aus = 0;  
      int valmin = 25; 
      int valmax = 255; 
      
      while (aus < 40) {
         time = millis();
         unsigned long int tempo = 0;   
         if (time > FLICKER_TIME+FLICKER_FREQ) {
            aus++; 
            FLICKER_TIME = millis();  
            for (int acceso=0;acceso BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
                      BUTTON_SCROLL_TIME = millis();  
                      ShiftPWM.SetAll(0);
                      resetRings();
                      return true;
                    } 
            
                    buttonModeState = digitalRead(BUTTON_MODE);  
                    if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
                       BUTTON_MODE_TIME = millis();  
                       ShiftPWM.SetAll(0);
                       resetRings();
                       modalita = 0;
                       resetRings();  
                       return true;
                    }    
        
                    if (led == acceso) { 
                       ShiftPWM.SetRGB(led, valmax, valmax, valmax); 
                    } else {
                      if (led == acceso-1) { 
                         ShiftPWM.SetRGB(led, valmax-30, valmax-30, valmax-30); 
                      }
                      if (led == acceso-2) { 
                         ShiftPWM.SetRGB(led, valmax-60, valmax-60, valmax-60); 
                      }
                      if (led == acceso-3) { 
                         ShiftPWM.SetRGB(led, valmax-90, valmax-90, valmax-90); 
                      }
                      if ((led != acceso) & (led != acceso-1) & (led != acceso-2) & (led != acceso-3)) { 
                         ShiftPWM.SetRGB(led, valmin, valmin, valmin); 
                        
                      }    
                   } 
                   
                }
       
                delay(5);
                for(int led=0;led 0) valmin--;
          }
  
       } 
       return false;
    }
}




boolean astro(int numRGBLeds){
  
   if (modalitaArray[modalita] == "DEMO") {
      int i = 0;
      ShiftPWM.SetAll(0);
      analogWrite(RED_LED_PIN, 255-20);
      analogWrite(GREEN_LED_PIN, 255-20);
      analogWrite(BLUE_LED_PIN, 255-50);
      lcd.clear();
      lcd.setCursor(1, 0);
      lcd.print("COLOR MACHINE");
      lcd.setCursor(4, 1);
      lcd.print("Astro");
      int valmax = 255;
      int valmin = 0;

      for (int i = 0;i<500;i++) {
         time = millis();
         for (int acceso=0;acceso BUTTON_SCROLL_TIME + BUTTON_DELAY)) {
            BUTTON_SCROLL_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            return true;
         } 
            
         buttonModeState = digitalRead(BUTTON_MODE);  
         if ((buttonModeState == HIGH) && (time > BUTTON_MODE_TIME + BUTTON_DELAY)) {
            BUTTON_MODE_TIME = millis();  
            ShiftPWM.SetAll(0);
            resetRings();
            modalita = 0;
            resetRings();  
            return true;
         }       
  
      }
   }
 
   return false;

  }

}

Download this source code for Arduino

MAIN SUPPLIERS & INSIGHTS


Arduinowww.arduino.cc
Adafruitwww.adafruit.com
EmmeShopwww.emmeshop.it
Fritzingwww.fritzing.org
Fritzing Fabfab.fritzing.org
Front Panel Expresswww.frontpanelexpress.com
Impoluxwww.led-dealer.de
Robot-Italywww.robot-italy.com
RS Onlinewww.rs-online.com
Sparkfunwww.sparkfun.com

Credits

Concept, electronics & software development: Fabio Ghidini
Ironware & advice: Stefano Guerrini
Copyright © 2013