Simple Example for SHift In!

Im using CD4021BCN Shift In Register i wanted to read 3-4v on these pins , want to have a small working example to make it work.

http://arduino.cc/en/Reference/ShiftIn
It's really a pretty simple concept.

IM actually trying to condense this code http://arduino.cc/en/Tutorial/ShftIn12

the link that you give just a function.

i wanted to understand the relevance of this code , the code above this is understood

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

////// ----------------------------------------shiftIn function
///// just needs the location of the data pin and the clock pin
///// it returns a byte with each bit in the byte corresponding
///// to a pin on the shift register. leftBit 7 = Pin 7 / Bit 0= Pin 0

byte shiftIn(int myDataPin, int myClockPin) {
int i;
int temp = 0;
int pinState;
byte myDataIn = 0;

pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, INPUT);
//we will be holding the clock pin high 8 times (0,..,7) at the
//end of each time through the for loop

//at the begining of each loop when we set the clock low, it will
//be doing the necessary low to high drop to cause the shift
//register's DataPin to change state based on the value
//of the next bit in its serial information flow.
//The register transmits the information about the pins from pin 7 to pin 0
//so that is why our function counts down
for (i=7; i>=0; i--)
{
digitalWrite(myClockPin, 0);
delayMicroseconds(0.2);
temp = digitalRead(myDataPin);
if (temp) {
pinState = 1;
//set the bit to 0 no matter what
myDataIn = myDataIn | (1 << i);
}
else {
//turn it off -- only necessary for debuging
//print statement since myDataIn starts as 0
pinState = 0;
}

//Debuging print statements
//Serial.print(pinState);
//Serial.print(" ");
//Serial.println (dataIn, BIN);

digitalWrite(myClockPin, 1);

}
//debuging print statements whitespace
//Serial.println();
//Serial.println(myDataIn, BIN);
return myDataIn;
}

Maybe you should try a version of the 74hc165 , it can be clocked at a max of 21Mhz. No need for delays in the read code.
But I would think this:

pin 3 is the input data line
pin 10 is the clock
pin 9 is the latch.

Pin 3 is always showing the last bit ( first to shift in )

Make pin 9 LOW to read data.
Start read loop
Read pin 3 for bit
Make pin 10 HIGH to shift next bit
Make pin 10 LOW
Loop until all bits read.
Make pin 9 HIGH to allow parallel inputs to set.

Connect pin 11 to ground or to pin 3 of secondary register if chaining.

Hi Pyro so as per you i made the following code:

int latchPin = 9;
int dataPin = 3;
int clockPin = 10;
byte switchVar1;
char note2sing[] = {'C', 'd', 'e', 'f', 'g', 'a', 'b', 'c'}; 


void setup() {
  //start serial
  Serial.begin(9600);

  //define pin modes
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, INPUT);
}

void loop(){
digitalWrite(latchPin,0);//Make pin 9 LOW to read data.
delayMicroseconds(20);
switchVar1 = shiftIn(dataPin, clockPin);//Read pin 3 for bit
 for (int n=0; n<=7; n++)//start reading the loop
  {
      if (switchVar1 & (1 << n) ){
      //print the value of the array location
      Serial.println(note2sing[n]);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);      
    }
  }

digitalWrite(latchPin,1);
}

It shows an error "at this point in file" :

D:\Removable Disk\arduino-1.0\hardware\arduino\cores\arduino/Arduino.h: In function 'void loop()':
D:\Removable Disk\arduino-1.0\hardware\arduino\cores\arduino/Arduino.h:111: error: too few arguments to function 'uint8_t shiftIn(uint8_t, uint8_t, uint8_t)'
sketch_jan29a:20: error: at this point in file

The pins are the pins on the shift register see

I don't think the shiftIn is compatible with this shift register.

int latchPin = 9;
int dataPin = 8;
int clockPin = 7;

char c_Result;

