Things used in this project

Hardware components:
Photon new
Particle Photon
×1
12009 06
SparkFun Logic Level Converter - Bi-Directional
×1
SparkFun RS485 Transceiver
This board does not need a logic level converter as it operates at 3.3V A regular MAX485 breakout board can also be used instead of this, but with a converter to 5V
×1
Alfa Zeta XY5 Flip Dot Display 7x28
×1
24V 0.8A min DC Power Supply
×1
Software apps and online services:
Particle Web IDE

Schematics

Fritzing Diagram
Screen shot 2017 05 05 at 2 54 46 pm tahst4grz5

Code

FlipDotTimeCodeArduino
/*
* Using the Particle Photon to control an Alfa Zeta 7x28 flip dot display.
* The program displays the respective time in either 12 or 24 hour format.
* 
* Hardware Needed:
* - Particle Photon
* - Alfa Zeta flip dot display
* - RS485 converter (5V operating logic! The photon is 3.3V)
* - Logic level converter (optionally a MAX3485 chip for the RS485 converter can be used which operates at 3.3V OR 5V therefore eliminating this component)
* - 24V Power supply
* - 5V Power supply (USB power is fine)
* Date: May 5, 2017
* By: Mariano Elia
*/

//Each number from left to right in the 2D array, is the respective dots from right to left to be lit up 
//
  byte numbersInBinary[][4]{
  {0b111110, 0b100010, 0b100010, 0b111110}, //zero
  {0b111110, 0b000000, 0b000000, 0b000000}, //one
  {0b111010, 0b101010, 0b101010, 0b101110}, //two
  {0b111110, 0b101010, 0b101010, 0b100010}, //three
  {0b001000, 0b111110, 0b001000, 0b111000}, //four
  {0b101110, 0b101010, 0b101010, 0b111010}, //five
  {0b001110, 0b001010, 0b001010, 0b111110}, //six
  {0b111110, 0b100000, 0b100000, 0b110000}, //seven
  {0b111110, 0b101010, 0b101010, 0b111110}, //eight
  {0b111110, 0b101000, 0b101000, 0b111000} //nine

};

