user66656: I'm using two of these together to create a single 16bit register which will give me access to 16 outputs. I have gotten them to work but not exactly how I imagined them to work. The code written is for a 18650 cell charger/discharger. The first 6 bits (0-5) of the shift register will be connected to 6 NPNs which will turn on or off each of their tp4056s connected in series. The next 6 bits (5-11) will be connected to 6 different constant current loads. The user selects if they want to charge or discharge their cell and depending on the mode, that particular cell's charger or current sink is turned on (but both not on the same time). In reality, I have to firstly shift 6 bits manually by selecting a mode and then pressing select for all 6 cells in the register for it to show something and even after that it misses bits randomly. btw last 4 bits (12-15) will also get used in the final product. For experimenting, I've connected LEDs to all outputs.
#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>


//initalisation
LiquidCrystal_I2C lcd(0x27, 20, 4);
Encoder encoder(2, 3);

//software constants
const int numOfCells = 6;
const int analogInput[numOfCells] = {A0, A1, A2, A3, A6, A7};
const float arduinoPowerLine = 4.80;
const long interval = 60000; //60 seconds
const char* functions [2] = {"CHARGE   ", "DISCHARGE"}; //mode select array
const int dataPin  = 12;//DS - pin 9
const int latchPin = 11;//ST_CP --pin12
const int clockPin = 8;//SH_CP --pin11

//Encoder setup
long oldPostion = -999;
long newPostion = 0;
long prevPostion;

//making battery arrays and setting their default flags
double batteryVoltage[numOfCells];
bool noBatteryFlag[numOfCells] = {LOW, LOW, LOW, LOW, LOW, LOW}; 
float minimum = 3.00; //Cutoff voltage
float capacity[numOfCells];
 
//mode variables
int modeState[numOfCells];
int confirmedModeState[numOfCells];

//button setup
int inputPin = 5;
int inputState;
int lastInputState = LOW;
int inputFlag = LOW;

//debounce timer
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

//lcd varuables
int currentCell = -1;

//Cell timers
unsigned long prevMillis[numOfCells];
int minute[numOfCells];
unsigned long currentMillis;

//shift resister variables
word outputs = 0B0000000000000000; 


void updateShiftRegister(word bits){//takes bits from the resolvemode function and sets them appropriately
  byte resisterOne  = lowByte(outputs);//right most byte
  byte resisterTwo = highByte(outputs);//left most byte
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterOne); 
  digitalWrite(latchPin, HIGH);
}
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(inputPin, INPUT_PULLUP);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);  
  pinMode(clockPin, OUTPUT);
  updateShiftRegister(outputs);//Resets all shift resister output to LOW
}
void BatteryVoltage(){//reading each cells and converting the adc value into voltage
  for (int i = 0; i < numOfCells; i++){
    int reading = analogRead(analogInput[i]);
    batteryVoltage[i] = (reading * arduinoPowerLine) / 1023;
    //flagging stuff
    if (batteryVoltage[i] <= 0.50) {//checking if a battery is inserted in the holder
    noBatteryFlag[i] = HIGH;
    }else{
      noBatteryFlag[i] = LOW;
    }
  }
}
void ButtonDebounce(){//checking input state and flaggint button
  int reading = digitalRead(inputPin);
  if (reading != lastInputState){
    lastInputState = millis();
  }
  if ((millis() - lastInputState > debounceDelay)){//debouncing button 
    if (reading != inputState){
      inputState = reading;
      if (inputState == HIGH) {
        inputFlag = HIGH;
      }
    }
  }
  lastInputState = reading;
}
void ResolveFlags(){
   if (inputFlag == HIGH){ //incrementing currentscreen 
       if (currentCell == numOfCells - 1){ //if counter at its limit ,it wraps back to the start
        currentCell = 0;
      } else {
        currentCell++;
      }
      confirmedModeState[currentCell] = modeState[currentCell]; //mode selected in stored
      lcd.clear();//clears lab every time button is pressed
        inputFlag = LOW; 
  }
}
void BatteryTimeKeeper(){//keeping track of battery time while it is discharging
for (int i = 0; i < numOfCells; i++){
  if (currentMillis - prevMillis[i] > interval){
    if (noBatteryFlag[i] == LOW){//if a battery is in the holder
      if (batteryVoltage[i] > minimum){//and if it is greater then 3v, it can be discharged
   minute[i]++; 
   prevMillis[i] = currentMillis;
  }
  if (batteryVoltage[i] <= minimum){
    capacity[i] = (minute[i] / 60) * 500; //total time taken divided by 500mA (constant current load)
    minute[i] = 0;
    }
  }
}
    if (noBatteryFlag[i] == HIGH){//if a battery is removed, its timer is reset back to 0
      minute[i] = 0;
    }
  }
}
void EncoderFunctionNavigator(){//tracks encoder
  newPostion = encoder.read();
  if (newPostion != oldPostion){
    oldPostion = newPostion;
  }
  if(prevPostion < newPostion){
    modeState[currentCell]++;
  } else if(prevPostion > newPostion){
    modeState[currentCell]--;
  }
  if (modeState[currentCell] == 2){ //wraps back selection mode
    modeState[currentCell] = 0;
  } else if (modeState[currentCell] < 0){
    modeState[currentCell] = 1;
  }
}
void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}
void PrintScreen(){//printing all the info in lcd
  lcd.home();
  int cellCounter = currentCell + 1; //this is here because I have ocd
  char buffer[25];
  sprintf(buffer, "Cell#:%d    %s", cellCounter, functions[modeState[currentCell]]);
  lcd.print(buffer);
  lcd.setCursor(0, 1);
  lcd.print("VOL:");
  lcd.setCursor(4, 1);
  lcd.print(batteryVoltage[currentCell]);
  lcd.setCursor(0, 2);
  lcd.print("Cap:");
  lcd.setCursor(4, 2);
  lcd.print(capacity[currentCell]);
}
void loop() {
 currentMillis = millis(); //main currentmillis variable
 BatteryVoltage();
 BatteryTimeKeeper();
 ButtonDebounce();
 EncoderFunctionNavigator();
 ResolveFlags();
 PrintScreen(); 
 ResolveMode();
 prevPostion = newPostion; //records the last postion of encoder
}


