//4 Digit 7 Segment VFD Arduino Based Clock w/o LED Seconds Circle
//by Frank Zheng, REV 1.1 - based on niq_ro
//Alle Pins ausser Shift-Register-Steuerpins sind Active Low!
//Modified for BCD decoder (such as 74LS48) and active high output to UDN6118A.
//May also be used with neon gas discharge displays.

//Anzeigenpin-Zuweisung

int digit1 = 9; //Arduino Pin D6~, PWM, Pin 12, T9 (tens hours)
int digit2 = 8; //Arduino Pin D9~, PWM, Pin 15, T10 (hours)
int digit3 = 7; //Arduino Pin D10~, PWM, Pin 16, T11 (tens minutes)
int digit4 = 6; //Arduino Pin D11~, PWM, Pin 17, T12 (minutes)


//Segmentpin-Zuweisung 
int segA = 2; //Arduino Pin D2, Pin 4, T1 (1's bit)
int segB = 3; //Arduino Pin D3, Pin 5, T2 (2's bit)
int segC = 4; //Arduino Pin D4, Pin 6, T3 (4's bit)
int segD = 5; //Arduino Pin D5, Pin 11, T4 (8's bit)


//Einstellknopf-Zuweisung
byte SW0 = A0;
byte SW1 = A1;
byte SW2 = A2;


//Praeprozessor
#include <Wire.h>
#include "RTClib.h"
#include "TimerOne.h"

RTC_DS1307 RTC;


//Globale Sekundendefinition
//int alle_x_sekunden = 1;
//int secondreset = 0;
//Aktuelle Sekunde definieren
//int sekaktuell = 0;

//Hex-Dec-Konversion (niq_ro)

int zh, uh, ore;
int zm, um, miniti;

//Initialisierung
void setup() {
    
    //Initialisierung RTC
    //Serial wird fuer Shift-Register
verwendet
    //Serial.begin(57600);
    Wire.begin();
    RTC.begin();
    //RTC.adjust(DateTime(__DATE__, __TIME__));
    
    //LED-Blink/PWM-Modulation
    Wire.beginTransmission(0x68);
    Wire.write(0x07); //Pointer uebertragen, PWM
    //Wire.write(0x00); //PWM Ausschalten
    Wire.write(0x10); //0x10 (h) 00010000 (b) an Kontrollregister: 1Hz Blink
    //Wire.write(0x13); //0x13 (h) 00010011 (b) 32kHz
    
    Wire.endTransmission();
    
    //RTC-Aktiv?
    if (! RTC.isrunning()) {
        //Serial.println("RTC is not running!");
        //Nein -> Schreibe Systemzeit in RTC

        RTC.adjust(DateTime(__DATE__, __TIME__));
    }
    
    
    // dht.begin();
    
    //Pin-I/O-Zuweisung

    
    pinMode(segA, OUTPUT);
    pinMode(segB, OUTPUT);
    pinMode(segC, OUTPUT);
    pinMode(segD, OUTPUT);
    
    pinMode(digit1, OUTPUT);
    pinMode(digit2, OUTPUT);
    pinMode(digit3, OUTPUT);
    pinMode(digit4, OUTPUT);
    
    pinMode(SW0, INPUT); 
    pinMode(SW1, INPUT); 
    pinMode(SW2, INPUT); 
    
    
    //Digital-Pull-Up
    
    digitalWrite(SW0, HIGH);
   
digitalWrite(SW1, HIGH);
   
digitalWrite(SW2, HIGH);
    
    // Serial.begin(9600);
    // Serial.println("HARDWARECOP VFD Clock - Welcome");

    
}
    
