Help with how "functions" work.

Hi folks.

Another dumb question. :wink:

I don't know if they are called "functions", or "macros", or what ever......

For instance:
I want to have multiple timers running.

I make my "function" called TIMER and it is called. All the routine needs to know is who is calling it to derive the time to run. This may need work. But for the sake of learning this question....

So if I call it 4 times, will they all collide with each other, or will it automatically make 4 occurrences of the code?

Too vague a question.
If you have one TIMER, (macro or function or both) any storage either automatic or static will have only one instance.
If you want four different events at different times, you'll need to know to pass the function all state information for that event, or make TIMER a class with per instance storage.

lost_and_confused:
I don't know if they are called "functions", or "macros", or what ever......

Any of these could be appropriate, but without knowing what you're trying to achieve it's impossible to say which would work best.

What are you trying to achieve? Descriptions such as "have multiple timers running" are too vague - terms such as "timer" and "running" could have many different meanings. It also makes a difference whether you are working in an object-oriented environment or not, since different approaches would make sense in that environment.

Depends on your code...

You could have 4 timer classes all fire off and behave independenly of each other or you could be calling the same class 4 times and end up with memory issues...

But generally you pass the arguments, and then it goes off to where the procedure, function is in memory and begins executing the routine ... (not going into pointers, memory addresses, stack and heaps, jumps etc)

lost_and_confused:
I make my "function" called TIMER and it is called.

So show us the code so we know what you are actually doing?

If you are creating a normal function, as long as you do not use the static keyword, the instances will be totally independant of each other, but you can only call one at a time, since execution in the calling routine will stop until the function finishes.

KeithRB's comment is correct. If you define the function using the keyword static:

static int myFunction() {
   int i = 0;
   // and so on
}

only one copy of the function is defined in any case. However, if variable i is defined as static, only one instance of that variable is created for all calls to the function. In that case, function calls aren't quite independent of one another.

KeithRB:
If you are creating a normal function, as long as you do not use the static keyword, the instances will be totally independant of each other

econjack:
If you define the function using the keyword static only one copy of the function is defined in any case.

You both seem to be implying that without the use of static, it would be possible to end up with multiple copies of a function. Unless you're talking about methods (rather than functions), I think that implication is wrong. (If we're talking about methods then the examples quoted are wrong since they show ordinary functions.)

What I meant, and I was unclear that the static keyword only applied to variables declared and defined in the function, was that as long as no variables are declared static (and no global variables are referenced!), all calls to the function are independent from each other.

The static declaration of the function doesn't mean anything for this question.

I want to have multiple timers running.

OK. A common desire.

All the routine needs to know is who is calling it to derive the time to run. This may need work.

This is not particularly the way that functions work. You do not "figure out who is calling it" to derive what to do. Instead, you would pass information about what to do as parameters to the function.

So if I call it 4 times, will they all collide with each other, or will it automatically make 4 occurrences of the code?

A "function" would have a single occurrence of the code, and you would have to "take steps" to insure that it retains data for "multiple timers." A macro would repeat code 4 times, but you'd still have to take similar steps to make sure it didn't use the same data and "collide" anyway. Neither one will results in four things that run "at the same time."

Here's some code I wrote recently that does something similar to what I think you're trying to do. For the function "delay_without_delaying", the caller passes in information about a variable for storing data for that particular "timer", and how often it should expire.

boolean delay_without_delaying(unsigned long &since, unsigned long time) {
  // return false if we're still "delaying", true if time ms has passed.
  // this should look a lot like "blink without delay"
  unsigned long currentmillis = millis();
  if (currentmillis - since >= time) {
    since = currentmillis;
    return true;
  }
  return false;
}

unsigned long ledtime = 0;
unsigned long atime, btime, ctime, nltime;

void loop() {
  static int ledstate = false;
  if (delay_without_delaying(ledtime, 500)) {
    ledstate = !ledstate;
    digitalWrite(13, ledstate);
  }
  if (delay_without_delaying(atime, 100)) {
    Serial.print("A");
  }
  if (delay_without_delaying(btime, 200)) {
    Serial.print("B");
  }
  if (delay_without_delaying(ctime, 30)) {
    Serial.print("C");
  }
  if (delay_without_delaying(nltime, 1000)) {
    Serial.print("\n");
  }
}

Hi folks.

Sorry for the long delay in the reply.

CLASS - I think - is what I am wanting.

That name/term escaped me when I originally posted.

