Use serial to input argument into class

Is there a way to use serial input to change the arguments (might not be the right word) in a class?
I may be using the wrong terminology here, so please correct me if I’ve gotten anything wrong.
(As a side note, does anyone know of a of good tutorial that explains all of the terminology in a class?)

I have a program to control a series of 6 solenoid valves, opening and closing the valves at specified times. Since the basic code is the same for each valve, I have it set up as a class in a library. Each valve has its own instance with 5 variables for each instance: The valves number in the series, two pin numbers (the valves have a + open wire and a + close wire with a common ground), a variable for the time the valve should open, and a variable for the duration it should remain open.

In my main sketch I call (is that the right word?) 6 instances of the class (one for each valve) which sets the values of the valve number, open pin, close pin, open time, and open duration. The times are set as variables so I can quickly alter the code to change the times in hours, and it converts this to millis.

// Just here to show how the instance is set up
Valve 1(Valve number, Open pin, Close pin, Ground pin, Open time, Run time)

// Calling? the actual instances
Valve 1(1, 4, 5, Valve_1_openTime, valve_1_run_time)
Valve 2(2, 6, 7, valve_2_openTime, valve_2_run_time)

It all works great, but if I want to change the times, I have to alter the actual code and re-upload it. I’d like to be able to use the serial monitor to type in the times from my computer when the arduino first powers up, but it think the class is already initialized by the time the serial port is up so it’s too late to change the variables.

I found an old post about objects being destructed and re-constructed but that it shouldn’t actually be done in practice as it leads to memory leaks, and I couldn’t understand the scrap of code given as the final answer in the post. It’s an old post so I can’t just respond to it.

I have tried to play with something like a class.begin() command, thinking I could use this to initialize the class after the serial input was complete, but it seems like this can’t actually be used to change the arguments in an instance.

Since the times are different for each valve, I can’t just use an extern to send the variable to all of the instances.

The only workaround I can think of is to set the times as external variables in the main sketch and then use a series of if() statements within the class to assign the variable to the correct instance such as:

// In main sketch I could set open times
valve_1_openTime = x
valve_2_openTime = y

// Then in the class:
if (valve_number == 1)
{ open_time = valve_1_openTime; }
if (valve_number == 2)
{ open_time = valve_2_openTime;}

but this doesn’t seem very elegant. There must be a better way.

So now I’m stuck. Is there a way to change the arguments or to re-initialize the class? Or is there another method that is used to send such variables into a class that I should look into? Maybe another method of sending a variable to a class that could be unique to each instance of the class?

Usually I can find solutions by digging through the forums, but in this case, I’m probably not even searching for the right thing since I’m not sure what I’m looking for so if anyone could point me in the right direction it would be greatly appreciated.

Valve.cpp (8 KB)

Valve-class-serial2.ino (9.18 KB)

Valve.h (1.2 KB)

If I understand what you’re asking, the standard technique is to provide a (public) instance method that is called from your program and takes the new value as its argument. This instance method then updates the (private) instance variable.

gfvalvo:
If I understand what you’re asking, the standard technique is to provide a (public) instance method that is called from your program and takes the new value as its argument. This instance method then updates the (private) instance variable.

Thanks for the response. This sounds like what I’m looking for.
How do I initiate this new instance? Is there a command for this? The only information I’ve been able to find seems to indicate that the variables for an instance are passed to the class as soon as the arduino powers up. If I don’t declare the arguments for the instances before the setup(), the code won’t compile because there haven’t been arguments declared for that call.
Could you provide an example or point me towards a guide of some kind?

Thanks again

You already have one instance method (aka instance function) declared and defined in your Valve class -- Update(). The syntax is the same for adding another one.

BTW, you also declared begin() as an instance function, but have not defined it. That’s gonna be a problem since you use it on you instances of the Valve class in your .ino file.

Not sure what your experience level is, but you might want to take a step back and Google search for tutorials on Object Oriented Programming in general and its particular implementation in C++.

gfvalvo:
Thanks for the responses. I don't think I asked my question clearly.

BTW, you also declared begin() as an instance function, but have not defined it. That's gonna be a problem since you use it on you instances of the Valve class in your .ino file.

I see what you mean about the begin(), that's a leftover from my experimentation that I haven't cleaned up yet.

Not sure what your experience level is, but you might want to take a step back and Google search for tutorials on Object Oriented Programming in general and its particular implementation in C++.

I have very little experience, this is my first program. I've read a number of tutorials on OOP, but I'm still working on understanding it.

After re-reading your message a few time's, I think I understand, but I think I'm already doing what you suggest.

In my main program I have

Valve di(1, 15, 16, diwstart, diw); 
Valve tr(2, 3, 4, tritstart, trit);
Valve sd(3, 5, 6, sdcstart, sdc);
Valve na(4, 7, 8, naclstart, nacl);
Valve dn(5, 9, 10, dnasestart, dnase);
Valve pb(6, 11, 12, pbsstart, pbs);

Which establishes the variables and passes them to Valve.cpp, where I have

Valve::Valve(int v_num, int Opin, int Cpin, long start, long flow)
{

  valve_num = v_num;
  open_pin = Opin;
  close_pin = Cpin;  
  start_time = start;
  flow_time = flow;  // Duration valve is supposed to be open  

  
     pinMode(open_pin, OUTPUT);     
     pinMode(close_pin, OUTPUT); 

     updatepulse = pulse;
  
     valveopen = false; 
     Opin_state = LOW;
     Cpin_state = LOW;
     already_run = false;
     current_running = false;
     valveopen_state = false;
     openedMillis = 0;
     closedMillis = 0;
     run_time = 0;
}

When I call for Update() in void loop of my main program

