Trying to use JC_Button library with adafruit MCP23017 library

I’m posting some test code that I’m having trouble getting to compile. It’s intended for an Arduino Uno, but I’m just using the “Verify” button in the IDE right now.

JC_Button library: GitHub - JChristensen/JC_Button: Arduino library to debounce button switches, detect presses, releases, and long presses
adafruit MCP23017 library: GitHub - adafruit/Adafruit-MCP23017-Arduino-Library

According to the JC_Button library examples, you create your button objects like so:

#include <JC_Button.h>

Button MyButton(pinID#);   // defines the button and assigns it to pin pinID#

void setup()
{
    MyButton.begin();
}

The MCP23017 I/O extender is setup and used thusly:

#include "Adafruit_MCP23017.h"

Adafruit_MCP23017 mcp;
  
void setup() 
{  
  mcp.begin(); 
  mcp.pinMode(0, INPUT);
}

I’m having trouble trying to use the JC_Button library to create button objects attached to pins on the I/O extender. Here are some of my attempts, and the results when I hit the “Verify” button:

Attempt #1:

#include <JC_Button.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;

mcp.Button MyBtn01(0);
mcp.Button MyBtn02(1);

void setup()
{
  mcp.begin();
  MyBtn01.begin();
  MyBtn02.begin();
}

void loop()
{

}

This resulted in the error:

TestCode:7:1: error: 'mcp' does not name a type
 mcp.Button MyBtn01(0);
 ^~~
TestCode:8:1: error: 'mcp' does not name a type
 mcp.Button MyBtn02(1);
 ^~~
C:\Users\dloyer\Documents\Arduino\TestCode\TestCode.ino: In function 'void setup()':
TestCode:13:3: error: 'MyBtn01' was not declared in this scope
   MyBtn01.begin();
   ^~~~~~~
TestCode:14:3: error: 'MyBtn02' was not declared in this scope
   MyBtn02.begin();
   ^~~~~~~
exit status 1
'mcp' does not name a type

Thinking the issue is that the I/O expander needed to be instantiated before I attempted to use it to define my button object, I pulled it out of setup and placed it before the creation of my button objects.

Attempt #2:

#include <JC_Button.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;

mcp.begin();

mcp.Button MyBtn01(0);
mcp.Button MyBtn02(1);

void setup()
{ 
  MyBtn01.begin();
  MyBtn02.begin();
}

void loop()
{

}

Which resulted in this error:

TestCode:7:1: error: 'mcp' does not name a type
 mcp.begin();
 ^~~
TestCode:9:1: error: 'mcp' does not name a type
 mcp.Button MyBtn01(0);
 ^~~
TestCode:10:1: error: 'mcp' does not name a type
 mcp.Button MyBtn02(1);
 ^~~
C:\Users\dloyer\Documents\Arduino\TestCode\TestCode.ino: In function 'void setup()':
TestCode:14:3: error: 'MyBtn01' was not declared in this scope
   MyBtn01.begin();
   ^~~~~~~
TestCode:15:3: error: 'MyBtn02' was not declared in this scope
   MyBtn02.begin();
   ^~~~~~~
exit status 1
'mcp' does not name a type

OK, maybe I needed to move the button creation into Setup instead

Attempt #3:

#include <JC_Button.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;



void setup()
{
  mcp.begin();

  mcp.Button MyBtn01(0);
  mcp.Button MyBtn02(1);
  MyBtn01.begin();
  MyBtn02.begin();
}

void loop()
{
  
}

Still no luck, but a defferent error:

C:\Users\dloyer\Documents\Arduino\TestCode\TestCode.ino: In function 'void setup()':
TestCode:13:7: error: 'class Adafruit_MCP23017' has no member named 'Button'
   mcp.Button MyBtn01(0);
       ^~~~~~
TestCode:14:7: error: 'class Adafruit_MCP23017' has no member named 'Button'
   mcp.Button MyBtn02(1);
       ^~~~~~
TestCode:15:3: error: 'MyBtn01' was not declared in this scope
   MyBtn01.begin();
   ^~~~~~~
TestCode:16:3: error: 'MyBtn02' was not declared in this scope
   MyBtn02.begin();
   ^~~~~~~
exit status 1
'class Adafruit_MCP23017' has no member named 'Button'

Out of desperation, I moved the mcp instatiation out of setup again, and tried moving the reference to the mcp pin ID into the button call instead.

Attempt #4:

#include <JC_Button.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;

mcp.begin();
Button MyBtn01(mcp(0));
Button MyBtn02(mcp(1));

void setup()
{
  

  
  MyBtn01.begin();
  MyBtn02.begin();
}

void loop()
{
  
}

With this result:

TestCode:7:1: error: 'mcp' does not name a type
 mcp.begin();
 ^~~
TestCode:8:21: error: no match for call to '(Adafruit_MCP23017) (int)'
 Button MyBtn01(mcp(0));
                     ^
TestCode:9:21: error: no match for call to '(Adafruit_MCP23017) (int)'
 Button MyBtn02(mcp(1));
                     ^
exit status 1
'mcp' does not name a type

For my last trick, I tried moving it all back into setup again.

Attempt #5:

#include <JC_Button.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;



void setup()
{

  mcp.begin();
  Button MyBtn01(mcp(0));
  Button MyBtn02(mcp(1));

  MyBtn01.begin();
  MyBtn02.begin();
}

void loop()
{

}

And got this result:

C:\Users\dloyer\Documents\Arduino\TestCode\TestCode.ino: In function 'void setup()':
TestCode:13:23: error: no match for call to '(Adafruit_MCP23017) (int)'
   Button MyBtn01(mcp(0));
                       ^
TestCode:14:23: error: no match for call to '(Adafruit_MCP23017) (int)'
   Button MyBtn02(mcp(1));
                       ^
exit status 1
no match for call to '(Adafruit_MCP23017) (int)'

I’m now grasping at straws. Are these two libraries simply incompatable with eachother?

Is there maybe a way I can define something as a pin on the I/O extender and then use that in the button creation?

I.E.

#define BlahBlah mcpPin#
Button MyButton(BlahBlah);

void setup()
{
    MyButton.begin();
}

Or is there some way of easily modifying either library so they play nice together? Or is there a different library for the MCP23017 that will work with the JC_Button library?

Thanks for any insight you can give me,
Dennis

The JC_Button library doesn’t know anything about the MCP23017 library, and the MCP23017 library knows nothing about the JC_Button library. JC_Button has no idea how to read the pins of an MCP23017, so you cannot use it for buttons connected through the MCP.

I maintain the Arduino Helpers library which supports MCP23017 expanders and has classes for debouncing buttons and detecting long presses. The button classes explicitly support reading from MCP23017 pins.

For example:

/*
 * Connect a push button between the GPIOA0 pin of an MCP23017 and ground.
 * Connect the SDA/SCL lines of the MCP to the SDA/SCL lines of the Arduino.
 * Connect either one of the interrupt pins of the MCP to pin 2 of the Arduino.
 * If the address lines of the MCP are not pulled to ground, change the I²C
 * address offset below.
 * 
 * When the push button is pressed, the on-board LED turns on. When pressed 
 * again, it turns off.
 */

#include <Arduino_Helpers.h>
#include <AH/Hardware/ExtendedInputOutput/MCP23017.hpp>
#include <AH/Hardware/Button.hpp>
#include <Wire.h>

using WireType = decltype(Wire); // The type of the I²C driver to use
MCP23017<WireType> mcp {
  Wire, // The I²C driver to use
  0x0,  // The I²C address offset (depends on the state of the address pins)
  2,    // Optional: interrupt pin to detect input changes 
};

Button button = mcp.pinA(0); // GPIOA0

void setup() {
  Wire.begin();          // Initialize the I²C interface
  Wire.setClock(800000); // Faster I²C clock
  mcp.begin();           // Initialize the MCP23017
  button.begin();        // Initialize the button (enables pull-up resistor)
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  static bool ledState = false;
  // Check if the button was pressed
  if (button.update() == Button::Falling) {
    ledState = !ledState; // Toggle the LED state
    digitalWrite(LED_BUILTIN, ledState ? HIGH : LOW);
  }
}

See the MCP23017.ino example and the Button.ino example for more details. These examples contain links that will take you to the relevant documentation pages.

Pieter

1 Like

Another alternative is the Bounce2 Library. It uses classes to separate the de-bouncing function from the function of handling hardware pins and physical buttons. So, you could write a class that inherits from the Debouncer class and feeds it with inputs from the MCP23017. Your class could either inherit from Adafruit_MCP23017 as well or encapsulate an object of the Adafruit_MCP23017 class.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.