Pointer to function in class

Hi,
I'm trying to call function thats in class from diferent class. Compiler accept this code but microcontroller didn't work properly. Can you please tell me how should I write code in correct way?

main.ino

#include "ClassIN.h"
#include "ClassOUT.h"


InputPeripherals buttonA;
OutputPeripherals leds;

void setup()
{
  delay(20);
  Serial.begin(9600);
  delay(20);
  Serial.println("\nTransfer started \n\n");
  leds.init();
  leds.number(5);
  buttonA.init(12,(void(*)) &leds.number);
}

void loop()
{
  buttonA.updateClass();
  delay(500);
  leds.number(8);
  delay(500);
  Serial.print("end loop\n\n");
}

ClassIN.h

#ifndef fceIN_h
#define fceIN_h
#include "Arduino.h"

class InputPeripherals              
{
  public:                 
    InputPeripherals();     
    void init(int buttonAdress,void (*funkce) (byte number)); 
    void updateClass();
  private:                
    int _pin;       
    void (*_fooShowNumber) (byte number);
};
#endif

ClassIN.ino

#include "ClassIN.h"

InputPeripherals::InputPeripherals(){}

void InputPeripherals::init(int buttonAdress, void (*foo) (byte number))
{
  Serial.println("Output set INPUT_PULLUP");
  pinMode(buttonAdress,INPUT_PULLUP);
  _pin = buttonAdress;
  _fooShowNumber = foo;
}

void InputPeripherals::updateClass()
{
  Serial.print("Button value is: ");
  Serial.println(digitalRead(_pin));
  if(digitalRead(_pin) == 0)
  {
    Serial.println("calling 3");
    _fooShowNumber(3);
  }
  else
  {
    Serial.println("calling 1");
    _fooShowNumber(1);
  }
}

ClassOUT.h

#ifndef fceOUT_h
#define fceOUT_h
#include "Arduino.h"

class OutputPeripherals              
{
  public:                 
    OutputPeripherals();     
    void init();         // !!! správně by tady mělo být vkládání pole(_leds[8] ale pro zjednodušení jsem ho vynechal
    void number(byte number);
  private:                
    int _leds[8] {3,4,5,6,7,8,9,10};       
};
#endif

ClassOUT.ino

#include "ClassOUT.h"

OutputPeripherals::OutputPeripherals() {}

void OutputPeripherals::init()
{
  for(int i = 0; i < 8;i++)
  {
    pinMode(_leds[i],OUTPUT);
  }
}

void OutputPeripherals::number(byte number)
{     
  Serial.print("Incomming number: ");
  Serial.println(number);
  
  for (int i = 0; i < 8; i++)
  {

    digitalWrite(_leds[i],number & (0x01<<i));
  }
}

But output from arduino doesn't make any sence:

Transfer started 


Incomming number: 5
Output set INPUT_PULLUP
utton value is: 1
calling 1
Incomming number: 10
Incomming number: 8
end loop

Button value is: 1
calling 1
Incomming number: 10
Incomming number: 8
end loop

Sometimes even arduino switch from input_pullup to output "0" thats make me scary can you tell me whats wrong?

Make the "number" function in OutputPeripherals 'static'. That way it is common to all instances and can be called through a pointer.
static void number(byte number);

You may have to change the initialization of buttonA to:
buttonA.init(12,(void(*)) &OutputPeripherals::number);

It's true that by declaring a function member as static, you make it independent of any particular object of the class and the function can be called even if no objects of the class exist, so you can get a pointer to that function.

but... a static member function have a class scope and they do not have access to the this pointer of the class so they can only access static data member (and other static member functions and any other functions from outside the class).

➜ it won't work as you won't be able to perform this for example (_leds being a private instance variable, non static)

for (int i = 0; i < 8; i++)
  {
    digitalWrite(_leds[i],number & (0x01<<i));
  }

This version compiles without error or warning and seems to produce reasonable output:

class InputPeripherals
{
  public:
    InputPeripherals();
    void init(int buttonAdress, void (*funkce) (byte number));
    void updateClass();
  private:
    int _pin;
    void (*_fooShowNumber) (byte number);
};

class OutputPeripherals
{
  public:
    OutputPeripherals();
    void init();         // !!! správně by tady mělo být vkládání pole(_leds[8] ale pro zjednodušení jsem ho vynechal
    static void number(byte number);
  private:
    static int _leds[8];
};


InputPeripherals buttonA;
OutputPeripherals leds;

void setup()
{
  delay(20);
  Serial.begin(115200);
  delay(20);
  Serial.println("\nTransfer started \n\n");
  leds.init();
  leds.number(5);
  buttonA.init(12, OutputPeripherals::number);
}

void loop()
{
  buttonA.updateClass();
  delay(500);
  leds.number(8);
  delay(500);
  Serial.print("end loop\n\n");
  delay(10000);
}


