Fun with Arduino 40 Station Platform Departure Display with Analog Clock

Now that we have the OLED screen working (see previous video) we can do something fun with it for an HO model railway: a station platform train departure display, with an analog clock that really works.

40020

The 128×32 pixel display is just a little bit on the tall side for HO scale, but it doesn’t look too bad. It is fun to have one or more of these signs on your station platforms.

stationsignoverview

The real sign has dark text on a white background. This can be chosen by wiring pin 8, the COLOR_PIN, to GND. Personally I think the white text on dark background looks better.

40040

To display the texts is quite straightforward with the oled.setCursor(x,y) and the oled.print(“text”) commands.

The clock also is not too difficult to make … it’s a series of draw line commands:

oled.drawLine(x1, y1, x2, y2, color);

To draw the clock’s 5 minute ticks we use a for() loop where we run the pointer from 0 – 360, with increments of 30 degrees. Some math with cos(angle) and sin(angle) that you might remember from high school render us the start- and end points of the 5 minute tick lines:

for(int z=0; z<360; z=z+30){
  angle = (float)z / 57.3;        // Convert degrees to radians 
  int x1=(16+(sin(angle)*15));    // 16,15 is mid point of clock circle
  int y1=(15-(cos(angle)*15));
  int x2=(16+(sin(angle)*(12)));  // 15 - 12 specifies line length
  int y2=(15-(cos(angle)*(12)));
  oled.drawLine(x2,y2,x3,y3,fg);
}

The seconds, minutes and hour hands are drawn in a similar manner.

angle=((float)second * 6 / 57.3); // Convert degrees to radians 
int x2=(16+(sin(angle)*(14)));
int y2=(15-(cos(angle)*(14)));
oled.drawLine(16,15,x3,y3,fg);

To update the departure times and texts, 6 inputs are used. These can be connected to manual operated push buttons, or they can be connected to a DCC decoder, to accomplish that every time a train leaves the station a new departure time and text is shown. A random time between Tmin and Tmax is generated for the next departure time.

In the Netherlands the platform signs have a white background with dark blue text. This white background mode can be selected by making the COLOR_PIN low. Personally I found the readability of white text on a black background much better, this is the default with the COLOR_PIN not connected or high.

Read on below the video …

The complete code:

// OLED Model railway Station Platform Display - Rudy B, August 2019
// 6 different messages can be shown, based on 6 inputs
// OLED SSD1306 - I2C wires: SDA or A4, SCL or A5

#define MSG1_PIN   2
#define MSG2_PIN   3
#define MSG3_PIN   4
#define MSG4_PIN   5
#define MSG5_PIN   6
#define MSG6_PIN   7
#define COLOR_PIN  8
#define TMIN       5 // departure time of next train, minimum of random time
#define TMIN      13 // departure time of next train, maximum of random time

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// setup oled
Adafruit_SSD1306 oled(4);
#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
byte hour, minute, second; 
byte bg, fg, msgnr, msgnr_old, msgflag, msghour, msgminute;
unsigned long time_to_update;
float angle;

void calc_msg_time() {
  msgminute = minute + random(TMIN, TMAX);
  msghour = hour;
  if (msgminute > 59) {
    msghour = (msghour + 1) % 24;
    msgminute = msgminute - 60;
  }
}

void print_msg_time() {
  oled.setTextColor(fg);
  oled.setTextSize(1);
  oled.setCursor(40,2);
  if(msghour < 10) oled.print(" ");
  oled.print(msghour);
  oled.print(":");
  if(msgminute < 10) oled.print("0");
  oled.print(msgminute);
}

