NixieClock mit Adruino IDE und Attiny84

Hallo Liebe Ardujaner,
hier eine kleine Projektvorstellung. Ich habe endlich nach langem meine Nixie-Clock fertig.
Im Anhang ein kleines Bild.
Folgende Komponenten:
-4* Nixie Röhren Z573M
-4*Nixie Driver K155ID1 (russische SN74141)
-2 Schieberegister 74HC595
-Attiny 84 (Clock int.)
-RTC DS1307 via I2C
-Nixie Power Supply von Taylor Electronics Bad insert location redirector

Die alles läuft hervorragen mit dem Attiny84. Ich musste die TinyWire Lib anpassen auf den Attiny84 und dann lief auch diese Problemlos mit dem I2C Bus. PullUp-Widerstände sind zwingend erforderlich, da diese nicht wie bei den Atmegas bei Benutzung der I2C intern aktiviert werden. Die RTC ist Batterie gepuffert. Ich habe extra eine 32.768kHz Crystal genommen mit einer Kapazität von 6pF da diese empfohlen ist von den Herstellern auf einer anderen Uhr habe ich diese erfolgreich im Einsatz d.h.8Wochen 1min zu langsam.

Hier noch der Codeder Schaltplan kommt später

/*
Attiny84 Big 7 Segment Uhr mit 74HC595
 
 */


#include <TinyWireM.h>
#include <USI_TWI_Master.h>


#define Shiftdata  8          // Pin 8 Datenleiung Schieberegister connected to Data in (DS) of 74HC595
#define Shiftclock 10           // Pin 9 Clockleitung connected to clock pin (SH_CP) of 74HC595
#define Shiftlatch 9         // Pin 10 Latchleitung connected to latch pin (ST_CP) of 74HC595
#define PWMOUT 7
#define BUTTON 1
#define RTCPuls 2
#define LDR 3
#define RTC_ADDRESS 0x68
#define TIME 750

byte ie,iz,hz,he,mz,me=0;  // Modulespeicher der stunden Minuten
boolean ldruck,druck=false;   // Stellknopf für Zeit 
boolean longpress,shortpress=false;  // Unterscheidung langer kurzer druck
boolean blinktakt=false;             // Blinktakt 500ms
boolean lpuls,puls=false;            // Sekundenpuls
boolean hell=false;
unsigned long lmillis,start,ptime=0;
byte ss=0;
byte mm=0;
byte hh=0;
byte minuten,stunden=0;
byte setmode=0;
byte PWMArray[7]={
  4,20,50,100,150,255};
byte Pointer=4;


byte SDec2Shift(byte x){
  byte xeiner=x%10;
  byte xzehner=(x-xeiner)/10;
  return (xzehner<<4)+xeiner;
  ;
}


void setup(){
  pinMode(Shiftdata,OUTPUT);
  pinMode(Shiftclock,OUTPUT);
  pinMode(Shiftlatch,OUTPUT);
  pinMode(BUTTON,INPUT_PULLUP);
  pinMode(RTCPuls,INPUT);
  pinMode(PWMOUT,OUTPUT);
  TinyWireM.begin();                                  // Start I2C Kommunikation
  TinyWireM.beginTransmission(0x68);                  // Beginn Kommunikation auf  Adresse 0x68 
  TinyWireM.send(0x07);                               // Pointer auf Control Register 0x07   
  TinyWireM.send(0x10);                               // Steuerwort Ex "0x30" Bin110000 Ausgang RTC Ausgang auf 1Hz Logic normal Levels setzn
  TinyWireM.endTransmission();                        // Beenden der I2C Kommunitkation
  HourRead();                                         // RTC Funktion lesen der aktuellen zeit Stunden
  MinuteRead();                                       // RTC Funktion lesen der aktuellen zeit Minuten
  RTC_Start();                                        // Start der Uhr
}