InputPeripherals::InputPeripherals() {}

void InputPeripherals::init(int buttonAdress, void (*foo) (byte number))
{
  Serial.println("Output set INPUT_PULLUP");
  pinMode(buttonAdress, INPUT_PULLUP);
  _pin = buttonAdress;
  _fooShowNumber = foo;
}

void InputPeripherals::updateClass()
{
  Serial.print("Button value is: ");
  Serial.println(digitalRead(_pin));
  if (digitalRead(_pin) == 0)
  {
    Serial.println("calling 3");
    _fooShowNumber(3);
  }
  else
  {
    Serial.println("calling 1");
    _fooShowNumber(1);
  }
}

int OutputPeripherals::_leds[8] = {3, 4, 5, 6, 7, 8, 9, 10};

OutputPeripherals::OutputPeripherals() {}

void OutputPeripherals::init()
{
  for (int i = 0; i < 8; i++)
  {
    pinMode(_leds[i], OUTPUT);
  }
}

void OutputPeripherals::number(byte number)
{
  Serial.print("Incomming number: ");
  Serial.println(number);

  for (int i = 0; i < 8; i++)
  {

    digitalWrite(_leds[i], number & (0x01 << i));
  }
}

but then the _leds are shared amongst all the instances (seems to be matching OP needs but then there is little value of embedding this into the class if it's hardwired)

That's what I thought, too.

If the reason for an "OutputPeripherals" class was to have multiple instances that could each output a 'number' the pointer in the InputPeripherals class should point to an instance of OutputPeripherals. Then the InputPeripherals instance could call myOutputPeripheral->number(value); to display the number 'value' on the selected output peripheral.

Then with a LEDOutputPeripheral class could be a derived class of OutputPeripherals.

Here is a version where LEDOutputPeripheral is a derived class of OutputPeripherals. That way the OutputPeripherals class doesn't need a list of LED pins and different LEDOutputPeripheral can have different lists of pins.

class OutputPeripherals
{
  public:
    virtual void init() {};         // !!! správně by tady mělo být vkládání pole(_leds[8] ale pro zjednodušení jsem ho vynechal
    virtual void number(byte n) = 0;
};

class InputPeripherals
{
  public:
    InputPeripherals();
    void init(int buttonAdress, OutputPeripherals &periph);
    void updateClass();
  private:
    int _pin;
    OutputPeripherals *_periph;
};


class LEDOutputPeripheral : public OutputPeripherals
{
  public:
    LEDOutputPeripheral() : _leds {3, 4, 5, 6, 7, 8, 9, 10} {}
    void init();         // !!! správně by tady mělo být vkládání pole(_leds[8] ale pro zjednodušení jsem ho vynechal
    void number(byte n);
  private:
    int _leds[8];
};

InputPeripherals buttonA;
LEDOutputPeripheral leds;

void setup()
{
  delay(20);
  Serial.begin(115200);
  delay(20);
  Serial.println("\nTransfer started \n\n");
  leds.init();
  leds.number(5);
  buttonA.init(12, leds);
}

void loop()
{
  buttonA.updateClass();
  delay(500);
  leds.number(8);
  delay(500);
  Serial.print("end loop\n\n");
  delay(10000);
}


InputPeripherals::InputPeripherals() {}

void InputPeripherals::init(int buttonAdress, OutputPeripherals &periph)
{
  Serial.println("Output set INPUT_PULLUP");
  pinMode(buttonAdress, INPUT_PULLUP);
  _pin = buttonAdress;
  _periph = &periph;
}

void InputPeripherals::updateClass()
{
  Serial.print("Button value is: ");
  Serial.println(digitalRead(_pin));
  if (digitalRead(_pin) == 0)
  {
    Serial.println("calling 3");
    _periph->number(3);
  }
  else
  {
    Serial.println("calling 1");
    _periph->number(1);
  }
}


void LEDOutputPeripheral::init()
{
  for (int i = 0; i < 8; i++)
  {
    pinMode(_leds[i], OUTPUT);
  }
}

void LEDOutputPeripheral::number(byte number)
{
  Serial.print("Incomming number: ");
  Serial.println(number);

  for (int i = 0; i < 8; i++)
  {
    digitalWrite(_leds[i], number & (0x01 << i));
  }
}

Than you very much this is probably solution for me, but I hoped I would be able to create in future another class forexample Display and give InputPeripherals pointer to his method and then create another class and so on. So I can't make static connection between those two classes. Am I right?

Thank you.

Yes, you can derive as many classes from OutputPeripherals as you like.

class Display : public OutputPeripherals
{
  public:
    Display() {}
    void init();         // !!! správně by tady mělo být vkládání pole(_leds[8] ale pro zjednodušení jsem ho vynechal
    void number(byte n);
  private:
};

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