Push Button Mode Control

I got this code from a guy at Instructables, but I can't seem to get the push button section working. I've looked around a bit on the forums, trying to figure out his logic, but I can't make sense of it. I was wondering if anyone could look at it and explain what's going on, and how to fix the problem.

The push button is supposed to select between four different modes, but when I push it, it just starts the first mode over again. I know the button is working, so I figure it must be some logic problem in the code. Either that, or the button I have wired up won't work the code. It's an SPST momentary contact push button, wired to digital pin 4 along GND and a 2.2K resistor to HOT. Any help is greatly appreciated, thanks.

//example use of LCD4Bit library with a 20x4 Display
#include <LCD4Bit.h> 
LCD4Bit lcd = LCD4Bit(2); 

char decBuffer[] = {0,0,0,0,0,0,0};
char decFill = '0';

int bootUp = 0; 

//-- Variables-------------
float h;
int h_int;
int hVal=0;
int r=0, g=0, b=0;
int oldHue;
int newHue;
int glowHue;
int lcdRefreshRate=0;

//-- input Controls---------
int potPin = 2;              // Switch connected to analog pin 2
int potVal =0;

//-- button pins-----------------
#define Sw0 4 /* digital line to read "Sw0"... "SWitch zero"  Wire it for closed pulls line low (i.e. to 0v)*/
boolean boItWasOn;
boolean boItIsOn;

byte bCount=1;    //btn count
int btnPin = 4;   // choose the input pin (for a pushbutton)
//----------------------------------

//-- output controls -------
int rpin = 3;
int gpin = 5;
int bpin = 6;

//--lcd pins ---------------
// pins 7,8,9,10
//
//--------------------------


#define MODESPEED 0
#define MODEHUE 1
#define MODERANDHUE 2
#define MODEGLOW 3


void h2rgb(float h, int &R, int &G, int &B);

void setup() { 
  //pinMode(ledPin, OUTPUT);  //we'll use the debug LED to output a heartbeat
  lcd.init();
  
  pinMode(btnPin, INPUT);    // declare pushbutton as input 
  Serial.begin(9600);           // set up Serial library at 9600 bps
  h=0;  
  
  boItWasOn=boSw0();
}

void loop() {
  
  do {
    boItIsOn=boSw0();
    selectMode(bCount);
    
    if (bootUp == 0) { bootMsg(); bootUp++;}
    
  }while (not(boItWasOn xor boItIsOn));
  boItWasOn=boItIsOn;

  delay(300);
  bCount++;
  if (bCount==6){bCount=0;}; 
  
}

void selectMode(byte bToWrite)
{

switch (bToWrite)
  {
  case 0:{}
  case 1:{
           modeSpeed();
           lcdPrint(MODESPEED);
           serialPrint(MODESPEED);
           break;
         }
  case 2:{}
  case 3:{
           modeHue();
           lcdPrint(MODEHUE);     
           serialPrint(MODEHUE);
           break;
         }
  case 4:{}
  case 5:{
           modeRandomHue();
           lcdPrint(MODERANDHUE);
           serialPrint(MODERANDHUE);
           break;
         }
  case 6:{}
  case 7:{
           modeGlowHue();
           lcdPrint(MODEGLOW);
           serialPrint(MODEGLOW);
           break;
         }
  };
}

//----modeSpeed hue loop, control loop speed
void modeSpeed(){
  potVal=analogRead(potPin);    // Read the pin and display the value

  
  //------------------------------
  potVal = pow((potVal/100),1.25)+1;
  
  hVal = hVal + potVal;  
  if (hVal >1024) { hVal=0;}
  //---------------------------------
  
  h = ((float)hVal)/1024;
  h_int = (int) 360*h;
  h2rgb(h,r,g,b);

  
  analogWrite(rpin, r);
  analogWrite(gpin, g);
  analogWrite(bpin, b);    
}


//----modeHue SELECT hUE
void modeHue(){
  potVal=analogRead(potPin);    // Read the pin and display the value

  h = ((float)potVal)/1024;
  h_int = (int) 360*h;
  h2rgb(h,r,g,b);

 
  analogWrite(rpin, r);
  analogWrite(gpin, g);
  analogWrite(bpin, b);  
}

void modeRandomHue(){
 
  potVal=analogRead(potPin)/102; 
   
  if (newHue >= oldHue) { 
      oldHue = oldHue + potVal; 
      if (oldHue >= newHue) { newHue=random(1,1024); } //if random hue from old to new are equal, pick new random hue
  }
  if (newHue <= oldHue) { 
      oldHue = oldHue - potVal;  
      if (oldHue <= newHue) { newHue=random(1,1024); } //if random hue from old to new are equal, pick new random hue
  }

  h = ((float)oldHue)/1024;
  h_int = (int) 360*h;
  h2rgb(h,r,g,b);

  analogWrite(rpin, r);
  analogWrite(gpin, g);
  analogWrite(bpin, b);  
}

