Language structure - passing an instance name as a variable (I think!)

Hi there
My first project is to control a set of points, signals and power on a vintage model railway/railroad layout using a Mega 2560 and 4 x 16 relay boards. Progress is good and I have the code working reasonably OK.

I am trying to improve the coding by creating functions for repetitive tasks and have struggled to find a way to achieve this with a common piece of code.

All the relay boards are connected via i2c and have been attached via 4 PCF8575 expanders using the PCF8575.h library. The setup for the boards is

PCF8575 board0(0x20);
PCF8575 board1(0x21);
PCF8575 board2(0x23);
PCF8575 board3(0x24);

One of the many repeated sections of my sketch is

//Control Point C
void Cpoint(int State) {
  switch (State) {
    case 0:
      board2.digitalWrite(CpointM, LOW);
      delay(pointtime);
      board2.digitalWrite(CpointM, HIGH);
      Serial.println("Point C Main");
      break;
    case 1:
      board2.digitalWrite(CpointS, LOW);
      delay(pointtime);
      board2.digitalWrite(CpointS, HIGH);
      Serial.println("Point C Switched");
      break;
  }
}

I have tried to pass board0/1/2/3 as a variable into a function along with e.g CpointM/S e.g.

fncName(board_name, point_name, pointtime, strstring)

which always fails to compile on board_name.

This part of the code is a function itself and basically pulses one of the two coils on an electrical track point/switch to change the direction of the train

Please can anyone help me to resolve this problem?

Thanks
P

which always fails to compile

Why?

My thinking is that it is because I don't know how to properly declare the variable 'board_name'.

Arduino: 1.8.10 (Windows 10), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

\NAS241FED\home\Arduino\Fiddlematrixj\Fiddlematrixj.ino: In function 'void Apoint(int)':

Fiddlematrixj:762:23: error: could not convert 'board2' from 'PCF8575' to 'String'

testpointswitch(board2);

^

\NAS241FED\home\Arduino\Fiddlematrixj\Fiddlematrixj.ino: In function 'void testpointswitch(String)':

Fiddlematrixj:1732:17: error: 'class String' has no member named 'digitalWrite'

boardname.digitalWrite(4, LOW);

^~~~~~~~~~~~

exit status 1
could not convert 'board2' from 'PCF8575' to 'String'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

In testing I used the following call to function
testpointswitch(board2);

and the following function definition:

void testpointswitch(String boardname){
boardname.digitalWrite(4, LOW);
Serial.println (boardname);

}

PCF8575& would be a reference.

code parts are very difficult to debug.
Make the smallest sketch showing your problem.

regarding:

void testpointswitch(String boardname){
boardname.digitalWrite(4, LOW);
Serial.println (boardname);

}

boardname should not be an Arduino String.

Try something like

void testpointswitch(PCF8575& boardname){
      boardname.digitalWrite(4, LOW);
      Serial.println (boardname);

}

if you don't get it working, post an example sketch.

If you put your object declarations in an array:

PCF8575 Boards[] = {0x20, 0x21, 0x23, 0x24};

Then it's easy to treat your 64 output pins as a single range of 0 to 63.

   Boards[pin/16].function(pin%16. arg1, arg2);
1 Like

With C/C++ the variable names that you write don't exist in the compiled program so they cannot be used as references. The compiler converts all variable and function names to addresses in memory.

...R

Thank you all for your help, and special thanks to noiasca for the following which looks very promising. I will test it more fully tomorrow and report back on any success.

