Results 1 to 3 of 3

Thread: Example sketch for MCP23017 GPIO expander

  1. #1
    75+ Posting Member
    Join Date
    Sep 2013
    California, USA

    Example sketch for MCP23017 GPIO expander

    Hi Guys, Here is a sketch for anyone wanting to add some inexpensive I/O to their cockpit. It uses up to eight MCP23017-E/SP GPIO expander chips for a total of 128 possible I/O on the i2c bus. These chips are available from Digikey for under $1.50 each and the 28pin PDIP package fits easily onto a breadboard or Arduino prototype shield.

    /* -----------------------------------------------------------
      /* -----------------------------------------------------------
       This sketch reads and/or writes contacts connected to
       up to 8 MCP23017 GPIO expanders (128 possible contacts) used 
       to monitor cockpit switch position for L2FSX.
       When configured as inputs, the interrupts are used to notify the Arduino, 
       (using pull-up resistors) that a switch has changed position, 
       triggering a data refresh (for that expander only). Switches move
       infrequently, so many switches can be monitored with this 
       technique on a single Arduino with relatively little i2c traffic.
       The MCP23017 can also be used for Outputs, but care must be taken so that
       the i2c communication does not overload.
       The MCP23017 defaults to 0x20 and can be changed by hardwiring at
       device pins A0|A1|A2.
       This code is public domain for use with L2FSX.
       Steve Lutz 5/17/2014
      //MCP23017 registers. Everything except direction defaults to 0)
      #define IODIRA     0x00    // IO direction (0=output, 1=input(default))
      #define IODIRB     0x01
      #define IOPOLA     0x02    // IO polarity (0=normal, 1=inverse)
      #define IOPOLB     0x03
      #define GPINTENA   0x04    // Interrupt on change (0=disable, 1=enable)
      #define GPINTENB   0x05 
      #define DEFVALA    0x06    // If GPINTEN=1 and INTCON=1, this register is used
      #define DEFVALB    0x07    //           to set definition of normal pin states
      #define INTCONA    0x08    // Interrupt control (0=compare to last state
      #define INTCONB    0x09    //                    1=compare to DEFFVAL)
      #define IOCON      0x0A    // IO configuration register( bank/mirror/seqop/disslw/haen/odr/intpol/unused)
      #define GPPUA      0x0C    // Pull-up resistor (0=disabled, 1=enabled)
      #define GPPUB      0x0D 
      #define INFTFA     0x0E    // Interrupt flag (read only)(0=no interrupt pending, 1=Pin caused interrupt)
      #define INFTFB     0x0F 
      #define INTCAPA    0x10    // Interrupt Capture (read only)(value of GPIO at time of interrupt) 
      #define INTCAPB    0x11 
      #define GPIOA      0x12    // Port value (read/write)
      #define GPIOB      0x13
      #define OLLATA     0x14    // Output latch (write)
      #define OLLATB     0x15
      //i2c address of expander device
      #define EXPANDER20 0x20    // MCP23017 on i2c port 0x20
      #define EXPANDER21 0x21    // MCP23017 on i2c port 0x21
      #define EXPANDER22 0x22    // MCP23017 on i2c port 0x22
      #define EXPANDER23 0x23    // MCP23017 on i2c port 0x23
      #define EXPANDER24 0x24    // MCP23017 on i2c port 0x24
      #define EXPANDER25 0x25    // MCP23017 on i2c port 0x25
      #define EXPANDER26 0x26    // MCP23017 on i2c port 0x26
      #define EXPANDER27 0x27    // MCP23017 on i2c port 0x27
      byte mask = 1;
      byte index;
      byte bank1;                  // Variable to store switch condition as bytes
      byte bank2;
      byte bankOut;
      boolean GPIO_A[8][8];           // Array of individual switch positions
      boolean GPIO_B[8][8];
      boolean interrupt20;         // interrupt pin status from MCP23017 at 0x20
      boolean interrupt21;         // interrupt pin status from MCP23017 at 0x21
      boolean interrupt22;         // interrupt pin status from MCP23017 at 0x22
      boolean interrupt23;         // interrupt pin status from MCP23017 at 0x23
      boolean interrupt24;         // interrupt pin status from MCP23017 at 0x24
      boolean interrupt25;         // interrupt pin status from MCP23017 at 0x25
      boolean interrupt26;         // interrupt pin status from MCP23017 at 0x26
      boolean interrupt27;         // interrupt pin status from MCP23017 at 0x27
      boolean out1;                //Digital OUTPUTS of your choice, corresponding
      boolean out2;                //to a single group of lights or other binary
      boolean out3;                //signals wired to one bank of a MCP23017.
      boolean out4,                //rename as necessary
      boolean out5;
      boolean out6;
      boolean out7;
      boolean outTrigger;
      //Turn "outTrigger" ON when L2FSX data has changed so data will be written
      //to the expander.  It resets automatically.
      //DO NOT USE the expander for any data which changes frequently.                              
    void setup(){ 
      pinMode(32,INPUT_PULLUP);      //Interrupt pin assignment for 0x20
      pinMode(33,INPUT_PULLUP);      //Interrupt pin assignment for 0x21 
      pinMode(34,INPUT_PULLUP);      //Interrupt pin assignment for 0x22  
      pinMode(35,INPUT_PULLUP);      //Interrupt pin assignment for 0x23  
      pinMode(36,INPUT_PULLUP);      //Interrupt pin assignment for 0x24  
      pinMode(37,INPUT_PULLUP);      //Interrupt pin assignment for 0x25  
      pinMode(38,INPUT_PULLUP);      //Interrupt pin assignment for 0x26
      pinMode(39,INPUT_PULLUP);      //Interrupt pin assignment for 0x27
      configureExpander(EXPANDER20); //Repeat for every EXPANDER
      configureOutput(EXPANDER20);//add this line for any EXPANDER used as outputs
    }    //end of void setup
    void loop(){
    // ----------------------------------------------
    //  This section reads all 16 inputs from a MCP23017 (ex: EXPANDER20)
    //  and stores the data in an array for further use
    //  ----------------------------------------------
      if(interrupt20==0) {
      }    //end of if
    // -------------------------------------------------------------
    //   Repeat the above "if" statement for each MCP23017 used for inputs
    // -------------------------------------------------------------
    //     Now do something with the data. 
    //     As an example, to obtain the status of "switchAnyName", which has hypothetically
    //     been connected at pin #7(bankB GPB6) on the MCP23017 at address 0x23, you would be 
    //     read the status as follows:
    //          switchAnyName = GPIO_B[6][EXPANDER23];
    //  ------------------------------------------------------------
    //  ------------------------------------------------------------
    //    The next section writes a block of 8 digital outputs to one output bank.
    //    The outputs are labled out1-out8, this example writes to bankA of
    //    a MCP23017 at address 0x27
    //    ----------------------------------------------------------
       expanderWrite(EXPANDER27, GPIOA, bankOut);
       }   // end of if
    }      // end of void loop
    void configureExpander(byte device){
      expanderWrite(device, IOCON, 0b01100100);
      expanderWrite(device, GPINTENA, 0xff);
      expanderWrite(device, GPINTENB, 0xff);
      expanderWrite(device, GPPUA, 0xff);
      expanderWrite(device, GPPUB, 0xff);
    }    //end configureInputs
    void configureOutput(byte device){
      expanderWrite(device, IODIRA, 0x00);
      expanderWrite(device, IODIRB, 0x00);
    }    //end configureOutput
    void expanderRead(int device){
      Wire.beginTransmission (device);
      Wire.write (GPIOA);
      Wire.requestFrom (device, 1);
      bank1= Wire.receive();
      Wire.beginTransmission (device);
      Wire.write (GPIOB);
      Wire.requestFrom (device, 1);
      bank2= Wire.receive(); 
      index = 0;
      for(mask = 00000001; mask>0; mask<<= 1)
          /* mask one bit at a time and check to see which
           switches are closed.
           First GPIO A,  second GPIO B  
          if(bank1 & mask)
            GPIO_A[index][device] = 1;
           else GPIO_A[index][device] = 0; 
          if(bank2 & mask)
            GPIO_B[index][device] = 1;
           else GPIO_B[index][device] = 0; 
          index = index+1;
      }   //end of for(mask)
    //  -----------------------------------------------------
    //    The following Serial.prints will output the bank bytes 
    //    and switch conditions on EXPANDER20 to the serial monitor 
    //    for testing purposes
    //  -----------------------------------------------------
      Serial.print("bank1 = ");
      Serial.println(bank1, BIN);
      Serial.print("bank2 = ");
      Serial.println(bank2, BIN);
      Serial.print("switch01 : ");
      Serial.print("switch02 : ");
      Serial.print("switch03 : ");
      Serial.print("switch04 : ");
      Serial.print("switch05 : ");
      Serial.print("switch06 : ");
      Serial.print("switch07 : ");
      Serial.print("switch08 : ");
      Serial.print("switch09 : ");
      Serial.print("switch10 : ");
      Serial.print("switch11 : ");
      Serial.print("switch12 : ");
      Serial.print("switch13 : ");
      Serial.print("switch14 : ");
      Serial.print("switch15 : ");
      Serial.print("switch16 : ");
    }  //end of void expanderRead
    void expanderWrite (const byte device, const byte reg, const byte data){
      Wire.beginTransmission (device);
      Wire.write (reg);
      Wire.write (data);
      Wire.endTransmission ();
    }    //end of expanderWrite()
    Last edited by SteveL; 05-19-2014 at 04:17 PM. Reason: post correction

  2. #2
    75+ Posting Member
    Join Date
    Sep 2013
    California, USA

    Re: Example sketch for MCP23017 GPIO expander

    I accidentally skipped pasting a few lines in the void expanderRead function when I copied the code to the forum. It has been corrected.

  3. #3
    Our new friend needs to reach 10 posts to get to the next flight level
    Join Date
    May 2015

    Re: Example sketch for MCP23017 GPIO expander

    I've been testing the script out on latest arduino uno but the script is failing with the following errors:

    MCP23017.ino: In function 'void loop()':
    MCP23017.ino:130:86: error: expected ';' before ')' token
    MCP23017.ino: In function 'void expanderRead(int)':
    MCP23017.ino:154:15: error: 'class TwoWire' has no member named 'receive'
    MCP23017.ino:159:15: error: 'class TwoWire' has no member named 'receive'
    Error compiling.