digitalWrite(latchPin,0);//Make pin 9 LOW to read data.
delayMicroseconds(20); //Do you need this?

 for (int n=0; n<=7; n++)//start reading the loop
  {
     c_Result |= ( digitalRead( dataPin ) << n );
     digitalWrite(clockPin, HIGH);
     digitalWrite(clockPin, LOW);      
    }
  }
digitalWrite(latchPin,1);

Result should be in c_Result.

But on the other hand if shiftIn is compatible, try

digitalWrite(latchPin,0);
char c_Result = ShiftIn( dataPin, clockPin, MSBFIRST );
digitalWrite(latchPin,1);

Result should be in c_Result.

I don't think the shiftIn is compatible with this shift register.

These Arduino Guys here think it is >> http://arduino.cc/en/Tutorial/ShftIn12

delayMicroseconds(20); //Do you need this?

I'll be using the CD4021B shift register only as im unable to procure those 165's at this time.

But on the other hand if shiftIn is compatible, try

Code:
digitalWrite(latchPin,0);
char c_Result = ShiftIn( dataPin, clockPin, MSBFIRST );
digitalWrite(latchPin,1);

if it supports Then the code becomes

int latchPin = 9;
int dataPin = 8;
int clockPin = 7;

char c_Result;

digitalWrite(latchPin,0);//Make pin 9 LOW to read data.
delayMicroseconds(20); //Do you need this?

 for (int n=0; n<=7; n++)//start reading the loop
  {
      digitalWrite(latchPin,0);
     char c_Result = ShiftIn( dataPin, clockPin, MSBFIRST );
     digitalWrite(latchPin,1); 
    }
  }
digitalWrite(latchPin,1);

I edited my post above with a shiftIn usage, the tutorial is fairly the same,

Delay may not be needed if you set the latch high once shifting is done, rather than pulsing it up and down before shifting.

if it supports Then the code becomes

No the shift in function retrieves 8 bits

int latchPin = 9;
int dataPin = 8;
int clockPin = 7;

char c_Result;

digitalWrite(latchPin,0);//Make pin 9 LOW to read data.
c_Result = ShiftIn( dataPin, clockPin, MSBFIRST );
digitalWrite(latchPin,1);

I will be not using switches with this rather i would be giving 2-3 volts out of a voltage divider or 7805 regulator to switch register pins

what will i get in c_Result , alphabet corresponding to shift register pin?

Each of the shift registers parallel input pins are sampled when the latch is HIGH, when LOW the values of the samples in the internal registers are shifted towards Q8 ( data pin ), the first bit is filled in with the Serial In pin ( 5v or GND or chained shift registers )
the shiftIn function loops 8 times reading each of the serial input values, placing each one in an 8-bit value.

c_Result will contain the 8-bits passed into the register through the parallel inputs.

shiftOut passes 8-bits out
shiftIn reads 8-bits in

shiftIn can be called multiple times if you have more than one shift register chained together.

Actually i want to do a IF condition based on the value extracted from the register corresponding to a particular button pressed or voltage applied ,how that operation can be done?

THis is the circuit what im trying to make:

After reading the register using shiftIn check if a certain bit is set.

this #define should work.

#define READ_REGISTER_PIN( pin, data ) ( ( data & ( 1 << pin ) ) != 0 )
int latchPin = 9;
int dataPin = 8;
int clockPin = 7;

char c_Result;

inline unsigned int BitsSet( unsigned int u_Value )
  {
    unsigned int u_Return;
    for (u_Return = 0; u_Value; u_Return++)
      u_Value &= u_Value - 1; 
    return;
  }

digitalWrite(latchPin,0);//Make pin 9 LOW to read data.
c_Result = ShiftIn( dataPin, clockPin, MSBFIRST );
digitalWrite(latchPin,1);

//Print out each input state.
for( int i_Index = 0 ; i_Index < 8 ; ++i_Index ){
  Serial.println( READ_REGISTER_PIN( i_Index, c_Result ) );
}


