I have been working on trying to solve this for over 8 hours, I am stuck. I think it's quite simple but I am not seeing it. My project is over 1000 lines (so far), so I have made a test example to keep this simple.
I have two PCF8575's operating on a single channel of i2c on a ESP32. Because of the complexity and scope of the project, I really need to be able to define the pins on one of the pcf8575's listed as "pcf8575D" in the example as integers.
The example code communicates well with both chips, but does not blink the "pfc8575D" - instead it only outputs a HIGH signal. It does however blink the "pcf8575". I have narrowed to problem down to the int functions - when deleted and the loop rewritten as it is for the "pcf8575" it works fine.
What am I doing wrong? How can I get the pin definitions to work?
What value do you think is written to the RelayL1 constant?
digitalWrite(RelayL1, LOW);
This definitely doesn't do what you probably expect it to do. digitalWrite() is only used for the onboard pins. You can never use it to set any of the pins on the PCF8575s. To set them you have to use the method (of the same name) of the corresponding objects.
Define abstract numbers for these pins and use a own function to decode them.
I think that makes sense to me. From the overall project viewpoint it may be too complicated to reasonably implement (I would guess it would add 200-300 more lines of code since I will be using about 30 of the pins) - and it shows me why many people just setup multiple Arduino's when they need more pins.
I may just call out every instance individually instead since that does seem to work, such as:
pcf8575.digitalWrite(P0, HIGH);
But I wonder why this works as long as an integer is not used, must be in the PCF8575.h library?
From the overall project viewpoint it may be too complicated to reasonably implement (I would guess it would add 200-300 more lines of code since I will be using about 30 of the pins) - and it shows me why many people just setup multiple Arduino's when they need more pins.
I don't understand. I implemented the whole stuff in under 10 lines. Even if you add 30 constant definitions for the pins that about 40 lines in all. Where's the problem?
But I wonder why this works as long as an integer is not used, must be in the PCF8575.h library?
What's the relation between that and an integer? You must be confused by something but I didn't find out yet what that is.
const int RelayL1 = (pcf8575D, 0);
const int RelayL2 = (pcf8575D, P5);
These statements should be showing at least a warning in the compiler, because they are not valid. You are telling the compiler to set an integer to two numbers separated by a comma, which it doesn't know what to do with, so it just ignores one of the numbers.
A slightly different technique, that uses a single byte to store which pcf8575 the port is located on along with the pin number, then uses a function to write to the correct port, with no need for a separate if statement for each pin:
#include "PCF8575.h"
// Set i2c address
PCF8575 pcf8575(0x20), pcf8575D(0x22);
const byte pcf_8575 = B10000000; //value used to indicate pin is on pcf8575
const byte pcf_8575D = B11000000; //value used to indicate pin is on pcf8575D
//can define up to 8 pcf8575 chips with values from B10000000 through B11110000
const byte RelayL1 = (pcf_8575D + P0); //defines pin and pcf8575 chip used for RelayL1
const byte RelayL2 = (pcf_8575D + P5);
void pcfDigitalWrite(byte pcfNpin, byte data) {
//function to write data to either arduino port or one of several pcf8575 chips
//if pcfNpin does not specify a pcf8575 port expander then port is on the arduino
const byte pcfMask = B11110000; //masks off pcf part of pcfNpin
const byte pinMask = B00001111; //masks off pin part of pcfNpin
if ((pcfNpin & pcfMask) == pcf_8575) {
pcf8575.digitalWrite((pcfNpin & pinMask), data);
} else if ((pcfNpin & pcfMask) == pcf_8575D) {
pcf8575D.digitalWrite((pcfNpin & pinMask), data);
} else {
digitalWrite(pcfNpin, data);
}
}
void setup()
{
Serial.begin(115200);
//Set pinMode to OUTPUT
pcf8575.pinMode(P0, OUTPUT);
pcf8575D.pinMode(P0, OUTPUT);
pcf8575D.pinMode(P1, OUTPUT);
pcf8575D.pinMode(P5, OUTPUT);
pcf8575.begin();
pcf8575D.begin();
}
void loop()
{
pcf8575.digitalWrite(P0, HIGH);
delay(1000);
pcf8575.digitalWrite(P0, LOW);
delay(1000);
pcfDigitalWrite(RelayL1, HIGH);
delay(1000);
pcfDigitalWrite(RelayL1, LOW);
delay(1000);
pcfDigitalWrite(RelayL2, HIGH);
delay(1000);
pcfDigitalWrite(RelayL2, LOW);
delay(1000);
}
Thank you for taking the time to write out the code and explain how it works in detail. I had seen the byte method before but did not know how to make it function without writing to every pin - the mask(s) makes sense and it solves the problem.
I uploaded your code and it works perfect. Now I just need to add the remaining pins and integrate it with my program.
My wiring and design skills are significantly stronger then my Arduino IDE abilities - so I really appreciate both your effort and pylon's to try and walk me through it. I am learning but at a slower rate then my projects growth.
david_2018:
You are telling the compiler to set an integer to two numbers separated by a comma, which it doesn't know what to do with, so it just ignores one of the numbers.
The compiler totally knows what to do with this: the C language "comma" operator is a thing.
These statements should be showing at least a warning in the compiler, because they are not valid. You are telling the compiler to set an integer to two numbers separated by a comma, which it doesn't know what to do with, so it just ignores one of the numbers.
Not so. The compiler knows EXACTLY what to do with it, since the comma IS a valid operator. Google "c comma operator". But, while it absolutely WILL compile without error, ,it will absolutely NOT do anything remotely useful in this case.
RayLivingston:
Not so. The compiler knows EXACTLY what to do with it, since the comma IS a valid operator. Google "c comma operator". But, while it absolutely WILL compile without error, ,it will absolutely NOT do anything remotely useful in this case.
Regards,
Ray L.
I obviously could have phrased that better. The compiler does generate a warning message if you have the compiler warnings turned on, but warnings do not stop a successful compilation.
/home/defaultuser/Arduino/sketch_feb18a/sketch_feb18a.ino:6:32: warning: left operand of comma operator has no effect [-Wunused-value]
const int RelayL1 = (pcf8575D, 0);
^