(131.5 MB) 00:38:13
2017-03-12 11:00 🛈Die WS2812B, auch bekannt als Neopixel, sind RGB-LEDs mit internem Steuer-IC, welche sich über einen einzelnen Datenpin kaskadieren und separat ansteuern lassen. Als in meinem Feed ein Angebot für ¼-Kreise mit 15 dieser LEDs durchtickerte war der Plan schnell klar: 4 ¼-Kreise á 15 LEDs macht 60 LEDs. Passend für eine Uhr. Mal schauen, ob es auch funktioniert.
Zur Zeithaltung kommt ein DS3231 zum Einsatz – ein I²C-Chip, welcher speziell für Uhren gedacht ist und genauer funktioniert als die internen Taktgeber der üblichen µCs.
Inhalt:
- 00:00 LED-Module & Aufbauplan
- 08:22 LED-Test mit Adafruit-Library
- 12:32 Warum RTC statt Systemtakt / millis()?
- 17:05 Blick auf die Software
- 34:13 Uhr in Aktion
Code:
/**
 * NeoClock
 * 
 * Clock using 60 WS2812B/Neopixel LEDs and DS3231 RTC
 * 
 * Libraries needed:
 *   * Adafruit NeoPixel (Library Manager) - Phil Burgess / Paint Your Dragon for Adafruit Industries - LGPL3
 *   * Rtc by Makuna (Library Manager) - Michael C. Miller
 *   * Arduino Timezone Library (https://github.com/JChristensen/Timezone) - Jack Christensen - CC-BY-SA
 *   * Time Library (https://github.com/PaulStoffregen/Time) - Paul Stoffregen, Michael Margolis - LGPL2.1
 */
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#if defined(ESP8266)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#include <SoftwareWire.h>  // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
#include <Time.h>        //http://www.arduino.cc/playground/Code/Time
#include <Timezone.h>    //https://github.com/JChristensen/Timezone
#include <EEPROM.h>
//Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     //Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};       //Central European Standard Time
Timezone CE(CEST, CET);
TimeChangeRule *tcr;        //pointer to the time change rule, use to get the TZ abbrev
time_t utc;
SoftwareWire myWire(8, 9);
RtcDS3231<SoftwareWire> Rtc(myWire);
#define PIN 6
unsigned long lastMillis = millis();
byte dimmer = 0x88;
byte hmark = 0;
byte ohour=0;
byte ominute=0;
byte osecond=0;
boolean fader=true;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
void setup() {
  Serial.begin(115200);
  
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Rtc.Begin();
  Rtc.Enable32kHzPin(false);
  Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); 
  if (!Rtc.GetIsRunning())
  {
      Serial.println("RTC was not actively running, starting now");
      Rtc.SetIsRunning(true);
  }
  if (!Rtc.IsDateTimeValid()) 
  {
      // Common Cuases:
      //    1) the battery on the device is low or even missing and the power line was disconnected
      Serial.println("RTC lost confidence in the DateTime!");
  }
  byte eechk = EEPROM.read(0);
  if(eechk == 0xAA) { //Assume this is our config and not a fresh chip
    dimmer = EEPROM.read(1);
    hmark = EEPROM.read(2);
    fader = EEPROM.read(3);
  }
  timeSync();
}
void calcTime(void) {
  utc = now();
  CE.toLocal(utc, &tcr);
  ohour = hour(utc);
  ominute = minute(utc);
  if(osecond != second(utc)) {
    osecond = second(utc);
    lastMillis = millis();
    if(ominute == 0 && osecond == 0) {
      //Every hour
      timeSync();
    }
  }
}
void addPixelColor(byte pixel, byte color, byte brightness) {
  color *= 8;
  uint32_t acolor = brightness;
  acolor <<= color;
  uint32_t ocolor = strip.getPixelColor(pixel);
  ocolor |= acolor;
  strip.setPixelColor(pixel, ocolor);
}
void drawClock(byte h, byte m, byte s) {  
  strip.clear();
  
  addPixelColor(m, 1, dimmer);
  if(hmark > 0) {
    for(byte i = 0; i<12; i++) {
      addPixelColor((5*i), 2, hmark);
    }
  }
  h %= 12;
  h *= 5;
  h += (m/12);
  addPixelColor(h, 2, dimmer);
  // 0x RR GG BB
  if(fader) {
    byte dim_s1 = dimmer;
    byte dim_s2 = 0;
    byte px_s2 = s+1;
    if(px_s2 >= 60) px_s2 = 0;
    unsigned long curMillis = millis()-lastMillis;
    if(curMillis < 250) {
      dim_s2 = 0;
      dim_s1 = dimmer;
    }else{
      dim_s2 = map(curMillis, 250, 1000, 0, dimmer);
      dim_s1 = dimmer - map(curMillis, 250, 1000, 0, dimmer);
    }
    
    addPixelColor(s, 0, dim_s1);
    addPixelColor(px_s2, 0, dim_s2);
  }else{
    addPixelColor(s, 0, dimmer);
  }
  
  strip.show();
}
byte rounds = 0;
void loop() {
  calcTime();
  if(rounds++ > 100) {
    Serial.print(ohour);
    Serial.print(":");
    Serial.print(ominute);
    Serial.print(":");
    Serial.println(osecond);
    rounds = 0;
  }
  
  drawClock(ohour,ominute,osecond);
  delay(10);
  
  chkSer();
}
void timeSync(void) {
  RtcDateTime dt = Rtc.GetDateTime();
  setTime(dt.Hour(),dt.Minute(),dt.Second(),dt.Day(),dt.Month(),dt.Year());
    
  Serial.print("Synced to: ");
  Serial.print(dt.Year());
  Serial.print("-");
  Serial.print(dt.Month());
  Serial.print("-");
  Serial.print(dt.Day());
  Serial.print("-");
  Serial.print(dt.Hour());
  Serial.print("-");
  Serial.print(dt.Minute());
  Serial.print("-");
  Serial.println(dt.Second());
}
void timeSave(void) {
  utc = now();
  
  RtcDateTime store = RtcDateTime(year(utc), month(utc), day(utc), hour(utc), minute(utc), second(utc));
  Rtc.SetDateTime(store);
  Serial.print("Synced to: ");
  Serial.print(year(utc));
  Serial.print("-");
  Serial.print(month(utc));
  Serial.print("-");
  Serial.print(day(utc));
  Serial.print("-");
  Serial.print(hour(utc));
  Serial.print("-");
  Serial.print(minute(utc));
  Serial.print("-");
  Serial.println(second(utc));
  
}
void setBrightness(byte brightness) {
  dimmer = brightness;
}
void chkSer(void) {
  unsigned int iy;
  byte im,id,iH,iM,iS;
  
  if(!Serial.available()) return;
  switch(Serial.read()) {
    case 'b':
      setBrightness(Serial.parseInt());
      Serial.print(F("Brightness changed to: "));
      Serial.println(dimmer);
      EEPROM.put(0, 0xAA);
      EEPROM.put(1, dimmer);
      break;
    case 't':
      iy = Serial.parseInt();
      im = Serial.parseInt();
      id = Serial.parseInt();
      iH = Serial.parseInt();
      iM = Serial.parseInt();
      iS = Serial.parseInt();
      setTime(iH,iM,iS,id,im,iy);
      Serial.println(F("System time changed"));
      break;
    case 'f':
      fader = false;
      EEPROM.put(0, 0xAA);
      EEPROM.put(3, 0);
      Serial.println(F("Fader off"));
      break;
    case 'F':
      fader = true;
      EEPROM.put(0, 0xAA);
      EEPROM.put(3, 1);
      Serial.println(F("Fader on"));
      break;
    case 'm':
      hmark = Serial.parseInt();
      EEPROM.put(0, 0xAA);
      EEPROM.put(2, hmark);
      Serial.println(F("HMark changed"));
      break;
    case 's':
      timeSync();
      Serial.println(F("Synced RTC to System"));
      break;
    case 'S':
      timeSave();
      Serial.println(F("Synced System to RTC"));
      break;
    default:
      Serial.println('?');
  }
}
 
		 
						