user42015: To put the comments into an answer:
You are controlling the shift registers in this function
void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}

Since the updateShiftRegister() call is inside the for loop, you are updating the shift registers for every bit, that you set. I guess this is the point, where you get your weird behavior. You don't need to update for every bit. Instead change all needed bits inside the outputs variable, and then at the end of ResolveMode() you can update the registers with all data at once.
So just move updateShiftRegister(outputs); one line down to outside of the for loop.

66656: <p>I'm using two of these together to create a single 16bit register which will give me access to 16 outputs. I have gotten them to work but not exactly how I imagined them to work. The code written is for a 18650 cell charger/discharger. The first 6 bits (0-5) of the shift register will be connected to 6 NPNs which will turn on or off each of their tp4056s connected in series. The next 6 bits (5-11) will be connected to 6 different constant current loads. The user selects if they want to charge or discharge their cell and depending on the mode, that particular cell's charger or current sink is turned on (but both not on the same time). In reality, I have to firstly shift 6 bits manually by selecting a mode and then pressing select for all 6 cells in the register for it to show something and even after that it misses bits randomly. btw last 4 bits (12-15) will also get used in the final product. For experimenting, I've connected LEDs to all outputs.</p>
<pre><code>#include &lt;Arduino.h&gt;
#include &lt;LiquidCrystal_I2C.h&gt;
#include &lt;Encoder.h&gt;


//initalisation
LiquidCrystal_I2C lcd(0x27, 20, 4);
Encoder encoder(2, 3);

//software constants
const int numOfCells = 6;
const int analogInput[numOfCells] = {A0, A1, A2, A3, A6, A7};
const float arduinoPowerLine = 4.80;
const long interval = 60000; //60 seconds
const char* functions [2] = {&quot;CHARGE   &quot;, &quot;DISCHARGE&quot;}; //mode select array
const int dataPin  = 12;//DS - pin 9
const int latchPin = 11;//ST_CP --pin12
const int clockPin = 8;//SH_CP --pin11

//Encoder setup
long oldPostion = -999;
long newPostion = 0;
long prevPostion;

//making battery arrays and setting their default flags
double batteryVoltage[numOfCells];
bool noBatteryFlag[numOfCells] = {LOW, LOW, LOW, LOW, LOW, LOW}; 
float minimum = 3.00; //Cutoff voltage
float capacity[numOfCells];
 
//mode variables
int modeState[numOfCells];
int confirmedModeState[numOfCells];

//button setup
int inputPin = 5;
int inputState;
int lastInputState = LOW;
int inputFlag = LOW;

//debounce timer
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

//lcd varuables
int currentCell = -1;

//Cell timers
unsigned long prevMillis[numOfCells];
int minute[numOfCells];
unsigned long currentMillis;

//shift resister variables
word outputs = 0B0000000000000000; 


