LED and model railways.

I have a question regarding programming LEDs.
Not sure if this is the correct place.

But I am setting up signalling on my model railway using an arduino.

So that when a train passes an IR detector the signal (it is passing) goes from green to red.
It stays that way until some time has elapsed (say 10 seconds) and the arduino returns the signal to green.

My problem is that I don't want the main loop delayed for ten seconds as other signal work will be missed.

My solution is to timestamp the change from green to red (in array, one slot per signal).
The main loop, as it goes though one pass of the loop, checks each timestamp in the array.
When a timestamp has 'expired' the signal change to green is called (resetting the timestamp).

My question is:- Is this a sensible way to handle the signal elapsing? or is it too much work for the arduino?. I checked the interrupt options and there will probably not be enough available for my signalling.

Have a look at the blink without delay example sketch in the IDE.
Your approach sounds OK.

Thanks for prompt reply. :slight_smile:

I will continue with my approach.

I will check the IDE blink with no delay. :slight_smile:

edit: I've just checked the blink without delay. It's exactly what I want. :slight_smile:

Well of course, this is not how a genuine railway signalling system works at all.

Nevertheless, that aside, please do not get confused with the concept of "interrupts". They have absolutely nothing whatsoever to do with your application (or in fact the vast majority of applications overall). Just forget about them entirely.

Paul__B:
Well of course, this is not how a genuine railway signalling system works at all.

Nevertheless, that aside, please do not get confused with the concept of "interrupts". They have absolutely nothing whatsoever to do with your application (or in fact the vast majority of applications overall). Just forget about them entirely.

Thanks for your advice. :slight_smile:

Please help me with some sort of strange bug.

I am trying to generate a simple signalling system for my model railway.
Trains interrupting an IR beam will cause a green signal to flip to red. After 5 seconds of the beam not interrupted the signal will flip back to red.
(The signal ‘unit’ has two LEDs one red one green.)

At the moment I’m ‘testing’ the system using a push button to represent the IR beam breakage.
The input pin has a pull-down resistor of 10Kohms.

The problem I get is that the sketch works fine when the main loop contains a Serial.print statement; without this statement the signal is jammed permanently on red.

(also unexpected, though not a serious problem, the LED signalling starts at boot-up on red then drops back to green and behaves from then on as expected)

I have attached the program, but I have no software for doing a circuit diagram.

Hope that makes sense, all help greatly appreciated.

full_signal_program_version_2.ino (2.27 KB)

long signal_timestamps[6] should be type unsigned long

/* traffic test and signal change */

/* variable declarations
 *  
 *  each signal uses a set of three pins and a signal timestamp
 *  the signal timestamp is part of an array
 */

// variables for 1st signal
int traffic_signal_1 = 1;
int signal_1_red = 2;
int signal_1_green = 3;

// variables for 2nd signal
int traffic_signal_2 = 4;
int signal_2_red = 5;
int signal_2_green = 6;

long signal_timestamps[6] = {0L,0L,0L,0L,0L,0L};

// work variables
int this_signal = 1;
int traffic_value = LOW;


/* this routine is called when traffic has passed the signal detector
*  it is a generalised routine and the signal number is passed to it as a parameter 
* when it is invoked
 */
void change_to_red(){

  digitalWrite( (this_signal + 1), HIGH);   // turn the red signal on
  digitalWrite( (this_signal + 2), LOW);   // turn the green signal off
  signal_timestamps[ (this_signal-1)] = millis(); // save the time this IR beam interrupt occured

}

/* this routine is called when the ‘on red’ time period has elapsed.
*  it is a generalised routine and the signal number is passed to it as a parameter 
* when it is invoked
*/
void change_to_green(){

  digitalWrite( (this_signal + 1), LOW);   // turn the red signal off
  digitalWrite( (this_signal + 2), HIGH);   // turn the green signal on
 }

// the setup function 



// runs once when you press reset or power the board
void setup() {

 Serial.begin(9600);
  pinMode(signal_1_red, OUTPUT);
  pinMode(signal_1_green, OUTPUT);
  pinMode(traffic_signal_1, INPUT);

   
    digitalWrite( (signal_1_red), LOW);   // turn the red signal off
    digitalWrite( (signal_1_green), LOW);   // turn the green signal on

  delay(2000);

int traffic_value = LOW;
}