Shall look into it more.

PS:
Thanks for the example code.

Thanks westfw,

I SHALL look at the code, but other things have been happening.

With what I want to do, I was looking around and:

Click_button seems like a good thing to use as I can assign multiple functions to a button.

So thinking about the program flow and how to conceptualise it:
Are ven-diagrams useful?
They show how much of one thing is used/need in another and so variable names can be seen in relationship to the bigger picture.

I am starting to bash out some code, but it has been so long.

I have 5 outputs from the arduion.
1 for each of the outlets and 1 "main" one which powers everything.

The idea is that the circuit is usually DEAD.
I press a momentary action button which powers up the arduino. This immediately turns on the 5'th output which keeps power to the system.

If no buttons are pressed in 'n' seconds, it releases the relay.

If a button is pressed, other things happen.
Either an output is turned on, or the running time is edited.

If an output is turned on, it keeps/bypasses the time out until there are no outputs active.

But I am becoming (or always was) confused about how programs work at this level.

eg:
(in basics)
Print "This is a test"
Print "Hello world"

That is easy.
Now:
J$ = "This is a test"
K$ = "Hello world"
Print J$
Print K$

In the second one: Is the PRINT a "function", "Macro", "Routine", or "Class".
I believe with THIS example it is a function - as it does something.
But so do macro's, routine's and (maybe) classes.

In my code, so I scan for key inputs (using Click_button) at the "big" level, or do I call what I call routines and check for input there?

I shall do a bit more writing and then post my efforts.
For now they are "chicken's breakfast" and I don't want to annoy anyone looking through the code.
When I have a better grip on it, I shall post it.

Thanks.

Since we don't program in BASIC here, it doesn't really matter. But PRINT is a command, a built in operation of the intrepeter.

And venn diagrams have little to do with programming. Flow charts would be a bit more helpful. Are you trying to learn programming by dictionary?

As was already stated. Tell us what you want the program to do. If you can't describe it in words, you cannot program it.

Idea:
4 x mains outlets for chargers of different devices.
Arduino controlled relays to switch the chargers on/off when a button is pressed.
LCD to display time/status of outputs.
1 x "start" button to get things going.

Status quo:
No power.
I press a button and power is supplied to the Arduino.
It switches on a relay (parallel with the switch) and keeps power on.
If nothing happens in 'x' seconds, relays releases and everything is dead.

If a button is pressed, the relay for that outlet operates and power is given for 'n' minutes then it is turned off.
When 0 relays are operating, the unit "times out" and switches off.

Here is my SECOND attempt.

Yes, work is needed.

What I understand:
I shall have to write code to find out which button was pressed and return it.

The buttons will have MULTIPLE functions.
Normal functions select the outlet to turn on/off.
Holding the button takes you into the edit menu where you edit the times with "up/down and yes/no" buttons. (no long hold functions yet.) Though I may make long hold move times quicker.

The display will show the status of each outlet and time left - future work.

Where I am getting confused is:
The buttons are "classes" - I think the term is.
So down the code I turn the outlets on/off with discreet blocks of code.
Can I make that code like the buttons?

If so: How?
Granted I probably (obviously) don't understand it, but I am TRYING.
Could someone give me a helping shove?

/*
/*
This is my routine to control 4 power points for timed periods.
There are 4 buttons used.  Each has multiple functions.

There are:
5 output pins.
and 4 input pins.

I also need to change the pins later when I add a display.
For now I am just using pins for the sake of testing and getting my head around the code.
The fancy stuff comes later.

*/

#include "ClickButton.h"

#define Main_Power 6
#define Output1 7
#define Output2 8
#define Output3 9
#define Output4 10
#define B1P 2
#define B2P 3
#define B3P 4
#define B4P 5

#define timeout 5      // number of seconds for timeout of unit.

long currentTime;

const int buttonPin1 = B1P;
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
const int buttonPin2 = B2P;
ClickButton button2(buttonPin2, LOW, CLICKBTN_PULLUP);
const int buttonPin3 = B3P;
ClickButton button3(buttonPin3, LOW, CLICKBTN_PULLUP);
const int buttonPin4 = B4P;
ClickButton button4(buttonPin4, LOW, CLICKBTN_PULLUP);