void updateShiftRegister(word bits){//takes bits from the resolvemode function and sets them appropriately
  byte resisterOne  = lowByte(outputs);//right most byte
  byte resisterTwo = highByte(outputs);//left most byte
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterOne); 
  digitalWrite(latchPin, HIGH);
}
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(inputPin, INPUT_PULLUP);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);  
  pinMode(clockPin, OUTPUT);
  updateShiftRegister(outputs);//Resets all shift resister output to LOW
}
void BatteryVoltage(){//reading each cells and converting the adc value into voltage
  for (int i = 0; i &lt; numOfCells; i++){
    int reading = analogRead(analogInput[i]);
    batteryVoltage[i] = (reading * arduinoPowerLine) / 1023;
    //flagging stuff
    if (batteryVoltage[i] &lt;= 0.50) {//checking if a battery is inserted in the holder
    noBatteryFlag[i] = HIGH;
    }else{
      noBatteryFlag[i] = LOW;
    }
  }
}
void ButtonDebounce(){//checking input state and flaggint button
  int reading = digitalRead(inputPin);
  if (reading != lastInputState){
    lastInputState = millis();
  }
  if ((millis() - lastInputState &gt; debounceDelay)){//debouncing button 
    if (reading != inputState){
      inputState = reading;
      if (inputState == HIGH) {
        inputFlag = HIGH;
      }
    }
  }
  lastInputState = reading;
}
void ResolveFlags(){
   if (inputFlag == HIGH){ //incrementing currentscreen 
       if (currentCell == numOfCells - 1){ //if counter at its limit ,it wraps back to the start
        currentCell = 0;
      } else {
        currentCell++;
      }
      confirmedModeState[currentCell] = modeState[currentCell]; //mode selected in stored
      lcd.clear();//clears lab every time button is pressed
        inputFlag = LOW; 
  }
}
void BatteryTimeKeeper(){//keeping track of battery time while it is discharging
for (int i = 0; i &lt; numOfCells; i++){
  if (currentMillis - prevMillis[i] &gt; interval){
    if (noBatteryFlag[i] == LOW){//if a battery is in the holder
      if (batteryVoltage[i] &gt; minimum){//and if it is greater then 3v, it can be discharged
   minute[i]++; 
   prevMillis[i] = currentMillis;
  }
  if (batteryVoltage[i] &lt;= minimum){
    capacity[i] = (minute[i] / 60) * 500; //total time taken divided by 500mA (constant current load)
    minute[i] = 0;
    }
  }
}
    if (noBatteryFlag[i] == HIGH){//if a battery is removed, its timer is reset back to 0
      minute[i] = 0;
    }
  }
}
void EncoderFunctionNavigator(){//tracks encoder
  newPostion = encoder.read();
  if (newPostion != oldPostion){
    oldPostion = newPostion;
  }
  if(prevPostion &lt; newPostion){
    modeState[currentCell]++;
  } else if(prevPostion &gt; newPostion){
    modeState[currentCell]--;
  }
  if (modeState[currentCell] == 2){ //wraps back selection mode
    modeState[currentCell] = 0;
  } else if (modeState[currentCell] &lt; 0){
    modeState[currentCell] = 1;
  }
}
void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i &lt; numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) &amp;&amp; bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) &amp;&amp; bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}
void PrintScreen(){//printing all the info in lcd
  lcd.home();
  int cellCounter = currentCell + 1; //this is here because I have ocd
  char buffer[25];
  sprintf(buffer, &quot;Cell#:%d    %s&quot;, cellCounter, functions[modeState[currentCell]]);
  lcd.print(buffer);
  lcd.setCursor(0, 1);
  lcd.print(&quot;VOL:&quot;);
  lcd.setCursor(4, 1);
  lcd.print(batteryVoltage[currentCell]);
  lcd.setCursor(0, 2);
  lcd.print(&quot;Cap:&quot;);
  lcd.setCursor(4, 2);
  lcd.print(capacity[currentCell]);
}
void loop() {
 currentMillis = millis(); //main currentmillis variable
 BatteryVoltage();
 BatteryTimeKeeper();
 ButtonDebounce();
 EncoderFunctionNavigator();
 ResolveFlags();
 PrintScreen(); 
 ResolveMode();
 prevPostion = newPostion; //records the last postion of encoder
}
</code></pre>
 42015: <p>To put the comments into an answer:</p>
<p>You are controlling the shift registers in this function</p>
<pre><code>void ResolveMode(){//sets shift resister output on or off depending on the mode selected
  for (int i = 0; i &lt; numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) &amp;&amp; bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) &amp;&amp; bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}
</code></pre>
<p>Since the <code>updateShiftRegister()</code> call is inside the for loop, you are updating the shift registers for every bit, that you set. I guess this is the point, where you get your weird behavior. You don't need to update for every bit. Instead change all needed bits inside the <code>outputs</code> variable, and then at the end of <code>ResolveMode()</code> you can update the registers with all data at once.</p>
<p>So just move <code>updateShiftRegister(outputs);</code> one line down to outside of the for loop.</p>
