Uhrzeit mit WS2812 (Alternative Equinox)

Habe hier eine Funktion bei der ich ein paar Probleme hab.
Kurz zur Funktionsweise:

Die Funktion rtcMinuten gibt auf einem LED Strip von 60 LEDs die Zeit an. Dabei ist der StartPunkt jedes mal jedes "Ziffernblatt" (0, 5, 10, 15, ....). Nun beginnt die Uhr bei Minute 0 mit dem leuchten der ersten LED 255.

Nun fadet die LED jede 12 Sekunden ein Feld weiter und lässt das vorherige aktiv. Sind die vollen 5 Minuten erreicht, werden die LEDs 0, 1, 2, 3, 4, nicht mehr angesprochen und der Vorgang startet erneut bei diesmal Startpunkt 5.

Habe nun das Problem, ich habe noch nicht die 60er Strips. Teste gerade immer nur 8 Leds. Deshalb setze ich jedes mal meinen DS3231 auf 0.
Die ersten 5 Minuten laufen wie gewünscht ab. Ab Minute 5 und Sekunde 0 funktioniert folgender Teil nicht mehr

  static unsigned long test;

  if(millis() - test > 1000) {
    Serial << F(" m:") << m << F(" s:") << s 
      << F("  ") << a << F(":") << b
      << F(":") << c << F(":") << d 
      << F(":") << e << F(":") << f 
      << F("   ") << hm1 << F(" ") << hm1+1 
      << F(" ") << hm1+2 << F(" ") << hm1+3 
      << F(" ") << hm1+4 << F(" ") << hm1+5
      << F("  ") << hm << F(" ") << hm2
      << endl;
    test = millis();
  }

Zu Beginn des Sketches sind er mir jede Sekunde einmal den aktuellen Stand. Ab 5 Minuten wird die If Abfrage nicht mehr beachetet und er schickt jeden Durchlauf die Daten.

// RTC
#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>

#include <Streaming.h>

// LED Strip
#include <FastSPI_LED2.h>
#define NUM_LEDS 8
#define DATA_PIN 4
CRGB leds[NUM_LEDS];

void setup() {
  // Serielle Schnittstelle
  Serial.begin(9600);
  time_t t;
  tmElements_t tm;
  tm.Year = 2000;
  tm.Month = 1;
  tm.Day = 1;
  tm.Hour = 0;
  tm.Minute = 0;
  tm.Second = 0;
  t = makeTime(tm);
  RTC.write(tm);
  setTime(t);

  // LED Strip
  FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
}


void loop() {
  for(int x = 0; x < 8; x++) leds[x] = CRGB(0,0,0);

  // RTC
  tmElements_t tm;
  RTC.read(tm);
  byte h = tm.Hour * 5;
  byte m = tm.Minute;
  byte s = tm.Second;

  rtcMinuten(m, s);

  FastLED.show();
}