void setup()
{
  // put your setup code here, to run once:
  
  //  This is the pins and what they do.
  //  Not sure if I need the first 4 lines for the inputs.
  pinMode(B1P,INPUT);
  pinMode(B2P,INPUT);
  pinMode(B3P,INPUT);
  pinMode(B4P,INPUT);
  pinMode(Main_Power,OUTPUT);
  pinMode(Output1,OUTPUT);
  pinMode(Output2,OUTPUT);
  pinMode(Output3,OUTPUT);
  pinMode(Output4,OUTPUT);

  bootup(1);             // Turn on power to the system.
  
}

void loop()
{
  // put your main code here, to run repeatedly:
  int time_left;        //  How many seconds left before shut down
  int active_timer;     //  Returns 1 if any of the 4 outputs are active
  int shut_down;        //  Returns 1 if system to be shut down.
  int button_pressed;   //  Says a button is pressed.
  //
  //
  
  // Need to check if any timers are running and if they are, skip this function.
  shut_down = timer_reset();
  if (shut_down == 1)
  {
    bootup(0);
  }
  //
  button_pressed = check_buttons();
  switch (button_pressed)
  {
    case 0:
    break;
    
    case 1:
    outlet_1();
    break;
  
    case 2:
    outlet_2();
    break;

    case 3:
    outlet_3();
    break;

    case 4:
    outlet_4();
    break;
  
    case 5:
    edit(1);
    break;
  
    case 6:
    edit(2);
    break;
  
    case 7:
    edit(3);
    break;
  
    case 8:
    edit(4);
    break;
  }
  
}
//========================================================================
void bootup(int action)
{
  //
  if (action == 1)
    digitalWrite(Main_Power,HIGH);
  else
  if (action == 0)
    digitalWrite(Main_Power,LOW);
  //
}
//========================================================================
int timer_reset()
{
  currentTime = (long)millis();
  return (0);  // for now.
}
//========================================================================
int check_buttons()
{
  //  This routine checks if any button has been pressed.
  return (0);   // for now.
  int button_value;
  button1.Update();
  if (button1.click != 0)
  {
    if (button1.click == 1)
      button_value = 1;
    if (button1.click == 2)
      button_value = 5;
  }
  button2.Update();
  if (button2.click != 0)
  {
    if (button2.click == 1)
      button_value = 2;
    if (button2.click == 2)
      button_value = 6;
  }
  button3.Update();
  if (button3.click != 0)
  {
    if (button3.click == 1)
      button_value = 3;
    if (button2.click == 2)
      button_value = 7;
  }
  button4.Update();
  if (button4.click != 0)
  {
    if (button4.click == 1)
      button_value = 4;
    if (button2.click == 2)
      button_value = 8;
  }
  return (button_value);
}
//========================================================================
void outlet_1()
{
  //
  
}
//========================================================================
void outlet_2()
{
  //
  
}
//========================================================================
void outlet_3()
{
  //
  
}
//========================================================================
void outlet_4()
{
  //
  
}
//========================================================================
int edit(int outlet)
{
  //
  
}

Ok,

I have learned some things, but it still isn't working.

I have mod'ed the code to only 1 input pin and it sort of works.

When I press the button I get/see a result on the screen scrolling past and the values look right.

But when the value is 0, the LED doesn't turn off.

Help!

Yes there is a lot of remarked code. That shows how much I am stuck.

If you see things wrong, let me know.

But it is supposed to turn the LED off, loop looking for the switch to be pressed.
When it does, it toggles the LED.

Yeah, the turn off is in the main loop. Hang on.

The LED never turns off.

It is off at initial loading of the code, but after a couple of seconds it is on and always on.

If/when I get it working, I shall change the structure a bit - which is why I left in the other code.
It may be problematic.
But I may get to it when I get past this problem, but am still looking for help.

/*
This is my routine to control 4 power points for timed periods.
There are 4 buttons used.  Each has multiple functions.

There are:
5 output pins.
and 4 input pins.

I also need to change the pins later when I add a display.
For now I am just using pins for the sake of testing and getting my head around the code.
The fancy stuff comes later.

*/


#include "ClickButton.h"

#define Main_Power 6
#define Output1 7
#define Output2 8
#define Output3 9
#define Output4 10
#define B1P 2
#define B2P 3
#define B3P 4
#define B4P 5

#define timeout 5      // number of seconds for timeout of unit.

int LED_State = 0;

int button1_function = 0;
int button2_function = 0;
int button3_function = 0;
int button4_function = 0;

long currentTime;