if( READ_REGISTER_PIN( 0, c_Result ) ){
  Serial.println( "Button 0 Pressed" );
}

if( BitsSet( c_Result ) > 1 ){
  Serial.println( "Multiple buttons pushed" );
}

Hi pyro,

I have finalized the circuit for the parallel in and serial out functioning using the same CD4021B so please have a look and tell me that the code will work fine with that circuits setting.(look in the Attachement)

Thanks and Regards,
Nishant

Hi I have had a look, and to the best of my ability I would be happy to turn my device on with this code.

I have changed the pin numbers to match your diagram.

Also I re-read the datasheet and took a closer look at this:

When the parallel/serial control input is in the logical “0”
state, data is serially shifted into the register synchronously
with the positive transition of the clock. When the parallel/
serial control is in the logical “1” state, data is jammed into
each stage of the register asynchronously with the clock.

I have added in a few lines after the shiftIn call as it appears to load the register it has to be clocked once.
Comment out those lines or add in the delay if its not reading the correct data.

Also the BitsSet function is untested ( wont affect test though ).

You also might want to change MSBFIRST to LSBFIRST if your readings seem backwards.

#define READ_REGISTER_PIN( pin, data ) ( ( data & ( 1 << pin ) ) != 0 )

int latchPin = 8;  //Goes to pin 9 on register
int dataPin = 9;   //Goes to pin 3 on register
int clockPin = 7;  //Goes to pin 10 on register

//Returns the number of bits set ( untested )
unsigned int BitsSet( unsigned int u_Value );

void setup()
  {
    pinMode( latchPin, OUTPUT );
    pinMode( dataPin, INPUT );
    pinMode( clockPin, OUTPUT );
    
    //Load parallel side first.
    digitalWrite(latchPin, HIGH ); 
    digitalWrite(clockPin , HIGH );
    //Add delay here if needed.
    digitalWrite(clockPin , LOW );    
    return;
  }

void loop()
  {
    char c_Result;
    
    //Read serial side.
    digitalWrite(latchPin, LOW );
    c_Result = shiftIn( dataPin, clockPin, MSBFIRST );
    digitalWrite(latchPin, HIGH );

    //Ammendment Relead parallel side.
    digitalWrite(clockPin , HIGH );
    //Add delay here if needed.
    digitalWrite(clockPin , LOW );

    
    //Print out each input state.
    for( int i_Index = 0 ; i_Index < 8 ; ++i_Index ){
      Serial.println( READ_REGISTER_PIN( i_Index, c_Result ) );
    }

    if( READ_REGISTER_PIN( 0, c_Result ) ){
      Serial.println( "Button 0 Pressed" );
    }

    if( BitsSet( c_Result ) > 1 ){
      Serial.println( "Multiple buttons pushed" );
    }
    return;
  }    


//Returns the number of bits set ( untested )
inline unsigned int BitsSet( unsigned int u_Value )
  {
    unsigned int u_Return;
    for (u_Return = 0; u_Value; u_Return++) 
      u_Value &= u_Value - 1; 
    return u_Return;
  }

//Returns the number of bits set ( untested )
inline unsigned int BitsSet( unsigned int u_Value )
{
unsigned int u_Return;
for (u_Return = 0; u_Value; u_Return++)
u_Value &= u_Value - 1;
return u_Return;
}

Need clarity on this one!?

It is a very efficient way of counting the number of bits set.

Effectively, it will only loop as many times as bits are set.

any single bit -1 is every lower bit set, So the & keeps all the unchecked bits while removing the highest.
This loops until the value has all of its bits depleted.

Far more efficient than masking each bit looking for a 1.

//A possible slower method.
for( i=0 ; i<8 ; ++i ){
  if( value & ( 1 << i ) )
    count++;
}

Reference for optimised version: Peter Wegner in CACM 3 (1960)

Can be templated to handle data types of any size