void rtcMinuten(byte m, byte s) {
  byte hm = m / 5; 
  byte hm1 = hm * 5;// Startpunkt
  byte hm2 = m%5;
  byte sneu = s/5;
  byte a = 0;
  byte b = 0;
  byte c = 0;
  byte d = 0;
  byte e = 0;
  byte f = 0;
  byte ledHelligkeit[] = { 
    0, 20, 25, 32, 40, 50, 64, 80, 101, 127, 161, 202, 255     };

  switch(hm2) {
  case 0:
    // 0 - 11
    a = ledHelligkeit[12];
    b = ledHelligkeit[sneu];
    break;
  case 1:
    // 12 - 23
    a = ledHelligkeit[12];
    b = ledHelligkeit[12];
    c = ledHelligkeit[sneu];
    break;
  case 2:
    // 24 - 35
    a = ledHelligkeit[12];
    b = ledHelligkeit[12];
    c = ledHelligkeit[12];
    d = ledHelligkeit[sneu];
    break;
  case 3:
    // 36 - 47
    a = ledHelligkeit[12];
    b = ledHelligkeit[12];
    c = ledHelligkeit[12];
    d = ledHelligkeit[12];
    e = ledHelligkeit[sneu];
    break;
  case 4:
    // 48 - 59
    a = ledHelligkeit[12];
    b = ledHelligkeit[12];
    c = ledHelligkeit[12];
    d = ledHelligkeit[12];
    e = ledHelligkeit[12];
    f = ledHelligkeit[sneu];  
    break;
  }

  leds[hm1].g = a;
  leds[hm1+1].g = b;
  leds[hm1+2].g = c;
  leds[hm1+3].g = d;
  leds[hm1+4].g = e;
  leds[hm1+5].g = f;

  static unsigned long test;

  if(millis() - test > 1000) {
    Serial << F(" m:") << m << F(" s:") << s 
      << F("  ") << a << F(":") << b
      << F(":") << c << F(":") << d 
      << F(":") << e << F(":") << f 
      << F("   ") << hm1 << F(" ") << hm1+1 
      << F(" ") << hm1+2 << F(" ") << hm1+3 
      << F(" ") << hm1+4 << F(" ") << hm1+5
      << F("  ") << hm << F(" ") << hm2
      << endl;
    test = millis();
  }

}

Habe nun nochmal einen neuen Ansatz versucht und insgesamt 15 Leds in Reihe nun angeschlossen. Habe das Sketch oben soweit erstmal verworfen und einen anderen Ansatz versucht. Funktioniert soweit schonmal mit dem gewünschten Fading.

void rtcSekunden(byte s) {
  byte ledArray[] = {
    59, 0,1,2,3,4,5,6,7,8,9,
    10,11,12,13,14,15,16,17,18,19,
    20,21,22,23,24,25,26,27,28,29,
    30,31,32,33,34,35,36,37,38,39,
    40,41,42,43,44,45,46,47,48,49,
    50,51,52,53,54,55,56,57,58,59, 0 };
static byte sAlt;
unsigned long aZeit = millis();
static unsigned long vZeit;
static unsigned long dZeit;

if(s != sAlt) {
  vZeit = aZeit;
  sAlt = s;
}

// Vergangene Zeit seit der letzen Sekundenänderung
dZeit = aZeit - vZeit;
// Berechnung des Fadings
byte x = 255-(255*dZeit/1000);
byte y = 255;
byte z = 255*dZeit/1000;

    
leds[ledArray[s]].b = x;
leds[ledArray[s+1]].b = y;
leds[ledArray[s+2]].b = z;

// Debuginfo
if(debug == 3) Serial << x << F("<<") << y << F("<<") << z << endl; 

}

Nun eine kleine Frage, ist eine Funktion so möglich? Ich würde sie gerne fürs debuggen nutzen.

void 3dig(byte i) {
  if(i >= 100) Serial << i;
  else if(i >= 10) Serial << F(" ") << i;
 else if(i >= 0) Serial << F("  ") << i;
}

Es sollt relativ einfach mit in den Code geschrieben werden.
z.B. so

if(debug == 3) Serial << 3dig(x) << F("<<") << 3dig(y) << F("<<") << 3dig(z) << endl;
Ich habe noch eine andere Lösung in einem anderen Sketch das mit dem C Serial.print arbeitet. Finde die Variante aber unschön.
Es geht mir drum, dass führende Nullen mit angeben werden.

Oder so:

void 3dig(byte i) 
{
   if(i >= 10) Serial << F(" ") ;
   if(i >= 100) Serial << F(" ");

   Serial << i;
}

So ähnlich hatte ich es schon und funktionierte nicht. Vermutlich mach ich da gerade großen Syntaxmist ;D

// Debuginfo
if(debug == 3) Serial << 3dig(x) << F("<<") << 3dig(y) << F("<<") << 3dig(z) << endl;
void 3dig(byte i) {
   if(i >= 10) Serial << F(" ") ;
   if(i >= 100) Serial << F(" ");
   Serial << i;
}

