// MCP23017 - General Simple Subroutines
// for initialising, reading, writing to ports
// and setting of interrupts
// Written by : Rod McMahon
// Written : 26 May 2022
// Thanks to Nick Gammon
//----------------------------------------------------------------------
#include <Wire.h>
//MCP23017 General
uint8_t PortAState; // Used for setting and storing output states
uint8_t PortBState; // Used for setting and storing output states
// MCP23017 registers (everything except direction defaults to 0)
// Thanks to Nick Gammon
#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 // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB 0x07
#define INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB 0x09
#define IOCONA 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
#define IOCONB 0x0B
#define GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB 0x0D
#define INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB 0x0F
#define INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB 0x11
#define GPIOA 0x12 // Port value. Write to change, read to obtain value
#define GPIOB 0x13
#define OLLATA 0x14 // Output latch. Write to latch output.
#define OLLATB 0x15
//--------------------------------------------------
// Writes Data to Register in MCPAdd
//--------------------------------------------------
void MCPWrite(uint8_t MCPAdd,uint8_t Reg, uint8_t Data)
{
Wire.beginTransmission(MCPAdd);
Wire.write(Reg);
Wire.write(Data);
Wire.endTransmission();
}
//--------------------------------------------------
//Reads data from Register in MCPAdd
//--------------------------------------------------
uint8_t MCPRead(int MCPAdd, uint8_t Reg)
{
Wire.beginTransmission(MCPAdd);
Wire.write(Reg); //Sets address to Port B
Wire.endTransmission();
Wire.requestFrom(MCPAdd,1,true); //Gets one uint8_t from register, stops request message
return Wire.read(); //Reads in the uint8_t
}
//--------------------------------------------------
// Initialises the two IOPorts on MCPAdd
// Ports are labelled "Input" or "Output"
// IOPOLA and GPPUA can be deteted or others added
//----------------------------------------------------
void MCPInitialize(uint8_t MCPAdd,String IOPortAType,String IOPortBType)
{
if(IOPortAType =="Input")
{
MCPWrite(MCPAdd, IODIRA,0xFF); // IODIRA set all of bank A to Inputs
MCPWrite(MCPAdd, IOPOLA,0xFF); // IOPOLA Invert all Inputs
MCPWrite(MCPAdd, GPPUA, 0xFF); // GPPUA set all of bank A Pull Ups
}
if(IOPortAType =="Output")
MCPWrite(MCPAdd, IODIRA,0x00); // IODIRA set all of bank A to Outputs
if(IOPortBType =="Input")
{
MCPWrite(MCPAdd, IODIRB,0xFF); // IODIRB set all of bank B to Inputs
MCPWrite(MCPAdd, IOPOLB,0xFF); // IOPOLB Invert all Inputs
MCPWrite(MCPAdd, GPPUB, 0xFF); // GPPUB set all of bank B Pull Ups
}
if(IOPortBType =="Output")
MCPWrite(MCPAdd, IODIRB,0x00); // IODIRB set all of bank B to Outputs
}
//-------------------------------------------------
// Sets or clears one output of an IOPort on MCPAdd
// Port_x_State is a global variable so each IO change
// does not loose the other output states
// Pin Number = 0 to 7
// Value
//-------------------------------------------------
void MCPSetOutput(uint8_t MCPAdd,uint8_t IOPort,uint8_t PinNumber,boolean Value)
{
if (IOPort == GPIOA )
{
if (Value = true)
PortAState = bitSet(PortAState,PinNumber); // Sets the bit in PortAState
else
PortAState = bitClear(PortAState,PinNumber); // Clears the bit in PortAState
MCPWrite(MCPAdd,GPIOA,PortAState);
}
if (IOPort == GPIOB)
{
if (Value = true)
PortBState = bitSet(PortBState,PinNumber);
else
PortBState = bitClear(PortBState,PinNumber);
MCPWrite(MCPAdd,GPIOB,PortBState);
}
}
//-------------------------------------------------
// Sets interrupt for Change only
// not for reference to DEVAL
// Interrupt pin set normally High
// Uses the default that INTCON register is 0x00
//-------------------------------------------------
void MCPSetIntChange(uint8_t MCPAdd,uint8_t IOPort)
{
uint8_t ClearInt;
if (IOPort == GPIOA)
{
MCPWrite(MCPAdd,GPINTENA,0xFF); // GPINTENA Interrupt all IO on change
MCPWrite(MCPAdd,IOCONA, 0b00000010); // Interrupt pin normally High
ClearInt = MCPRead(MCPAdd, INTCAPA); // Reads to clear interrupt
}
if (IOPort == GPIOB)
{
MCPWrite(MCPAdd,GPINTENB,0xFF); // GPINTENB Interrupt all IO on change
MCPWrite(MCPAdd,IOCONB, 0b00000010); // Interrupt pin normally High
ClearInt = MCPRead(MCPAdd, INTCAPB); // Reads to clear interrupt
}
}
//-------------------------------------------------
// Sets interrupt for difference to DEVAL
// Interrupt pin set normally High
// IntConState determines which pin is compared to the values in DEFVAL
// DefvalState defines the state that the pin is compared against
// GPINTEN can be masked so only some pins change on interrupt
//-------------------------------------------------
void MCPSetIntDefvalChange(uint8_t MCPAdd,uint8_t IOPort, uint8_t IntConSet, uint8_t DefvalSet)
{
uint8_t ClearInt;
if (IOPort == GPIOA)
{
MCPWrite(MCPAdd,GPINTENA,0xFF); // GPINTENA Interrupt all IO on change
MCPWrite(MCPAdd,IOCONA, 0b00000010); // Interrupt pin normally High
MCPWrite(MCPAdd,INTCONA,IntConSet); // Determines which pins are compared to DEVALA
MCPWrite(MCPAdd,DEFVALA,DefvalSet); // Mask for DEFVALA
ClearInt = MCPRead(MCPAdd, INTCAPA); // Reads to clear interrupt
}
if (IOPort == GPIOB)
{
MCPWrite(MCPAdd,GPINTENB,0xFF); // GPINTENA Interrupt all IO on change
MCPWrite(MCPAdd,IOCONB, 0b00000010); // Interrupt pin normally High
MCPWrite(MCPAdd,INTCONB,IntConSet); // Determines which pins are compared to DEVALA
MCPWrite(MCPAdd,DEFVALB,DefvalSet); // Mask for DEFVALA
ClearInt = MCPRead(MCPAdd, INTCAPB); // Reads to clear interrupt
}
}
//-------------------------------------------------
// Reads the interrupt flag
// Should be called after every interrupt detected
// 1= input that caused interrupt
// This also resets interrupts
//-------------------------------------------------
uint8_t MCPReadInterrupt(uint8_t MCPAdd,uint8_t IOPort)
{
if (IOPort == GPIOA)
return MCPRead(MCPAdd, INTCAPA);
if (IOPort == GPIOB)
return MCPRead(MCPAdd, INTCAPB);
}
//-------------------------------------------------
//Turns ON all of the outputs of a IOPort
//-------------------------------------------------
void MCPPortAllOn(uint8_t MCPAdd,uint8_t IOPort)
{
if (IOPort ==GPIOA)
MCPWrite(MCPAdd,GPIOA,0xFF);
if (IOPort ==GPIOB )
MCPWrite(MCPAdd,GPIOB,0xFF);
}
//-------------------------------------------------
//Turns OFF all of the outputs of a IOPort
//-------------------------------------------------
void MCPPortAllOff(uint8_t MCPAdd,uint8_t IOPort)
{
if (IOPort ==GPIOA)
MCPWrite(MCPAdd,GPIOA,0x00);
if (IOPort ==GPIOB )
MCPWrite(MCPAdd,GPIOB,0x00);
}
//-------------------------------------------------------------------
// Turns ON the outputs depending on the mask sent
// This does not use the Port-x-State variable
// The selection is from Pin 7 on Left to Pin 0 on right
// So Pin 7 and Pin 1 = 0bx10000010
//------------------------------------------------------------------
void MCPPortOutSelection(uint8_t MCPAdd,uint8_t IOPort, uint8_t IOMask)
{
if (IOPort ==GPIOA)
MCPWrite(MCPAdd,GPIOA,IOMask);
if (IOPort ==GPIOB)
MCPWrite(MCPAdd,GPIOB,IOMask);
}
//-------------------------------------------------------------------
// Read one input from an IOPort
// Output 1 or 0 depends on setting of IOPOLA
//-------------------------------------------------------------------
boolean MCPReadOneInput(uint8_t MCPAdd,uint8_t IOPort, uint8_t IONo)
{
uint8_t IOState = MCPRead(MCPAdd,IOPort); //Reads state of IO selected
if (bitRead(IOState,IONo)==1)
return true;
else
return false;
}
//-------------------------------------------------------------------
void setup()
{
Wire.begin();
Serial.begin(115200);
MCPInitialize(0x20,"Output","Output");
MCPInitialize(0x21,"Input","Input");
MCPInitialize(0x22,"Input","Output");
MCPSetIntChange(0x21,GPIOA);
MCPSetIntChange(0x21,GPIOB);
MCPPortAllOff(0x22,GPIOB);
delay(1000);
MCPPortOutSelection(0x22,GPIOB,0b01011001);
//MCPPortAllOn(0x22,GPIOB);
}
void loop()
{
Serial.print("A = ");
Serial.println(MCPReadOneInput(0x21,GPIOA,0));
Serial.print("B = ");
Serial.println(MCPReadOneInput(0x21,GPIOB,3));
MCPReadInterrupt(0x21,GPIOA);
MCPReadInterrupt(0x21,GPIOB);
}Preformatted text