Wortuhr mit Neopixel LED-Streifen

Da hat du natürlich recht... Ich geändert! Ich habe eh viel zu schneiden und zu löten... Hoffentlich klappt das alles wenn es fertig ist...
Montag kommt die Grundplatte und dann geht's los!
 
Problem: Es leuchtet nur der halbe LED-Streifen --> Meine Lösung: Das Array war mit signed char definiert, ich habe signed short draus gemacht. Bei mir sind 227 LEDs im Einsatz.
Trotzdem habe ich das Problem das die letzten beiden Pixel (226,227) nicht leuchten wollen... Was habe ich übersehen?!?

Nachtrag: Fehler wurde gefunden... War wohl schon zu spät :D
Ich habe der Variable LED_ANZAHL nur 227 LED angegeben... Beim Zählen habe ich mit 0 angefangen... daher kam ich nur auf 227 und nicht auf 228...
Fehler behoben, nun gehts ans Löten! Langwierige Aufgabe!
 
Zuletzt bearbeitet:
Update: Die Frontplatte mit den Buchstabenausschnitten ist bestellt. Diese Wird aus Holz bestehen, die Buchstaben werden ausgelasert. Ich bin gespannt wie das ganze dann wirkt! Bilder folgen in einigen Wochen - Wenn ich die Platte in meinen Händen halten darf.
 
So, die Uhr ist heute fertig geworden! Ich denke es ist ein wirklich tolles Teil geworden!

Der Code sieht zur Zeit so aus:
C++:
/*  
*  
*    Realisiert von Stefan Hagel, Pansdorf
*  
*    Private-use only! (you need to ask for a commercial-use)
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*  Private-use only! (you need to ask for a commercial-use)
*  
*  
*   ---------------------------------------------------------------------------------------------------------------------------------
*   Remake einer "qlocktwo", realisiert mit einem Arduino Nano, einem "Neopixel RGB-Streifen" und einem "I2C DS1307 Uhrmodul"
*  
*   Das DS1307-Modul wird an VCC mit 5V versorgt (Unbedingt darauf achten das die Knopfzelle auch ein AKKU und keine Batterie verbaut ist!),
*   GND an Masse, SDA an Pin A4, SCL an Pin A5. (Angaben sind für den Arduino Nano: Andere Modelle haben eine andere Pinbelegung. Bitte nach dem passenden Modell und "Pinout"
*   suchen um die richtigen Pins zu finden!)
*  
*   Die Datenleitung des Neopixel-Streifens ist auf Pin D9 definiert (Kann weiter unten auch verändert werden.)
*  
*   In einem 2-Dimensionalen Array werden die Neopixel definiert die für den Aufruf eines Wortes (oder mehrerer Worte) benötigt werden.
*   Es werden im weiteren Verlauf des Programmes Worte definiert (ES_IST) und mit der entsprechenden Zeile aus dem Array verknüpft.
*   ES_IST findet man in der ersten Zeile(0). Es wird von 0 an aufwärts gezählt.
*  
*   Zum einstellen der Uhrzeit werden 3 Taster benötigt. Der "Sicherheitstaster muss gedrückt werden um die Uhrzeit zu verstellen, die zwei anderen Taster
*   werden für das Einstellen der Minuten und Stunden benötigt.
*   Die Taster müssen gegen Masse schalten. D2 = Sicherheitstaster, D3 = Stundentaster, D4 = Minutentaster.
*  
*  
*   Es fehlt hier noch:
*  
*   Die möglichkeit der automatischen Sommer/Winterzeitumstellung.
*  
*   Eine Möglichkeit zur Einstellung per App. (Datum/Zeit einstellen, Farben einstellen, Sommwe/Winterzeit konfigutation und weiteres.
*  
*   Dimmfunktion (Helle Umgebung = hohe Leuchtkraft...) mit eventuellem Farbwechsel auf rot in der Nacht.
*   ---------------------------------------------------------------------------------------------------------------------------------
*/

#include <Adafruit_NeoPixel.h>                                                                              // Bibliothek für den Neopixel-Streifen einbinden
#include <Wire.h>                                                                                           // Bibliothek für die Schnittstelle zur Uhr einbinden

#ifdef __AVR__
#include <avr/power.h>                                                                                     // Required for 16 MHz Adafruit Trinket
#endif

unsigned long color, color_background;                                                                      // Globale Variablen deklarieren
int hours, minutes, seconds;

