question on Functions and syntax

First can I calculate several variables within a function and then in the loop call just the variable that I need? If so how do I write it?

Would it be something like this? Assuming all variables were defined previously

int outputCalc() 
{
float output1;
float output2;
float output3;
float output4;
output1 = signal1 * manual / 4092.0;
output2 = signal2 * manual / 4092.0;
output3 = signal3 * manual / 4092.0;
output4 = signal4 * manual / 4092.0;
return output1; //is it possible to list multiple data in the return?
}

Then in the loop use

pwmout = outputCalc(output4);
// will this call a single value from the function?

I calculate several variables within a function and then in the loop call just the variable that I need?

No.

That code doesn't even return a value.

OK, so its not possible to pull a single variable from a function?
So then I have to set my input value before each function call. In that case does this look like a usable function?

// function for calculation
int targetCal() {
  float rangehigh = target + target * .10;
  float rangelow = target - target * .10;
  float dzhigh = target + target * .03;
  float dzlow = target - target * .03;
  float pwm;
  if (signal < rangelow) {
   pwm +=20; //increase fast
}
   else if (signal > rangelow && signal < dzlow){
   pwm ++;  //increase slow
} 
if (signal > rangehigh) {
    pwm -=20;  //decrease fast
}
   else if (signal < rangehigh && signal > dzhigh){
   pwm --;  //decrease slow
} 
  
 return pwm;
}

Assuming before each function call I set the current value of “signal”, then

pwm1out = targetCal();

If pwm is a global variable why do you have to return it from the function?

I think what you're after is an array of output values

#define scale(x) ((x) * manual /4092.0) /* (shorthand) */

float opv[] = { scale(signal1),scale(signal2),scale(signal3),scale(signal4) };

so that you can reference these values by subscript

pwmout = opv[3];

I see pwm is declared as a local variable (was that your edit?). Now it's well and truly broken, pwm will take a value of whatever happens to be on the stack, adjust it and return it.

Have you considered using the PID library - seems well suited to what you're trying to do 'by hand'

return output1; //is it possible to list multiple data in the return?

No, this isn’t Lua or similar languages.

  • You can return a single value.
  • You can alter a global variable which can then be referenced outside the function.
  • You can pass an array by reference, and change it, see example below
void calc (float (& foo) [5])
  {
  for (byte i = 0; i < 5; i++)
    foo [i] *= 2.5;
  }
  
void setup ()
 {
 float bar [5] = { 42, 33, 22, 11, 5 };
 calc (bar);
 }
 
void loop () {}

So then I have to set my input value before each function call.

Just define target as the function argument:

int targetCal(float target)

The function ...

void outputCalc(float* result1, float* result2, float* result3, float* result4)
{
    *result1 = signal1 * manual / 4092.0;
    *result2 = signal2 * manual / 4092.0;
    *result3 = signal3 * manual / 4092.0;
    *result4 = signal4 * manual / 4092.0;
}

... and how to call it by passing the address of the variables for the function to fill-in.

float result1;
float result2;
float result3;
float result4;
outputCalc(&result1, &result2, &result3, &result4);

You can avoid all those pointers:

void outputCalc(float & result1, float & result2, float & result3, float & result4)
{
    result1 = signal1 * manual / 4092.0;
    result2 = signal2 * manual / 4092.0;
    result3 = signal3 * manual / 4092.0;
    result4 = signal4 * manual / 4092.0;
}

Called like this:

float result1;
float result2;
float result3;
float result4;
outputCalc(result1, result2, result3, result4);

For some reason I thought the ever helpful IDE interfered with the use of references for functions located within the ‘pde’ file based on early experiments on my part. Glad to find out I was somehow mistaken and wonder how I became so confused on this one?

JHEnt: First can I calculate several variables within a function and then in the loop call just the variable that I need? If so how do I write it?

Would it be something like this? Assuming all variables were defined previously

int outputCalc() 
{
float output1;
float output2;
float output3;
float output4;
output1 = signal1 * manual / 4092.0;
output2 = signal2 * manual / 4092.0;
output3 = signal3 * manual / 4092.0;
output4 = signal4 * manual / 4092.0;
return output1; //is it possible to list multiple data in the return?
}

Then in the loop use

pwmout = outputCalc(output4);
// will this call a single value from the function?

Without commenting on the suitability of the code you have defined a function that takes no parameters and returns an int (nothing wrong with that but) then you call the function with a parameter, output4. You shouldn't be able to compile that.