//Routine
void loop() {
    
    //DP-Anzeige einschalten
    
    //Zeitabgleich

    DateTime now = RTC.now();
    
    //Zeit = Stunde * 100 + Minute (14h * 100 + 25 min) = 1425
    
    int timp = now.hour()*100+now.minute();
    //int timp = (now.minute(), DEC);
    //displayNumber(12);
    //int timp = 1234;
    
    
    // display parts 

    for(int i = 150 ; i >0 ; i--) {
        if (timp >= 1000) displayNumber01(timp); 
        //e.g. 2142 -> timp = 2, 1, 4, 2 -> GOTO displayNumber01(2142)
        else displayNumber02(timp); 
        //e.g. 0943 -> timp = 0, 9, 4, 3 -> GOTO displayNumber02(0943)
        //Leading zero is blanked out by new code, e.g. " 943"
   
    
    for(int i = 150 ; i >0 ; i--) {
       
if (timp >= 1000) displayNumber03(timp); 
       
else displayNumber04(timp); 
    } 

    
    //Einstellknopf gedrueckt?
    if (!(digitalRead(SW0))) set_time(); //Waehrend SW0 Low: Zeit einstellen!


//Zeit einstellen (niq_ro)
void set_time() {
    byte minutes1 = 0;
    byte hours1 = 0;
    byte minutes = 0;
    byte hours = 0;
    
    while (!digitalRead(SW0))
    {
       
minutes1=minutes;
       
hours1=hours;
        
       
while (!digitalRead(SW1)) // set minutes
        { 
           
minutes++; 
            // converting hexa in zecimal:
            zh = hours / 16;
           
uh = hours - 16 * zh ;
           
ore = 10 * zh + uh
           
zm = minutes / 16;
           
um = minutes - 16 * zm ;
           
miniti = 10 * zm + um
            
           
for(int i = 20 ; i >0 ; i--) {
               
displayNumber01(ore*100+miniti); 
            }
            
            
           
if ((minutes & 0x0f) > 9) minutes = minutes + 6;
           
if (minutes > 0x59) minutes = 0;
            //Serial.print("Minutes = ");
            //if (minutes >= 9) Serial.print("0");
            //Serial.println(minutes, HEX);

            delay(150); 
        }

        while (!digitalRead(SW2)) // set hours
        { 
           
hours++; 

            // converting hexa in zecimal:
            zh = hours / 16;
           
uh = hours - 16 * zh ;
           
ore = 10 * zh + uh
           
zm = minutes / 16;
           
um = minutes - 16 * zm ;
           
miniti = 10 * zm + um
            
           
for(int i = 20 ; i >0 ; i--) {
               
displayNumber01(ore*100+miniti); 
            }
        
        
           
if ((hours & 0x0f) > 9) hours = hours + 6;
           
if (hours > 0x23) hours = 0;
            //Serial.print("Hours = ");
            //if (hours <= 9) Serial.print("0");
            //Serial.println(hours, HEX);

            delay(150);
        }
    
       
Wire.beginTransmission(0x68); // activate DS1307
        Wire.write(0); // where to begin
        Wire.write(0x00); //seconds
        Wire.write(minutes); //minutes
        Wire.write(0x80 | hours); //hours (24hr time)
        Wire.write(0x06); // Day 01-07
        Wire.write(0x01); // Date 0-31
        Wire.write(0x05); // month 0-12
        Wire.write(0x09); // Year 00-99
        Wire.write(0x10); // Control 0x10 produces a 1 HZ square wave on pin 7. 
        Wire.endTransmission();
        
        // converting hexa in zecimal:
        zh = hours / 16;
       
uh = hours - 16 * zh ;
       
ore = 10 * zh + uh
       
zm = minutes / 16;
       
um = minutes - 16 * zm ;
       
miniti = 10 * zm + um
    
       
for(int i = 20 ; i >0 ; i--) {
           
displayNumber01(ore*100+miniti); 
        }

        // delay(150);
    }
}


//Anzeige 1:
void displayNumber01(int toDisplay) {

    #define DISPLAY_BRIGHTNESS 1500
    #define DIGIT_ON HIGH
    #define DIGIT_OFF LOW

    for(int digit = 4 ; digit > 0 ; digit--) {
        //PWM: Kurz einschalten
        switch(digit) {
           
case 1:
           
digitalWrite(digit1, DIGIT_ON);
           
break;
           
case 2:
           
digitalWrite(digit2, DIGIT_ON);
           
break;
           
case 3:
           
digitalWrite(digit3, DIGIT_ON);
           
break;
           
case 4:
           
digitalWrite(digit4, DIGIT_ON);
           
break;
        }
       
lightNumber(toDisplay % 10);
       
toDisplay /= 10;
       
delayMicroseconds(DISPLAY_BRIGHTNESS)
        
        //Segmente ausschalten
        lightNumber(10); 
    
        //Anzeigen ausschalten
        digitalWrite(digit1, DIGIT_OFF);
       
digitalWrite(digit2, DIGIT_OFF);
       
digitalWrite(digit3, DIGIT_OFF);
       
digitalWrite(digit4, DIGIT_OFF);
    }
}
 

//Anzeige 2:
void displayNumber02(int toDisplay) {
    
    #define DISPLAY_BRIGHTNESS 1500
    #define DIGIT_ON HIGH
    #define DIGIT_OFF LOW

    
    for(int digit = 4 ; digit > 0 ; digit--) {
        //PWM: Kurz einschalten
        switch(digit) {
           
case 1:
           
digitalWrite(digit1, DIGIT_OFF); //blank leading zero
            break;
           
case 2:
           
digitalWrite(digit2, DIGIT_ON);
           
break;
           
case 3:
           
digitalWrite(digit3, DIGIT_ON);
           
break;
           
case 4:
           
digitalWrite(digit4, DIGIT_ON);
           
break;
        }
       
lightNumber(toDisplay % 10);
       
toDisplay /= 10;
       
delayMicroseconds(DISPLAY_BRIGHTNESS); 
        
        //Segmente ausschalten
        lightNumber(10); 
        
  
      //Anzeigen ausschalten
        digitalWrite(digit1, DIGIT_OFF);
       
digitalWrite(digit2, DIGIT_OFF);
       
digitalWrite(digit3, DIGIT_OFF);
       
digitalWrite(digit4, DIGIT_OFF);
    } 


//Anzeige 3:
void displayNumber03(int toDisplay) {

    #define DISPLAY_BRIGHTNESS 1500
    #define DIGIT_ON HIGH
    #define DIGIT_OFF LOW

    for(int digit = 4 ; digit > 0 ; digit--) {
        //PWM: Kurz einschalten
        switch(digit) {
           
case 1:
           
digitalWrite(digit1, DIGIT_ON);
           
break;
           
case 2:
           
digitalWrite(digit2, DIGIT_ON);
           
break;
           
case 3:
           
digitalWrite(digit3, DIGIT_ON);
           
break;
           
case 4:
           
digitalWrite(digit4, DIGIT_ON);
           
break;
        }
       
lightNumber(toDisplay % 10);
       
toDisplay /= 10;
       
delayMicroseconds(DISPLAY_BRIGHTNESS)
        
        //Segmente ausschalten
        lightNumber(10); 
    
        //Anzeigen ausschalten
        digitalWrite(digit1, DIGIT_OFF);
       
digitalWrite(digit2, DIGIT_OFF);
       
digitalWrite(digit3, DIGIT_OFF);
       
digitalWrite(digit4, DIGIT_OFF);
    }
}
 

//Anzeige 4:
void displayNumber04(int toDisplay) {
    
    #define DISPLAY_BRIGHTNESS 1500
    #define DIGIT_ON HIGH
    #define DIGIT_OFF LOW

    
    for(int digit = 4 ; digit > 0 ; digit--) {
        //PWM: Kurz einschalten
        switch(digit) {
           
case 1:
           
digitalWrite(digit1, DIGIT_OFF); //blank leading zero
            break;
           
case 2:
           
digitalWrite(digit2, DIGIT_ON);
           
break;
           
case 3:
           
digitalWrite(digit3, DIGIT_ON);
           
break;
           
case 4:
           
digitalWrite(digit4, DIGIT_ON);
           
break;
        }
       
lightNumber(toDisplay % 10);
       
toDisplay /= 10;
       
delayMicroseconds(DISPLAY_BRIGHTNESS); 
        
        //Segmente ausschalten
        lightNumber(10); 
        
  
      //Anzeigen ausschalten
        digitalWrite(digit1, DIGIT_OFF);
       
digitalWrite(digit2, DIGIT_OFF);
       
digitalWrite(digit3, DIGIT_OFF);
       
digitalWrite(digit4, DIGIT_OFF);
    } 


//Zeichenbedingungen:
//Fuerr case 10 ist Anzeige mit allen Segmenten eingeschaltet

void lightNumber(int numberToDisplay) {
    
   
#define SEGMENT_ON HIGH //bit = 1
   
#define SEGMENT_OFF LOW //bit = 0
    
   
switch (numberToDisplay){
        
        //Zahl 0
        //BCD data

        case 0: //BCD 0000
       
digitalWrite(segA, SEGMENT_OFF);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 1: //BCD 0001
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 2: //BCD 0010
       
digitalWrite(segA, SEGMENT_OFF);
       
digitalWrite(segB, SEGMENT_ON);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 3: //BCD 0011
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_ON);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 4: //BCD 0100
       
digitalWrite(segA, SEGMENT_OFF);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_ON);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 5: //BCD 0101
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_ON);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 6: //BCD 0110
       
digitalWrite(segA, SEGMENT_OFF);
       
digitalWrite(segB, SEGMENT_ON);
       
digitalWrite(segC, SEGMENT_ON);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 7: //BCD 0111
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_ON);
       
digitalWrite(segC, SEGMENT_ON);
       
digitalWrite(segD, SEGMENT_OFF);
       
break;
        
       
case 8: //BCD 1000
       
digitalWrite(segA, SEGMENT_OFF);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_ON);
       
break;
        
       
case 9: //BCD 1001
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_OFF);
       
digitalWrite(segC, SEGMENT_OFF);
       
digitalWrite(segD, SEGMENT_ON);
       
break;
        
       
//Alles ein
       
case 10: //illegal BCD value 1111 blanks display
       
digitalWrite(segA, SEGMENT_ON);
       
digitalWrite(segB, SEGMENT_ON);
       
digitalWrite(segC, SEGMENT_ON);
       
digitalWrite(segD, SEGMENT_ON);
       
break;
        
    }
}