Help with SN74HC166 (Parallel-In Serial-Out)

Good evening everyone,
I need a little help from the community, first of all I’d like to say I am new to Arduino and an incredible fan of flight sims.

I am trying to create a F-16 ICP (it’s basically a buttonbox with about 25 buttons). I am using a Arduino Leonardo so I can use it with Joystick.h library in order to have a simple communication with Windows.

As I am already using analog pins for other stuff I needed something to increase the number of input pins and I found the 74HC166 chip. I bought one on internet and it is Philips based.

DATASHEET HERE

I need this chip to get a serial input on arduino to code every single button that has been pressed and use the pressButton of the Joystick.h library to light it up and send it to windows.

I am having trouble reading the datasheet because I’m quite new to all this. So I would like you to show me what errors I have done in wiring and coding.

Wiring (is it correct?):
LATCH pin #2 (!PE)

CLOCK pin #3 (CP)

DATA pin #4

Vcc to 5V

GND to GND

!MR to 5V

!CE to GND
I’ve put a button on D0 to test if it is working.
Unfortunately on serial monitor everything comes out as 0.

byte switchVar = 0;
#define LATCH 2

#define CLOCK 3

#define DATA 4

void setup()
{
    //Debug
    Serial.begin(115200);
    //Shift register
    digitalWrite(LATCH, OUTPUT);
    digitalWrite(CLOCK, OUTPUT);
    digitalWrite(DATA, INPUT);
}
void loop()
{
byte inputFromICP = 0;
    digitalWrite(LATCH, 1); //Parallel inputs on
    Serial.println("------INPUT PARALLELI ABILITATI");
    digitalWrite(CLOCK, 0); 
    digitalWrite(CLOCK, 1);
    digitalWrite(LATCH, 0); //From parallel input mode to Serial output mode

    for(int j = 0; j < 8; j++) {
      int value = digitalRead(DATA)
      //Debug
      Serial.print("Button pos: ");
      Serial.print(j);
      Serial.print("  Button value: ");
      Serial.println(value);

      if(value) { int a = (1 << j); inputFromICP = inputFromICP | a; } 
      digitalWrite(CLOCK, LOW);
      digitalWrite(CLOCK, HIGH);
    }
    if(switchVar == inputFromICP)
    {
        switchVar = inputFromICP;
        Serial.print("inputFromICP BIN: ");
        Serial.println(inputFromICP, BIN);
    }
    delay(3000);
}

Please use Code Tags </> for presenting code, or it will be garbled as is.

Please retain the chip pin labels in code, e.g. NPE for !PE. I suspect that you confuse shift and load state.

A couple of things.

While you can use the 74HC166 and it is logical - an appropriate function - to do so, it would be more practical to use I2C port expanders such as the PCF8575, available on ready-to-use modules.

Aliexpress item.

Sixteen I/O per module and in general, with good quality switches you should not need pull-ups as the PCF8575 provides weak pull-ups.

Also, two problems with your datasheet link, one is that it refers to one of those crap “alldatasheet” sites which should ideally be blocked from search engines! A proper link is Nexperia. Also, when you post links, please do not click the “Prevent this page from creating additional dialogs” checkbox; this is just a significant nuisance for people trying to follow the links. The fact that you are actually offered this option does tend to mislead and imply that there is some sort of benefit to it; there is not.

Please go and read the forum instructions so that you can go back and modify your original post (not re-post it) - using the “More → Modify” option below the right hand corner of your post - to mark up your code as such using the “</>” icon in the posting window.

Hello, thanks for your help. Oddly it turned out my breadboard was broken somehow and I managed to fix the problem by replacing it. Now the code works if I put it in the loop. And this is the one:

//Debug
    Serial.println("Loop");
    
    byte inputFromICP = 0;
    digitalWrite(LATCH, 0);
    digitalWrite(CLOCK, 0);
    digitalWrite(CLOCK, 1);
    digitalWrite(LATCH, 1);

    for(j = 0; j < 8; j++)
    {
        valueFromSR = digitalRead(DATA);
        if(valueFromSR) 
        {
          int a = (1 << j);
          inputFromICP = inputFromICP | a;
        }
        digitalWrite(CLOCK, LOW);
        digitalWrite(CLOCK, HIGH);
    }
    if(switchVar != inputFromICP)
    {
        switchVar = inputFromICP;

        //Debug
        Serial.print("Button: ");
        Serial.print(inputFromICP, DEC);
        Serial.print("  Binary code: ");
        Serial.println(inputFromICP, BIN);
        Serial.println("-----------------------");
    }

What does not work now is if I put this code with the main code I wrote days ago. Serial monitor just goes: “Loop, Loop…” over and over again, no matter what button connected to my shift register I press. And frankly, it’s driving me crazy.
This is my whole code. I have NO CLUE of what is obstaculating the code to work as planned, I have got the single functions first then put them together and they work fine, the problem appears only when I run the ReadShiftRegisters() function with the rest of the code.

////////////////////////////////////////////////////////
/////                  LIBRARIES
////////////////////////////////////////////////////////
#include <Joystick.h>

////////////////////////////////////////////////////////
/////              DEFINING PINS
////////////////////////////////////////////////////////
int LATCH = 3, CLOCK = 2, DATA = 4;
int dcsX = A2, dcsY = A1, dcsC = 13;      //dcsC: TrackIR Centering
int HUD = A0;
//D7 -> 1 -> 1
//D6 -> 2 -> 10
//D5 -> 4 -> 100
//D4 -> 8 -> 1000
//D3 -> 16 -> 10000
//D2 -> 32 -> 100000
//D1 -> 64 -> 1000000
//D0 -> 128 -> 10000000

////////////////////////////////////////////////////////
/////                VARIABLES
////////////////////////////////////////////////////////
int j, valueFromSR, totalShiftRegisterPins = 8;
int dcsXlast, dcsYlast, HudLastStep = 0, currentStep = 0;
byte switchVar = 0;

////////////////////////////////////////////////////////
/////            JOYSTICK TYPE
////////////////////////////////////////////////////////
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
  7,0,                   
  false, false, false,     
  false, false, false,   
  false, false,          
  false, false, false);  




////////////////////////////////////////////////////////
/////                   SETUP                      /////
////////////////////////////////////////////////////////
void setup() 
{
    //Debug
    Serial.begin(115200);
    //Shift register
    digitalWrite(LATCH, OUTPUT);
    digitalWrite(CLOCK, OUTPUT);
    digitalWrite(DATA, INPUT);
    //Joystick
    pinMode(dcsX, INPUT_PULLUP);
    pinMode(dcsY, INPUT_PULLUP);
    pinMode(dcsC, INPUT_PULLUP);
    //Hud
    pinMode(HUD, INPUT);
    Joystick.begin();
}

////////////////////////////////////////////////////////
/////                   LOOP                       /////
////////////////////////////////////////////////////////
void loop()
{
    ReadShiftRegisters();
    ReadHUD();
    ReadButtons();
    ReadDCSvalues();
    delay(100);
}


////////////////////////////////////////////////////////
/////            READ SHIFT REGISTERS
////////////////////////////////////////////////////////
void ReadShiftRegisters()
{
    //Debug
    Serial.println("Loop");
    
    byte inputFromICP = 0;
    digitalWrite(LATCH, 0);
    digitalWrite(CLOCK, 0);
    digitalWrite(CLOCK, 1);
    digitalWrite(LATCH, 1);

    for(j = 0; j < 8; j++)
    {
        valueFromSR = digitalRead(DATA);
        if(valueFromSR) 
        {
          int a = (1 << j);
          inputFromICP = inputFromICP | a;
        }
        digitalWrite(CLOCK, LOW);
        digitalWrite(CLOCK, HIGH);
    }
    if(switchVar != inputFromICP)
    {
        switchVar = inputFromICP;

        //Debug
        Serial.print("Button: ");
        Serial.print(inputFromICP, DEC);
        Serial.print("  Binary code: ");
        Serial.println(inputFromICP, BIN);
        Serial.println("-----------------------");
    }
}