void setup() {
  pinMode(MSG1_PIN,  INPUT_PULLUP);
  pinMode(MSG2_PIN,  INPUT_PULLUP);
  pinMode(MSG3_PIN,  INPUT_PULLUP);
  pinMode(MSG4_PIN,  INPUT_PULLUP);
  pinMode(MSG5_PIN,  INPUT_PULLUP);
  pinMode(MSG6_PIN,  INPUT_PULLUP);
  pinMode(COLOR_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  Wire.begin();
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C

// generate random startup time
  randomSeed(analogRead(A0));
  hour   = random(7, 20);
  minute = random(0, 60);
}

void loop() {

// determine background- and foreground color based on COLOR_PIN
  if(digitalRead(COLOR_PIN) == HIGH) {bg = WHITE; fg = BLACK;}
  else {bg = BLACK; fg = WHITE;}

// update time
  if(millis() > time_to_update) {
    time_to_update = millis() + 1000UL;
    second = second + 1;
    if(second == 60) {
      second = 0;
      minute = minute + 1;
    }
    if (minute == 60) {
      minute = 0;
      hour = (hour + 1) % 24;
    }
  }

// clear oled  
  oled.clearDisplay();
  oled.fillRect(0,0,127,31,bg);

// draw clock ticks
  for(int z=0; z<360;z=z+30){
    angle = (float)z / 57.3;
    int x1=(16+(sin(angle)*15));
    int y1=(15-(cos(angle)*15));
    int x2=(16+(sin(angle)*(12)));
    int y2=(15-(cos(angle)*(12)));
    oled.drawLine(x1,y1,x2,y2,fg);
  }
// draw clock second
  angle=((float)second * 6 / 57.3) ; //Convert degrees to radians  
  int x2=(16+(sin(angle)*(14)));
  int y2=(15-(cos(angle)*(14)));
  oled.drawLine(16,15,x2,y2,fg);

// draw clock minute
  angle=((float)minute * 6 / 57.3) ; //Convert degrees to radians  
  x2=(16+(sin(angle)*(12)));
  y2=(15-(cos(angle)*(12)));
  oled.drawLine(16,15,x2,y2,fg);

// draw clock hour
  angle=((float)hour * 30 + (float)minute / 2) / 57.3 ; //Convert degrees to radians  
  x2=(16+(sin(angle)*(10)));
  y2=(15-(cos(angle)*(10)));
  oled.drawLine(16,15,x2,y2,fg);

/*
// platform number
  oled.fillRect(107, 5, 19, 22, fg);
  oled.setTextSize(2);
  oled.setTextColor(bg);
  oled.setCursor(111,9);
  oled.print("3"); 
*/

// display time and messages
  if(!digitalRead(MSG1_PIN)) msgnr = 1;
  if(!digitalRead(MSG2_PIN)) msgnr = 2;
  if(!digitalRead(MSG3_PIN)) msgnr = 3;
  if(!digitalRead(MSG4_PIN)) msgnr = 4;
  if(!digitalRead(MSG5_PIN)) msgnr = 5;
  if(!digitalRead(MSG6_PIN)) msgnr = 6;

  if(msgnr != msgnr_old) {
    calc_msg_time();
    msgnr_old = msgnr;
  }
  
  print_msg_time();

  switch (msgnr) {
    case 1:
      oled.setCursor(72,2);  oled.print("Intercity");    // max 10 characters
      oled.setCursor(40,12); oled.print("Eindhoven");    // max 14 characters
      oled.setCursor(40,22); oled.print("via Strijp-S"); // max 14 characters
    break;

    case 2:
      oled.setCursor(72,2);  oled.print("Sprinter");
      oled.setCursor(40,12); oled.print("sHertogenbosch");
      oled.setCursor(40,22); oled.print("via Boxtel");
    break;

    case 3:
      oled.setCursor(72,2);  oled.print("Stoptrein");
      oled.setCursor(40,12); oled.print("Maliebaan");
      oled.setCursor(40,22); oled.print("via Eindhoven");
    break;

      case 4:
      oled.setCursor(72,2);  oled.print("Intercity");
      oled.setCursor(40,12); oled.print("Venlo");    
      oled.setCursor(40,22); oled.print("via Deurne");
    break;

    case 5:
      oled.setCursor(72,2);  oled.print("Intercity");
      oled.setCursor(40,12); oled.print("Maastricht");
      oled.setCursor(40,22); oled.print("via Sittard");
    break;

    case 6:
      oled.setCursor(72,2);  oled.print("Intercity");
      oled.setCursor(40,12); oled.print("Heerlen");  
      oled.setCursor(40,22); oled.print("via Weert");
    break;
  }
// refresh screen
  oled.display();
}

In this code a random time is generated for the clock at startup. It is possible however to display the real time via the use of a so called Real Time Clock module. This is the subject of the next video.

— 0 —

5 thoughts on “Fun with Arduino 40 Station Platform Departure Display with Analog Clock

    • Of course you can. Simplest way would be to place the texts to display in a switch – case and generate the number of the case via the 6 input pins with n = pin6 * 32 + pin5 * 16 + … etc.

      Like

  1. Hello, I like your project very much. If you are willing, I would like to ask you to create some arduino and display module development for me. Looking forward to your reply

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s