#define LED_PIN     9                                                                                       // An welchem PWM-Ausgang am Arduino sind die NeoPixel angeschlossen?
#define LED_ANZAHL  224                                                                                     // Wie viele NeoPixel sind angeschlossen?
byte helligkeit=200;                                                                                        // Helligkeit der LEDs (von 0 bis 255)
#define DS1307_ADDRESS 0x68                                                                                 // I²C Addresse für Uhrmodul

Adafruit_NeoPixel strip(LED_ANZAHL, LED_PIN, NEO_GRB + NEO_KHZ800);                                         // Neopixel-Streifen definieren
/*
* Argument 1 = Anzahl der NeoPixel
* Argument 2 = Arduino PWM-Pin an dem der LED-Streifen angeschlossen ist
* Argument 3 = Welche Art von NeoPixel-Streifen wird verwendet?:
* NEO_KHZ800  800 KHz bitstream (meistverwendet --> NeoPixel w/WS2812 LEDs)
* NEO_KHZ400  400 KHz (classic 'v1' (nicht v2) FLORA pixels, WS2811 treiber)
* NEO_GRB     Pixels sind für GRB bitstream vorgesehen (meistverwendet)
* NEO_RGB     Pixels sind für RGB bitstream vorgesehen (v1 FLORA pixels, not v2)
* NEO_RGBW    Pixels sind für RGBW bitstream vorgesehen (NeoPixel RGBW Produkte)
*/



//Array eröffnen. Die LEDs, die zur Anzeige des benötigten Wortes nötig sind, werden hier deklariert.
//Der Eintrag -1 ist ein Abbruchkriterium und weist auf das Ende des Wortes/der Wörter hin. (Wird in der Schleife verwendendet)

#define NUM_PIXELS 15                                                                                       // Maximale Anzahl der Pixel für eine Zahl
signed short leds[26][NUM_PIXELS] = {                                                                       // WORT           ANZAHL BENÖTIGTER LEDs
  { 0, 1, 39, 38, 79, 78, 80, 81, 119, 118, -1 },                                                           // ES IST         11
  { 159, 158, 160, 161, 199, 198, 200, 201, -1 },                                                           // FUENF          9
  { 2, 3, 37, 36, 42, 43, 77, 76, -1 },                                                                     // ZEHN           9
  { 84, 85, 115, 114, 124, 125, 155, 154, 164, 165, 195, 194, 204, 205, -1 },                               // VIERTEL        15
  { 82, 83, 117, 116, 122, 123, 157, 156, 162, 163, 197, 196, 202, 203, -1 },                               // ZWANZIG        15
  { 8, 9, 31, 30, 48, 49, 71, 70, -1 },                                                                     // HALB           9
  { 126, 127, 153, 152, 166, 167, -1 },                                                                     // VOR            7
  { 46, 47, 73, 72, 86, 87, 113, 112, -1 },                                                                 // NACH           9
  { 50, 51, 69, 68, 90, 91, 109, 108, -1 },                                                                 // EINS           9
  { 10, 11, 29, 28, 50, 51, 69, 68, -1 },                                                                   // ZWEI           9
  { 27, 26, 52, 53, 67, 66, 92, 93, -1 },                                                                   // DREI           9
  { 145, 144, 174, 175, 185, 184, 214, 215, -1 },                                                           // VIER           9
  { 147, 146, 172, 173, 187, 186, 212, 213, -1 },                                                           // FUENF          9
  { 21, 20, 58, 59, 61, 60, 98, 99, 101, 100, -1 },                                                         // SECHS          11
  { 109, 108, 130, 131, 149, 148, 170, 171, 189, 188, 210, 211, -1 },                                       // SIEBEN         13
  { 23, 22, 56, 57, 63, 62, 96, 97, -1 },                                                                   // ACHT           9
  { 65, 64, 94, 95, 105, 104, 134, 135, -1 },                                                               // NEUN           9
  { 103, 102, 136, 137, 143, 142, 176, 177, -1 },                                                           // ZEHN           9
  { 14, 15, 25, 24, 54, 55, -1 },                                                                           // ELF            7
  { 111, 110, 128, 129, 151, 150, 168, 169, 191, 190, -1 },                                                 // ZWOELF         11
  { 178, 179, 181, 180, 218, 219, -1 },                                                                     // UHR            7
  { 223, -1 },                                                                                              // 1              3
  { 222, 223, -1 },                                                                                         // 2              3
  { 221, 222, 223, -1 },                                                                                    // 3              3
  { 220, 221, 222, 223, -1 },                                                                               // 4              3
  { 50, 51, 69, 68, 90, 91, -1 }                                                                            // EIN (UHR) - Volle Stunde   7
};


