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 |