di.Update();
tr.Update();
sd.Update();
na.Update();
dn.Update();
pb.Update();

Update() runs using the variables.

However, the problem is that the variables are passed from

Valve di(1, 15, 16, diwstart, diw); 
Valve tr(2, 3, 4, tritstart, trit);
Valve sd(3, 5, 6, sdcstart, sdc);
Valve na(4, 7, 8, naclstart, nacl);
Valve dn(5, 9, 10, dnasestart, dnase);
Valve pb(6, 11, 12, pbsstart, pbs);

in the main program to valve.cpp when the arduino powers up. I'm trying to figure out how to update the private variables through the serial monitor to change the private variables AFTER the arduino has powered up.

Here is striped down bit of my code to try to try to illustrate my question.

++++++ Main Sketch ++++++

Main.ino

1      // Declare variables for valve open and valve run times
2      long valve_1_open_time 
3      long valve_2_open_time 
4 
5      long valve_1_runTime 
6      long valve_2_runTime 
7 
8 
9      // Create instances and define variables to be passed to class using the format
10    // Valve "instance name"(valve number, open pin, close pin, open time, run time)
11
12    Valve V1(1, 4, 5, valve_1_open_time, valve_1_runTime);
13    Valve V2(2, 6, 7, valve_2_open_time, valve_2_runTime);
14
15
16    void setup()
17    {
18    Serial.begin...
18
19    Code to take variables from serial monitor and save as variables for open times and run times
20 
21    valve_1_open_time = number from PC
22    valve_2_open_time = number from PC
23
24    }
25
26
27    void loop()
28    {
29    // Calling the class with the arguments declared above
30    V1.Update();
31    V2.Update();
32    }
33
34
35    ++++++ Valve library ++++++
36
37    Valve.cpp
38
39    // Establish how declared arguments are parsed into variables for the class
40
41    Valve::Valve(int valve_number, int Open_pin, int Close_pin, long start_time, long run_time) 
42
43    {
44    _valve_number = valve_number;
45    _Open_pin = Open_pin;
46    _Close_pin = Close_pin;
47    _start_time = start_time;
48    _run_time = run_time;
49    }
50
51
52
53    void Valve::Update()
54    {
55    // Do stuff with the variables from Valve::Valve
56    Send voltage to open pin at start_time;
56    Send voltage to close pin after run_time has been completed;
57   }

My understanding of the flow is that I define the arguments in line 12 (ie valve_open_time) when I write the program. Then when the arduino powers up, the argument from line 12 (valve_open_time) is passed to the class, valve.cpp line 41 as (start_time), where it is converted/renamed to a private variable (_start_time).

Then when I call an instance of Update() from my main sketch as in line 30, Update() runs with the appropriate private variables established by line 41 (ie _start_time).

What I'd like to do is enter a variable through serial monitor in line 21 (valve_1_open_time) and have this variable replace the argument in line 12 (ie valve_open_time) and be passed to line 41 and ultimately to Update().

However, since the passing of arguments from line 12 to line 41 occurs at startup, if I later alter the line 12 variables through serial monitor, it's too late, they won't be passed to line 41. Is there a way to run line 12 again to pass the variables to line 41?

I'm looking for a way to alter the private variables (ie _start_time, line 47) after the arduino has powered up.
Or some other way to send a specific variable (ie _start_time) a specific instance of Update() (ie V1.Update().

This is essentially what you want to do. But, before going too much further, you should pause to gain a more accurate understanding of how classes work and how instances of them are created and used. Your posts contain too many misconceptions for me to correct. You need to do some self-study.

Good luck, enjoy learning to program and working on your projects.

PS -- I combined all the code into one file for simplicity of posting. You could break it into individual files at the places shown. If you do, be sure to add #include guards to the .h file.

//--------------------- Valve.h Starts Here ---------------------
class Valve {
  public:
    Valve(int16_t);
    void begin();
    void update();
    void changePrivateVariable(int16_t);

  private:
    int16_t privateVariable;
};
//--------------------- Valve.h Ends Here ---------------------





//--------------------- Valve.cpp Starts Here ---------------------
//#include Valve.h
Valve::Valve(int16_t priv) {
  // Constructor -- Initialize instance stuff here
  privateVariable = priv;
}

void Valve::begin() {
  // Begin Funtion --- Do your pinMode stuff here, NOT IN THE CONSTRUCTOR!!!!!!!!!!
}

void Valve::update() {
  // Update function for instances of the class
}

void Valve::changePrivateVariable(int16_t newValue) {
  privateVariable = newValue;
}
//--------------------- Valve.cpp Ends Here ---------------------



//--------------------- Main .ino File Starts Here ---------------------
//#include Valve.h
Valve instanceOfValve(7);

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

void loop() {
  instanceOfValve.update();

  // if (it's time to change the private variable to new value XXXX) {
  //   instanceOfValve.changePrivateVariable(XXX);
  // }
}

gfvalvo

gfvalvo:
This is essentially what you want to do. But, before going too much further, you should pause to gain a more accurate understanding of how classes work and how instances of them are created and used. Your posts contain too many misconceptions for me to correct. You need to do some self-study.

Good luck, enjoy learning to program and working on your projects.

PS -- I combined all the code into one file for simplicity of posting. You could break it into individual files at the places shown. If you do, be sure to add #include guards to the .h file.

Thank you for your efforts and multiple responses, I can't imagine how difficult it must be to try to dig through my amateur code and try to help.

Your code was very helpful and allowed me to solve my problem. I was trying to establish all of my variables in the the constructor rather than within the functions.
The trouble is, none of the tutorials or sample code I looked at used arguments within the individual functions so I didn't even realize this was possible until looking at your example above.

Now I need to rewrite most of my code to implement what I have learned :slight_smile:

Thanks again.