//To invert white with black, a ~ is used as a prefix
byte invertedNumbersInBinary[][4]{
  {~0b111110, ~0b100010, ~0b100010, ~0b111110}, //zero
  {~0b111110, ~0b000000, ~0b000000, ~0b000000}, //one
  {~0b111010, ~0b101010, ~0b101010, ~0b101110}, //two
  {~0b111110, ~0b101010, ~0b101010, ~0b100010}, //three
  {~0b001000, ~0b111110, ~0b001000, ~0b111000}, //four
  {~0b101110, ~0b101010, ~0b101010, ~0b111010}, //five
  {~0b001110, ~0b001010, ~0b001010, ~0b111110}, //six
  {~0b111110, ~0b100000, ~0b100000, ~0b110000}, //seven
  {~0b111110, ~0b101010, ~0b101010, ~0b111110}, //eight
  {~0b111110, ~0b101000, ~0b101000, ~0b111000} //nine
};
byte colonOn[]  = {0x0, 0x14, 0x0};
byte colonOff[] = {0x0, 0x0, 0x0};
byte invertedColonOn[] = {0x7F, 0x6D, 0x7F};
byte invertedColonOff[] = {0x7F, 0x7F, 0x7F};
byte space[] = {0x0};
byte invertedSpace[] = {0x7F};
//All pixels white
byte allWhite[] { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}; //equivalent to 0b1111111
//All pixels black
byte allBlack[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //equivalent to 0b0000000

//prepare the display to receive data.
byte startTransmission[] = {0x80, 0x83, 0xFF};
//confirm the end of the bytes sent
byte endTransmission[] = {0x8F};
int colonState = true;
unsigned long previousMillis = 0; 

/*
* Variables to change for customization
*/
const long interval = 1000; //interval in which to flip on and off the colon    
bool inverted = false; //choose to have black as digits, or as blank space
bool flashingColon = true;  //change to false if a static colon is wanted instead
int timeZone = -4; //change time zone


void setup() {
    //Serial is the usb port, Serial1 are the TX/RX pins, and Serial2 are the built in LED pins.
    //Serial1 is being used for this project.
   Serial1.begin(57600);  
   flipBlackAndWhite(); //start with a cool effect
}


void loop() {
    displayTime();
}


/*
* Retrieves the most recent time, and displays it on the flip dot.
* A flashing center colon is optional. 
*/
void displayTime(){

    //Retrieve the most recent time, and separate it up into individual integers
    int currentTime = getTime();
    int thousands = currentTime/1000; 
    int hundreds = currentTime%1000/100;
    int tens = ((currentTime%1000)%100)/10;
    int ones = ((currentTime%1000)%100)%10;
    //The display is 28 columns long. The columns are displayed right to left
    Serial1.write(startTransmission, 3); //send a 3 byte message to start the Serial communication
    displayDigit(-1); //three spaces on the right
    displayDigit(-1);
    displayDigit(-1);
    displayDigit(ones); //each digit is 4 columns long
    displayDigit(-1); //add a space in between digits
    displayDigit(tens);
    displayColon(); // 3 columns long
    displayDigit(hundreds);
    displayDigit(-1);
    displayDigit(thousands);
    displayDigit(-1); //add 4 spaces to the beginning
    displayDigit(-1);
    displayDigit(-1);
    displayDigit(-1);
    Serial1.write(endTransmission, 1); //Tell the flip dots to change
}
/*
* Uses Particle's time library to retrieve internet time. The time zone can be altered.
* Returns an int with the concatinated hour and minute. Ex 12:45 is 1245
*/
int getTime(){
    Time.zone(timeZone);
    //Uncomment if a 24 hour variant is wanted
    //return (Time.hour())*100+Time.minute(); //24 hour
    return (Time.hourFormat12())*100+Time.minute(); //12 hour
}

/*
* A single integer number to be displayed on the flip dots.
* A -1 signifies a space, which is one column wide and all black.
*/
void displayDigit(int num){
    if (!inverted){ 
    if (num == -1){
        Serial1.write(space, 1);
    }
    else{
    Serial1.write(numbersInBinary[num], 4);
    }
    }
    //else if it is inverted
    else {
        if (num == -1){
        Serial1.write(invertedSpace, 1);
    }
    
    else{
    Serial1.write(invertedNumbersInBinary[num], 4);
    }
    }
    
}

/*
* Displays the center colon in a flashing or static manner.
*/
void displayColon(){
     /*
    Instead of using a delay which stops the processor, a much better approach is to use a timer to
    turn on and off the colon separator when the proper time is reached.
    */
    if (flashingColon){ //*hint*, the same as if (flashingColon == true){
     unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) { //use a timer based delay
         previousMillis = currentMillis;
        if (colonState){
            if(!inverted) //if it is not inverted, display a normal colon
            Serial1.write(colonOn, 3);
            else
        Serial1.write(invertedColonOn, 3); //display an inverted colon
        colonState = false;
        }
        else {
            if(!inverted)
        Serial1.write(colonOff, 3);
        else
        Serial1.write(invertedColonOff, 3);
        colonState = true;
        }
    }
    }
    
    else { //choose between a static colon, or no colon
    if (!inverted){
    Serial1.write(colonOn, 3);
    //Serial1.write(colonOff, 3);
    }
    else{
    Serial1.write(invertedColonOn, 3);
    //Serial1.write(invertedColonOff, 3); 
    }
}
}
/*
* An effect which turns all pixels white, delays half a second, then black, then white again.
*/
void flipBlackAndWhite(){
    Serial1.write(startTransmission, 3);
    Serial1.write(allWhite, 28);
    Serial1.write(endTransmission, 1);
    delay(500);
    Serial1.write(startTransmission, 3);
    Serial1.write(allBlack, 28);
    Serial1.write(endTransmission, 1);
    delay(500);
     Serial1.write(startTransmission, 3);
    Serial1.write(allWhite, 28);
    Serial1.write(endTransmission, 1);
    delay(500);
}

Credits

Photo
Mariano Elia

Queen's University: Computer Engineering. RSGC High School

Contact
Thanks to iizukak.

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Blynk GPS Tracker
Intermediate
  • 3
  • 1

Full instructions

Simple GPS tracker using a Particle Photon (or Electron) and an EM406 GPS module with location visible on Blynk app map.

Pool Buddy
Intermediate
  • 1,482
  • 11

Work in progress

Monitor and log water quality (pH & ORP) and temperature from everywhere.

Smart Garden
Intermediate
  • 1,992
  • 17

Smart Garden is a plant environmental monitoring system.

WiFi Messenger
Intermediate
  • 1,195
  • 13

Protip

Calling my son from his room using 2 ESP8266 modules, instead of shouting.

IoT Thermometer Using Python
Intermediate
  • 791
  • 8

Full instructions

How to develop a simple but powerful IoT thermometer using a Zerynth-powered single-board MCU and the Zerynth App.

WiDC: Wi-Fi-Controlled FPV Robot
Intermediate
  • 5,962
  • 39

Full instructions

What about using a Wi-Fi remote-controlled robot for exploring your surroundings, reaching inaccessible places, spying and take pictures?

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login
Feedback