Adding subroutines after setup() and loop()

Hi Guys

Sorry if this topic has been answered somewhere else but I just cant find exactly what I'm looking for. I have perfected my Model Train Level Crossing program but I want to add a couple of basic turn on/turn off subroutines to my program so I can independently control street lights, building lights, track lights, etc. with my Mega2560. I've looked at quite a few sketches from other people but I still don't understand how to add subs after the void loop() routine.

Thankyou in advance for your advice and replies

I've looked at quite a few sketches from other people but I still don't understand how to add subs after the void loop() routine.

Just like everybody else does it. A function is, effectively, a named block of code with a return type and zero or more arguments.

returnType functionName(argType1 argName1, ..., argTypeN argNameN)
{
   // The code goes here

   return aValueOfTheCorrectType; // Not needed if the type is void
}

Then, in place of the block of code that you have now, you call the function:

   returnType variable = functionName(argValue1, ..., argValueN);

Any C book should have plenty of examples of writing and calling functions. Last time I checked, there were even a few resources available online.

This is the main program :

#include <Servo.h>

Servo myservo;
   
const int R1 = 9;  // 1st Red LED
const int R2 = 10;  // 2nd Red LED
const int G = 11;  // Green Active LED
const int R = 12;  // Red inactive LED
const int SW1 = 2; // switch number and input pin


int SW1State = 0;     // variable for reading switch #1
int running = 0;
int long interval = 500;
long previousMillis = 0;
int R1State = HIGH;
int pos = 0;

void setup() {
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(R, OUTPUT);
  pinMode(SW1, INPUT);     
  myservo.attach(7);
  digitalWrite(SW1, HIGH);

}
  
  // the loop routine runs and stops after last command
void loop() {
  
  int SW1 = digitalRead(SW1);
  
       
    // the switch has been activated and the program can run 
  if (SW1 == HIGH && running == 0) {
    int running = 1;
     tone(8, 900, 500); // play SOUND
     digitalWrite(G, HIGH); // turn on GREEN LED
     myservo.write(45);
     delay(1500);
     digitalWrite(G, LOW); // turn off GREEN LED
     digitalWrite(R2, LOW); // turn the LED off
     digitalWrite(R1, LOW); // turn the LED off
     delay(250);
     digitalWrite(R1, HIGH); // turn the LED on
     digitalWrite(R2, HIGH); // turn the LED on
     delay(2500);
           SW1 = digitalRead(SW1);
        while(SW1 == LOW && running == 1)  {

// Timer used instead of delay to allow input to be read at the same time
          unsigned long currentMillis = millis(); 
          
          if(currentMillis - previousMillis > interval) {
            previousMillis = currentMillis;
            
            if (R1State == HIGH){ // Switches lights over
              digitalWrite(R1, LOW);
              digitalWrite(R2, HIGH);
              R1State = LOW;
            }
            else {
              digitalWrite(R1, HIGH); // Switches lights over
              digitalWrite(R2, LOW);
              R1State = HIGH;
            }
          }
 // Terminates program and switches off lights if the trigger input is detected
            SW1 = digitalRead(SW1); 
            if (SW1 == HIGH){
              digitalWrite(10, LOW); // turn the LED off
              digitalWrite(9, LOW); // turn the LED off 
              tone(8, 900, 500); // play SOUND 
              digitalWrite(12, HIGH); // turn on RED LED
              delay(1500);
              myservo.write(0);
              digitalWrite(12, LOW); // turn off RED LED
              int R1State = LOW;
              delay(5000);
              int running = 0;
              break;
            }
          }
        }
  }

This is the main program

And? Was there a question?

              int running = 0;
              break;

This local variable is not the same as this local variable:

    int running = 1;