sketch_sep16b.ino:16:6: error: invalid suffix "dig" on integer constant
sketch_sep16b.ino:90:26: error: invalid suffix "dig" on integer constant
sketch_sep16b.ino:90:48: error: invalid suffix "dig" on integer constant
sketch_sep16b.ino:90:70: error: invalid suffix "dig" on integer constant
sketch_sep16b.ino:94:6: error: invalid suffix "dig" on integer constant
sketch_sep16b:16: error: expected unqualified-id before numeric constant
sketch_sep16b:94: error: expected unqualified-id before numeric constant

Denke er will in Funktionensnamen keine Zahlen haben.

Wenn ich 3dig durch test ersetze meckert er aber auch noch

sketch_sep16b.ino: In function 'void rtcSekunden(byte)':
sketch_sep16b:90: error: no match for 'operator<<' in 'Serial << test(x)'
D:\Dropbox\Arduino\libraries\Streaming/Streaming.h:54: note: candidates are: Print& operator<<(Print&, const _BYTE_CODE&)
D:\Dropbox\Arduino\libraries\Streaming/Streaming.h:73: note: Print& operator<<(Print&, const _BASED&)
D:\Dropbox\Arduino\libraries\Streaming/Streaming.h:91: note: Print& operator<<(Print&, const _FLOAT&)
D:\Dropbox\Arduino\libraries\Streaming/Streaming.h:102: note: Print& operator<<(Print&, _EndLineCode)

Ja, ich glaube Methoden-Namen können nicht mit Zahlen anfangen. Deshalb der erste Fehler-Salat

Der zweite Fehler ist dass du etwas in den Stream geben musst. Das hatte ich vorhin völlig übersehen. Dazu müsste die Methode dann einen Wert zurückgeben und nicht void.

So sollte es auch gehen (mit passendem Methoden-Namen!):

if(debug == 3)
{
   3dig(x); Serial << F("<<"); 3dig(y); Serial << F("<<"); 3dig(z); Serial << endl; 
}

EDIT:
Ich habe mal in Visual C++ gespielt und das hier funktioniert:

char dig(int i)
{
   if(i >= 10) cout << " "; 
   if(i >= 100) cout << " "; 

   cout << i;
   return '  ';
}

Mann kann dann cout << dig(...) machen, da das Leerzeichen an den Stream übergeben wird. Geht vielleicht als Workaround. In der Arduino IDE compiliert das auch (dann mit Serial statt cout) aber getestet habe ich es nicht.

Wenn man da nichts zurückgibt, meckert der Compiler deutlicher herum:
"error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'void' (or there is no acceptable conversion)"

Das hier ist vielleicht sauberer:

byte dig(byte i)
{
   if(i >= 10) Serial << " "; 
   if(i >= 100) Serial << " "; 

   return i;
}

Damit gibt man die Leerzeichen aus, reicht den Wert einmal durch die Methode und hat keine zusätzlichen Zeichen auf der Ausgabe.

Danke!

Es geht nun mit deinem kleinen Workaround. Jedoch hattest du die if Anweisungen noch verdreht XD

byte dig(byte i) {
  if(i < 10) Serial << " ";
  if(i < 100) Serial << " ";
  return i;
}

Ich habe nun die Anzeige für die Sekunden soweit fertig. Sieht schonmal nicht ganz so schlecht aus :wink: Hat jedoch noch kleine Ruckeler drin. Werde ich versuchen mit den PWM Steppings noch anzupassen. Was sind Erfahrungswerte für die Anzahl logarithmischer Werte in einem PWM Array? Des weiteren darf die loop Zeit nicht zu weit im Keller huschen. Leistungsdaten sind mit dem späteren Pro Mini ja soweit gleich.

Habe nun die erste Version meines Sketches fertig. Gibt noch einiges zu tun.

  • Dimmung nach Tageszeit
  • Alarmmodus (Rundumleuchte der LEDs, evtl. + Buzzer)
  • Sketch einkürzen/optimieren (sind noch einige Berechnung, die unnötig Rechenzeit verschlingen)
  • ...

