Is a class the answer to my function mess?


I periodically write code for embedded microcontrollers. Most of it is pretty simple. I've gotten by using functions. Some functions have static variables which will change value but are meant to stay in memory indefinitely, but this doesn't work when the function is used for more than one thing.

In my current project I've written several similar functions which return a float value representing a point in time of a waveform.
Some of these are used in multiple instances, so instead of using static variables in the function I am keeping variables in main and passing multiple variables from main to the function. This creates quite a mess. I've considered making multiple instances of each function, but I think this would be hard to maintain.

The function is called like this:

 
oscillator1 = TriangleWave (oscProgress1, oscPeriod1, oscStartTime1, oscAmplitude1);


The oscProgress1 variable is the only variable which changes every time the function is called.
I think a class would allow me to send the other variables when necessary and have multiple instances, right?
Are there simple examples of how you can send data to different instances and variables of a class and return data?

Forgive me if my terminology is poor. I'm not formally trained and have learned mostly from tutorials, examples and a couple of books.

Thanks

If the variables and functions are closely related you should move them into classes. This will clean up your code and allow you to create multiple instances of those classes.
The oscProgress1 variable is the only variable which changes every time the function is called.

If the period, starttime, amplitude all go together, you could just have something like:

1
2
3
4
5
struct osc {
    Type period;
    Type startTime;
    Type amplitude;
};


And then just have the function pass in the osc object.
Type TriangleWave(Type oscProgress1, const osc& the_osc);

1
2
3
4
5
osc osc1 { 1.0, 2.0, 3.0 };
for (int i = 0; i < 10; i++)
{
    TriangleWave(i, osc1);
}


(Note: "Type" is just a placeholder for whatever actual types you have)

_____________________________

But it should be said: We can't tell what exactly is messy about your code. All you've shown is a function or constructor with 5 parameters. 5 parameters isn't the end of the world, so if something is getting too complex, show us that part of your code, and someone could probably give more detailed advice.
Last edited on

All you've shown is a function or constructor with 5 parameters. 5 parameters isn't the end of the world, so if something is getting too complex, show us that part of your code, and someone could probably give more detailed advice.


I did spend some time writing some simplified code before I posted, but felt like it would lead to answers for questions I'm not asking. I'm using mbed for a 32 bit microcontroller. There are hardware specific lines of code, mbed library calls, hardware & timer interrupts. There is also a function to periodically read hardware pin with processing time considerations that uses several global variables. Up to 8 waveforms output in real time through a DAC.
I usually ask question on the mbed forum, but they are good at hardware questions, not so much about answers for general C++ structure.

I might not understand the use of classes (or structs as the example you gave) I have a lot of repetition and static variables. There's currently about 4000 lines of code. On several of the waveforms I'd like to add several more variables as this progresses. Being on a micocontroller resending this information over and over takes up a lot of time which is a problem when it's also trying to send the signals through a DAC in real time. Basically everything would be so much easier if variables could be sent independently when they are calculated for several instances of the same/similar "function."

Anyway I'm not sure I understand the code you posted.

1
2
3
4
5
struct osc {
    Type period;
    Type startTime;
    Type amplitude;
};

This is what I can call from main? This is like public in a class?


1
2
3
4
5
osc osc1 { 1.0, 2.0, 3.0 };
for (int i = 0; i < 10; i++)
{
    TriangleWave(i, osc1);
}

This is the method/function? The for loop is just an example of the waveform, not some other purpose?

I am probably asking too inelegantly.







the struct creates a user defined type. His struct has no functions, just data grouped together. you can use it like this:

osc x;
x.period = 3.14;

what he did was create a variable named osc1 with values ... the {} is like saying int x =3, its an init statement. Then he calls your function with the object instead of 4 loose variables. It just groups the 4 variables into one -- the most basic use of a struct is to group some variables together.

We don't know what your triangle function does, he is just calling it with reduced parameters by grouping them into the struct. everything else is the same.
however I suspect it may look more like this:

1
2
3
4
5
6
7
8
for (int i = 0; i < 10; i++)
{
     osc1.period = someperiodvariable;
     osc1.amplitude = someotherthing;
     ... ///etc
    TriangleWave(i, osc1);
}


BUT, here is the thing.
it you move the triangle function INTO the struct, you can do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct osc {
    Type period;
    Type startTime;
    Type amplitude; 
     double triangle() { return something;} //whatever your function returns... 
//this function can now use period etc as if local variables.
};

osc1.period = whatever; // maybe you set these one by one?
//OR
osc1.update(); //maybe you have a computation or function that can set all the fields to a new value at once from something?

result = osc1.triangle(); //it just works off the updated values now.    


maybe at this point it would be best if you show us sort of the syntax you would like to write (the useage parts). It may be slightly off from what is allowed, but we will see what you want to do... It may also be worth a quick review of what your embedded tool supports; some embedded tools do not support all of C++.

you can't really completely hide the fact that you have 4 items of data and need to set them. But you can reduce the number of times you tap all 4 over and over significantly.

depending on what you need done, you can also array it.
enum structlike {period, start, amp, max_sl};
double osc1[max_sl];
osc1[period] = 3.14; //etc
now you can pass it around as one double * and the named indices from the enum make it pretty. This is kind of C-ish but again, some embedded systems need a less-is-more coding approach.
Last edited on
To make Jonnin's suggestion fully match your original post, you'd add a progress parameter:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct osc {
    Type period;
    Type startTime;
    Type amplitude; 
     double triangle(Type progress) { return something;} //whatever your function returns... 
//this function can now use period etc as if local variables.
};

osc1.period = whatever; // maybe you set these one by one?
//OR
osc1.update(); //maybe you have a computation or function that can set all the fields to a new value at once from something?

result = osc1.triangle(progress); //it just works off the updated values now.  

felt like it would lead to answers for questions I'm not asking.
Perhaps, but you may find that there are ways to simplify your code that you aren't aware of.
Topic archived. No new replies allowed.