/* the first part of the loop checks all IR detectors for traffic passage
 *  
 */
void loop() {


  this_signal = 1;


// test if traffic found at signal 1
  traffic_value = digitalRead(this_signal);
  Serial.print(this_signal); // sketch only works with this statement included
  if (traffic_value == HIGH) {  change_to_red();};
  this_signal = this_signal + 1;




/* the second part of the loop now checks all timestamps for elapsedness
 *  
 */
  this_signal = 1;
  if ( (  (signal_timestamps[this_signal - 1] + 5000) < millis() ) ){change_to_green();}; // signal 1 expired?
  
  
  

  this_signal = 1;
}

Hi, don’t use Arduino pins 0 or 1. They are used for serial communication with the PC (for example Serial.println() which i suspect explains the effect you are seeing).

PaulRB:
Hi, don't use Arduino pins 0 or 1. They are used for serial communication with the PC (for example Serial.println() which i suspect explains the effect you are seeing).

Hi Paulrb thanks for the advice.

I followed your idea, but it did not help, in fact now, even with the serial.print statement, the breadboard just shows solid red!

LarryD:
long signal_timestamps[6] should be type unsigned long

Thanks for your help, larry. I tried it but it didn't have any effect. But thanks anyway :slight_smile:

I found one bug; my variable 'this_signal' is meant to be an index into the timestamp array. I actually used it as the input digital pin number. doh!!!

Didn't completely solve my problem yet. :frowning:

Oops programming all to cock. I've realised I've used 'this_signal' incorrectly throughtout.

please ignore this topic. If I can't fix it by correcting my misuse of said variable I'll ask for help again. Thanks for all help anyway.

Hmmm.

Give this a try.

/* traffic test and signal change */

/* variable declarations
    each signal uses a set of three pins and a signal timestamp
*/

byte sensor[]     = {2, 5, 8};
byte signal_red[] = {3, 6, 9};
byte signal_grn[] = {4, 7, 10};
unsigned long signal_timestamps[] = {0L, 0L, 0L, 0L, 0L, 0L};
const byte N_signals = 3;

// work variables
int traffic_value = LOW;

/* this routine is called when traffic has passed the signal detector
   it is a generalised routine and the signal number is passed to it as a parameter
  when it is invoked
*/
void change_to_red(byte this_signal) {
  digitalWrite( signal_red[this_signal], HIGH);  // turn the red signal on
  digitalWrite( signal_grn[this_signal], LOW);   // turn the green signal off
  signal_timestamps[this_signal] = millis();     // save the time this IR beam interrupt occured
}

/* this routine is called when the 'on red' time period has elapsed.
   it is a generalised routine and the signal number is passed to it as a parameter
  when it is invoked
*/
void change_to_green(byte this_signal) {
  digitalWrite( signal_grn[this_signal], HIGH);  // turn the green signal on
  digitalWrite( signal_red[this_signal], LOW);   // turn the red signal off
}

// the setup function runs once when you press reset or power the board
void setup() {

  Serial.begin(9600);

  for (int i = 0; i < N_signals; i++) {
    pinMode(signal_red[i], OUTPUT);
    pinMode(signal_grn[i], OUTPUT);
    pinMode(sensor[i], INPUT);
    digitalWrite( (signal_red[i]), LOW);   // turn the red signal off
    digitalWrite( (signal_grn[i]), HIGH);  // turn the green signal on
  }
  delay(2000);

}

/* the first part of the loop checks all IR detectors for traffic passage */
void loop() {

  for (int i = 0; i < N_signals; i++) {
    // test if traffic found at signal
    traffic_value = digitalRead(sensor[i]);
    // Serial.print(i); // sketch only works with this statement included
    if (traffic_value == HIGH) {
      change_to_red(i);
    } else {
      /* the second part of the loop now checks all timestamps for elapsedness */
      if  ( millis() - signal_timestamps[i] >= 5000UL )  {
        change_to_green(i);
        signal_timestamps[i] = millis();     // reset the counter
      }; // signal 1 expired?
    }
  }
}

Common threads merged.