// Hier wird den Worten eine Zeile aus dem Array zugewiesen. (0 ist die erste Zeile!)
#define ES_IST      0
#define M_FUENF     1
#define M_ZEHN      2
#define VIERTEL     3
#define ZWANZIG     4
#define HALB        5
#define VOR         6
#define NACH        7
#define H_EINS      8
#define H_ZWEI      9
#define H_DREI      10
#define H_VIER      11
#define H_FUENF     12
#define H_SECHS     13
#define H_SIEBEN    14
#define H_ACHT      15
#define H_NEUN      16
#define H_ZEHN      17
#define H_ELF       18
#define H_ZWOELF    19
#define UHR         20
#define M_EINS      21
#define M_ZWEI      22
#define M_DREI      23
#define M_VIER      24
#define H_EIN       25


// Setup wird einmal beim Programmstart ausgeführt!
void setup()  {
  Wire.begin();                                                                                             // Treiber für den Datenbus initialisieren.
  Serial.begin(115200);                                                                                     // Baudrate für die Kommunikation mit dem Uhrmodul

  strip.begin();                                                                                            // Initialisieren des NeoPixel Objectes (Treiber installation und ähnliches...)
  strip.show();                                                                                             // Alle Pixel ausschalten
  strip.setBrightness(helligkeit);                                                                          // Wert der Helligkeit wird weiter oben eingestellt.

  color = strip.Color(110,255,30);                                                                           // RGB-Farbe der Uhrzeit
  color_background = strip.Color(0,0,0);
                                                                                                            // Pins definieren für das Einstellen der Uhrzeit
  pinMode(2, INPUT_PULLUP);                                                                                 // Sicherheitstaster
  pinMode(3, INPUT_PULLUP);                                                                                 // Stundentaster
  pinMode(4, INPUT_PULLUP);                                                                                 // Minutentaster

//Startsequenz anzeigen
rainbow();

}


// Hier folgen jetzt die Funktionen

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow() {
  // Hue of first pixel runs 5 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
  // means we'll make 5*65536/256 = 1280 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
    //delay(10);  // Pause for a moment
  }
}


void setLeds(int i) {                                                                                       //Die Funktion setLeds liest aus der entsprechenden Zeile des Arrays die einzelnen Werte und übergibt sie dem Neopixelstreifen. Pixel für Pixel.
  for (int k = 0; k < NUM_PIXELS; k++) {
    if (leds[i][k] > -1) {
      strip.setPixelColor(leds[i][k], color);
    }
    else {
      break;
    }
  }
}


void displayTime() {                                                                                        //Die Funktion displayTime errechnet werte aus der ausgelesenen Zeit mit denen dann die passenden Worte der Uhrzeit ausgewählt werden.
  int mins = minutes - (minutes % 5);                                                                       //Erklärung für die Rechnung mit dem Modulo (%): Beispiel mins=28(minutes)%5 = 3 (Ergebnis ist 5 rest 3. Es wird nur der Rest ausgegeben. Somit ist mins=3)
  int hrs;
  int vor = 0;

  strip.clear();                                                                                            //Strip löschen

for (int a = 0; a < LED_ANZAHL; a++) {                                                                      //Alle Uhrzeit-Pixel wird ein Farbwert zugewiesen. Alle anderen Pixel in einer anderen Farbe (color_background).
  strip.setPixelColor(a, color_background);
}

  setLeds(ES_IST);

  switch (mins / 5) {                                                                                       //Hier werden die Minutenworte geschaltet
    case 0:                                                                                                 // Volle Stunde
      setLeds(UHR);
      break;
    case 1:
      setLeds(M_FUENF);
      setLeds(NACH);
      break;
    case 2:
      setLeds(M_ZEHN);
      setLeds(NACH);
      break;
    case 3:
      setLeds(VIERTEL);
      setLeds(NACH);
      break;
    case 4:
      setLeds(ZWANZIG);
      setLeds(NACH);
      break;
    case 5:
      setLeds(M_FUENF);
      setLeds(VOR);
      setLeds(HALB);
      vor = 1;
      break;
    case 6:
      setLeds(HALB);
      vor = 1;
      break;
    case 7:
      setLeds(M_FUENF);
      setLeds(NACH);
      setLeds(HALB);
      vor = 1;
    break;
    case 8:
      setLeds(ZWANZIG);
      setLeds(VOR);
      vor = 1;
      break;
    case 9:
      setLeds(VIERTEL);
      setLeds(VOR);
      vor = 1;
      break;
    case 10:
      setLeds(M_ZEHN);
      setLeds(VOR);
      vor = 1;
      break;
    case 11:
      setLeds(M_FUENF);
      setLeds(VOR);
      vor = 1;
      break;
  }

switch (minutes % 5) {                                                                                      // Hier werden die LEDs für die Minutenanzeige (1-4) geschaltet.
  case 0:
    break;
  case 1:
    setLeds(M_EINS);
    break;
  case 2:
    setLeds(M_ZWEI);
    break;
  case 3:
    setLeds(M_DREI);
    break;
  case 4:
    setLeds(M_VIER);
    break;
  }

  hrs = hours + vor;                                                                                        // hrs ist die Angezeigte Stunde. Bei zehn vor vier ist es 15:50Uhr. Daher wird eine Stunde hinzugezählt um von 15 auf 16 zu kommen (zehn VOR 4)
  if (hrs > 12) {                                                                                           // Stunde 13 ist nicht in den Worten enthalten. Daher werden Stundenzahlen größer als 12 auf 0 zurückgesetzt.
    hrs = hrs - 12;
  }
  if (hrs == 0) {                                                                                           // Da wir keine null Uhr haben wird die Stunde null zur stunde 12 gemacht.
    hrs = 12;
  }

                                                                                                            // STUNDEN
  switch (hrs) {
  case 1:
    if(mins/5==0){
    setLeds(H_EIN);
    break;
    }
    else {
    setLeds(H_EINS);
    break;
    }
  case 2:
    setLeds(H_ZWEI);
    break;
  case 3:
    setLeds(H_DREI);
    break;
  case 4:
    setLeds(H_VIER);
    break;
  case 5:
    setLeds(H_FUENF);
    break;
  case 6:
    setLeds(H_SECHS);
    break;
  case 7:
    setLeds(H_SIEBEN);
    break;
  case 8:
    setLeds(H_ACHT);
    break;
  case 9:
    setLeds(H_NEUN);
    break;
  case 10:
    setLeds(H_ZEHN);
    break;
  case 11:
    setLeds(H_ELF);
    break;
  case 12:
    setLeds(H_ZWOELF);
    break;
  }
  strip.show();                                                                                             // Zeit anzeigen
}