As pointed out, you can pass pointers/references as function parameters (really called arguments or args) including array addresses (address of int var[10] is var) to 'get inside' of a function or you can use globals inside the function and not need the args (which do grow the stack until function return which shrinks the stack) at all. In a larger environment I'd be against the globals but with so little SRAM I am certainly not.

For some reason I thought the ever helpful IDE interfered with the use of references for functions located within the 'pde' file based on early experiments on my part. Glad to find out I was somehow mistaken and wonder how I became so confused on this one?

There IS a problem with functions with reference arguments. That is that the IDE fails to create prototypes for functions with reference arguments. You can create the function prototype, though, and use functions with reference arguments.

Here's what I am wanting to do. I am building an offroad vehicle with 4 wheel suspension. I want to use active pwm hydraulic pressure to regulate the ride height of the suspension based on pots or non contact pot type sensors. I believe I have a working code for direct proportional output based on sensor input but due to the front to rear axel weights being very different and the rear axel load changing by as much as 5000lbs I think a target based control will work much better. I am taking 4 pot sensors and averaging 10 readings each in separate indexes. So in my main code I get left front wheel as average1. I was wanting to learn about using the functions to cut back on reentering the same equation and statements 4 times in the loop. So if it is not easy to get 4 results separate out of a function I was going to assign "signal" = "average1", then call "lfoutput" = to the return of the function. Then again after doing the right front average setting "signal" = "average2" then call "rfoutput" = to the function return value and so on in the loop.

Please keep in mind I am learning as I go here. Someone pointed me in the direction of the Arduino a week ago and this is the first programming I have done since 20 years ago in BASIC.

Post your code. It's highly likely that a function can simplify it - you can probably have a function that takes the pot pin as an argument and handles getting the 10 readings and returning an average for example. Consider giving your variables more meaningful names too - average1 isn't very helpful.

Consider giving your variables more meaningful names too - average1 isn't very helpful.

Arrays are very useful, too. You have 4 pretty much identical things. They belong in an array.

Distinguishing which one you want to deal with can be a challenge. Is the right, front wheel index 3 or is it 0 or is it something else?

That's where an enum is so useful: enum wheel {RF, LF, RR, LR};