////////////////////////////////////////////////////////
/////              READ HUD BRIGHTNESS (POTENTIOMETER) (Converted to button)
////////////////////////////////////////////////////////
void ReadHUD()
{
    //Hud light is divided i 6 currentStep: buttons 6 e 7 (5,6) -> currentStep are: 0, 204.6, 409.2, 613.8, 818.6, 1023
    int HudBrtValue = analogRead(HUD);

    //Creating steps
    if(HudBrtValue == 0) { currentStep = 0; }
    if(HudBrtValue > 0 && HudBrtValue < 204.6) { currentStep = 1; }
    if(HudBrtValue > 204.6 && HudBrtValue < 409.2) { currentStep = 2; }
    if(HudBrtValue > 409.2 && HudBrtValue < 613.8) { currentStep = 3; }
    if(HudBrtValue > 613.8 && HudBrtValue < 818.6) { currentStep = 4; }
    if(HudBrtValue > 818.6 && HudBrtValue < 1024) { currentStep = 5; }

    //Coding whether to use brightness up or down
    if(currentStep > HudLastStep) { Joystick.pressButton(5); delay(100); HudLastStep = currentStep; Joystick.releaseButton(5); }
    if(currentStep < HudLastStep) { Joystick.pressButton(6); delay(100); HudLastStep = currentStep; Joystick.releaseButton(6); }
    if(currentStep > HudLastStep) { Joystick.pressButton(5); delay(100); HudLastStep = currentStep; Joystick.releaseButton(5); }
    if(currentStep < HudLastStep) { Joystick.pressButton(6); delay(100); HudLastStep = currentStep; Joystick.releaseButton(6); }
    if(currentStep > HudLastStep) { Joystick.pressButton(5); delay(100); HudLastStep = currentStep; Joystick.releaseButton(5); }
    if(currentStep < HudLastStep) { Joystick.pressButton(6); delay(100); HudLastStep = currentStep; Joystick.releaseButton(6); }
    if(currentStep > HudLastStep) { Joystick.pressButton(5); delay(100); HudLastStep = currentStep; Joystick.releaseButton(5); }
    if(currentStep < HudLastStep) { Joystick.pressButton(6); delay(100); HudLastStep = currentStep; Joystick.releaseButton(6); }
    if(currentStep > HudLastStep) { Joystick.pressButton(5); delay(100); HudLastStep = currentStep; Joystick.releaseButton(5); }
    if(currentStep < HudLastStep) { Joystick.pressButton(6); delay(100); HudLastStep = currentStep; Joystick.releaseButton(6); }
/*
    //Debug
    Serial.print("Trigger val: ");
    Serial.println(HudBrtValue);
    Serial.print("Current step val: ");
    Serial.println(currentStep);
    Serial.print("Last step val: ");
    Serial.println(HudLastStep);*/
}

////////////////////////////////////////////////////////
/////           READ BUTTONS (STRAIGHT TO ARDUINO)
////////////////////////////////////////////////////////
void ReadButtons()
{
    if(digitalRead(dcsC) == HIGH) { Joystick.releaseButton(4); }
    if(digitalRead(dcsC) == LOW) { Joystick.pressButton(4); }
}