void TastenLesen() {                                                                                        //Mit dieser Funktion soll die Uhzeit eingestellt werden können. 3 Taster benötigt. (Taster müssen vom PIN auf Masse schalten)
  int Sicherheitstaster =   digitalRead(2);
  int Stundentaster =       digitalRead(3);
  int Minutentaster =       digitalRead(4);
  if(Sicherheitstaster == 0){
    if(Stundentaster == 0){
      //readTime();
      hours++;
        if(hours>=24) {
          hours=0;
        }
        seconds = 0;
        setDate();
        delay(250);
    }
    else{
      if(Minutentaster == 0){
        minutes++;
        if(minutes>=60){
          minutes=0;
        }
        seconds = 0;
        setDate();
        delay(250);
      }
    }
  }
}


void readTime() {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);

  seconds = bcdToDec(Wire.read());
  minutes = bcdToDec(Wire.read());
  hours   = bcdToDec(Wire.read() & 0b111111);
}


void setDate() {                                                                                            // Funktion zum schreiben der Zeit auf das Uhrmodul. Bitte hier die Aktuelle Zeit zum angeben. Diese wird beim ersten Start auf das Uhrmodul geschrieben.
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(seconds));                                                                            // sekunden
  Wire.write(decToBcd(minutes));                                                                            // minuten
  Wire.write(decToBcd(hours));                                                                              // stunden (24-hour format)
  Wire.write(decToBcd(4 ));                                                                                 // wochentag (1=Sonntag)
  Wire.write(decToBcd(07));                                                                                 // tag
  Wire.write(decToBcd(04));                                                                                 // monat
  Wire.write(decToBcd(2021));                                                                               // jahr
  Wire.write(0x00);
  Wire.endTransmission();
}


int bcdToDec(int value) {                                                                                   // Binärcode in Dezimalzahl umwandeln
  return ((value/16*10) + (value%16));
}


int decToBcd(int value) {                                                                                   // Dezimalzahl in Binärcode umwandeln
  return ((value/10*16) + (value%10));
}


void loop()                                                                                                 // Diese Funktion wird in einer nie endenden Schleife ausgeführt! Zeit vom Uhrmodul lesen, Zeit anzeigen, 250ms warten und wieder von vorne.
{
  readTime();
  displayTime();
  TastenLesen();
  delay(10);
}

Ich hoffe der Code ist für jeden verständlich - Falls jemand fragen hat, immer raus damit!
Wenn jemand so eine Uhr nachbauen möchte, zeigt es doch auch gerne hier. Ich freue mich über "Mittäter"! Vielleicht habt Ihr ja auch noch änderungen im Code vorgenommen, dann schreibt es auch gerne hier.