void testpointswitch(PCF8575& boardname){

Please could anyone advise me of the correct terminology for this syntax. I searched unsuccessfully, mainly because I had no clue how to word the search :slight_smile: Is this an object declaration?

I will also try your solution johnwasser as I like the thinking.

P

Please could anyone advise me of the correct terminology for this syntax.

there are basically two ways to hand over variables to functions
call by value
call by reference

most of the time you might have used call by value up to now.
In your new project you don't want to hand over the content of a variable to your function. You want to hand over a refernece to an object.

if you google "call by reference" you might find better explanations (sorry I'm no native speaker...)

HornbyDublo:
void testpointswitch(PCF8575& boardname){

Please could anyone advise me of the correct terminology for this syntax. I searched unsuccessfully, mainly because I had no clue how to word the search :slight_smile: Is this an object declaration?

In ancient times, the '&' was called the 'address of' operator and was used to get a pointer to a variable rather than the variable itself:

int var = 3;
int *varPtr = &var;
*varPtr = 7;  // Changes 'var' to 7

Simple variables like int, float, and pointer are passed 'by value' to functions. That means that the function only gets a copy of the value of the variable and can't change the variable. In ancient times, if you wanted to pass a variable 'by reference' to a function so the function could change the variable, you had to pass a pointer to the variable 'by value' and de-reference (*) the pointer in the function:

int var = 3;
  function(&var);

void function(int *varPtr)
{
  *varPtr = 7;  // Changes 'var' to 7.
}

In modern times the passing 'by reference' was simplified by using the '&' as a 'reference to' operator:

int var = 3;
  function(var);

void function(int &varRef)
{
  varRef = 7;  // Changes 'var' to 7.
}

This automatically passes the address of the variable as a pointer and, in the function, removes the need to de-reference (*) the pointer to store a value in the variable.

Hi All

I have achieved what I needed and learnt a few more things in the process. Many thanks for your input.

Whilst I still need to do further code optimisation on the full sketch, particularly in the use of arrays where possible, here is the (cut-down) test code that I used with your guidance. It is a bit crude, but did the business :slight_smile:

#include <Keypad.h>
#include <PCF8575.h>

// ---------------------------------------------------------------------------------------
// Define Keypad
// ---------------------------------------------------------------------------------------

const byte ROWS = 5; //five rows
const byte COLS = 5; //five columns
char keys[ROWS][COLS] = {
  {1, 2, 3, 4, 5},
  {6, 7, 8, 9, 10},
  {11, 12, 13, 14, 15},
  {16, 17, 18, 19, 20},
  {21, 22, 23, 14, 25}
};

byte rowPins[ROWS] = {A0, A1, A2, A3, A4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {A8, A9, A10, A11, A12}; //connect to the column pinouts of the keypad

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

// ---------------------------------------------------------------------------------------
// Define i2c address for relay boards
// ---------------------------------------------------------------------------------------

PCF8575 board0(0x20);
PCF8575 board1(0x21);
PCF8575 board2(0x23);
PCF8575 board3(0x24);

// the delay for point energisation.  (Tested with points down to 50)
const int pointtime = 100;


void setup() {
  // put your setup code here, to run once:
  // open the serial port at 9600 bps:
  Serial.begin(9600);

  // Set pinMode on all boards to OUTPUT - boards are on i2c:
  for (int i = 0; i <= 15; i++) {
    board0.pinMode(i, OUTPUT);
    board1.pinMode(i, OUTPUT);
    board2.pinMode(i, OUTPUT);
    board3.pinMode(i, OUTPUT);
  }

  // Start all boards
  board0.begin();
  board1.begin();
  board2.begin();
  board3.begin();

  // Set all outputs on all boards to HIGH i.e Relays off - boards are on i2c:
  for (int i = 0; i <= 15; i++) {
    board0.digitalWrite(i, HIGH);
    board1.digitalWrite(i, HIGH);
    board2.digitalWrite(i, HIGH);
    board3.digitalWrite(i, HIGH);
  }

  // set debounce time for keypad
  kpd.setDebounceTime(100);

}

void loop() {
  // put your main code here, to run repeatedly:

  // This section reads the keypad matrix
  //char key = kpd.getKey();

  // check for keypad activity
  if (kpd.getKeys())  {
    // don't handle multiple keypresses, just single ones, so just use key index 0
    const byte key = kpd.key[0].kchar;
    const byte state = kpd.key[0].kstate; // IDLE, PRESSED, HOLD, RELEASED

    // this section carries out actions with Points and Power

    testpointswitch(1, board3, 0, "Point A");
    testpointswitch(0, board3, 0, "Point A");

  }


}

void testpointswitch(int State, PCF8575& boardname, int pointname, String detailstr) {
  switch (State) {
    case 0:
      boardname.digitalWrite(pointname, LOW);
      delay(pointtime);
      boardname.digitalWrite(pointname, HIGH);
      Serial.print(detailstr + " Main");
      break;
    case 1:
      boardname.digitalWrite(pointname + 1, LOW);
      delay(pointtime);
      boardname.digitalWrite(pointname + 1, HIGH);
      Serial.print(detailstr + " Switched");
      break;
  }
}