Then, the right, front (RF) wheel is at some position in the array (the exact position matters, but you son't need to remember what it is). Simply know that the RF pin is in an array, and the RF data is in another array. The pin number and data will be in the same position in the two arrays, but the exact position is not useful for you to know.

Here’s what I have so far

const int numReadings = 10;
 
int lfindex[numReadings];      // the readings from the analog input
 int index = 0;                  // the index of the current reading
 int total = 0;                  // the running total
 int average = 0;                // the average
 
 int rfindex[numReadings];                 
 int total1 = 0;
 int lrindex[numReadings];        
 int total2 = 0;
int rrindex[numReadings];     
 int total3 = 0;
 int index1 = 0;
int index2 = 0;
int index3 = 0;
int average1 = 0;
int average2 = 0;
int average3 = 0;

// pin assignments
int switchpin = 4;
int lfin = A0;
int rfin = A1;
int lrin = A2;
int rrin = A3;
int man = A4;
int lfout = 3;
int rfout = 5;
int lrout = 6;
int rrout = 9;

// variables start at zero

int switchstate;
int lfpwm = 0;
int rfpwm = 0;
int lrpwm = 0;
int rrpwm = 0;
int signal;
int target = 520;
float manual;

void setup()
 {
 
   Serial.begin(9600);                   
 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     lfindex[thisReading] = 0; 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     rfindex[thisReading] = 0;
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     lrindex[thisReading] = 0;
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     rrindex[thisReading] = 0;
     
pinMode (lfout, OUTPUT);
pinMode (rfout, OUTPUT);
pinMode (lrout, OUTPUT);
pinMode (rrout, OUTPUT);
pinMode (switchpin, INPUT);
pinMode (lfin, INPUT);
pinMode (rfin, INPUT);
pinMode (lrin, INPUT);
pinMode (rrin, INPUT);
pinMode (man, INPUT);

     
 }
// function for calculation
int targetCal() {
  float rangehigh = target + target * manual;
  float rangelow = target - target * manual;
  float dzhigh = target + target * .03;
  float dzlow = target - target * .03;
  float pwm;
  if (signal < rangelow) {
   pwm +=20; //increase fast
}
   else if (signal > rangelow && signal < dzlow){
   pwm ++;  //increase slow
} 
if (signal > rangehigh) {
    pwm -=20;  //decrease fast
}
   else if (signal < rangehigh && signal > dzhigh){
   pwm --;  //decrease slow
} 
  
 return pwm;
} 
 
void loop() 
{
manual = analogRead(man) / 100.0; // operator input potentiomter
switchstate = digitalRead(switchpin); // operator on off switch

// left front control
  total= total - lfindex[index];          
   lfindex[index] = analogRead(lfin); 
   total= total + lfindex[index];         
   index = index + 1;                    
   if (index >= numReadings)              
    index = 0;                           
   average = total / numReadings; 
   signal = average;
   
  lfpwm = targetCal();
  
  if (switchstate == HIGH) {
  analogWrite (lfout, lfpwm); 
  }
  else {
  digitalWrite(lfout, LOW);
  }
  total1= total1 - rfindex[index1];          
   rfindex[index1] = analogRead(rfin); 
   total1= total1 + rfindex[index1];         
   index1 = index1 + 1;                    
   if (index1 >= numReadings)              
    index1 = 0;                           
   average1 = total1 / numReadings; 
   signal = average1;
   
   rfpwm = targetCal();
   
   if (switchstate == HIGH)   {
   analogWrite (rfout, rfpwm);
   }
   else {
  digitalWrite(rfout, LOW);
  }
  
   total2= total2 - lrindex[index2];          
   lrindex[index2] = analogRead(lrin); 
   total2= total2 + lrindex[index2];         
   index2 = index2 + 1;                    
   if (index2 >= numReadings)              
    index2 = 0;                           
   average2 = total2 / numReadings; 
  signal = average2;
  
  lrpwm = targetCal();
  
  if (switchstate == HIGH)   {
  analogWrite (lrout, lrpwm);
  }
  else {
  digitalWrite(lrout, LOW);
  }
  
  total3= total3 - rrindex[index3];          
   rrindex[index3] = analogRead(rrin); 
   total3= total3 + rrindex[index3];         
   index3 = index3 + 1;                    
   if (index3 >= numReadings)              
    index3 = 0;                           
   average3 = total3 / numReadings; 
 signal = average3;
 
 rrpwm = targetCal();
 
 if (switchstate == HIGH)  {
  analogWrite (rrout, rrpwm);
 }
 else {
  digitalWrite(rrout, LOW);
  }
 
  
  Serial.print(lfpwm);
  Serial.print("\t");
  Serial.print(rfpwm);
  Serial.print("\t");
  Serial.print(lrpwm);
  Serial.print("\t");
  Serial.print(rrpwm);
  Serial.print("\t" );
  Serial.print(manual);
  Serial.print("\t");
  Serial.print("");
  Serial.println("left front, right front, left rear, right rear, manual input");
  
  
}
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     lfindex[thisReading] = 0; 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     rfindex[thisReading] = 0;
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     lrindex[thisReading] = 0;
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
     rrindex[thisReading] = 0;

vs:

  for (int thisReading = 0; thisReading < numReadings; thisReading++)
  {
     lfindex[thisReading] = 0; 
     rfindex[thisReading] = 0;
     lrindex[thisReading] = 0;
     rrindex[thisReading] = 0;
  }

Typically, loop variables are single letter names.

  for (int n = 0; n < numReadings; n++)
  {
     lfindex[n] = 0; 
     rfindex[n] = 0;
     lrindex[n] = 0;
     rrindex[n] = 0;
  }
// variables start at zero
int target = 520;

Zero, huh?

  float rangehigh = target + target * manual;
  float rangelow = target - target * manual;
  float dzhigh = target + target * .03;
  float dzlow = target - target * .03;

I’d strongly recommend some parentheses in these statements, to make it clear what you are trying to do.

  if (signal < rangelow) {
   pwm +=20; //increase fast
}
   else if (signal > rangelow && signal < dzlow){
   pwm ++;  //increase slow
}

would be so much easier to read as:

  if (signal < rangelow)
  {
    pwm +=20; //increase fast
  }
  else if (signal > rangelow && signal < dzlow)
  {
    pwm ++;  //increase slow
  }
   index = index + 1;

Sooner or later, you’ll embrace the ++ operator, and look less like a Fortran programmer.

PaulS: There IS a problem with functions with reference arguments. That is that the IDE fails to create prototypes for functions with reference arguments. You can create the function prototype, though, and use functions with reference arguments.

I seem to recall having this problem and placing the function prototypes ahead of their usage but the IDE interfered and placed conflicting prototypes somewhere that caused the compiler to complain. I guess I'll have to backtrack and experiment some more to find my point of confusion.

Anyway, thanks for the correction Paul.