Gute Nacht, jetzt wird erstmal gemäääääht.... ;-)
 
Ich denke grade darüber nach, ob es nicht möglich ist ein esp8266 esp 01 zu verwenden. Benötigt wird eine I2C Schnittstelle und ein PWM Pin...
 
Man benötigt ja gar keine I2C Schnittstelle... Man kann ja auch die Zeit aus dem Internet abgleichen... Von einem NTP Server!
 
Die Möglichkeiten sind ja alle gegeben. Ich habe es zur Zeit so gelöst dass ich das Uhrmodul komplett weglasse und die Zeit in regelmäßigen Abständen mit einem Timeserver abgleicht um Abweichungen zu vermeiden.
Der Pin 2 vom ESP-01 ist für die Ansteuerung der LEDs zuständig.
Es fehlt quasi nur noch die Front der Uhr.
 

Anhänge

  • IMG_20210406_124933.jpg
    IMG_20210406_124933.jpg
    4,5 MB · Aufrufe: 6
  • IMG_20210313_111401.jpg
    IMG_20210313_111401.jpg
    6,8 MB · Aufrufe: 6
  • IMG_20210406_124937.jpg
    IMG_20210406_124937.jpg
    4,7 MB · Aufrufe: 5
  • IMG_20210424_212458.jpg
    IMG_20210424_212458.jpg
    5 MB · Aufrufe: 6
  • IMG_20210319_230904.jpg
    IMG_20210319_230904.jpg
    5 MB · Aufrufe: 7
  • IMG_20210423_203022.jpg
    IMG_20210423_203022.jpg
    4,5 MB · Aufrufe: 8
  • IMG_20210406_165853.jpg
    IMG_20210406_165853.jpg
    1,6 MB · Aufrufe: 6
  • IMG_20210424_212448.jpg
    IMG_20210424_212448.jpg
    5,3 MB · Aufrufe: 6
  • IMG_20210313_111351.jpg
    IMG_20210313_111351.jpg
    6,8 MB · Aufrufe: 7
  • IMG_20210429_114417.jpg
    IMG_20210429_114417.jpg
    1,8 MB · Aufrufe: 5
weitere Fotos
 

Anhänge

  • IMG_20210309_203142.jpg
    IMG_20210309_203142.jpg
    4 MB · Aufrufe: 3
  • IMG_20210309_203152.jpg
    IMG_20210309_203152.jpg
    4,9 MB · Aufrufe: 3
  • IMG_20210414_162604.jpg
    IMG_20210414_162604.jpg
    4,1 MB · Aufrufe: 4
  • IMG_20210406_164326.jpg
    IMG_20210406_164326.jpg
    5,5 MB · Aufrufe: 6
  • IMG_20210414_170341.jpg
    IMG_20210414_170341.jpg
    3,7 MB · Aufrufe: 6
  • IMG_20210429_114403.jpg
    IMG_20210429_114403.jpg
    1,9 MB · Aufrufe: 5
  • IMG_20210414_162612.jpg
    IMG_20210414_162612.jpg
    4,5 MB · Aufrufe: 7
  • IMG_20210424_122149.jpg
    IMG_20210424_122149.jpg
    1,6 MB · Aufrufe: 7
  • IMG_20210406_122354.jpg
    IMG_20210406_122354.jpg
    1,1 MB · Aufrufe: 6
Sehr schoen;-) Es sieht aus, als benutzt du einen Arduino Mini [clone]?! Hast du schon mal an einen ESP32 gedacht? Der koennte WiFI und die ntp/internet Zeit benutzen. Dann entfaellt das stellen der Uhr;-) Oder als Alternative, einen einfachen GPS Empfaenger mit verbauen. Der koennte dir auch die Zeit lliefern.

Viel Spass;-)
 
Ich hatte in dieser Konstellation einen Arduino Nano und ein Uhrmodul genommen.
Waren die Anfänge! Eine Uhr mit Glasfront und Funkuhr Modul habe ich auch gebaut, da die Uhr an ihrem Arbeitsplatz kein WLAN hat.

Als kleinste Möglichkeit habe ich ein ESP-01 Modul mit WLAN und ntp Zeit versucht. Klappt auch wunderbar!

Nun bin werde ich mal eine Uhr für mich bauen. Da habe ich ein sehr umfangreiches Projekt von Manfred Hofmann auf GitHub gefunden. https://github.com/manfred-hofmann/Wortuhr_ESP8266

Ich hoffe dass das Projekt bis zum Sommer fertig wird.
 
Oben