/* PCF8575 over I2C and Wire.h, with no other LIBS
CODE simple as possible
SIMULATION : https://wokwi.com/projects/400225742336659457
MUST TEST ON HARDWARE
-------------NOTES-------------
INPUTS Connection:
Must be SET as HIGH, input action must place the port direct at GND.
OUTPUTS Connection: : can't drive more than 1mA, but can SINK +/- 25mA
So, outputs just can´t work to power but SINKing current
Vcc->LED/RELAY/etc/-> port PCF8575(sink to GND)
can drice MOSFEtS ????
READING:
- Sense all port are connected via Resistor to Vcc, the reading values will be 1,
when a input occours (place the port direct at GND ) the reading values will be 0, to invert
te reading: 1=Presses ( port=GND) and 0=notPressed ( port=Vdd) de "Wire.read" most be INVERTED with "~Wire.read"
- read the first 8 byte P00-P07 and then separated 8 byte P10-P17 maybe doesnt make to must sense,
the time and code that we spend, better read the 16 bits and then check what we need
make sense create a GLOBAl variable with 2 bytes to writte on PCF8575 ??
" volatile uint16_t gpio_writte = 0; ""
Inspered exempes:
https://wokwi.com/projects/405889503258723329
https://www.instructables.com/Using-The-PCF8575-i2c-io-Expander-To-Read-Inputs-/
https://www.youtube.com/watch?v=mXMkgQf3fqU
https://www.geeksforgeeks.org/store-two-numbers-in-one-byte-using-bit-manipulation/
*/
#include <Wire.h>
#define PCF8575_ADDRESS 0x20
#define input 1
#define Sink_on 0 // when it is LOW it will SINK
#define Sink_off 1 // when it is high it will SINK
// STORE all the values to SEND to PCF8575
volatile uint16_t gpio_writte = 0;
void setup() {
Wire.begin();
PCF8575_prepare_all_ports();
Serial.begin(115200);
delay(1000);
}
void loop() {
read_exemple();
writte_exemple();
delay(1000);
}
void writte_exemple(){
Serial.println("Sink_on = LED ON");
PCF8575_prepare_port_state(10,Sink_on);
PCF8575_prepare_port_state(11,Sink_on);
PCF8575_prepare_port_state(12,Sink_on);
PCF8575_prepare_port_state(13,Sink_on);
PCF8575_writte(PCF8575_ADDRESS, gpio_writte);
delay(2000);
Serial.println("Sink_oFF = LED OFF");
PCF8575_prepare_port_state(10,Sink_off);
PCF8575_prepare_port_state(11,Sink_off);
PCF8575_prepare_port_state(12,Sink_off);
PCF8575_prepare_port_state(13,Sink_off);
PCF8575_writte(PCF8575_ADDRESS, gpio_writte);
delay(500);
}
void read_exemple(){
Serial.println("");
uint16_t teste = PCF8575_read_P00_P07(PCF8575_ADDRESS);
//Serial.print("read_P00_P07: ");
//Serial.println(teste);
teste = PCF8575_read_P10_P17(PCF8575_ADDRESS);
//Serial.print("read_P10_P17: ");
// Serial.println(teste);
Serial.println(PCF8575_read_indivual_from_all(teste,2));
teste = PCF8575_read_all(PCF8575_ADDRESS);
//Serial.print("ALL : ");
//Serial.println(teste);
Serial.print("bit : ");
for (uint8_t i = 0; i < 16; i++) {
Serial.print(PCF8575_read_indivual_from_all(teste,i));
(i==7)? Serial.print("_") : Serial.print(",");
}
}
void PCF8575_prepare_port_state(uint8_t port, bool state){
(state==0)? gpio_writte &= ~ (1 << port) : gpio_writte |= (1 << port) ;
}
void PCF8575_prepare_all_ports(){
// Set all PORTS to HIGH = HIGH can read INPUTS - LED are in PULLUP
// since we use PCF8575 as a SINK/conenction the output to ground. all ports must be High
for (uint8_t i = 0; i < 16; i++) {
PCF8575_prepare_port_state(i,1);
//delay(100);
}
PCF8575_writte(PCF8575_ADDRESS, gpio_writte);
}
void PCF8575_writte(uint8_t addr, uint16_t val ){
Wire.beginTransmission(addr);
Wire.write(val & 0xFF); // Low writing 8 bits
Wire.write((val >> 8) & 0xFF); // high writing 8 bits
Wire.endTransmission();
}
uint8_t PCF8575_read_P00_P07(uint8_t addr ) {
Wire.beginTransmission(addr);
Wire.requestFrom(addr, 1);
uint8_t Data_In = ~Wire.read();
Wire.endTransmission();
return Data_In;
}
uint8_t PCF8575_read_P10_P17(uint8_t addr ) {
Wire.beginTransmission(addr);
Wire.requestFrom(addr, 2);
//1st read doenst matter
uint8_t Data_In = Wire.read(); // Read 1 when not "botton" pressed: "~" invert bits
//Serial.print("read_P10_P17 1 : ");
//Serial.println(Data_In);
Data_In = ~Wire.read(); // Read 1 when not "botton" pressed: "~" invert bits
//Serial.print("read_P10_P17 2 : ");
//Serial.println(Data_In);
Wire.endTransmission();
return Data_In;
}
uint16_t PCF8575_read_all(uint8_t addr ) {
uint8_t Data_In_A =0;
uint8_t Data_In_B =0;
Wire.beginTransmission(addr);
Wire.requestFrom(addr, 2);
Data_In_A =~Wire.read(); //
//Serial.print("All 1 : ");
//Serial.println(Data_In_A);
Data_In_B = ~Wire.read(); // Read a uint16_t
//Serial.print("All 2 : ");
//Serial.println(Data_In_B);
Wire.endTransmission();
return (Data_In_B<<8) | (Data_In_A <<0);
}
// From a "value", read a "port_position" specific bit and return as 1(Pressed=port=gnd) or 0(NotPressed=port=Vdd)
bool PCF8575_read_indivual_from_all(uint16_t value, uint8_t port_position ) {
return (value & (1 << port_position));
}
nINT
interrupt indicator
PCF8575
interrupt
indicator