trying to use shiftIn with adafruit button checker

Hi Guys, this is my first post here so please go easy...
Anyway, I've been learning as much as I can about the arduino and coding over the past couple months and have managed to get pretty far (by my standards), but I have recently come up against a challenge that I cant seem to figure out on my own.

I am attempting to use a cd4021 to read buttons using the shiftIn function. I've got this part working.

what I can't get is how to use the adafruit's"button checking" function combined with the shiftIn function.

I have a couple of projects going on where I use them separately, but the code I have written to combine them into one sketch doesn't seem to work and I can't figure out where I have gone wrong.

The hardware all seems fine as I can get the two functions to work with the hardware when run individually.

Heres the code i am working with.
I apologize if it's long. I believe the problem lies in either the Loop (which is pretty short) or the button checker function (at the end).

//Pin connected to ST_CP of 74HC595
int latchPinSo = 17; //to pin 12 on SR
//Pin connected to SH_CP of 74HC595
int clockPinSo = 16; //to pin 11 0n shift
////Pin connected to DS of 74HC595
int dataPinSo = 15; //to pin 14 on SR


//define where your pins are
int latchPinSi = 8;
int dataPinSi = 9;
int clockPinSi = 7;
byte switchVar1 = 0;  //01001000
byte switchVar2 = 0;  //01001000


//adafruit button checker
#define DEBOUNCE 10  
byte buttons[] = {0, 1, 2, 3}; 
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'currently pressed' 
byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];



void setup() 
{  
  //define pins for shiftOut
  pinMode(latchPinSo, OUTPUT);
  pinMode(clockPinSo, OUTPUT);
  pinMode(dataPinSo, OUTPUT);  

  //define pins for ShiftIn
  pinMode(latchPinSi, OUTPUT);
  pinMode(clockPinSi, OUTPUT); 
  pinMode(dataPinSi, INPUT);
}

void loop() 
{
  
    //Adafruit Button Checker
  check_switches();  

   if (pressed[0])   
   {
     switchVar2 = 72;  // I am using this to check if the button is recognized as "pressed"
   }
  else
   {
     switchVar2 = 0;
   }
  
  
  digitalWrite(latchPinSi,HIGH);
  digitalWrite(latchPinSi,LOW);
  switchVar1 = shiftIn(dataPinSi, clockPinSi);

 for (int n=0; n<=7; n++)
  {
    if (switchVar1 == (1 << n) )
    {
    buttons[n] = 1;
    }
  }
 
 
  //shift out part
    digitalWrite(latchPinSo, LOW);            // set pin low to prepare to shift out
    shiftOut(dataPinSo, clockPinSo, MSBFIRST, (switchVar1 | switchVar2));  // shift data to register (when this was << over it was essentially shifting it twice
    digitalWrite(latchPinSo, HIGH);          // write data out of shift register
}

//------------------------------------------------end main loop







////// ----------------------------------------shiftIn function
byte shiftIn(int mydataPinSi, int myclockPinSi) 
{ 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myclockPinSi, OUTPUT);
  pinMode(mydataPinSi, INPUT);

  for (i=7; i>=0; i--)
  {
    digitalWrite(myclockPinSi, LOW);       
    temp = digitalRead(mydataPinSi);
    
    if (temp) 
    {
      myDataIn = myDataIn | (1 << i);
    }
    
    digitalWrite(myclockPinSi, HIGH);
  }
  return myDataIn;  
}


void shiftOut(byte dataPinSo, byte clockPinSo, byte bitOrder, byte val)
{
  for (int i = 0; i < 8; i++)    
    {
          if (bitOrder == LSBFIRST)
                digitalWrite(dataPinSo, !!(val & (1 << i))); 
          else      
                digitalWrite(dataPinSo, !!(val & (1 << (7 - i)))); 
                                                
          digitalWrite(clockPinSo, HIGH);
          digitalWrite(clockPinSo, LOW);            
    }
}