void modeGlowHue(){
 ///---not worked on. don't know how i want to acheive this effect
  modeRandomHue();
  potVal=analogRead(potPin)/102; 
  
  analogWrite(rpin, r+ (r - potVal));
  analogWrite(gpin, g+ (g - potVal));
  analogWrite(bpin, b+ (b - potVal)); 
}

void serialPrint(int Mode){

      switch (Mode)
        {
        case MODESPEED:{
                  Serial.print(" [ Speed : ");
                  Serial.print(potVal); 
                  Serial.print(" ] ");
                break;
               }
        case MODEHUE:{
                  Serial.print(" [ Hue : ");
                  Serial.print(h_int);
                  Serial.print(" ] ");
                break;
               }
        case MODERANDHUE:{
                  Serial.print(" [ old Hue : ");
                  Serial.print(oldHue);
                  Serial.print(" ] ");
                  Serial.print(" [ new Hue : ");
                  Serial.print(newHue);
                  Serial.print(" ] ");
                break;
               }
/*
        case MODEGLOW:{
                  Serial.print(" [ Glow Hue : ");
                  Serial.print(h_int);
                  Serial.print(" ] ");
                break;
               }
*/
        };  
      Serial.print(" [ bCount : ");
      Serial.print(bCount); 
      Serial.print(" ] ");
  
      Serial.print(" [ rgb: ");
      Serial.print(r); 
      Serial.print(","); 
      Serial.print(g); 
      Serial.print(",");     
      Serial.print(b); 
      Serial.print(" ] ");      

      Serial.println("");
}

void h2rgb(float H, int& R, int& G, int& B) {

  int var_i;
  float S=1, V=1, var_1, var_2, var_3, var_h, var_r, var_g, var_b;

  if ( S == 0 )                       //HSV values = 0 [ch65533] 1
  {
    R = V * 255;
    G = V * 255;
    B = V * 255;
  }
  else
  {
    var_h = H * 6;
    if ( var_h == 6 ) var_h = 0;      //H must be < 1
    var_i = int( var_h ) ;            //Or ... var_i = floor( var_h )
    var_1 = V * ( 1 - S );
    var_2 = V * ( 1 - S * ( var_h - var_i ) );
    var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) );

    if      ( var_i == 0 ) { 
      var_r = V     ; 
      var_g = var_3 ; 
      var_b = var_1 ;
    }
    else if ( var_i == 1 ) { 
      var_r = var_2 ; 
      var_g = V     ; 
      var_b = var_1 ;
    }
    else if ( var_i == 2 ) { 
      var_r = var_1 ; 
      var_g = V     ; 
      var_b = var_3 ;
    }
    else if ( var_i == 3 ) { 
      var_r = var_1 ; 
      var_g = var_2 ; 
      var_b = V     ;
    }
    else if ( var_i == 4 ) { 
      var_r = var_3 ; 
      var_g = var_1 ; 
      var_b = V     ;
    }
    else                   { 
      var_r = V     ; 
      var_g = var_1 ; 
      var_b = var_2 ;
    }

    R = (1-var_r) * 255;                  //RGB results = 0 [ch65533] 255
    G = (1-var_g) * 255;
    B = (1-var_b) * 255;
  }
}


boolean boSw0()
{
/* The remmed out material is equivalent to the remaining
single line... longer, but more clear! If you are happy taking
the obscure shortcut, there is no need to "package" it in the
function, of course.

boolean boReturn;
if (digitalRead(Sw0)==1)
    {boReturn=true;}
  else
    {boReturn=false;};
return boReturn;*/

return digitalRead(Sw0);//More strictly typed languages wouldn't allow this.
}

void waitForChange()
{
  //Bad programming... reference made to global variables.
  //Especially bad: Changing their values.
  do {
    boItIsOn=boSw0();
  }
  while (not(boItWasOn xor boItIsOn));
  boItWasOn=boItIsOn;
}

Note: I took out unnecessary functions pertaining to LCD display. Also, the WaitForChange() function at the the end there isn't called anywhere; maybe it should be?
boolean boSw0()
{
return ! digitalRead(Sw0);//More strictly typed languages wouldn't allow this.
}

You've wired the button with a pull-up resistor. The code is written for the button to be wired with a pull-down resistor. Put a NOT (!) in front of the digitalRead as I've shown above and you should be good to go.

  • Brian

Tried that; no luck. It seems to me like the bcount variable isn't getting changed somewhere along the way. But I get lost trying to sort out the logic here.

P.S.: I just realized I described the button wiring wrong. There's a 2.2K resistor on digital pin 4, which goes into the button with HOT, and GND on the other side.

Ok, problem solved. I had the push button wired up like the diagram from the picture in my previous post. The junction between HOT, GND, and digital pin 4 needed to be AFTER the resistor, not before. In other words, HOT had to pass the through the resistor before it went to the pin OR out to ground, when the button was pushed.

I should have thought of that before, since the reset button on the board operates the same way, but it taught me something at least. Thanks for the help.