//const int buttonPin1 = B1P;
ClickButton button1(2, LOW, CLICKBTN_PULLUP);
//const int buttonPin2 = B2P;
//ClickButton button2(B2P, LOW, CLICKBTN_PULLUP);
//const int buttonPin3 = B3P;
//ClickButton button3(B3P, LOW, CLICKBTN_PULLUP);
//const int buttonPin4 = B4P;
//ClickButton button4(B4P, LOW, CLICKBTN_PULLUP);


void setup()
{
  // put your setup code here, to run once:

  Serial.begin(9600);
  
  //  This is the pins and what they do.
  //  Not sure if I need the first 4 lines for the inputs.
  pinMode(Main_Power,OUTPUT);
  pinMode(Output1,OUTPUT);
  pinMode(Output2,OUTPUT);
  pinMode(Output3,OUTPUT);
  pinMode(Output4,OUTPUT);

  // Setup button timers (all in milliseconds / ms)
  // (These are default if not set, but changeable for convenience)
  button1.maxPresses     = 3;    // max button multiclick count
  button1.debounceTime   = 20;   // Debounce timer in ms
  button1.multiclickTime = 250;  // Time limit for multi clicks
  button1.heldDownTime   = 1000; // time until "held-down clicks" register

/*
  // Setup button timers (all in milliseconds / ms)
  // (These are default if not set, but changeable for convenience)
  button2.maxPresses     = 3;    // max button multiclick count
  button2.debounceTime   = 20;   // Debounce timer in ms
  button2.multiclickTime = 250;  // Time limit for multi clicks
  button2.heldDownTime   = 1000; // time until "held-down clicks" register

  // Setup button timers (all in milliseconds / ms)
  // (These are default if not set, but changeable for convenience)
  button3.maxPresses     = 3;    // max button multiclick count
  button3.debounceTime   = 20;   // Debounce timer in ms
  button3.multiclickTime = 250;  // Time limit for multi clicks
  button3.heldDownTime   = 1000; // time until "held-down clicks" register

  // Setup button timers (all in milliseconds / ms)
  // (These are default if not set, but changeable for convenience)
  button4.maxPresses     = 3;    // max button multiclick count
  button4.debounceTime   = 20;   // Debounce timer in ms
  button4.multiclickTime = 250;  // Time limit for multi clicks
  button4.heldDownTime   = 1000; // time until "held-down clicks" register
*/



  bootup(1);             // Turn on power to the system.
  
}

void loop()
{
  // put your main code here, to run repeatedly:
  delay(100);
  Serial.println("Looping");
  int time_left;        //  How many seconds left before shut down
  int active_timer;     //  Returns 1 if any of the 4 outputs are active
  int shut_down;        //  Returns 1 if system to be shut down.
  int button_pressed;   //  Says a button is pressed.
  
  digitalWrite(13,0);
  Serial.println(" ");
  Serial.println("**");
  //
  //
  
  // Need to check if any timers are running and if they are, skip this function.
  shut_down = timer_reset();
  if (shut_down == 1)
  {
    bootup(0);
  }
  //
//  button_pressed = check_buttons();
  //  This routine checks if any button has been pressed.
  button1.Update();
  if (button1.click != 0) button_pressed = button1.click;
  
  if (button1.click == 1) button_pressed = 1;
  if (button1_function == 2) button_pressed = 5;
  Serial.println(button_pressed);

  switch (button_pressed)
  {
    case 0:
    break;
    
    case 1:
    outlet_1();
    break;
  
    case 2:
    outlet_2();
    break;

    case 3:
    outlet_3();
    break;

    case 4:
    outlet_4();
    break;
  
    case 5:
    edit(1);
    break;
  
    case 6:
    edit(2);
    break;
  
    case 7:
    edit(3);
    break;
  
    case 8:
    edit(4);
    break;
  }
  
  
}
//========================================================================
void bootup(int action)
{
  //
  if (action == 1)
    digitalWrite(Main_Power,HIGH);
  else
  if (action == 0)
    digitalWrite(Main_Power,LOW);
  //
}
//========================================================================
int timer_reset()
{
  currentTime = (long)millis();
  return (0);  // for now.
}
//========================================================================
int check_buttons()
{
  //  This routine checks if any button has been pressed.
  button1.Update();
  if (button1.click != 0) button1_function = button1.click;
  
  if (button1.click == 1) return (1);
  if (button1_function == 2) return (5);
}
  
    /*
  {
    //
    button1_function = button1.click;
    Serial.println("Boo!");
//    if (button1.click == 1)
    if (button1.click == 1)
    {
      button_value = 1;
      return (button_value);
    }
    if (button1.click == 2)
      button_value = 5;
  }
  button2.Update();
  if (button2.click != 0)
  {
    if (button2.click == 1)
      button_value = 2;
    if (button2.click == 2)
      button_value = 6;
  }
  button3.Update();
  if (button3.click != 0)
  {
    if (button3.click == 1)
      button_value = 3;
    if (button2.click == 2)
      button_value = 7;
  }
  button4.Update();
  if (button4.click != 0)
  {
    if (button4.click == 1)
      button_value = 4;
    if (button2.click == 2)
      button_value = 8;
  */