Konnte mit 15 WS2812 RGB Leds nur beschränkt testen. Warte auf meine Lieferung mit 144 Leds/m. Hoffe auch, dass ich dann zeitnah meinen Rahmen für den Aufbau bekomme.
Meine Uhr ist vom Aufbau deutlich kleiner als die Equinox oder die Planung von Stefan(Eisebaer).

Ich habe mich für die 144 Leds/m entschieden, da mir die Equinox selber etwas zu bullig wirkt und man schlecht ein Netzteilkabel die Wand hochlegen kann, wenn noch keine Renovierung ansteht, habe mich entschlossen. Die kleine Equinox zu bauen, soll später fürs Regal/Schreibtisch sein.

Hier mal ein kurzes Video als 3D Modell. Mit den Leds wird ein leicht lichtundurchlässiger Plexiglas-Ring bestrahlt. Falls dieser zu wenig Licht auffängt, kann ich mit satinieren einfach nachhelfen. Die Ober bzw Unterplatte habe ich weggelassen. Ist aber identlisch mit der gegenüberliegenden Seite. Ggf. bekommt eine Seite noch ein Logo. Im inneren zwischen dem Ring für die 60 Leds und dem Loch ist ausreichen Platz für deinen Ardunio Mini Pro (vermutlich auch nano ...), sowie ein RTC Modul und was sonst noch anfällt.

// RTC
#include <DS3232RTC.h>
#include <Wire.h>
#include <Time.h>

// F-Makro
#include <Streaming.h>

// LED Strip
#include <FastSPI_LED2.h>
#define NUM_LEDS 60
#define DATA_PIN 4
CRGB leds[NUM_LEDS];

// Ausgabe Debug Serial Monitor
byte debug = 3;
unsigned long lZeit = 0;


void setup() {
  // Serielle Schnittstelle öffnen
  Serial.begin(115200);

  // RTC Uhrzeit holen
  setSyncProvider(RTC.get);
  setSyncInterval(3600);
  if(timeStatus() != timeSet) Serial << F("Sync nicht erfolgreich") << endl;
  else Serial << F("Sync erfolgreich!") << endl;

  // LED Strip
  FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
}


void loop() {
  // Erfassung der loopZeit
  unsigned long aZeit = millis();

  // Aktivieren des Debuggers über den Serial Monitor
  if(Serial.available()) debug = Serial.parseInt();
  


  // Alle LEDs löschen
  for(int x = 0; x < 60; x++) leds[x] = CRGB(0,0,0);

  rtcStunden();
  rtcMinuten();
  rtcSekunden();

  FastLED.show();

  // Erfassung der loopZeit
  lZeit = millis() - aZeit;
  if(debug == 0) {
    //Serial << F("lZeit : ") << dig2(lZeit) << endl;
  }
}

void rtcSekunden() {
  byte s = second();

  byte ledArray[] = {
    59, 0,1,2,3,4,5,6,7,8,9,10,
    11,12,13,14,15,16,17,18,19,20,
    21,22,23,24,25,26,27,28,29,30,
    31,32,33,34,35,36,37,38,39,40,
    41,42,43,44,45,46,47,48,49,50,
    51,52,53,54,55,56,57,58,59, 0
  };

  byte pwmFadeX[] = {
    217,186,158,135,115,98,84,71,
    61,52,44,38,32,27,23,20
  };

  byte pwmFadeZ[] = {
    20,23,27,32,38,44,52,61,
    71,84,98,115,135,158,186,217
  };

  // Vergangene Zeit seit der letzen Sekundenänderung
  static byte sAlt;
  unsigned long aZeit = millis();
  static unsigned long vZeit;
  static unsigned long dZeit;
  if(s != sAlt) {
    vZeit = aZeit;
    sAlt = s;
  }
  dZeit = aZeit - vZeit;

  // Berechnung des Fadings
  byte i = dZeit/62;
  if(i >= 16 ) i = 15;

  // 10 Schritte/Sekunde
  byte x = pwmFadeX[i];
  byte y = 255;
  byte z = pwmFadeZ[i];

  // Zuweisung
  leds[ledArray[s]].b = x;
  leds[ledArray[s+1]].b = y;
  leds[ledArray[s+2]].b = z;
}