void loop(){
  /*=>Routine OneButton Control<=*/
  druck=digitalRead(BUTTON);            // Einlesen des Button (Achtung invertierte Logik da intrener Pull Up Widerstand aktiviert)
  if (druck==false&&ldruck==true){      // Steigende Flanke des Button
    start=millis();                     // Startzeit des Bettätigen
    ldruck=false;                       // Hilfsflag zur Flanken erkennung
  }
  if (druck==true&&ldruck==false){      // Falende Flanke des Buttons
    ptime=millis()-start;               // Die Länge in ms des Gedückten Zustandes
    ldruck=true;
  }
  if (ptime>=TIME){                    // Wenn der Druck länger (Hier750ms) 
    longpress=true;                    // War ein Langer druck
    ptime=0;                           // Zeit wieder Zurücksetzten
  }
  if (ptime<TIME&&ptime>=50) {         // Wenn der Druck kürzer 750ms und länger 50ms (gegen prellen)
    shortpress=true;                   // War ein kurzer Durck
    ptime=0;                           // Zeit wieder zurücksetzuten
  }
  /*One Button End*/

  puls=digitalRead(RTCPuls);                 // Einlessen des RTC Sekunden Puls
  if (puls==true&&lpuls==false){             // wenn Sekundenpuls da und vorher nicht da war (steigende Flanke)
    lpuls=true;
    ss++;                                    // intern Sekunden zählen
  }
  if (ss>=60&&setmode==0){                   // Nach 60 Sekunden
    HourRead();                              // RTC Funktion lesen der aktuellen zeit Stunden
    MinuteRead();                            // RTC Funktion lesen der aktuellen zeit Minuten
    ss=0;                                    // Rücksetzzeten internen Sekunden Zähler auf 0
  }
  if (puls==false){                          // RTC Sekunden Hilfspuls
    lpuls=false;
  }
  if (shortpress==true){                    // Routine Kurzes drücken
    if (setmode==0){                        // In Normalmodus 
      Pointer++;                            // ändern des Pointer der Helligkeit
      if (Pointer>=6){                      // Bei Pointer 6 und größer auf Pointer Null
        Pointer=0;
      }
    }
    if (setmode==1){                        // Minuten stellen
      mm++;
      if (mm>=60){
        mm=0;
      }
    }
    if (setmode==2){                        // Stunden stellen
      hh++;
      if(hh>=24){
        hh=0;
      }
    }
    shortpress=false;
  }
  if (longpress==true){                      // Routine Langes drücken
    setmode++;                               // Stellmodus erhöhen
    if (setmode==3){                         // Bei erreichen des Modus 3
      RTC_Set();                             // Neue Uhrzeit übernehmen in die RTC
      RTC_Start();                           // RTC Starten
      setmode=0;                             // Rücksetzten des Setmodes auf 0 (Normale Anzeige)
    }
    longpress=false;                         // Rücksetzten des Flags Langes Drücken
  }
  if (millis()-lmillis>=500){                // Aktalisiernung alle halbe Sekunden
    blinktakt= !blinktakt;                   // Blinktakt der Stellen anzeige
    minuten=SDec2Shift(mm);
    stunden=SDec2Shift(hh);
    if (blinktakt==false){                  // Blinkroutine des Stellmodus
      if(setmode==1){                       // Minuten stellen
        me=0;
        mz=0;
      }
      if (setmode==2){                      // Stunden Stellen
        he=0;
        hz=0;
      }
    }
    digitalWrite(Shiftlatch, LOW);     // Latch aussetzten um in den Storage speicher zu schreiben 
    shiftOut(Shiftdata, Shiftclock, MSBFIRST,  stunden);                    // Shift out der einzelenen Puffer wobei im letzten
    shiftOut(Shiftdata, Shiftclock, MSBFIRST,  minuten);                  // Shift out der einzelenen Puffer wobei im letzten
    digitalWrite(Shiftlatch, HIGH);                                        // Aktiverien des Latches (Schieben des Shift ind Storageregister) zum Anzeigen
    lmillis=millis();  
  }
  if (hh==22&&hell==true){                         // wenn Später 22Uhr und Früher als 8Uhr und es vorher Hell war dann dunkelschlaten
    Pointer=0;
    hell=false;
  }
  if (hh==10&&hell==false){                       // Wenn vor 22Uhr und nach 8 Uhr und vorher dunkel war dann Hell Schalten
    Pointer=5;
    hell=true;
  }
  analogWrite(PWMOUT,PWMArray[Pointer]);
}

byte Dec2Shift(byte x){
  byte shiftdata[11]={
    63,6,91,79,102,109,125,7,127,111                                                                                                                                                };
  return shiftdata[x];
}

void HourRead(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x02);               // Pointer auf Sekunden
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(RTC_ADDRESS, 1);
  hh= bcdToDec(TinyWireM.receive());
}

void MinuteRead(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x01);               // Pointer auf Sekunden
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(RTC_ADDRESS, 1);
  mm= bcdToDec(TinyWireM.receive());
}

void RTC_Start(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x00);
  TinyWireM.send(decToBcd(ss));    // 0 to bit 7 starts the clock
  TinyWireM.endTransmission();
}