//***************************************************************************
//Adafruit Button Checker
void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  static long lasttime;
  byte index;

  if (millis() < lasttime) 
  {
    // we wrapped around, lets just try again
    lasttime = millis();
  }

  if ((lasttime + DEBOUNCE) > millis()) 
  {
    // not enough time has passed to debounce
    return; 
  }
  // ok we have waited DEBOUNCE milliseconds, lets reset the timer
  lasttime = millis();

  for (index = 0; index < NUMBUTTONS; index++) 
  {
    justpressed[index] = 0;       // when we start, we clear out the "just" indicators
    justreleased[index] = 0;

    currentstate[index] = (buttons[index]);   // read the button

    if (currentstate[index] == previousstate[index]) 
    {
      if ((pressed[index] == 0) && (currentstate[index] == 1)) 
      {
        // just pressed
        justpressed[index] = 1;
      }
      else if ((pressed[index] == 1) && (currentstate[index] == 0)) 
      {
        // just released
        justreleased[index] = 1;
      }
      pressed[index] = currentstate[index];  
    }

    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}

the "justpressed" variable seems to be working.
However, the "pressed" variable seems to be switching between 1 and 0 very quickly, rather than just outputting a steady stream of 1's like I would expect (when held down).
Because the "pressed" variable isn't working, neither is the "justreleased" variable.

I'm guessing that this is related to the shiftIn function constantly checking the inputs and rewriting the values?
Though even if this is the problem I'm not sure what to do about it.

Any advice?

Thanks!

Hi

something i find very useful when trying to solve any problems with my code is to use the Serial Monitor.
You can output into your monitor any kind of information, like for instance any variables you are using.
So if you want to check if your variable "justchecked" is working ok, you can output it and see what is going on.

To do this, on void setup start the serial:

Serial.begin(9600);

and there on the void loop something like:

Serial.print("\t");                   // this will display the info in tabs. easier to read
Serial.print(justchecked[0]);
Serial.print("\t");
Serial.print(justchecked[1]);
Serial.print("\t");
Serial.print(justchecked[2]);
Serial.print("\t");
Serial.print(justchecked[3]);
Serial.println("\t");                 // new line

The Serial Monitor has helped me quite often debugging my projects. You can read more about it here:

Another question...
i just woke up, so please excuse me if i am saying something stupid.
on your code here:

if (currentstate[index] == previousstate[index])
    {
      if ((pressed[index] == 0) && (currentstate[index] == 1))
      {
        // just pressed
        justpressed[index] = 1;
      }

You are checking for a "justpressed" inside an if statement that compares if that currentstate is equal to previousstate.
Isn't just pressed a change in state, from not pressed to pressed?
If so, shouldn't you be checking for it inside a if statement that checks if currentstate and previousstate are different AND if button is pressed?

I hope this is useful to you. Good luck with your project!
:wink:

// this will display the info in tabs. easier to read

But nothing to indicate what the hell the data is, so it's just some raw data that requires guesswork to understand.

Serial.print("justchecked: ");                   // No tab needed at the start!
Serial.print(justchecked[0]);
Serial.print("\t");
Serial.print(justchecked[1]);
Serial.print("\t");
Serial.print(justchecked[2]);
Serial.print("\t");
Serial.print(justchecked[3]);
Serial.println();     // No tab needed at the end!

No guesswork needed.

Thanks for the help guys!

I eventually ended up getting it working...

turns out the problem was with a bitwise comparison operator (I think thats what you call it?).

I was using == to compare bits when what I needed to be using was &.

Anyway, thanks for the tips on serialread, I haven't used it as much as I probably should, simply because I'm not particularly proficient with how to set it up, those examples should help.

Heres the working code, for if anyone else has this problem in the future and stumbles across this thread...

//Pin connected to ST_CP of 74HC595
int latchPinSo = 17; //to pin 12 on SR
//Pin connected to SH_CP of 74HC595
int clockPinSo = 16; //to pin 11 0n shift
////Pin connected to DS of 74HC595
int dataPinSo = 15; //to pin 14 on SR


//define where your pins are
int latchPinSi = 8;
int dataPinSi = 9;
int clockPinSi = 7;
byte switchVar1 = 0;  //01001000
byte switchVar2 = 0;  //01001000

unsigned long functionDebounce = 0;
byte modeNum = 0;

//adafruit button checker
#define DEBOUNCE 10  
byte buttons[] = {0, 0, 0, 0}; 
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'currently pressed' 
static byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

int flag = 0;  //for debugging


void setup() 
{  
  Serial.begin(9600);
  
  //define pins for shiftOut
  pinMode(latchPinSo, OUTPUT);
  pinMode(clockPinSo, OUTPUT);
  pinMode(dataPinSo, OUTPUT);  

  //define pins for ShiftIn
  pinMode(latchPinSi, OUTPUT);
  pinMode(clockPinSi, OUTPUT); 
  pinMode(dataPinSi, INPUT);
}

void loop() 
{
  
    //Adafruit Button Checker
  check_switches();  

 
    if (pressed[3] && justpressed[0])    
     {
      modeNum = (modeNum >= 3) ? 0 : modeNum + 1;
     } 
 
     if (pressed[3] && justpressed[1])    
     {
      modeNum = (modeNum <= 0) ? 3 : modeNum - 1;
     } 
 
  
  
  digitalWrite(latchPinSi,HIGH);
  digitalWrite(latchPinSi,LOW);
  switchVar1 = shiftIn(dataPinSi, clockPinSi); 
  
 for (int n=0; n<=7; n++)
  {
    if (switchVar1 & (1 << n) )
    {
    buttons[n] = 1;
    }
    else
    {
    buttons[n] = 0;
    }
  }

 Serial.println(pressed[0]); 

  //shift out part
    digitalWrite(latchPinSo, LOW);            // set pin low to prepare to shift out
    shiftOut(dataPinSo, clockPinSo, MSBFIRST, (1<<modeNum));  
    digitalWrite(latchPinSo, HIGH);          // write data out of shift register
}


//------------------------------------------------end main loop


//---------------------------------------------------Functions---------------------------------------------

byte shiftIn(int mydataPinSi, int myclockPinSi) 
{ 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myclockPinSi, OUTPUT);
  pinMode(mydataPinSi, INPUT);

  for (i=7; i>=0; i--)                //this loop turns the clock on and off
  {
    digitalWrite(myclockPinSi, LOW);       // flip clock to allow reading of data
    temp = digitalRead(mydataPinSi);      // if mydatapin is high then temp is high/true
    
    if (temp) 
    {
      myDataIn = myDataIn | (1 << i);      //when temp is true, add the next bit of data to what is already there
    }
    
    digitalWrite(myclockPinSi, HIGH);    //flip clock to prep for next time through the loop
  }
  return myDataIn;                      //my data in should be (a byte) indicating what buttons are high
}


void shiftOut(byte dataPinSo, byte clockPinSo, byte bitOrder, byte val)
{
  for (int i = 0; i < 8; i++)    
    {
          if (bitOrder == LSBFIRST)
                digitalWrite(dataPinSo, !!(val & (1 << i))); 
          else      
                digitalWrite(dataPinSo, !!(val & (1 << (7 - i)))); 
                                                
          digitalWrite(clockPinSo, HIGH);
          digitalWrite(clockPinSo, LOW);            
    }
}


//***************************************************************************
//Adafruit Button Checker
void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  static long lasttime;
  byte index;

  if (millis() < lasttime) 
  {
    // we wrapped around, lets just try again
    lasttime = millis();
  }

  if ((lasttime + DEBOUNCE) > millis()) 
  {
    // not enough time has passed to debounce
    return; 
  }
  // ok we have waited DEBOUNCE milliseconds, lets reset the timer
  lasttime = millis();



//button checking begins here
  for (index = 0; index < NUMBUTTONS; index++) 
  {
    justpressed[index] = 0;       // when we start, we clear out the "just" indicators
    justreleased[index] = 0;

    currentstate[index] = (buttons[index]);   

    if (currentstate[index] == previousstate[index]) 
    {
      
      if ((pressed[index] == 0) && (currentstate[index] == 1)) 
      {
        // just pressed
        justpressed[index] = 1;
      }
      else if ((pressed[index] == 1) && (currentstate[index] == 0)) 
      {
        // just released
        justreleased[index] = 1;
      }
      
      pressed[index] = currentstate[index];  
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   
  }
}