Proton BASIC Compiler - Port expansion using the PCF8574A


  • PicŪ Basic


  • Port expansion using the PCF8574A

    The PCF8574 provides general purpose remote I/O expansion for most microcontroller families via the two-line bidirectional bus (I2C-bus).
    The device consists of an 8-bit quasi-bidirectional port and an I2C-bus interface.
    It also possesses an interrupt line (INT) which can be connected to the interrupt logic of the microcontroller.
    The PCF8574 and PCF8574A versions differ only in their slave address.

    There is not an Interrupt Capture Register for saving the condition that caused the interrupt. It is a big pain.
    Also has not any Configuration register. That's why I tried to create some virtual registry configuration to make living more easy.
    The code described here, attempts to exploit the full potential of the circuit.
    I remember unused commands are not flashed in the PIC(r).

    The number of data bytes transferred between the start and the stop conditions from transmitter to receiver is not limited. But the code written here sends one byte at a time.

    I present two libraries to use with the PCF8574A expander.
    The first library uses hardware MSSP module of the PIC(r). (immovable pins)
    The second library uses a software to create a dialogue on the I2C bus. (configurable pins)
    In both cases the ACK response of the expander is used to verify the proper operation of the I2C bus.

    Define the parameters of the library work.

    Configuration of the Interrogation mode:
    - Define the expander type. Uncomment the line to enable the expander used (PCF8574 or PCF8574A) only one.
    - Define the PCF8574 static address generated at compiler time.
    - Include the file.
    Code:
    '    $define PCF8574
        $define PCF8574A
        $define PCF8574x_Address 0
        Include "PCF8574A-H.Inc"
    Configuration of the Interrupt mode:
    NOTE: The Interrupt mode could be reserved for the advanced users.
    - Define the expander type. Uncomment the line to enable the expander used (PCF8574 or PCF8574A) only one.
    - Define the PCF8574 static address generated at compiler time.
    - Define if interrupt is used for the expander. (uncomment the line to enable the interrupt mode)
    - Define the interrupt PIC pin connected. (uncomment the line to enable the interrupt pin, only one)
    - Define the reading code that it's inside the Interrupt Handler or in main program. (uncomment the line to enable the option)
    - Include the file.
    Code:
    '    $define PCF8574
        $define PCF8574A
        $define PCF8574x_Address 0
        $define _PCF_Interrupt_
    $ifdef _PCF_Interrupt_
     $define _Read_Inside_INT_
        $define _INT0_
    '    $define _INT1_    
    '    $define _INT2_    
    $endif
        Include "PCF8574A-H.Inc"
    For the software library, only change the file: Include "PCF8574A-S.Inc" and define the I2C Bus pins, see the example code.

    COMMANDS:
    Mode READ the PCF8574A:
    Read the expander & loading an external buffer (ReadPCF) & the virtual input PORT returning the I2C acknowledge
    ReadPCF = PCF8574_Read(CheckAck)

    Read the expander & load an external buffer (ReadPCF) & the virtual input PORT.
    ReadPCF = PCF8574_Read()

    Read the expander & load the virtual input PORT returning the I2C acknowledge (CheckAck).
    PCF8574_Read(CheckAck)

    Read the expander & loading the virtual input PORT.
    PCF8574_Read()

    Mode WRITE a Byte to the PCF8574A:
    Set (active 0) the B7- B4 pins returning the I2C acknowledge (CheckAck) & the outputs states (DataOut) & loading the virtual Output PORT.
    DataOut = PCF8574_Write(001111,CheckAck)

    Set (active 0) the B7 - B4 pins returning the I2C acknowledge (CheckAck) & loading the virtual Output PORT.
    PCF8574_Write(001111,CheckAck)

    Set (active 0) the B7 - B4 pins of the expander outputs & load the virtual Output PORT.
    PCF8574_Write(001111)

    Mode WRITE one Pin of the Port to the PCF8574A (If these pins have been defined)
    Set (active 0) the LED1 pin returning the I2C acknowledge (CheckAck) & the outputs states (DataOut).
    DataOut = PCF8574_Write_PinPort(LED1pin,0,CheckAck)

    Set (active 0) the LED1 pin of the expander returning the I2C acknowledge (CheckAck).
    PCF8574_Write_PinPort(LED1pin,0,CheckAck)

    Set (active 0) the LED1 pin of the expander only.
    PCF8574_Write_PinPort(LED1pin,0)

    Clear the LED1 pin returning the I2C acknowledge (CheckAck) & the outputs states (DataOut).
    DataOut = PCF8574_Write_PinPort(LED1pin,1,CheckAck)

    Clear the LED1 pin of the expander returning the I2C acknowledge (CheckAck).
    PCF8574_Write_PinPort(LED1pin,1,CheckAck)

    Clear the LED1 pin of the expander only.
    PCF8574_Write_PinPort(LED1pin,1)

    Mode WRITE & Toggle one Pin of PORT to the PCF8574A:
    Toggle the LED4 pin returning the I2C acknowledge (CheckAck) & the outputs states (DataOut).
    DataOut = PCF8574_Toggle_PinPort(LED4pin,CheckAck)

    Toggle the LED4 pin of the expander returning the I2C acknowledge (CheckAck).
    PCF8574_Toggle_PinPort(LED4pin,CheckAck)

    Toggle the LED4 pin of the expander only.
    PCF8574_Toggle_PinPort(LED4pin)

    Problems of the expander:
    Write can modify read or block an input if an error position bit has occurred.
    The interrupt mode is specific problem of the PCF8574A expander. Every change of an input triggers an interrupt.
    Every write to the PORT triggers an interrupt.
    Very short input pulse cannot be read because the large delay of the I2C bus and the double interrupt output.

    Special features:
    To configure the expander one shadow register is created to simulate the 'Direction' register (inputs/outputs)
    This register avoids writing to the inputs and presents the bits of the inputs and outputs separately.
    To avoid writing to the PORT can trigger an interrupt, the INTx Interrupt Enable is disabled before write and enabled again after write.
    To avoid the problem of the short input pulse, the INTxIE (Interrupt Enable) is disabled inside the Interrupt Handler until the PORT has been read. The INTxIE is set again in the main program. (see the code example)

    CONCLUSION:
    Using the PCF8574A expander in interrupt mode is very difficult. The Interrupt mode could be reserved for the advanced users.
    Using the I2C bus with highest speed as possible can help working with the interrupt mode.
    The software library use the file 'Software_I2C.Inc' written by Les Johnson because it is the same structure as the HBUSOUT/HBUSIN commands. This file has been modified so please save your original file.

    Amicus18 Hardware:
    The codes have been tested with the Amicus18 Board with the PIC18F25K20 (+3.3v) and the PIC18F25K22 (+5.0v), and are working with succes.

    Testing: mantain one input to low level.
    An important test was to activate one input to a low level and try to trigger the interrupt output with the remaining inputs: The test is satisfactory.

    Alberto Freixanet
    Updated 02/04/2015
    Update the config fuses and modify the test program.
    PCF8574A-H.zip
    PCF8574A-S.zip