void RTC_Set(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x01);
  TinyWireM.send(decToBcd(mm));
  TinyWireM.send(decToBcd(hh));      // If you want 12 hour am/pm you need to set
  TinyWireM.endTransmission();
}

byte decToBcd(byte val)
{
  return ((val/10)<<4)+(val%10);
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ((val>>4)*10)+val%16;
}

In diesem Code fehlt noch das Blinken der LED unter den Nixies im Normalbetrieb leuchten die Dauerhaft oder sind aus (vorwählbar)
Bei stellen Minuten Blinken beide LED unter den Minuten bei stellen Stunden die unter den Stunden. Meine IDE mit Hilfe eines LDRs die Helligkeit zu regulieren habe ich verworfen. Die Uhr wird nur auf der Arbeit am schreibtisch stehen deswegen bekommt sie noch eine Schaltung die die Uhr nachts ausschaltet (kann ja eh keiner sehen).
Gruß
Der Dani

Danke für die Vorstellung. Man sieht hier sehr wenig solcher Sachen. Noch ein feines Plexiglasgehäuse drumrum. Die Verkabelung würde ich gerade so lassen. Das hat richtig was "technisches" und man kann erkennen daß hier Innovation eingeflossen ist.

Irgendwie nostalgisch und dennoch hi-Tech :) Klasse !

Geile Sache das! Davon gern mehr....

So noch mal ein Finales Bild. Heute endlich Fertig geworden.

Hier der letzte Stand des Codes. Da diese Uhr bei mir auf den Schreibtisch kommt habe ich da eine Routine drin das die Nixies um 19Uhr abends aus und morgens um 7 Uhr einschalte.
Die Nixies sind maximal mit 90% Ontime getaktet zur Lebensdauererhaltung.
Hier der Finale Code hoffe ausreichen Kommentier. Bei Intresse liefere ich noch einen Schema-Schaltplan

/*
Attiny84 Big 7 Segment Uhr mit 74HC595
Build von Volvodani ==> Arduino Forum
Main CPU Attiny84+ RTC 
 */


#include <TinyWireM.h>
#include <USI_TWI_Master.h>


#define Shiftdata  8          // Pin 8 Datenleiung Schieberegister connected to Data in (DS) of 74HC595
#define Shiftclock 10           // Pin 9 Clockleitung connected to clock pin (SH_CP) of 74HC595
#define Shiftlatch 9         // Pin 10 Latchleitung connected to latch pin (ST_CP) of 74HC595
#define PWMOUT 7
#define BUTTON 1
#define RTCPuls 2
#define LED 0
#define RTC_ADDRESS 0x68
#define TIME 750

byte ie,iz,hz,he,mz,me=0;  // Modulespeicher der stunden Minuten
boolean ldruck,druck=false;   // Stellknopf für Zeit 
boolean longpress,shortpress=false;  // Unterscheidung langer kurzer druck
boolean blinktakt=false;             // Blinktakt 500ms
boolean lpuls,puls=false;            // Sekundenpuls
boolean hell=false;
unsigned long lmillis,start,ptime=0;
byte ss=0;
byte mm=0;
byte hh=0;
byte minuten,stunden=0;
byte setmode=0;
byte PWMArray[7]={
  0,20,40,80,120,160,240};
byte Pointer=5;


byte SDec2Shift(byte x){
  byte xeiner=x%10;
  byte xzehner=(x-xeiner)/10;
  return (xzehner<<4)+xeiner;
  ;
}


void setup(){
  pinMode(Shiftdata,OUTPUT);
  pinMode(Shiftclock,OUTPUT);
  pinMode(Shiftlatch,OUTPUT);
  pinMode(BUTTON,INPUT_PULLUP);
  pinMode(RTCPuls,INPUT);
  pinMode(PWMOUT,OUTPUT);
  pinMode(LED,OUTPUT);
  TinyWireM.begin();                                  // Start I2C Kommunikation
  TinyWireM.beginTransmission(0x68);                  // Beginn Kommunikation auf  Adresse 0x68 
  TinyWireM.send(0x07);                               // Pointer auf Control Register 0x07   
  TinyWireM.send(0x10);                               // Steuerwort Ex "0x30" Bin110000 Ausgang RTC Ausgang auf 1Hz Logic normal Levels setzn
  TinyWireM.endTransmission();                        // Beenden der I2C Kommunitkation
  HourRead();                                         // RTC Funktion lesen der aktuellen zeit Stunden
  MinuteRead();                                       // RTC Funktion lesen der aktuellen zeit Minuten
  RTC_Start();                                        // Start der Uhr
}