// snip snip
        while(SW1 == LOW && running == 1)  {

I suspect that you meant to set the first running to 0, not create a new one. Remove the int declaration on the second statement. The compiler can remember that running is an int.

Oops!! Sorry.. My question is can I just simply add :

void BuildingLights()

as a subroutine and put in some code to be able to turn the lights on and off without interfering with the main void loop() ??

My question is can I just simply add...as a subroutine and put in some code to be able to turn the lights on and off

Yes.

without interfering with the main void loop() ??

I'm not sure what you mean by "interfering with". You have to call the function. It will take as much time as it needs to execute, and then return and execute the next instruction in loop().

Creating a function is not a way to spawn another thread. The Arduino doesn't do threads.

All is revealed here

All is revealed here

I looked for that. Not too hard, I'll admit.

I had time to look properly to help another member earlier today....

OK, so how would I go about integrating this code into my program?

int ledPin = 5;
int buttonApin = 9;
int buttonBpin = 8;
 
byte leds = 0;
 
void setup() 
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonApin, INPUT_PULLUP);  
  pinMode(buttonBpin, INPUT_PULLUP);  
}
 
void loop() 
{
  if (digitalRead(buttonApin) == LOW)
  {
    digitalWrite(ledPin, HIGH);
  }
  if (digitalRead(buttonBpin) == LOW)
  {
    digitalWrite(ledPin, LOW);
  }
}

OK, so how would I go about integrating this code into my program?

Using a text editor?

Your existing code does something. That code does something. The combined code should do something. Those three somethings are not defined, though, so we can't help you.

With all due respect PaulS, What exactly am I needing to define, bearing in mind I'm only a newby and still trying to understand this stuff?

What you said in your last post was that you wanted to incorporate this code into that code.

This code looks pretty simple. Turn an LED on if a switch is pressed. Turn it off if a different switch is pressed.

That code was posted in reply #2, but there was no explanation of what it does.

When you merge this code and that code to produce a new program, the new program should do so stuff.

What you need to do is explain what that stuff should be, so that we can help you merge the two programs.

It really looks like you just need to copy the two pinMode() calls from this setup() to that setup() and copy all the code from this loop() to that loop().

The potentially blocking nature of that code, though, could be a problem.

This my program with the new part added but I've done something wrong cause the new part doesn't work? Any ideas?

#include <Servo.h>

Servo myservo;
   
const int R1 = 9;  // 1st Red LED
const int R2 = 10;  // 2nd Red LED
const int G = 11;  // Green Active LED
const int R = 12;  // Red inactive LED
const int SW1 = 2; // switch number and input pin
const int SW2 = 3;
const int SW3 = 4;
const int Building = 53;  // Building lights pin

int SW1State = 0;     // variable for reading switch #1
int running = 0;
int long interval = 500;
long previousMillis = 0;
int R1State = HIGH;
int pos = 0;

void setup() {
  pinMode(R1, OUTPUT);  // RHS Flasher
  pinMode(R2, OUTPUT);  // LHS Flasher
  pinMode(G, OUTPUT);  // Active Program
  pinMode(R, OUTPUT);  // Inactive Program
  pinMode(Building, OUTPUT);  // Building Lights
  pinMode(SW1, INPUT);  // Crossing switch
  pinMode(SW2, INPUT);  // Building lights on
  pinMode(SW3, INPUT);  // Building lights off
  myservo.attach(7);  // Boom gate servo
  digitalWrite(SW1, HIGH);

}
  
  // the loop routine runs and stops after last command