//  }
  
//  return (button_value);
//}
//========================================================================
void outlet_1()
{
  //
  LED_State = !LED_State;
  Serial.println(" ");
  Serial.println(" ");
  Serial.println("Button 1 pressed");
  Serial.println(LED_State);
  Serial.println(" ");
  Serial.println(" ");
  digitalWrite(13,LED_State);
  
}
//========================================================================
void outlet_2()
{
  //
  
}
//========================================================================
void outlet_3()
{
  //
  
}
//========================================================================
void outlet_4()
{
  //
  
}
//========================================================================
int edit(int outlet)
{
  //
  
}




//  below is code I got from the example "click_button" function to show me how to make a countdown timer with no RTC and no delay.

/*
  currentTime = (long)millis();

  button1.Update();

  if (button1.click != 0) function = button1.click;
  
  // Toggle LED on single clicks
  if(button1.click == 1) ledState = !ledState;

  // fade if button is held down during single-click
  if(function == -1 && button1.depressed == true)
  {
    ledState = true;  // force lights on, since we want to fade it up or down
    
    if (oldFadeUp == fadeUp) fadeUp = !fadeUp; // Switch direction
    
    if ( currentTime - adjustFaderTime > fadeDelay)
    {
      adjustFaderTime = currentTime + fadeDelay;
      if (fadeUp) fadeValue++; else fadeValue--;

      // Some boundary checking
      // Using signed ints, we can check for below 0 and above 255 (byte limit)
      if (fadeValue > 255) fadeValue = 255;
      if (fadeValue < 0)   fadeValue = 0;
      
    }

  } else {
    // Save old fade direction for next time
    oldFadeUp = fadeUp;
    // Reset function
    function = 0;
  }
*/

Why complicate things?

Your IDE as example sketches that teach many things too.
Being unfamiliar with C, it's a good idea to get exposure to working code.

Well...Your code is very 'jumbled up' at the moment, which I put down to you being too ambitious while struggling to understand the fundamentals.

I honestly think the best thing you could do is read a book on learning to program. I highly recommend 'Beginning C for Arduino' by Jack Purdum (Ph.D.) It is not too expensive, not too long, not too heavy going and will get you up to speed, a lot faster than reading forum posts. You might even be able to find the book as a pdf download.

What I would do in your position, is get hold of a packet of LEDs and complete some simple projects. Each project should test one aspect of your design at a time, and teach you one thing at once. Make one button light one LED. Then put a timer on the LED. Then one button lighting two LEDs.

I am sure you will find more forum participants prepared to help you, if you are prepared to break your problem down.

GoForSmoke:
Why complicate things?
http://arduino.cc/en/Reference/FunctionDeclaration

Your IDE as example sketches that teach many things too.
Being unfamiliar with C, it's a good idea to get exposure to working code.

Thanks, but as someone said: I am not exactly writing SUB ROUTINES.

I am wanting to make a bit of code which can be run concurrently with multiple iterances (can't find the right spelling).

That is way beyond my programming experiences. I can deal with "GOSUB" and that kind of thing, but this is just a whole other layer.

I'll look for the book though and see if it can help me.

The problem with the code now is the LED doesn't turn off. I see the code happening to make it turn off - the value changes when I press the button - but the LED stays on.

Dunno why.

Anyway, I'll keep looking, learning and trying.

Thanks.

I am wanting to make a bit of code which can be run concurrently with multiple iterances

that is a complicated thing to do.

Were you able to figure out the "delay_without_delaying()" code that a posted a while back?

I think that you need the Nick Gammon how to do multiple things at once blog!
It's about making things happen on time, and is extremely well laid out for ease of learning.

This question comes up practically every day on the Arduino forum - "how do I blink two LEDs at different rates?" or "how do I turn on and off two motors at different times?".