void loop(){
  /*=>Routine OneButton Control<=*/
  druck=digitalRead(BUTTON);            // Einlesen des Button (Achtung invertierte Logik da intrener Pull Up Widerstand aktiviert)
  if (druck==false&&ldruck==true){      // Steigende Flanke des Button
    start=millis();                     // Startzeit des Bettätigen
    ldruck=false;                       // Hilfsflag zur Flanken erkennung
  }
  if (druck==true&&ldruck==false){      // Falende Flanke des Buttons
    ptime=millis()-start;               // Die Länge in ms des Gedückten Zustandes
    ldruck=true;
  }
  if (ptime>=TIME){                    // Wenn der Druck länger (Hier750ms) 
    longpress=true;                    // War ein Langer druck
    ptime=0;                           // Zeit wieder Zurücksetzten
  }
  if (ptime<TIME&&ptime>=50) {         // Wenn der Druck kürzer 750ms und länger 50ms (gegen prellen)
    shortpress=true;                   // War ein kurzer Durck
    ptime=0;                           // Zeit wieder zurücksetzuten
  }
  /*One Button End*/
  puls=digitalRead(RTCPuls);                 // Einlessen des RTC Sekunden Puls
  if (puls==true&&lpuls==false){             // wenn Sekundenpuls da und vorher nicht da war (steigende Flanke)
    lpuls=true;
    ss++;                                    // intern Sekunden zählen
  }
  if (ss>=60&&setmode==0){                   // Nach 60 Sekunden
    HourRead();                              // RTC Funktion lesen der aktuellen zeit Stunden
    MinuteRead();                            // RTC Funktion lesen der aktuellen zeit Minuten
    ss=0;                                    // Rücksetzzeten internen Sekunden Zähler auf 0
  }
  if (puls==false){                          // RTC Sekunden Hilfspuls
    lpuls=false;
  }
  if (shortpress==true){                    // Routine Kurzes drücken
    if (setmode==0){                        // In Normalmodus 
      Pointer++;                            // ändern des Pointer der Helligkeit
      if (Pointer>=7){                      // Bei Pointer 6 und größer auf Pointer Null
        Pointer=0;
      }
    }
    if (setmode==1){                        // Minuten stellen
      mm++;
      if (mm>=60){
        mm=0;
      }
    }
    if (setmode==2){                        // Stunden stellen
      hh++;
      if(hh>=24){
        hh=0;
      }
    }
    shortpress=false;
  }
  if (longpress==true){                      // Routine Langes drücken
    setmode++;                               // Stellmodus erhöhen
    if (setmode==3){                         // Bei erreichen des Modus 3
      RTC_Set();                             // Neue Uhrzeit übernehmen in die RTC
      RTC_Start();                           // RTC Starten
      setmode=0;                             // Rücksetzten des Setmodes auf 0 (Normale Anzeige)
    }
    longpress=false;                         // Rücksetzten des Flags Langes Drücken
  }
  if (millis()-lmillis>=500){                // Aktalisiernung alle halbe Sekunden
    blinktakt= !blinktakt;                   // Blinktakt der Stellen anzeige
    minuten=SDec2Shift(mm);
    stunden=SDec2Shift(hh);
    if (blinktakt==false){                  // Blinkroutine des Stellmodus
      if(setmode==1){                       // Minuten stellen
        minuten=B10101010;
      }
      if (setmode==2){                      // Stunden Stellen
        stunden=B10101010;
      }
    }
    digitalWrite(Shiftlatch, LOW);     // Latch aussetzten um in den Storage speicher zu schreiben 
    shiftOut(Shiftdata, Shiftclock, MSBFIRST,  stunden);                    // Shift out der einzelenen Puffer wobei im letzten
    shiftOut(Shiftdata, Shiftclock, MSBFIRST,  minuten);                  // Shift out der einzelenen Puffer wobei im letzten
    digitalWrite(Shiftlatch, HIGH);                                        // Aktiverien des Latches (Schieben des Shift ind Storageregister) zum Anzeigen
    lmillis=millis();  
  }
  if (hh==19&&hell==true){                         // wenn Später 22Uhr und Früher als 8Uhr und es vorher Hell war dann dunkelschlaten
    Pointer=0;
    hell=false;
  }
  if (hh==7&&hell==false){                       // Wenn vor 22Uhr und nach 8 Uhr und vorher dunkel war dann Hell Schalten
    Pointer=5;
    hell=true;
  }
  analogWrite(PWMOUT,PWMArray[Pointer]);
  if (Pointer==0){
    digitalWrite(LED,LOW);
  }
  else
    digitalWrite(LED,HIGH);
}