void loop() {
  
 [font=Verdana]if (digitalRead(SW2) == HIGH)  // these 4 lines are to turn the building
  {
    digitalWrite(Building, HIGH);  // lights on and off
  }
  if (digitalRead(SW3) == HIGH)  // but I think somewhere I have either
  {
    digitalWrite(Building, LOW);  // missed or forgotten something
  }[/font]
  
    int SW1 = digitalRead(SW1);
  
       
    // the switch has been activated and the program can run 
  if (SW1 == HIGH && running == 0) {
    int running = 1;
     tone(8, 900, 500); // play SOUND
     digitalWrite(G, HIGH); // turn on GREEN LED
     myservo.write(45);
     delay(1500);
     digitalWrite(G, LOW); // turn the LEDs off
     digitalWrite(R2, LOW); 
     digitalWrite(R1, LOW); 
     delay(250);
     digitalWrite(R1, HIGH); // turn the LEDs on
     digitalWrite(R2, HIGH);
     delay(2500);
           SW1 = digitalRead(SW1);
        while(SW1 == LOW && running == 1)  {

// Timer used instead of delay to allow input to be read at the same time
          unsigned long currentMillis = millis(); 
          
          if(currentMillis - previousMillis > interval) {
            previousMillis = currentMillis;
            
            if (R1State == HIGH){ // Switches lights over
              digitalWrite(R1, LOW);
              digitalWrite(R2, HIGH);
              R1State = LOW;
            }
            else {
              digitalWrite(R1, HIGH); // Switches lights over
              digitalWrite(R2, LOW);
              R1State = HIGH;
            }
          }
 // Terminates program and switches off lights if the trigger input is detected
            SW1 = digitalRead(SW1); 
            if (SW1 == HIGH){
              digitalWrite(10, LOW); // turn LEDs off
              digitalWrite(9, LOW); 
              tone(8, 900, 500); // play SOUND 
              digitalWrite(12, HIGH); // turn on RED LED
              delay(1500);
              myservo.write(0);
              digitalWrite(12, LOW); // turn off RED LED
              int R1State = LOW;
              delay(5000);
              int running = 0;
              break;
            }
          }
        }
  }

Any ideas?

Well, yes. Please refrain from ever again saying "it doesn't work".

The 2nd code you posted set the mode of the pin to INPUT_PULLUP. The integrated code sets the mode to INPUT. Why the change? Did you decide to add external pullup resistors for the hell of it?

the loop routine runs and stops after last command

Not true
The loop() function runs and unless something happens to stop it then it runs again, and again, and again........

You were asking about adding a subroutine (aka a function) after the loop() function but what you have done is to add more code inside the loop() function. A function would look more like this

void printMessage()
{
  Serial.println("This is a message");
}

and you would call it like thisprintMessage();
As to why your added code doesn't work, that will be at least partly due to your use of the delay() function in the body of the loop() function. The total delay is over 6 seconds. During that time the loop() function will not run again so cannot read your building light switches. Using a function would not solve that but use of millis instead of delay() would.

PaulS - I changed the pin to INPUT as I want the switches to be HIGH when pressed not grounded.

UKHeliBob - I've removed the code from main loop and put it at the end

    void BuildingLights()        
            
    if (digitalRead(SW2) == HIGH)  // these 4 lines are to turn the building - [u]This Line Was Highlighted After Compiling[/u]
  {
    digitalWrite(Building, HIGH);  // lights on and off
  }
  if (digitalRead(SW3) == HIGH)  // but I think somewhere I have either
  {
    digitalWrite(Building, LOW);  // missed or forgotten something
  }

I get this error when compiling :

train_crossing__3_.ino: In function 'void loop()':
train_crossing__3_:122: error: expected initializer before 'if'

What exactly am I initializing and how do I write it?

Look at your loop() function. See the curly braces at the start and end?
Look at your setup() function. See the curly braces at the start and end?

Look at your new function. See the curly braces at the start and end? I don't.

This is going to be trouble:

int SW1 = digitalRead(SW1);

You're using the same name for the pin number as its result. Worse, you've masked the pin number by declaring this local version, so you're not reading the pin you expect.

Change the declaration to have a different name and don't forget to change it where you use it a few lines later.

I've removed the code from main loop and put it at the end

If you have left the delays in then expect to wait several seconds for the building light switches to be acted upon. Incidentally, the names seem to imply that they are switches rather than buttons. There is nothing wrong with that per se, but if they are switches, might they both be on at the same time ?