Go Down

Topic: Shift Register, shifting 1 to far? (Read 3619 times) previous topic - next topic

Aemornion

Hello all,

I am trying to take an array, and output it on bit at a time to a shift register.
and this works,  But it appears to be off by one position. =/

Say I have 16 inputs and 2 shift registers in series.
Writing the array {1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1} using a for loop
I would expect to see 1000000000000101 output on my led's
but instead I see 0000000000001011

Before you all get critical of my not using shiftOut.  The reason, I am not using it has to do with the end goal for this project, which involves monitoring button pushes, and setting state changes, across a wide array of multiplexers for the purpose of monitoring a gas handling system in a piece of equipment we are seeking to control. using arrays, seems to be a bit cleaner way of handling all the states in terms of what i will have to do to it later.

Thank you for any help you can provide.

Below is my code
The input is being read from a CD4067 and the output is being sent to a 595 shift register.

Code: [Select]
/*
* CD4067 multiplexer attached as follows:
- address pin A: digital I/O 2
- address pin B: digital I/O 3
- address pin C: digital I/O 4
- address pin D: digital I/O 5
- input/output pins: digital I/O pin 6,7
- LEDs attached from each of the CD4067's output channels
to ground
*/

// put the address pin numbers in an array
// so they're easier to iterate over:

//shift register pins
int data = 11;
int clock = 12;
int latch = 8;

const int ABCD[] = {2, 3, 4, 5};
int currentState[16] ;
int inputState = 0;
int channel = 0;




// the output pin channel (mux's input):


void setup() {
    Serial.begin(9600);
    for (int abcd = 2; abcd < 6; abcd++) {pinMode(abcd, OUTPUT);}
    pinMode(6,INPUT);  //Input
   
    pinMode(data, OUTPUT);
    pinMode(clock, OUTPUT); 
    pinMode(latch, OUTPUT);
}

void loop() {
  // iterate over the 16 channels of the multiplexer:
  digitalWrite(latch, 0);
 
  for (channel = 0; channel < 16; channel++) { 
    // chooses 0-15, sets the channel pins based on the channel you want, iterates over the number of pins you're using:
    addressSet(channel);
   
    inputState = digitalRead(6);
    if(inputState == 1){
     delay(100); //debounce
     inputState = digitalRead(6);
       if(inputState == 1){
        if(currentState[channel] == 0){currentState[channel] = 1;}
        else{currentState[channel] = 0;}
        delay(100);
       }
    }
    digitalWrite(clock,1);
    digitalWrite(data, currentState[channel]);
    digitalWrite(clock, 0);
    Serial.print(currentState[channel]);
  }
  Serial.println("");
 
  digitalWrite(latch,1);
}

void addressSet (int Channel){
      for (int PIN = 0; PIN < 4; PIN++) {
        // chooses ABCD channel array value # 0,1,2,3 -> pins 2,3,4,5
        // forms essentially a 0000 byte, representing channels 0-15 in binary
        // sets the ABCD pins accordingly, to read from a particular channel
        digitalWrite(ABCD[PIN],bitRead(Channel, 3-PIN));
    }
}


larryd

inputState = digitalRead(6);
How is pin 6 wired to the Arduino?
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Aemornion

inputState=digitalRead(6);

Is connected to the arduino via a CD4067 multiplexer.
Reading the data is not the issue, as via Serial to the computer I get the correct values in the correct order.
Its just outputting to the 595 shift register where this issue appears.

ashkan1637

I had the same problem but with using the shiftout which is here:

http://forum.arduino.cc/index.php?topic=209695.0

whatever you do on coding it seems that you should shift out 8bit at the time. so 16bit >> two times.

runaway_pancake


You set this part up, a decision is made, where you do this stuff when inputState == 1

Code: [Select]

  for (channel = 0; channel < 16; channel++)
  { 
    if(inputState == 1)
    {
      delay(100); //debounce
      inputState = digitalRead(6);
      if(inputState == 1)
      {
        if(currentState[channel] == 0)
        {
          currentState[channel] = 1;
        }
        else
        {
          currentState[channel] = 0;
        }
        delay(100);
      }
    }
    digitalWrite(clock,HIGH);  // my change
    digitalWrite(clock,LOW);  // my change
    digitalWrite(data, currentState[channel]);  // ??
    Serial.print(currentState[channel]);
  }
  Serial.println("");
  digitalWrite(latch,1);
}


What's your default ("Plan B") when, way up there, inputState == 0 ?

That whole bit needs revision, doesn't it?