void rtcMinuten() {
    byte m = minute();
  byte s = second();

  byte pwmFade[] = {
    20,24,28,33,39,47,55,66,
    78,92,109,129,153,182,215,255
  };

  byte mStartTemp = m/5;
  byte mStart = mStartTemp*5;
  byte mMod = m%5;

  // Berechnung des Fadings
  byte i = s*16/60;
  if(i >= 16 ) i = 15;
  byte x = pwmFade[i];

  // Zuweisung
  for(int j = 0; j <= mMod; j++) leds[mStart+j].g = 255;
  leds[m+1].g = x;
}

void rtcStunden() {
  byte h = hourFormat12();
  byte m = minute();

  byte pwmFade[] = {
    20,24,28,33,39,47,55,66,
    78,92,109,129,153,182,215,255
  };

  // Berechnung des Fadings
  byte i = m/12;
  byte x = pwmFade[m-(i*12)];

  // Zuweisung
  for(int k = 0; k < i; k++) leds[h*5+i-k].r = 255;
  leds[h*5+i+1].r = x;
  leds[h*5].r = 255;
}


// 2 stellige Ausgabe von Zahlen
byte dig2(byte i) {
  if(i < 10) Serial << " ";
  return i;
}

// 3 stellige Ausgabe von Zahlen
byte dig3(byte i) {
  if(i < 10) Serial << " ";
  if(i < 100) Serial << " ";
  return i;
}

Du kannst noch die Time Library mit der RTC durch setSyncProvider und setSyncInterval synchronisieren. Und dann statt RTC.get die Zeit direkt von Time Lib lesen. Dann läuft die Zeit lokal und du musst vielleicht nur alle paar Minuten mal von der RTC lesen, statt jede Sekunde.

Wird notiert als nächste Aufgabe. Das kann man machen, ohne die 60 Leds zu haben. erledigt!
http://forum.arduino.cc/index.php?topic=188328.msg1394425#msg1394425

Mal eine kleine Frage nebenbei zu den WS Stripes.

Gibt es große Unterschiede zwischen dem WS2811/WS2812/WS2812B. Ich kann in der Bucht die WS2812B (144Stk/m) für 50€ inkl. Versand bekommen. Bei Alibaba habe ich diese leider nicht gefunden. Dort gibt es aber WS2811 in der gleichen Größenordnung für den halben Preis inkl. Versand.

Wellenlänge und Helligkeit werden in etwa bei beiden gleich angegeben. Beide Sets sind ebenfalls für 5V ausgelegt.

http://www.ebay.de/itm/1-Meter-144-Led-s-WS2812B-Streifen-Stripe-weiss-mit-WS2811-Controller-/271266418346?pt=Bauteile&hash=item3f28bd0eaa
http://de.aliexpress.com/item/1M-WS2811-Dream-Color-LED-Strip-Lights-144-Pixel-5050-RGB-SMD-WS2811-IC-Per-Meter/1095890888.html

sschultewolter:
Mal eine kleine Frage nebenbei zu den WS Stripes.

Gibt es große Unterschiede zwischen dem WS2811/WS2812/WS2812B. Ich kann in der Bucht die WS2812B (144Stk/m) für 50€ inkl. Versand bekommen. Bei Alibaba habe ich diese leider nicht gefunden. Dort gibt es aber WS2811 in der gleichen Größenordnung für den halben Preis inkl. Versand.

Wellenlänge und Helligkeit werden in etwa bei beiden gleich angegeben. Beide Sets sind ebenfalls für 5V ausgelegt.

