This project uses two PCF8574 i2c devices to visually echo the state of a bank of 8 digital Inputs to a bank of 8 digital Outputs.
It is easy to omit either the Inputs or Outputs if not needed, and easy to add additional banks of Inputs and/or Outputs if wished.
An i2c scanner subroutine is included for convenience, allowing easy confirmation of device availability and appropriate addresses.
The 'tombstone' jumper links on the blue type of module allow changing its address from (decimal) 32 all '-', to 39 all '+'.
The switches on the red type module allows changing address from 56 with all switches Off, to 63 with all switches On.
I was using PCF8574a_address = 32 as Input and PCF8574b_address = 33 as Output, so change/add/remove to suit your circumstances.
TIP: The address jumpers connect the address lines to either +v or 0v, so the unused accessible pins can be used as handy +v and 0v supplies.
Input changes trigger an interrupt-driven event handler to ensure changes are not 'blocked' or missed, and the periodic timer makes sure.
The 'changed' event-handler reads the first device Inputs and echoes them to the second's Outputs, so this is where you tailor to your needs.
The status of each of the individual ports is stored in the variables p0 to p7 for the onscreen LEDs, so can be used for your own control purposes.
If you add more modules, duplicate the relevant code for each additional device, and assign a separate interrupt pin for any used as Inputs.
Inputs are normally pulled high by internal pullups, therefore are active low when shorted to ground (like the gpio00 'flashing' button).
If your Output LEDs are normally On and going Off when selected, the variable outputV can be changed to make them normally Off going On.
Basic:
' Multi-IO
i2c.setup 4, 5 'i2c RX and TX pins need to be configured as appropriate
'goto i2cscanner 'uncomment to use i2c scanner
PCF8574a_address = 32 'set to first module i2c address - here used as active low inputs
PCF8574b_address = 33 'set to second module i2c address - used here as active high outputs
outputV = 1 'output logic - 0=active low, 1=active high
inputIRQ = 13 'interrupt trigger from pcf8574 'INT' pin
pin.mode inputIRQ, input, pullup
interrupt inputIRQ, changed
'the next line sets all ports of the specified device as inputs
PCF8574a_write 255
p0=1: p1=1: p2=1: p3=1: p4=1: p5=1: p6=1: p7=1
x = 0
r = 0
print "started"
wlog "started"
'the next lines echoes the input ports of the first device to the output ports of the second device
PCF8574a_read r
if outputV = 1 then r = r XOR 255
PCF8574b_write rtimer0 1000, changedgosub paintonhtmlreload paintwaitchanged:if pin(inputIRQ) = 0 then print "changed" wlog "changed" PCF8574a_read r if outputV = 1 then r = r XOR 255 Print r wlog str$(r) PCF8574b_write r showleds r endifreturnsub showleds x'p0 to p7 represent the status of each of the individual input ports p0 = x AND 1p1 = x AND 2p2 = x AND 4p3 = x AND 8p4 = x AND 16p5 = x AND 32p6 = x AND 64p7 = x AND 128refreshend subsub PCF8574a_write(x) i2c.begin PCF8574a_address i2c.write x i2c.endend subsub PCF8574b_write(x) i2c.begin PCF8574b_address i2c.write x i2c.endend subsub PCF8574a_read(x) i2c.begin PCF8574a_address i2c.reqfrom PCF8574a_address, 1 x = i2c.read i2c.endend subsub PCF8574b_read(x) i2c.begin PCF8574b_address i2c.reqfrom PCF8574b_address, 1 x = i2c.read i2c.endend subpaint:clsa$ = ""a$ = a$ + led$(p0)a$ = a$ + led$(p1)a$ = a$ + led$(p2)a$ = a$ + led$(p3)a$ = a$ + led$(p4)a$ = a$ + led$(p5)a$ = a$ + led$(p6)a$ = a$ + led$(p7) + "<br>"html a$returni2cscanner:wlog "Scanning for i2c devices..."for c = 1 to 126 i2c.begin c if i2c.end = 0 then wlog "found " + str$(c) + string$(5," ") + hex$(c) pause 50 end ifnext cwlog "Finished"endreturn'-------------------- End --------------------
This is a supplementary addition from litronic for the 16 port PCF 8575 module (not tried myself because don't have modules yet).
Basic:
'goto i2cscanner
let OBLED = 2 'onboard LED
'PCF8575 I2C pins
let SCL = 5 'D1
let SDA = 4 'D2
'let IRQ = 3 'RX
let IRQ = 14 'D5
i2c.setup SDA, SCL
let PCF8575_address = 32
pin.mode IRQ, input, pullup
interrupt IRQ, changed
p00=1: p01=1: p02=1: p03=1: p04=1: p05=1: p06=1: p07=1
p10=1: p11=1: p12=1: p13=1: p14=1: p15=1: p16=1: p17=1
let o = 255
let i = 255
PCF8575_write o, i ' input and output active low' ESPbreath initpin.mode OBLED, outputpin(OBLED) = 0let pwmdc = 0let maxdc = 1000let stepdc = 20timer0 20, ESPbreathgosub paintonhtmlreload paintwaitESPbreath: pwm(OBLED) = pwmdc let pwmdc = pwmdc + stepdc if pwmdc = maxdc or pwmdc = 0 then stepdc = -stepdc returnchanged: if pin(IRQ) = 0 then PCF8575_read o, i wlog "changed P1x: " + str$(i) PCF8575_write i, 255 ' inputs transferred to P00..P07 showleds i, i endifreturnsub showleds(x,y) 'p00 to p17 represent the status of each of the individual input ports p00 = x AND 1 p01 = x AND 2 p02 = x AND 4 p03 = x AND 8 p04 = x AND 16 p05 = x AND 32 p06 = x AND 64 p07 = x AND 128 p10 = y AND 1 p11 = y AND 2 p12 = y AND 4 p13 = y AND 8 p14 = y AND 16 p15 = y AND 32 p16 = y AND 64 p17 = y AND 128 refreshend subsub PCF8575_write(x,y) i2c.begin PCF8575_address i2c.write x i2c.write y i2c.endend subsub PCF8575_read(x,y) i2c.begin PCF8575_address i2c.reqfrom PCF8575_address, 2 x = i2c.read y = i2c.read i2c.endend subpaint: cls a$ = "PCF8575 TEST 3/3/2020<br>" a$ = a$ + "<br> P00 P01 P02 P03 P04 P05 P06 P07 -> Inputs<br>" a$ = a$ + led$(p00) a$ = a$ + led$(p01) a$ = a$ + led$(p02) a$ = a$ + led$(p03) a$ = a$ + led$(p04) a$ = a$ + led$(p05) a$ = a$ + led$(p06) a$ = a$ + led$(p07) + "<br>" a$ = a$ + "<br> P10 P11 P12 P13 P14 P15 P16 P17 -> Outputs<br>" a$ = a$ + led$(p10) a$ = a$ + led$(p11) a$ = a$ + led$(p12) a$ = a$ + led$(p13) a$ = a$ + led$(p14) a$ = a$ + led$(p15) a$ = a$ + led$(p16) a$ = a$ + led$(p17) + "<br>" html a$returni2cscanner: wlog "Scanning for i2c devices..." for c = 1 to 126 i2c.begin c if i2c.end = 0 then wlog "found DEC:" + str$(c) + " HEX:" + hex$(c) pause 50 end if next c wlog "Finished"end