Rotary Encoder With PCF8574 or 74HC165

i am attempting to read the below 7 way switch. its 5 buttons and an encoder. what is interesting about the encoder is that every "valley" the output switches from high/low. if A/B outputs are high then you click it once, both outputs drop low. they do not blip high then back low. They also bounce at minimum 1 each channel.

my issue is with the encoder outputs. my code is below for both types of i/o expander. i am constantly missing values or double counting. i know the 74HC165 isn't the best to use for encoders but honestly it works better than the PCF8574 even when using the interrupt pin on the PCF8574.

the end goal of this is to send the encoder direction to a PC as a button command. i prefer not to use the interrupts on the arduino because i have at least 4 encoders to read. i am using the pro micro that only has 5 interrupts. i can put multiple encoders on the same interrupts but will i have the same issues of delay that i am having with the 8574/74HC165?

the 74HC165 schematic is attached.

The PCF8574 is on a breakout and SDA/SLA are attached to pins 2 and 3 on the pro micro and have 10k pull up resistors. interrupt from the breakout goes to pin 7 on the pro micro.

PCF8574 Code

#include <PCF8574.h>
#include <Wire.h>
#include <Joystick.h>
Joystick_ Joystick;
PCF8574 pcf20(0x20);
int interruptPin = 7;
//int button[8];
int button1[8];
unsigned long timer1;
unsigned long time1 = 0;
unsigned long time2 = 1000;
int counter = 0;
volatile bool flag = false;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pcf20.begin();
  pinMode(7, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), buttonpress, RISING);

  Joystick.begin();

}
int input;

void loop() {
  if (flag == 1 && timer1 > 100) {
    flag = 0;
//    counter++;
    for (int i = 0; i <= 7; i++) {
      button1[i] = pcf20.readButton(i);
      Serial.print(button1[i]);
    }
    Serial.println("");
    Serial.print(" ");
    Serial.print(timer1);
    Serial.println("");
  }
  Serial.print("outside   ");
  Serial.println(counter);
}

void buttonpress() {
  flag = 1;
  time1 = time2;
  time2 = millis();
  timer1 = time2 - time1; // i know youre to do minimum amount of things in the ISR but it didnt seem to be entering correctly so i am debugging with this code
  if (timer1 > 100) {
    Serial.println(counter);
    counter++;
  }
}

74HC165 Code

#include <SPI.h>
#include <Joystick.h>
Joystick_ Joystick;
#define NUMBER_OF_SHIFT_CHIPS   3
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8
#define PULSE_WIDTH_USEC   5
#define POLL_DELAY_MSEC   1
#define BYTES_VAL_T unsigned int
int ploadPin        = 8;  // GREEN Connects to Parallel load pin the 165
int clockEnablePin  = 15;  // ORANGE Connects to Clock Enable pin the 165
int dataPin         = 14; // WHITE Connects to the Q7 pin the 165
int clockPin        = 9; // BLUE Connects to the Clock pin the 165
BYTES_VAL_T pinValues;
BYTES_VAL_T oldPinValues;
int bitVal[DATA_WIDTH];
int flag = 0;
int enc1A = 12;
int enc1B = 13;
int enc1Aval = 0;
int enc1Bval = 0;
int enc1Avalold = 0;
int enc1Bvalold = 0;
void setup()
{
  Serial.begin(9600);
  delay(5000);
  pinMode(ploadPin, OUTPUT);
  pinMode(clockEnablePin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, INPUT);
  digitalWrite(clockPin, LOW);
  digitalWrite(ploadPin, HIGH);
  Serial.print("test");
  long bitVal[DATA_WIDTH];
  BYTES_VAL_T bytesVal = 0;
  Joystick.begin();
}
void loop()
{

  read_shift_regs();
  delay(POLL_DELAY_MSEC);

}
BYTES_VAL_T read_shift_regs()
{
  BYTES_VAL_T bytesVal = 0;
  digitalWrite(clockEnablePin, HIGH);
  digitalWrite(ploadPin, LOW);
  delayMicroseconds(PULSE_WIDTH_USEC);
  digitalWrite(ploadPin, HIGH);
  digitalWrite(clockEnablePin, LOW);


  for (int i = 0; i < DATA_WIDTH; i++)
  {
    bitVal[i] = digitalRead(dataPin);
    bytesVal |= (bitVal[i] << ((DATA_WIDTH - 1) - i));
    digitalWrite(clockPin, HIGH);
    delayMicroseconds(PULSE_WIDTH_USEC);
    digitalWrite(clockPin, LOW);

    if (i == enc1A) {
      enc1Avalold = enc1Aval; // grabs old and new value of the encoder states to later determine if they have changed thus the encoder having been rotated
      bitVal[i] = enc1Aval; // grabs old and new value of the encoder states to later determine if they have changed thus the encoder having been rotated
    }
    if (i == enc1B) {
      enc1Bvalold = enc1Bval; // grabs old and new value of the encoder states to later determine if they have changed thus the encoder having been rotated
      bitVal[i] = enc1Bval; // grabs old and new value of the encoder states to later determine if they have changed thus the encoder having been rotated
    }
  }

  for (int i = 0; i < DATA_WIDTH; i++) {
    if (bitVal[i] == 1 && i != enc1A & i != enc1B) { // changes other buttons output to PC if they are NOT the encoder outputs. this code works well as intented
      Joystick.setButton(i, 1);
    }
    if (bitVal[i] == 0 && i != enc1A & i != enc1B) { // sets output back to 0 once button is released. this code works well as intented.
      Joystick.setButton(i, 0);
    }

    if (enc1Aval != enc1Avalold) { // this code doesn't work well. i am not even trying to debounce at all yet.
      Joystick.setButton(enc1A, 1);
      delay(1000);
      Joystick.setButton(enc1A, 0);
    }
  }
  Serial.print(enc1Aval);
  Serial.print(enc1Avalold);
  return (bytesVal);
}

74HC165_Reduced.ino (3 KB)

pcf8574code.ino (1.2 KB)

Well if you post your sketch within </> code tags and add a circuit diagram (not fritzing !) we can have a look.

updated original post with the code.

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