I found this post and I am having almost the exact same issue. Nick Gammon (the god of arduino) has an excellent answer but I can't for the life of me implement it myself. I am not an advanced user like the initial question asker.
So What I want to do is use 2 MCP23S17's (picture here). I have been messing with one of them all week and have it reading like a charm. I am using the githib library by n0mjs710 to do this. But writing to one will not work.
Along with the zipped library is a few examples. I am trying to read some BCD switches off of one "input MCP" and then display the digits on the "output MCP"
I have used external pullups so I did make one change to the code by commenting out the call for pullups. Here is what Doesn't work:
#include <SPI.h> // We use this library, so it must be called here.
#include <MCP23S17.h> // Here is the new class to make using the MCP23S17 easy.
MCP inputchip(1, 10); // Instantiate an object called "inputchip" on an MCP23S17 device at address 1
// and slave-select on Arduino pin 10
MCP outputchip(2, 10); // Instantiate an object called "outputchip" on an MCP23S17 device at address 2
// and slave-select on Arduino pin 10
void setup() {
inputchip.begin();
outputchip.begin();
inputchip.pinMode(0xFFFF); // Use word-write mode to set all of the pins on inputchip to be inputs
//inputchip.pullupMode(0xFFFF); // Use word-write mode to Turn on the internal pull-up resistors.
inputchip.inputInvert(0xFFFF); // Use word-write mode to invert the inputs so that logic 0 is read as HIGH
outputchip.pinMode(0x0000); // Use word-write mode to Set all of the pins on outputchip to be outputs
}
void loop() {
int value; // declare an integer to hold the value temporarily.
value = inputchip.digitalRead(); // read the input chip in word-mode, storing the result in "value"
outputchip.digitalWrite(value); // write the output chip in word-mode, using our variable "value" as the argument
// outputchip.digitalWrite(inputchip.digitalRead()); // this one line replaces the three above, and is more efficient
}
I have tried:
- slowing the SPI bus by changing the library to SPI_Divide the clock by 2
- changing the ss line and even splitting the lines so one chip uses pin 10 and the other uses pin 9
So after reading Mr. Gammon's post I have made some changes to the code attempting to rid myself of the old slave select pin low trick he mentioned. Here is my attempt:
MCP inputchip(1, 10); // Instantiate an object called "inputchip" on an MCP23S17 device at address 1
// and slave-select on Arduino pin 10
MCP outputchip(2, 9); // Instantiate an object called "outputchip" on an MCP23S17 device at address 2
// and slave-select on Arduino pin 10
int ssPin = 9;
void setup() {
pinMode(ssPin,OUTPUT);
inputchip.begin();
digitalWrite(ssPin, HIGH);
digitalWrite(ssPin, LOW);
outputchip.begin();
inputchip.pinMode(0xFFFF); // Use word-write mode to set all of the pins on inputchip to be inputs
//inputchip.pullupMode(0xFFFF); // Use word-write mode to Turn on the internal pull-up resistors.
inputchip.inputInvert(0xFFFF); // Use word-write mode to invert the inputs so that logic 0 is read as HIGH
digitalWrite(ssPin, HIGH);
digitalWrite(ssPin, LOW);
outputchip.pinMode(0x0000); // Use word-write mode to Set all of the pins on outputchip to be outputs
}
void loop() {
int value;
// declare an integer to hold the value temporarily.
value = inputchip.digitalRead(); // read the input chip in word-mode, storing the result in "value"
digitalWrite(ssPin, HIGH);
digitalWrite(ssPin, LOW);
outputchip.digitalWrite(value); // write the output chip in word-mode, using our variable "value" as the argument
}
So any advice would be great to get this working. Help me Obi wan Gammon your me only hope.
-
Try my library instead. That one looks horrible. github.com/MajenkoLibraries/MCP23S17Majenko– Majenko2016年08月18日 23:23:10 +00:00Commented Aug 18, 2016 at 23:23
-
I agree with Majenco...that one looks hard...I am no expert but i used the Adafruit library and found it very friendly... github.com/adafruit/Adafruit-MCP23017-Arduino-LibraryDoug– Doug2016年08月19日 11:23:49 +00:00Commented Aug 19, 2016 at 11:23
-
I will try yours now Mr. Majenko. Doug the library you posted is for the I2C version of the chip. I have worked with it before and found it excellent but must use the SPI for some applications.enterprisingsoul– enterprisingsoul2016年08月19日 15:32:12 +00:00Commented Aug 19, 2016 at 15:32
-
I have one question. Once you set the PinMode of an expander then can you change the mode without giving a reset? I mean, I have to use 3 expanders for controlling an SRAM: on one MCP I have the data lines, on the second one I have the control signals and on the last one I have the address lines. Firstly, I do a SRAM_WRITE, so I need the pins of the first expander to be OUTPUTs,then I do a READ_SRAM so a need the pins of the first expander to be INPUTs. Can I change the mode from output to input? Then I am trying to check the signals with an oscilloscope. When a do a pinMode OUTPUT of the expaGabriele– Gabriele2018年02月02日 10:17:53 +00:00Commented Feb 2, 2018 at 10:17
2 Answers 2
Majenko's library works. All praise to Majenko https://github.com/MajenkoLibraries/MCP23S17
-
Nick is only a Demi-god :P I am Zeus and Odin rolled into one. Maybe I should change my name to Zein ... or Odus...? ;)Majenko– Majenko2016年08月19日 23:58:32 +00:00Commented Aug 19, 2016 at 23:58
This sketch uses the Majenko Library with two MCP23S17 chips to demonstrate the library functions.
It was tested on an Arduino Uno with IDE 1.6.5.
/*
* MultiTest_Majenko_02.ino
* Library Ref: github.com/MajenkoLibraries/MCP23S17
*
* Lowell Bahner
* 2016年12月11日
*
* Hardware: Arduino UNO
* IDE: Arduino 1.6.5
*
* Useful SPI Ref: gammon.com.au/spi
*
* Wire the SPI Interface common lines (Mega2560 SPI pins shown in [ ]):
* Arduino SPI_MOSI pin 11 [51] <-> SI MCP23S17 pin 13
* Arduino SPI_MISO pin 12 [50] <-> SO MCP23S17 pin 14
* Arduino SPI_CLOCK pin 13 [52]<-> SCK MCP23S17 pin 12
* Arduino SPI_CS pin 10 [53] <-> SS MCP23S17 pin 11
* MCP23S17 VDD pin 9 to +5V
* MCP23S17 VSS pin 10 to Gnd
* MCP23S17 Reset pin 18 to +5V
* MCP23S17 Interrupt pins 19-20
* MCP23S17 A0,A1,A2 pins connect to Gnd or +5V (000 = Address 0, 100 = Address 1, 010 = Address 2, etc)
* MCP23S17 Port A pins are chip pins 21-28
* MCP23S17 Port B pins are chip pins 1-8
*
* This sketch runs a series of functions to demonstrate library capabilities.
* This sketch does not demonstrate interrupt functionality.
*
* This sketch instantiates 2 MCP23S17 chips.
* Bank2 (MCP23S17 address 1) pins are set as INPUT or INPUT_PULLUP.
* Normally HIGH, use switch to set a pin LOW.
* Bank1 (MCP23S17 address 0) pins are set as OUTPUT.
* MCP23S17 outputs will power LEDs up to 25ma through 1000ohm resistor to ground.
*
* Majenko MCP23S17 library functions (see .h,.cpp files for details):
*
* bank.pinMode(uint8_t pin, uint8_t mode)
* where modes are:
* OUTPUT - sets pin HIGH
* INPUT - sets pin LOW for sensing change to HIGH +V
* INPUT_PULLUP - sets pin HIGH for sensing change to LOW 0V
*
* bank.digitalWrite(uint8_t pin, uint8_t value)
* if mode=OUTPUT, pin value = LOW (0) or HIGH (1)
* if mode=INPUT, value LOW disables pullup on pin, value HIGH enables pullup on pin
*
* uint8_t value = bank.digitalRead(uint8_t pin)
* read the state of the pin
*
* uint8_t value = bank.readPort(uint8_t port)
* read entire 8-bit port of all INPUT pins on Port A (port=0) or Port B (port>=1)
*
* uint16_t longValue = bank.readPort()
* read both ports as 16-bit combined
*
* bank.writePort(uint8_t port, uint8_t val)
* write val (0 or 1, hex example 0x55) to all OUTPUT pins on Port A (port=0) or Port B (port>=1)
*
* bank.writePort(uint16_t val)
* write val (hex example 0x55AA) to all OUTPUT pins on Port A and Port B
*
* Also, interrupt functions are defined:
* enableInterrupt(uint8_t pin, uint8_t type);
* void disableInterrupt(uint8_t pin);
* void setMirror(boolean m);
* uint16_t getInterruptPins();
* uint16_t getInterruptValue();
* void setInterruptLevel(uint8_t level);
* void setInterruptOD(boolean openDrain);
*
*
*
*
Run Sketch: Serial Monitor Output
-- RWpins() --
Bank2: Switch i15: 1 (Push button switch not pushed, Bank2 INPUT pin 15 is HIGH +5V)
Bank1: Output j4: 1 (Bank1 OUTPUT pin 4 is HIGH.
Arduino pin 7 is set HIGH.
LED on pin 4 is ON. LED on pin 7 is ON.)
Bank2: Switch i15: 0 (Push button switch pushed, grounds Bank2 INPUT pin 15)
Bank1: Output j4: 0 (Bank1 OUTPUT pin 4 switches to LOW.
Arduino pin 7 is set LOW.
LED on pin 4 is OFF. LED on pin 7 is OFF.)
-- RWport() --
Bank1: Port A BIN: 00000000
Bank1: Port B BIN: 00000000
Bank1: Port A BIN: 11110100 DEC: 244
Bank1: Port B BIN: 00001011 DEC: 11
-- RWlongPortValue() --
Bank1: Port A & B BIN: 0000101111110100 HEX: 0x0BF4 DEC: 3060
-- RWlongPort() --
Bank1: Port A & B BIN: 1011100101000010 HEX: 0xB942 DEC: 47426
-- CyclePins() --
Bank1: Port A & B BIN: 0000000000000000 HEX: 0x0000 DEC: 0
Bank1: Port A & B BIN: 0000000000000001 HEX: 0x0001 DEC: 1
Bank1: Port A & B BIN: 0000000000000011 HEX: 0x0003 DEC: 3
Bank1: Port A & B BIN: 0000000000000111 HEX: 0x0007 DEC: 7
Bank1: Port A & B BIN: 0000000000001111 HEX: 0x000F DEC: 15
Bank1: Port A & B BIN: 0000000000011111 HEX: 0x001F DEC: 31
Bank1: Port A & B BIN: 0000000000111111 HEX: 0x003F DEC: 63
Bank1: Port A & B BIN: 0000000001111111 HEX: 0x007F DEC: 127
Bank1: Port A & B BIN: 0000000011111111 HEX: 0x00FF DEC: 255
Bank1: Port A & B BIN: 0000000111111111 HEX: 0x01FF DEC: 511
Bank1: Port A & B BIN: 0000001111111111 HEX: 0x03FF DEC: 1023
Bank1: Port A & B BIN: 0000011111111111 HEX: 0x07FF DEC: 2047
Bank1: Port A & B BIN: 0000111111111111 HEX: 0x0FFF DEC: 4095
Bank1: Port A & B BIN: 0001111111111111 HEX: 0x1FFF DEC: 8191
Bank1: Port A & B BIN: 0011111111111111 HEX: 0x3FFF DEC: 16383
Bank1: Port A & B BIN: 0111111111111111 HEX: 0x7FFF DEC: 32767
Bank1: Port A & B BIN: 1111111111111111 HEX: 0xFFFF DEC: 65535
Bank1: Port A & B BIN: 1111111111111111 HEX: 0xFFFF DEC: 65535
Bank1: Port A & B BIN: 0111111111111111 HEX: 0x7FFF DEC: 32767
Bank1: Port A & B BIN: 0011111111111111 HEX: 0x3FFF DEC: 16383
Bank1: Port A & B BIN: 0001111111111111 HEX: 0x1FFF DEC: 8191
Bank1: Port A & B BIN: 0000111111111111 HEX: 0x0FFF DEC: 4095
Bank1: Port A & B BIN: 0000011111111111 HEX: 0x07FF DEC: 2047
Bank1: Port A & B BIN: 0000001111111111 HEX: 0x03FF DEC: 1023
Bank1: Port A & B BIN: 0000000111111111 HEX: 0x01FF DEC: 511
Bank1: Port A & B BIN: 0000000011111111 HEX: 0x00FF DEC: 255
Bank1: Port A & B BIN: 0000000001111111 HEX: 0x007F DEC: 127
Bank1: Port A & B BIN: 0000000000111111 HEX: 0x003F DEC: 63
Bank1: Port A & B BIN: 0000000000011111 HEX: 0x001F DEC: 31
Bank1: Port A & B BIN: 0000000000001111 HEX: 0x000F DEC: 15
Bank1: Port A & B BIN: 0000000000000111 HEX: 0x0007 DEC: 7
Bank1: Port A & B BIN: 0000000000000011 HEX: 0x0003 DEC: 3
Bank1: Port A & B BIN: 0000000000000001 HEX: 0x0001 DEC: 1
Bank1: Port A & B BIN: 0000000000000000 HEX: 0x0000 DEC: 0
*
*
*
*/
// Majenko MCP23S17 Library
#include <MCP23S17.h>
// Arduino Library SPI.h
#include <SPI.h>
// SPI CS/SS chipselect pin can be changed by user as desired
const uint8_t chipSelect = 10;
// example Arduino board pin
uint8_t pin7 = 7;
// Create an object for each chip
// Bank1 is address 0. Pins A0,A1,A2 grounded.
// Bank2 is address 1. Pin A0=+5V, A1,A2 grounded.
MCP23S17 Bank1(&SPI, chipSelect, 0);
MCP23S17 Bank2(&SPI, chipSelect, 1);
void setup() {
// Slow down the master a bit if desired
SPI.setClockDivider(SPI_CLOCK_DIV8);
Serial.begin(9600);
Bank1.begin();
Bank2.begin();
// LED connected to Arduino pin 7 to test inter-device communication
pinMode(pin7, OUTPUT);
//
// Set MCP23S17 pin modes:
// example set one pin: chip.pinMode(0, OUTPUT); // sets chip pin 0 (Port A 0) to OUTPUT mode
//
// setChipPins(); // use loop to set individual pins
// or, since this library does not have a setPortPinMode, do 8 pin loops
setPortPins(); // example: set pins on each Port on each chip to different modes.
//
}
// Set all Chip pins to desired mode
void setChipPins() {
// Example usage
// Set all Bank1 pins to be OUTPUT
for (uint8_t i = 0; i <= 15; i++)
Bank1.pinMode(i, OUTPUT);
// Set all Bank2 pins to be INPUT_PULLUP
for (uint8_t i = 0; i <= 15; i++)
//Bank2.pinMode(i, INPUT); // unswitched pin voltages about +0.1V, switch must pull pin to +5V
Bank2.pinMode(i, INPUT_PULLUP); // unswitched pin voltages about +4.9V, switch must ground pin
}
// Set Port pins to desired mode
void setPortPins() {
// Example usage
// Set all Bank1 Port A pins to OUTPUT
for (uint8_t i = 0; i <= 7; i++)
Bank1.pinMode(i, OUTPUT);
// Set all Bank1 Port B pins to OUTPUT
for (uint8_t i = 8; i <= 15; i++)
Bank1.pinMode(i, OUTPUT);
// Set all Bank2 Port A pins to be INPUT
for (uint8_t i = 0; i <= 7; i++)
Bank2.pinMode(i, INPUT);
// Set all Bank2 Port B pins to be INPUT_PULLUP
for (uint8_t i = 8; i <= 15; i++)
Bank2.pinMode(i, INPUT_PULLUP);
}
//
// Change LED On/Off with button push
// 1) Switch an INPUT_PULLUP pin to ground
// 2) Read the pin value
// 3) Write the value to an OUTPUT pin
// 4) Turn LED On/Off
// Use functions digitalRead(pin) and digitalWrite(pin,value)
//
void RWpins() {
Serial.print("\n -- RWpins() --"); Serial.println("");
uint8_t b15 = 0; // Bank2 input pin value (0 push LOW, 1 normally open HIGH) with push button switch to gnd
uint8_t i = 15; // Bank2 pin number
uint8_t a4 = 0; // Bank1 output pin value
uint8_t j = 4; // Bank1 pin number
// read the switch value into b15
b15 = Bank2.digitalRead(i);
Serial.print("\nBank2: Switch i"); Serial.print(i); Serial.print(": "); Serial.println(b15);
// write the switch pin i, value b15, to the output pin j
Bank1.digitalWrite(j, b15);
a4 = Bank1.digitalRead(j);
Serial.print("Bank1: Output j"); Serial.print(j); Serial.print(": "); Serial.println(a4);
// Turn on/off LED connected to Arduino pin 7 through resistor to ground
digitalWrite(pin7, a4);
}
//
// Read and Write Port values
//
void RWport() {
Serial.print("\n -- RWport() --"); Serial.println("");
// set the port pin modes
setPortPins(); // all Bank1 pins are OUTPUT but set as Ports
// clear the port pin values to 0
uint8_t port = 0; // Port A
uint8_t val = 0x00; // set to 0000 0000
Bank1.writePort(port, val);
port = 1; // Port B
Bank1.writePort(port, val); // set to 0000 0000
// read the port pin values
uint8_t valueA = Bank1.readPort(0);
Serial.print("\nBank1: Port A BIN: "); print8Bits(valueA); Serial.println("");
uint8_t valueB = Bank1.readPort(1);
Serial.print("Bank1: Port B BIN: "); print8Bits(valueB); Serial.println("");
// set the port pin values
port = 0; // Port A
val = 0xF4; // set to 1111 0100
Bank1.writePort(port, val);
port = 1; // Port B
val = 0x0B; // set to 0000 1011
//val = 0xB0; // set to 1011 0000
Bank1.writePort(port, val);
// read the port pin values
valueA = Bank1.readPort(0);
Serial.print("\nBank1: Port A BIN: "); print8Bits(valueA);
Serial.print(" DEC: "); Serial.println(valueA, DEC);
valueB = Bank1.readPort(1);
Serial.print("Bank1: Port B BIN: "); print8Bits(valueB);
Serial.print(" DEC: "); Serial.println(valueB, DEC);
}
void RWlongPortValue() {
Serial.print("\n -- RWlongPortValue() --"); Serial.println("");
// Read the Bank1 Port pin values as a combined long value
uint16_t valueLong = Bank1.readPort();
Serial.print("\nBank1: Port A & B BIN: "); print16Bits(valueLong);
Serial.print(" HEX: "); crPrintHEX(valueLong, 4);
Serial.print(" DEC: "); Serial.println(valueLong, DEC);
}
void RWlongPort() {
Serial.print("\n -- RWlongPort() --"); Serial.println("");
// Write the Bank1 Port pin values as a combined long value
uint16_t valueLong = 0xB942;
Bank1.writePort(valueLong);
// Read the Bank1 Port pin values as a combined long value
uint16_t valueLongIn = Bank1.readPort();
Serial.print("\nBank1: Port A & B BIN: "); print16Bits(valueLongIn);
Serial.print(" HEX: "); crPrintHEX(valueLongIn, 4);
Serial.print(" DEC: "); Serial.println(valueLongIn, DEC);
}
//
// Cycle through OUTPUT pins with count-up count-down
//
void CyclePins() {
Serial.print("\n -- CyclePins() --"); Serial.println("\n");
// Set all Bank1 pins to be OUTPUT
for (uint8_t i = 0; i <= 15; i++)
Bank1.pinMode(i, OUTPUT);
// clear Bank1 using writePort
uint16_t valueLong = 0x0000;
Bank1.writePort(valueLong);
// Read the Bank1 Port pin values as a combined long value
for (int8_t i = -1; i <= 15; i++) {
if (i >= 0) Bank1.digitalWrite(i, 1); // i=-1 allows print of 0 data
valueLong = Bank1.readPort(); // read 16 bits
Serial.print("Bank1: Port A & B BIN: "); print16Bits(valueLong);
Serial.print(" HEX: "); crPrintHEX(valueLong, 4);
Serial.print(" DEC: "); Serial.println(valueLong, DEC);
}
Serial.println("");
for (int8_t i = 15; i >= -1; i--) { // i=-1 allows print of 0 data
// decrement after the read while reading down the values
valueLong = Bank1.readPort(); // read 16 bits
Serial.print("Bank1: Port A & B BIN: "); print16Bits(valueLong);
Serial.print(" HEX: "); crPrintHEX(valueLong, 4);
Serial.print(" DEC: "); Serial.println(valueLong, DEC);
Bank1.digitalWrite(i, 0);
}
}
void loop() {
// Change LED On/Off with button push
RWpins();
// Read and Write Port pins as a group
RWport();
// Read the Bank1 Port pin values as a combined long value
RWlongPortValue();
// Read and Write Chip 16 pins as a group
RWlongPort();
// Cycle through OUTPUT pins with count-up count-down
CyclePins();
delay(1000);
}
// print 8-bit byte as 8 bit binary string
void print8Bits(uint8_t myByte) {
for (byte mask = 0x80; mask; mask >>= 1) {
if (mask & myByte)
Serial.print('1');
else
Serial.print('0');
}
}
// print 16-bit word as 16 bit binary string
void print16Bits(uint16_t myWord) {
for (uint16_t mask = 0x8000; mask; mask >>= 1) {
if (mask & myWord)
Serial.print('1');
else
Serial.print('0');
}
}
//---------------------------------------------------------------------------------
// crPrintHEX print value as hex with specified number of digits
//---------------------------------------------------------------------------------
void crPrintHEX(unsigned long DATA, unsigned char numChars) {
unsigned long mask = 0x0000000F;
mask = mask << 4 * (numChars - 1);
Serial.print("0x");
for (unsigned int i = numChars; i > 0; --i) {
Serial.print(((DATA & mask) >> (i - 1) * 4), HEX);
mask = mask >> 4;
}
Serial.print(" ");
}