Der WS2811 ist der Controller ohne LED. Die RGB-LED muß extern angeschlossen werden. Er hat ein Pin um die Busfrequenz des Busses auszuwählen (400kHz oder 800kHz) http://www.adafruit.com/datasheets/WS2811.pdf
Der WS2812 ist ein RGB-LED mit integriertem WS2811 Controller. Er ist fix auf eine Busfrequenz von 800kHz eingestellt. Oft wird in den Produktbeschreibung fälschlicherweise als WS2811 bezeichnet. http://www.adafruit.com/datasheets/WS2812.pdf

Unterschied WS2812 und WS2812B hab ich das gefunden: http://www.rgb-123.com/files/WS2812B_VS_WS2812.pdf http://propaneandelectrons.com/blog/the-difference-between-ws2811-and-ws2812

Die B-Version ist eine Weiterentwicklung des WS2812. Sie ist teoretisch 100% kompatibel auch wenn auf dem vorläufigen Datenblatt die Timings für L und H leicht verschieden gegenüber der Vorgängerversion sind.
Der WS2812 hat 6 Pin und eine getrennte Spannungsversorgung für den Controller und die LED.
Der WS2812B hat 4 Pin und nur mehr eine gemeinsame Spannungsversorgung für den Controller und die LED. Er ist robuster da gegen Verpolung geschützt und intern ist der Controller weiter von den LED entfernt das der Wärmeableitung zu Gute kommt. Die LED sind heller. http://www.mikrocontroller.net/attachment/180459/WS2812B_preliminary.pdf

Bezüglich der Kosten kann ich Dir nichts sagen, aber wie Du weißt, ist die Bandbreite der Preise bei Elektronikbauteilen sehr groß.

Grüße Uwe

Dann denke ich, sind das die richtigen, die ich such.

http://www.aliexpress.com/item/144-Pixels-M-WS2812B-Chip-White-PCB-WS2811-IC-Digital-RGB-LED-Strip-Light-DC5V/1306267923.html

Auf die Lieferung kann ich warten. Lieber 2 zum Preis von einem :slight_smile:

sschultewolter:
Dann denke ich, sind das die richtigen, die ich such.

http://www.aliexpress.com/item/144-Pixels-M-WS2812B-Chip-White-PCB-WS2811-IC-Digital-RGB-LED-Strip-Light-DC5V/1306267923.html

Auf die Lieferung kann ich warten. Lieber 2 zum Preis von einem :slight_smile:

Die Beschreibung ist fürchterlich falsch.

Es sind keine WS2811IC

SPI control mode
Note: SIP control mode, the signal line and the clock do not reverse, light bar is a 5V voltage,

Der WS2811/12/12B hat keinen Takt. Der WS2801 hat einen Takteingang.

Grüße Uwe

Ja, das aber allgmein das Problem von den Chinesenmärkten :wink: Mir sind in der Bauform nur die WS2812B bekannt. Denke dass es die auch sind, werde aber lieber noch mal den Verkäufer anfragen.

Falls du mal etwas beim Prototyp varieren willst, kannst dir auch fertige Strips holen. Hab mir letzten hier ein paar von bestellt.
~~http://www.ebay.de/itm/271259424186?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2648~~
Sind immer 10 Leds pro Streifen, kannst nach jeder LED abschneiden. Ist alles bereits drauf.
Hab mir die abgeschnitten und Stiftleisten angelötet. Kann die so schön immer mit einander verbinden wie man sie haben möchte.
Sind derzeit nur provisorisch unter den Flaschen gelegt. Warte noch auf mein Podest dafür :wink:

Das sollte in den anderen Thread :smiley:

2013-09-17 14.43.07.jpg

hi,

vom bild her sind sie es. gib' bitte bescheid, was der verkäufer sagt...

gruß stefan

Ja das sind die normalen WS2812 (ohne B). Die haben mir aben einen zu großen Abstand. Ich will die kompakten. Ich melde mich sobald ich Rückmeldung bekomme.

Für die anderen interessierten, bei dem Link von AliExpress handelt es sich um die neuen WS2812. Wer ~2Wochen warten kann, bekommt 2 zum Preis von einem in DE. Zumal die scheinbar derzeit nur einer in der Bucht verkauft.