Using interrupt with PCF8574

Hi,
I'm experimenting with the PCF8574 expander and there are a couple of things that I don't understand...
The first one is that it is supposed that for setting the pins as inputs, I should write 1 in all of the bits (PCF_01.write8(0b11111111)).
The fact is that if I don't write this byte the pins still work as inputs.
Any idea why?

The second and more important for me is that, when using Interrupts for triggering the readings (I've connected 8 pushbuttons with PullDown resistors to de 8 pins of the expander), I miss some of the pressings of the buttons and in some cases, if one pin stays in HIGH (let's say pin 3), the rest of the press buttons won't work until I push pin 3 again and leave it in LOW position.
If I do the reading in the LOOP (without using the Interrupts), I read everything without problems but I'd like to make the interruption work.
Can anybody tell me what I'm doing wrong?

This is part of the code. I've removed the part in which I show the status of the byte "pinsContent" through 8 LEDs connected to 8 digital Outputs of Arduino UNO because I'm sure it works fine.

#include <Wire.h>
#include <PCF8574.h>

PCF8574 PCF_01(0x20); // Address PCF8574 for I2C communication.

boolean triggerReading = false;
unsigned long prevMillis = millis();
byte pinsContent = 0;

void ISRoutine() { // In case Interrupt occurs, change the flag
if (millis() > prevMillis + 250) {
triggerReading = true;
prevMillis = millis();
}
}

void setup() {
PCF_01.write8(0b11111111); // Set all expander's pins as INPUTS.

pinMode(2, INPUT_PULLUP); // Set Arduino pin for interrupts.
attachInterrupt(digitalPinToInterrupt(2), ISRoutine, CHANGE); // PCF8574 will interrupt through Pin2 in every change on its pins.
}

void loop() {
// If any pin on PCF9574 has changed:
if (triggerReading) {
triggerReading = false; // Reset the flag for next time you need it.
pinsContent = PCF_01.read8(); // Read the status of the pins on the PCF8574 and store it in "pinsContent".
}
}
delay(100);
}

Para_pregunt_sobre_PCF8675.ino (1.66 KB)

few quick ideas
triggerReading should be volatile
have you taken into account that your switches will bounce for ~ 10-20ms?

iirArduino:
Hi,
I'm experimenting with the PCF8574 expander and there are a couple of things that I don't understand...
The first one is that it is supposed that for setting the pins as inputs, I should write 1 in all of the bits (PCF_01.write8(0b11111111)).
The fact is that if I don't write this byte the pins still work as inputs.
Any idea why?

Because the part is designed to work that way.
I do sympathize because the datasheets are not very clear on this and some of the information that clarifies how the "quasi-bi-directional" pins work is buried down in the specs.
I prefer the NXP datasheet to the TI : https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf
See the section "Quasi-bidirectional I/Os" which describes how the pins work.

Here one very important thing to remember:
When you read the port register, you read the status of the signal on the physical pin - not what you wrote to the port register.
Reads always work regardless of state of any of the bits in the port register.

Additional information about how the bi-directional pins work can be gleamed from looking at the DC/static characteristics table.
If you look closely at IOL and IOH there is the answer.
Note that IOL is 25ma typical but IOH is only 300uA max.

Here is what that means:
The part does not drive the output pin signals both ways. It only sinks it does not drive.
To create a high level output signal on a pin, an internal pullup is turned on.
When you set a bit to one it turns on the pullup resistor for the pin (it does not drive the pin high).

This has some implications.
300uA is not much current, this means that if you want to do something like light up and LED, you must connect the anode side of the LED up to VCC and the cathode side of the LED to the PCF8574 and will set the bit for the pin to low to turn on the LED.
If you try it the other way around, the PCF8574 cannot source enough current to light the LED.

The reason that they say you must set the bit to 1 in order to read, isn't meaning that the mode for the pin changes to input mode but rather if there is an external signal that can be high or low connected to the pin, you don't want the chip driving that pin low - which is what a 0 for the bit would do.
Reads work regardless of whether the bit is set to 0 or 1, but you need the set the bit to 1 to ensure that the extern signal can drive the pin either way.

--- bill

guy_c:
few quick ideas
triggerReading should be volatile
have you taken into account that your switches will bounce for ~ 10-20ms?

You are totally right! I changed to volatile this variable but still doesn't work perfect...
For the debounce I use "prevMillis + 250". The smaller I put the number (i.e, 50 intead of 250), the better I get the readings, but still sometimes une LED gets "stuck".

bperrybap:
Because the part is designed to work that way.
I do sympathize because the datasheets are not very clear on this and some of the information that clarifies how the "quasi-bi-directional" pins work is buried down in the specs.
I prefer the NXP datasheet to the TI : https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf
See the section "Quasi-bidirectional I/Os" which describes how the pins work.

Here one very important thing to remember:
When you read the port register, you read the status of the signal on the physical pin - not what you wrote to the port register.
Reads always work regardless of state of any of the bits in the port register.

Additional information about how the bi-directional pins work can be gleamed from looking at the DC/static characteristics table.
If you look closely at IOL and IOH there is the answer.
Note that IOL is 25ma typical but IOH is only 300uA max.

Here is what that means:
The part does not drive the output pin signals both ways. It only sinks it does not drive.
To create a high level output signal on a pin, an internal pullup is turned on.
When you set a bit to one it turns on the pullup resistor for the pin (it does not drive the pin high).

This has some implications.
300uA is not much current, this means that if you want to do something like light up and LED, you must connect the anode side of the LED up to VCC and the cathode side of the LED to the PCF8574 and will set the bit for the pin to low to turn on the LED.
If you try it the other way around, the PCF8574 cannot source enough current to light the LED.

The reason that they say you must set the bit to 1 in order to read, isn't meaning that the mode for the pin changes to input mode but rather if there is an external signal that can be high or low connected to the pin, you don't want the chip driving that pin low - which is what a 0 for the bit would do.
Reads work regardless of whether the bit is set to 0 or 1, but you need the set the bit to 1 to ensure that the extern signal can drive the pin either way.

--- bill

Thank you so much. Now it's clear to me.