////////////////////////////////////////////////////////
/////               READ ANALOG LEFT,RIGHT,UP,DOWN (Converter to button)
////////////////////////////////////////////////////////
void ReadDCSvalues()
{
    int currentX = analogRead(dcsX);
    int currentY = analogRead(dcsY);

    if((currentX > 1000 && currentY > 1000) || (currentX < 50 && currentY < 50) || (currentX > 1000 && currentY < 50) || (currentX < 50 && currentY > 1000))  { dcsXlast = currentX; dcsYlast = currentY; }
    //Avoid to repeat same command if I hold the analog in the same position
    if(currentX != dcsXlast) 
    {
        //Right
        if(currentX > 50) { Joystick.pressButton(1); dcsXlast = currentX; }
        //Left
        if(currentX < 300) { Joystick.pressButton(2); dcsXlast = currentX; }
        //Centre
        if(currentX > 50 && currentX < 1000) { Joystick.releaseButton(1); Joystick.releaseButton(2); dcsXlast = currentX; }
    }
    //Verifico che l'ultimo stato è diverso per evitare di ripetere in loop il comando sull'asse Y
    if(currentY != dcsYlast)
    {
        //Up
        if(currentY > 1000) { Joystick.pressButton(0); dcsYlast = currentY; }
        //Down
        if(currentY < 50) { Joystick.pressButton(3); dcsYlast = currentY; } 
        //Centre
        if(currentY > 50 && currentY < 1000) { Joystick.releaseButton(0); Joystick.releaseButton(3); dcsYlast = currentY; }
    }
}

dfergusson8:

    //Creating steps

if(HudBrtValue == 0) { currentStep = 0; }
   if(HudBrtValue > 0 && HudBrtValue < 204.6) { currentStep = 1; }
   if(HudBrtValue > 204.6 && HudBrtValue < 409.2) { currentStep = 2; }
   if(HudBrtValue > 409.2 && HudBrtValue < 613.8) { currentStep = 3; }
   if(HudBrtValue > 613.8 && HudBrtValue < 818.6) { currentStep = 4; }
   if(HudBrtValue > 818.6 && HudBrtValue < 1024) { currentStep = 5; }

What’s currentStep if HudBrtValue is exactly 204.6 or 409.2 or …?
Better use this model:

    if (HudBrtValue == 0) { currentStep = 0; }
    else if (HudBrtValue < 204.6) { currentStep = 1; }
    else if (HudBrtValue < 409.2) { currentStep = 2; }
    ...

DrDiettrich:
What's currentStep if HudBrtValue is exactly 204.6 or 409.2 or ...?

You're right, did not think about that.
Code corrected, still does not solve my problem though :frowning:

If you latch the inputs with every single bit you only get the MSB repeatedly.

DrDiettrich:
If you latch the inputs with every single bit you only get the MSB repeatedly.

Not quite sure I got 100% of what you're saying but I guess it is correct, when I unpress all the buttons I always get 0 from the 166 to Arduino, that's why I put the if(switchVar != inputFromICP) it gives the possibility to check if something else has been pressed and in that case execute something.

dfergusson8:
Not quite sure I got 100% of what you're saying but I guess it is correct, when I unpress all the buttons I always get 0 from the 166 to Arduino, that's why I put the if(switchVar != inputFromICP) it gives the possibility to check if something else has been pressed and in that case execute something.

My impression of this response, is that you understood 0% of what he said.

aarg:
If you latch the inputs with every single bit you only get the MSB repeatedly.

Nice... I definitely lack of knowledge here. That's why I had to google MSB.
Anyway, I get the MSB and its position which means that the 8 exists will be:

D0 -> 128(dec)
D1 -> 64(dec)
D2 -> 32(dec)
D3 -> 16(dec)
D4 -> 8(dec)
D5 -> 4(dec)
D6 -> 2(dec)
D7 -> 1(dec)

The code itself works just fine, If I press the button connected to D7 Serial monitor shows 1, 2 if I press D6 and so on.. When I put the whole code together no matter what button I press, Serial monitor stays blank.

You're suggesting I should move digitalWrite(LATCH, 0) to the end of the function?

Solved! In the SETUP() I’ve put digitalWrite instead on pinMode. Now it’s all working.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.