void HourRead(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x02);               // Pointer auf Stunden
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(RTC_ADDRESS, 1);
  hh= bcdToDec(TinyWireM.receive());
}

void MinuteRead(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x01);               // Pointer auf Minuten
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(RTC_ADDRESS, 1);
  mm= bcdToDec(TinyWireM.receive());
}

void RTC_Start(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x00);
  TinyWireM.send(decToBcd(ss));    // 0 to bit 7 starts the clock
  TinyWireM.endTransmission();
}


void RTC_Set(){
  TinyWireM.beginTransmission(RTC_ADDRESS);
  TinyWireM.send(0x01);
  TinyWireM.send(decToBcd(mm));
  TinyWireM.send(decToBcd(hh));      // If you want 12 hour am/pm you need to set
  TinyWireM.endTransmission();
}

byte decToBcd(byte val)
{
  return ((val/10)<<4)+(val%10);
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ((val>>4)*10)+val%16;
}

Gruß
Der Dani

IMG_0586[1].jpg

IMG_0584[1].jpg

Wenn jemand interesse an Nixieröhren hat ich habe noch 4 von diesen Z573M. Diese kommen aus einer Ersatzplatine eines Tischrechners Elka 22M und sind nie gebraucht. evtl tausch gegen Arduino Nano. Gruß Der Dani

Hey schönes Projekt! Ich hab fast das gleiche aufgebaut. Mir fehlt nur noch ein schönes Gehäuse und ein neuer Trafo weil der Alte zu groß ist und die Isolierung nicht mehr so top ist. Wieviel Versand hast du für das Netzteil bezahlt und wie lange dauerte der Versand?

Gruß

Das Dingen bekommst du bei eBay ohne Versand Lieferung dauerte 7Tage aus Amerika Gruß Der Dani

Tante Edith sagt bring mal den link http://www.ebay.de/itm/Nixie-power-supply-1364-/320831453118 Ich nutze ihn bei 12V funktioniert von 1.8-16V Bei 5V Liefert der auf der Ausgangsseite bis zu 5W

Klasse, werd ich mir auch bestellen, danke! dann brauch ich nur noch ein schönes Gehäuse. Ich wollte eher Richtung Holz gehen, irgendwas das so alt aussieht wie die Röhren selbst.

Hej Volvodani,

könntest Du mir die angepasste TinyWire Lib Posten? Ich möchte die Attiny84-er für diverse Projekte nutzen aber finde die passende I2C Libery nicht! Danke für die hilfe

Ready

Hier die angepasste TinyWire Lib.
Ich habe die USI_TWI_Master.h angepasst da die define für die x4er Serie nicht drin waren.
Gruß
Der Dani

TinyWireM.zip (14.8 KB)

Sieht super aus - da liegt noch ein langer Weg vor mir, bis ich soweit bin.

Hallo Scherheinz,

welche Nixis hast du genommen? Das sind ja richtige Monster! :D

@ Dani: Nixis reagieren langfristig allerigisch auf Muxen oder PWM! Es gibt speziell dafür freigegebene Modelle (Datenblatt konsultieren), das ist aber eher die Ausnahme. Auf mikrocontroller.net wurde darüber diskutiert. Ansonsten wird von den Elektroden Material abgesputtert. In Folge leuchten dann nicht mehr die ganzen Symbole oder die Sichtfläche verfärbt sich. Die Projekte wären doch was für den Uhren-Tröt: http://forum.arduino.cc/index.php?topic=175674.0 :D

Gruß Gerald

Hallo Gerald! Ich denk das Bild lässt die Röhren größer wirken als sie sind. Das sind ganz normale NEC CD66A, also eher Standart Größe. Also ich hab jetzt auch ein Netzteil von Taylor verbaut, ich hoffe das es nicht allzuviel an Lebensdauer kostet. Außerdem will ich jetzt noch Innentemperatur und Außentemperatur sowie die Luftfeuchtigkeit anzeigen lassen. Dazu will ich einen Conrad Außenfühler mittels 433Mhz Empfänger auslesen. Bin mal gespannt ob der Empfänger und das Netzteil sich ins Gehege kommen. Was meint ihr dazu??

Gruß