Project - Multi-IO

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 r
timer0 1000, changed
gosub paint
onhtmlreload paint
wait

changed:
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
 endif
return

sub showleds x
'p0 to p7 represent the status of each of the individual input ports
p0 = x AND 1
p1 = x AND 2
p2 = x AND 4
p3 = x AND 8
p4 = x AND 16
p5 = x AND 32
p6 = x AND 64
p7 = x AND 128
refresh
end sub

sub PCF8574a_write(x)
 i2c.begin PCF8574a_address
 i2c.write x
 i2c.end
end sub

sub PCF8574b_write(x)
 i2c.begin PCF8574b_address
 i2c.write x
 i2c.end
end sub

sub PCF8574a_read(x)
 i2c.begin PCF8574a_address
 i2c.reqfrom PCF8574a_address, 1
 x = i2c.read
 i2c.end
end sub

sub PCF8574b_read(x)
 i2c.begin PCF8574b_address
 i2c.reqfrom PCF8574b_address, 1
 x = i2c.read
 i2c.end
end sub

paint:
cls
a$ = ""
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$
return

i2cscanner:
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 if
next c
wlog "Finished"
end
return

'-------------------- 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 init
pin.mode OBLED, output
pin(OBLED) = 0
let pwmdc = 0
let maxdc = 1000
let stepdc = 20
timer0 20, ESPbreath



gosub paint
onhtmlreload paint

wait


ESPbreath:
  pwm(OBLED) = pwmdc
  let pwmdc = pwmdc + stepdc
  if pwmdc = maxdc or pwmdc = 0 then stepdc = -stepdc  
return


changed:
  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
  endif
return

sub 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
  refresh
end sub

sub PCF8575_write(x,y)
  i2c.begin PCF8575_address
  i2c.write x
  i2c.write y
  i2c.end
end sub

sub PCF8575_read(x,y)
  i2c.begin PCF8575_address
  i2c.reqfrom PCF8575_address, 2
  x = i2c.read
  y = i2c.read
  i2c.end
end sub

paint:
  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$
return

i2cscanner:
  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