( Is "digitalWrite (clock,1); permitted?  Arduino Reference shows only HIGH and LOW as values. )
"Who is like unto the beast? who is able to make war with him?"
When all else fails, check your wiring!

Aemornion

Thanks for the replies.

Quote
What's your default ("Plan B") when, way up there, inputState == 0 ?


Allow me to clarify exactly what this code is doing.

It has an array, currentState[16] which represents individual on or off states.

I then use the CD4067 multiplexer to detect if a momentary button is pressed and then change the state in the current state array.
Code: [Select]

    inputState = digitalRead(6);
    if(inputState == 1){
     delay(100); //debounce
     inputState = digitalRead(6);
       if(inputState == 1){
        if(currentState[channel] == 0){currentState[channel] = 1;}
        else{currentState[channel] = 0;}
        delay(100);
       }
    }

This allows me to use just momentary push buttons rather than toggles switches.(which is necessary in the long term project goal)

So when I push a button, the corresponding state in currentState[16] switches from 0 to 1, or 1 to 0.
if I don't push a button, it just goes on its merry way and nothing changes.

Next, Looking at the over all structure (i remove things  and replace with pseudo code)
Code: [Select]

void loop() {
  // iterate over the 16 channels of the multiplexer:
  digitalWrite(latch, 0);
    for (channel = 0; channel < 16; channel++) { 

''"Part that sets the input channel according to the for loop""   
""Part that reads that input channel""
""if the input channel is HIGH, wait 100ms and check for HIGH again (debounce) ""
""flipflop the state of the bit in the corresponding channels array element""

    digitalWrite(clock,HIGH);
    digitalWrite(data, currentState[channel]);
    digitalWrite(clock, LOW);
    Serial.print(currentState[channel]);
  }
  digitalWrite(latch,1);
}


It shifts the bits out to the register, so using 0 and 1 in place of LOW and HIGH, still works. I did have it with HIGH and LOW and one point.
Changing it back to HIGH and LOW, showed no change to my problem.

All the shift register is looking for is the clock to go HIGH, then it looks for an incoming BIT, then to have the clock to go LOW again.
and this works.
I am getting Bits shifted out to the register, one bit at a time, exactly as I want it to.
the only issue being, that some how the last bit I enter, ends up at the top of the stack.
ie, the test case of what should be 1000000000000101  is actually output as 0000000000001011

Does the 595 shift register have some sort of wrap around feature I don't know about?
And if so, where is the extra bit, or lack of bit coming into play.

Askkan is suggesting that I should only shift out in 8 bit intervals.
Which would make sense when using the shift out command, But as I am shifting them out one at a time, I don't really see how adding a delay between the first 8 and second 8 could be accomplished, without knowing exactly what the shiftOut command does in between each bunch of 8.

I should mention that, using this one at a time method of sending data to the shift register was  presented elsewhere on this forum.
although I cant seem to find it again. It didn't mention my issue though.


runaway_pancake

1) No, the 595 doesn't have a wrap-around.

2) I pushed some of your code into a function (sub-routine): the_routine
I didn't "change" anything else.

Code: [Select]

int data = 11;
int clock = 12;
int latch = 8;
const int ABCD[] = {2, 3, 4, 5};
int currentState[16] ;
int inputState = 0;
int channel = 0;

void setup()
{
   Serial.begin(9600);
   for (int abcd = 2; abcd < 6; abcd++)
   {
     pinMode(abcd, OUTPUT);
   }
   pinMode(6,INPUT);  //Input
   pinMode(data, OUTPUT);
   pinMode(clock, OUTPUT); 
   pinMode(latch, OUTPUT);
}

void loop()
{
  // iterate over the 16 channels of the multiplexer:
  digitalWrite(latch, 0); 
  for (channel = 0; channel < 16; channel++)
  { 
    addressSet(channel);
    inputState = digitalRead(6);
    if(inputState == 1)                 // reading inputState
    {
      the_routine();
    }
    digitalWrite(clock,HIGH);
    digitalWrite(clock,LOW);
    digitalWrite(data, currentState[channel]);
    Serial.print(currentState[channel]);
  }
  Serial.println("");
  digitalWrite(latch,1);
}

void addressSet (int Channel)
{
  for (int PIN = 0; PIN < 4; PIN++)
  {
    digitalWrite(ABCD[PIN],bitRead(Channel, 3-PIN));
  }
}

void the_routine ()
{
  delay(100); //debounce
  inputState = digitalRead(6);      // reading inputState AGAIN?
  if(inputState == 1)
  {
    if(currentState[channel] == 0)
    {
      currentState[channel] = 1;
    }
    else
    {
      currentState[channel] = 0;
    }
    delay(100);
  }
}


The only time it ever branches into that is when there's a "1" from the digitalRead
Right?
(And even then your're digitalReading - again.)
When the digitalRead != 1 (when it's 0) then it goes on to toggling the clock pin and so on.
Is that how it's supposed to go?


"Who is like unto the beast? who is able to make war with him?"
When all else fails, check your wiring!

Aemornion

Thank you for the reply and my apologies for the delay,
The internet went out for a few days.


I went and looked at the code for shiftout and noticed that it pulses the clock, after it writes the data.
so using code of this form
 
Code: [Select]
   
    digitalWrite(latch, LOW)

for(x=0, x>n,x++){
    digitalWrite(data, BitToWrite);
    digitalWrite(clock,HIGH);
    digitalWrite(clock,LOW);
}

    DigitalWrite(Latch, HIGH)

Seems to work as it should =)

When I found the example before, They had the data being written during the clock pulse.


Now with the shiftIN function.
The code has the data being recieved during the clock pulse.
Perhaps this is where the confusion origionated.
But we will never be sure.


It looks like you came to a similar conclusion, as you have the clock pulse before the data, I think that will still result in an offset, but im unsure.

I like your routine,   I am going to incorporate that method into my code, its alot cleaner.


Thank you all for all your help on this matter.

Go Up