INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
[Vorstellung] Weihnachtsstern mit LPD6803
25.11.2017, 15:35
Beitrag #1
[Vorstellung] Weihnachtsstern mit LPD6803
Passend zur bevorstehenden Adventszeit habe ich mich für den Bau eines Adventssterns mit 50 RGB-LED LPD6803 und einem ESP8266 als Steuerteil entschieden. Zusätzlich kommt noch ein LDR (Photowiderstand) zum Einsatz, damit der Stern zusätzlich zur Zeit erst einschaltet, wenn es dunkel genug ist.
Weitere Kriterien waren:
- Zeit per NTP (einer von den 4 NTP-Pool-Servern in DE)
- Ein-/Ausschalten nach Stunde (16/22 Uhr)
- grundlegende Konfiguration (Zeiten, Durchläufe) per Webinterface (AJAX) änderbar
- wahlweise speichern der geänderten Konfiguration persistent auf SPIFFS
- lesen der Konfiguration beim Boot vom SPIFFS

Das Ganze wurde auf einer 2mm dicken 50cm x 50 cm Platte aus "Bastlerglas" aufgebaut und sieht so aus (Video mp4).
Hier einige Auszüge der Codes. Das komplette ZIP im Anhang.
Grundsketch:
Code:
// webserver mit externen Dateien im SPIFFS
// FS-Tool in Sketchbook/tools https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.2.0/ESP8266FS-0.2.0.zip
// Basis ist der Webserver auf http://bienonline.magix.net/public/esp8266-webserver-klasse.html
// Angepasste LPD 6803-Lib https://github.com/area3001/esp8266-arduino-lpd6803 - Störfestigkeit erhöht
/*****************************************************************
Hardware: WEMOS D1 mini pro, 50 RGB-LED mit LPD 6803
A0 ein LDR nach 3,3V und ein 22 kOhm nach GND (Umgebungsgelligkeit)
D5 = GPIO 14 = CLOCK = grün
D7 = GPOI 13 = DATA = weiss / gelb
Versorgung über USB
Speicheraufteilung 3MB Sketch 1MB SPIFFS (die kompletten 16MB werden noch nicht unterstützt)
******************************************************************
Copyright (c) 2017 Thomas Kühnert. All rights reserved.

This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This file 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
Lesser General Public License for more details.
*******************************************************************/
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// Die beiden Files müssen für SPIFFS eingebunden werden
#include <FS.h> // muss vor <detail\RequestHandlersImpl.h> stehen
#include <detail\RequestHandlersImpl.h>

#include <ArduinoOTA.h>  // OTA-Handling
#include <LPD6803.h>    
#include "settings.h"  // die WLAN-Daten


// Debugausgaben kompilieren (1) oder nicht (0)
#define DEBUG 0

#if (DEBUG == 0)
  #define sp(...)
  #define spn(...)
  #define sbeg(...)
#else
  #define sp(...) Serial.print(__VA_ARGS__)
  #define spn(...) Serial.println(__VA_ARGS__)
  #define sbeg(...) Serial.begin(__VA_ARGS__); while(!Serial)
#endif

const int dataPin = 13;       // 'yellow' wire weiss
const int clockPin = 14;      // 'green' wire
const int numLeds = 50;

// Config pro Effekt
typedef struct {
  char name[20];
  uint32_t param1;
  uint32_t param2;
  uint32_t param3;
  uint32_t param4;
} conf_t;

// Reihenfolge der Effekte bei Auto
const uint8_t autotab[] = {1,2,4,5,3,6,7,8,9,10};

// Zeit Einschalten / Ausschalten
const uint8_t einStd = 16, ausStd = 22;

// Anzahl der Effektfunktionen
const uint16_t ANZ_FUNC = 13;

// Konfiguration auch in SPIFFS. Kann über Website geändert werden
conf_t config[ANZ_FUNC] = { {"ALLGEMEIN", ANZ_FUNC, numLeds, 0, 150} // Anzahl Funktionen (incl.Basis), Anz. LED, gewählte Funktion 0= Auto, LDR-Schwelle
                           ,{"RAINBOW32", 100, 6, 0, 0} // intervall, anzahl nicht ausgewertet: colorset, richtung
                           ,{"UMLAUF_RAND", 125, 10, 0, 0} // Intervall, Anzahl, Colorset, Richtung (0=left, 1 = right)
                           ,{"SHIFT_L_RAND", 120, 5, 0, 0}
                           ,{"RAINBOW16_L", 50, 15, 0, 0}
                           ,{"SPITZE_L", 500, 15, 0, 0}
                           ,{"RAINBOWVERT", 600, 10, 0, 0}
                           ,{"RAINBOW_ALL", 200, 4, 0, 0} // Richtung nicht ausgewertet
                           ,{"SHIFT_R_RAND", 125, 10, 0, 1}
                           ,{"SPITZE_R", 500, 15, 0, 1}
                           ,{"RAINBOW16_R", 50, 15, 0, 1}
                           ,{"FARBTEST", 2000, 2, 0, 0}
                           ,{"AUS", 2000, 2, 0, 0}
                          };  

// aus der Lib herausgeführte Puffer
uint16_t *buf, *bufInt;
// Zeitsteuerungen
uint32_t oldIntern, intervallIntern = 50, oldLdr, intervallLdr = 10000;
uint8_t count = 0, anzahl = 6, status = ANZ_FUNC - 1, statusAlt = 0, idx, wahl, colset, autoidx = 1, dir = 0, progStatus = 0;
uint16_t color;
// Messwert LDR
int ldr;

// NTP-Zeiten zur Ausgabe
char lastSyncStr[] = "00:00:00 00.00.0000";
char actualTime[] = "00:00:00 00.00.0000";

// Webserver
ESP8266WebServer webserver(80); // Webserver-Instanz für Port 80 erstellen
// LED-Strip
LPD6803 strip = LPD6803(numLeds, dataPin, clockPin);

// etwas zufälligerer Startwert für Zufallsgenerator
void seedRandom32(uint8_t analogPort) {
uint32_t wert = analogRead(analogPort) & 0x1;
  for(uint8_t i = 0; i < 32; i++) {
    wert = wert << 1;
    wert |= analogRead(analogPort) & 0x1;    
  }
  sp("RandomStartWert: "); spn(wert,HEX);
  randomSeed(wert);
}

void setup() {
uint16_t res1, res2;
int counter = 0;  // Counter für Verbindung zum WLAN
  seedRandom32(A0);
  sbeg(115200);
  spn("\nStart\n");
  // Betrieb als Station
  WiFi.mode(WIFI_STA);
  // Eigene Config, besonders IP
  WiFi.config(myIP, gateway, subnet, dns);
  WiFi.begin(ssid, password);
    // Wait for connection
    while (WiFi.status() != WL_CONNECTED) {
        delay (500);
        sp (".");
    counter++;
    if (counter > 100) {
      spn("Kein WLAN. Restart!");
      ESP.restart();
    }
    }
    sp("\nConnected to ");
    spn( ssid );
    sp("IP address: ");
    spn(WiFi.localIP());

  // OTA
  initOTA();
  
  // Init SPIFFS
  if (!SPIFFS.begin()) {
    spn("SPIFFS nicht initialisiert! Stop!");
    while (1) yield();
  }
  spn("SPIFFS ok");
  // Webserver Handler einhängen
  webserver.onNotFound([](){
    if(!handleFileRead(webserver.uri()))
      webserver.send(404, "text/plain", "FileNotFound");
  });
  // Webserver-Funktionen
  // Stern steuern (AJAX)
  webserver.on("/setprog",HTTP_POST, handleSetProg);
  // Configfile schreiben
  webserver.on("/save",HTTP_GET,handleSave);
  // Aufruf ohne File
  webserver.on("/",handleRoot);
  // Werte abrufen (AJAX)
  webserver.on("/werte",handleWerte);
  
  // Handler der Verwaltung einhängen
  initSpiffsVerwaltung();

  webserver.begin(); // Web-Server starten
  spn("HTTP Server running on Port 80");
  // NTP-Zeit holen
  timeSetup();
  // LED-Strip
  strip.begin();
  // buf holen (zusätzlich eingebauter Zwischenpuffer zur Verminderung von Störungen)
  buf = strip.getBuffer();
  // interner Puffer der Lib zu Debugzwecken
  bufInt = strip.getIntBuffer();
  strip.show();  // alles aus
  // Schreiben / lesen der Config
  // res1 = writeConfig("/daten.cfg", (byte *)config, sizeof(config));
  res2 = readConfig("/daten.cfg", (byte *)config, sizeof(config));
  // welches Programm 0 = automatik
  wahl = config[0].param3;
  if (wahl != 0) status = wahl; else status = autotab[wahl];
#if DEBUG
  printConfig(config,sizeof(config)/sizeof(conf_t));
#endif
}

void loop() {
uint32_t aktMillis = millis();
  ArduinoOTA.handle();  // auf OTA prüfen
  webserver.handleClient(); // auf neuen HTTP-Request prüfen
  
  // nächster Schritt bei Effekten
  if (aktMillis - oldIntern >= intervallIntern) {
    oldIntern = aktMillis;  
    if (progStatus == 3) tick();
    else clear();
  }
  // Zeitstrings bilden
  timeActions();
  // LDR abfragen
  if (aktMillis - oldLdr >= intervallLdr) {
    oldLdr = aktMillis;
    ldr = analogRead(A0);
    sp("Ldr: "); spn(ldr);
  }  
  // wenn Einschalten per LDR erwartet
  if (progStatus == 2 && ldr < config[0].param4) progStatus = 3;
}

// Funktionen für Webserver  
// File an Browser senden
bool handleFileRead(String path){
  spn("handleFileRead: " + path);
  // Wir haben keine index.html
  // if(path.endsWith("/")) path += "index.html";
  String contentType = StaticRequestHandler::getContentType(path);
  if(SPIFFS.exists(path)){
    File file = SPIFFS.open(path, "r");
    size_t sent = webserver.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

// Grundgerüst der Seite aufbauen
void handleRoot() {
String html="<!DOCTYPE html>\n<html lang=\"de\"><head><meta charset=\"UTF-8\">\n<title>ESP82666 Weihnachtsstern</title>";
  html += "<link href=\"stern.css\" rel=\"stylesheet\"><script language=\"javascript\" type=\"text/javascript\" src=\"stern.js\"></script></head>";
  html += "<body onload=\"getWerte();\"><table border=\"0\"><tr style=\"background-color: #dadfcb;\"><td colspan=\"6\">Weihnachtsstern steuern</td></tr>";
  for(uint8_t i=0; i<ANZ_FUNC;i++) {
    html += "<tr style=\"background-color: #dadfcb;\"><td><span id=\"lb_"+String(i)+"\">"+String(config[i].name)+"</span></td>";
    html += "<td><input type=\"text\" class=\"ein\" id=\"t1_"+String(i)+"\" value=\""+String(config[i].param1)+"\" onkeyup=\"isChange(this);\"/></td>";
    html += "<td><input type=\"text\" class=\"ein\" id=\"t2_"+String(i)+"\" value=\""+String(config[i].param2)+"\" onkeyup=\"isChange(this);\"/></td>";
    html += "<td><input type=\"text\" class=\"ein\" id=\"t3_"+String(i)+"\" value=\""+String(config[i].param3)+"\" onkeyup=\"isChange(this);\"/></td>";
    html += "<td><input type=\"text\" class=\"ein\" id=\"t4_"+String(i)+"\" value=\""+String(config[i].param4)+"\" onkeyup=\"isChange(this);\"/></td>";
    html += "<td><button type=\"button\" id=\"bt_"+String(i)+"\" onclick=\"isclick('"+String(i)+"');\">Send</button></td></tr>";
  }
  html += "<tr style=\"background-color: #fecc80;\"><td colspan=\"3\">aktuelle Zeit:</td><td colspan=\"3\">letzter Sync:</td></tr>";
  html += "<tr style=\"background-color: #fecc80;\"><td colspan=\"3\"><span id=\"lb_zeit\">"+String(actualTime)+"</span></td>";
  html += "<td colspan=\"3\"><span id=\"lb_sync\">"+String(lastSyncStr)+"</span></td></tr>";
  html += "<tr style=\"background-color: #fecc80;\"><td>LDR:</td><td colspan=\"4\"><span id=\"lb_ldr\">"+String(ldr)+"</span></td>";
  html += "<td><button type=\"button\" class=\"save\" onclick=\"issave();\">Save</button></td></tr>";
  html += "<tr style=\"background-color: #fecc80;\"><td>Status:</td><td colspan=\"5\"><span id=\"lb_status\"></span></td></tr>";
  html += "</table></body></html>";
  webserver.send(200,"text/html",html);
}

// Config Parameter setzen (ohne Speichern)
void handleSetProg() {
uint16_t tempvals[5];
uint8_t errorCnt = 0;
String antwort = "";
spn("HandleProg");
int anzahl = webserver.args();
  // immer 5 Werte num, param1,param2,param3,param4 gefordert
  if (anzahl !=5) webserver.send(500,"text/plain","zuwenig Parameter");
  for(int i=0; i<5;i++) {
       tempvals[i]= (webserver.arg(i).toInt());
       sp(webserver.argName(i));sp("=");spn(tempvals[i]);
  }
  // alles ok, Werte anwenden
  config[tempvals[0]].param1=tempvals[1];
  config[tempvals[0]].param2=tempvals[2];
  config[tempvals[0]].param3=tempvals[3];
  config[tempvals[0]].param4=tempvals[4];
  String num = String(tempvals[0]);
  // Werte zurück schicken
  antwort = "t1_"+num+"="+String(tempvals[1])+"&t2_"+num+"="+String(tempvals[2])+"&t3_"+num+"="+String(tempvals[3])+"&t4_"+num+"="+String(tempvals[4]);  
  spn(antwort);
  // Allgemein geändert
  if (tempvals[0]==0) {
    wahl = config[0].param3;
    if (wahl != 0) status = wahl; else status = autotab[wahl];
    statusAlt = 0; // Änderung nach Ende des Effekts
#if DEBUG    
    printConfig(config,sizeof(config)/sizeof(conf_t));
#endif
  }
  webserver.send(200,"text/plain",antwort);
}

// Config in SPIFFS schreiben
void handleSave(){
uint16_t res1;
  String erg = "Saved";
  res1 = writeConfig("/daten.cfg", (byte *)config, sizeof(config));
  if (res1 == 0) erg = "Error by save";
    webserver.send( 200, "text/plain", erg );
}

// Zeiten und LDR-Wert senden
void handleWerte() {
  spn("handleWerte");
  String txt = "lb_zeit="+String(actualTime)+"&lb_sync="+String(lastSyncStr)+"&lb_ldr="+String(ldr);
  webserver.send(200,"text/plain",txt);
}
Dieser basiert auf einem normalen Webserver, in den zusätzlich die SPIFFS-Verwaltung, OTA und einige andere Teile eingehängt wurden.
Die Effekte wurden ausgelagert.
Code:
/******************************************************************
Copyright (c) 2017 Thomas Kühnert. All rights reserved.

This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This file 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
Lesser General Public License for more details.
*******************************************************************/

const uint16_t sixcolors[6] = {0x801e, 0x81ef, 0x85a0, 0xb120, 0xb800, 0xbc05};

// passt nicht zum Stern
const uint16_t fireColor[16]= {
0x8000,0x8400,0x8800,0x8C00,0x9000,0x9400,0x9800,0xFC00,
0xF820,0xF440,0xF060,0xEC80,0xE8A0,0xE4C0,0xE4C0,0xE4C0};

uint16_t randColor() {
uint8_t r,g,b,l;
uint16_t c;
  r = random(0,15);
  g = random(0,15);
  b = random(0,15);
  c = Color(r,g,b);
  return c;
}

// einen Schritt weiter
void tick() {
  // Wechsel des Effekts?
  if (statusAlt != status) initFunc();
  else schritt();
}

// Initialisierung neuer Effekt
void initFunc() {
  count = 0;
  idx = 0;
  intervallIntern = config[status].param1;
  anzahl = config[status].param2;
  colset = config[status].param3;
  dir = config[status].param4;
  clear();
  switch (status) {
    case 1:  // keine gesonderte initialisierung
      break;
    case 2:
      randUmlaufInit();
      break;  
    case 3:
    case 8:
      shiftRandInit();
      break;    
    case 4:
    case 10:
      rainbow16Init();
      break;
    case 5:
    case 9:
      spitzeInit();
      break;
    case 6:
      vertikalA();
      break;    
    case 7:
      color = 0;
      rBowAll();
      break;
    case (ANZ_FUNC -2):
      farbtest();
      break;      
    case (ANZ_FUNC -1):
      clear();
      break;      
    default:
      status = 1;
      count = 0;
      idx = 0;
  
  }
  statusAlt = status;
  sp("InitFunc: ");spn(status);
}

// Effekt nächster Schritt
void schritt() {
  switch (status) {
    case 1:
      rainbow32();
      break;
    case 2:
      randUmlauf();
      break;    
    case 3:
    case 8:
      shiftRand();
      break;      
    case 4:
    case 10:
      rainbow16();
      break;
    case 5:
    case 9:
      spitzeLauf();
      break;
    case 6:
      vertikalA();
      break;  
    case 7:
      rBowAll();
      break;      
    case (ANZ_FUNC -2):
      break;      
    case (ANZ_FUNC -1):
      clear();
      break;      
    default:
      sp("Default Status: ");spn(status);
      status = 1;
      count = 0;
      idx = 0;
  }
  if (count >= anzahl) {
    count = 0;
    if (wahl == 0) { // Automatik
      status = autotab[autoidx++];
      if (autoidx > sizeof(autotab)) {
        autoidx=0;
        status = autotab[autoidx++];
      }        
    }
  }  
}  

// Effekte

// Nur zum Testen
void farbtest() {
uint16_t c;
uint8_t r,g,b;
  for (int i=0; i < 32; i++) {
    c= Color(i,i,0);
    strip.setPixelColor(i,c);
    sp(i);sp(". 0x"); spn(c,HEX);    
  }
  strip.show();
}

// Alle mit einer der 96 Regenbogenfarbe füllen
void rBowAll() {
  fillAll(Wheel(idx % 96, 32));
  if (idx++ >= 95) {
    idx=0;
    count++;
  }
  strip.show();
}

// Vertikal scrollende Farben
void vertikalA() {
  for(uint8_t i=0;i<5;i++) {
    buf[10*i] = sixcolors[idx%6];
    buf[10*i+1] = sixcolors[(idx+1)%6]; buf[10*i+9] = sixcolors[(idx+1)%6];
    buf[10*i+2] = sixcolors[(idx+2)%6]; buf[10*i+8] = sixcolors[(idx+2)%6];
    buf[10*i+3] = sixcolors[(idx+3)%6]; buf[10*i+7] = sixcolors[(idx+3)%6];
    buf[10*i+4] = sixcolors[(idx+4)%6]; buf[10*i+6] = sixcolors[(idx+4)%6];
    buf[10*i+5] = sixcolors[(idx+5)%6];
  }
  idx++;
  strip.show();
  if (idx >= 6) {
    idx=0;
    count++;
  }
}

// Jede Spitze mit 1 Farbe initialisieren
void spitzeInit() {
  for(uint8_t i = 0;  i<10; i++) {
    buf[i] = sixcolors[0];
    buf[i+10] = sixcolors[1];
    buf[i+20] = sixcolors[2];
    buf[i+30] = sixcolors[3];
    buf[i+40] = sixcolors[4];
  }
  idx++;
  strip.show();
}

// Spitzen umlaufen lassen
void spitzeLauf() {
  if (!dir) shiftLeftX(10);
  else shiftRightX(10);
  strip.show();
  idx++;
  if (idx==5) {
    idx = 0;
    count++;
  }
}

// Eine zufällige Länge mit einer zufälligen Farbe initialisieren
void shiftRandInit() {
uint8_t l;
  color = randColor();
  l = random(10,20);
  for(uint8_t i=0; i<l;i++) buf[i] = color;  
  idx++;
  strip.show();
}

// umlaufen lassen
void shiftRand() {
uint8_t l;
  if (!dir) shiftLeft1();
  else shiftRight1();
  idx++;
  if (idx >= numLeds) {
    idx = 0;
    count++;
    clear();
    l = random(10,20);
    color = randColor();
    for(uint8_t i=0; i<l;i++) buf[i] = color;  
  }
  strip.show();
}

// zufällige Farbe
void randUmlaufInit() {
  color = randColor();
  sp("Color: 0x");spn(color, HEX);
  strip.setPixelColor(idx++,color);
  strip.show();
  // printBuf(buf);
}

// schrittweise auffüllen
void randUmlauf() {
uint8_t l;
  // spn("RandUmlauf");
  // shiftLeft1();
  buf[idx++] = color;
  // strip.setPixelColor(idx++,15);
  strip.show();
  if (idx >= numLeds) {
    idx = 0;
    color = randColor();
    // sp("Color: 0x");spn(color, HEX);
    count++;
  }
}

// Regenbogen mit 96 Farben
void rainbow32() {
  for (int i=0; i < numLeds; i++) {
    strip.setPixelColor(i, Wheel( (idx+i) % 96,32));  
  }
  idx++;
  if (idx >= 96) {
    idx = 0;
    count++;
    // sp("Count: ");spn(count);
  }  
  strip.show();   // write all the pixels out
  // spn("Rainbow32");
}

// Regenbogen mit 48 Farben füllen
void rainbow16Init() {
  for (int i=0; i < numLeds; i++) {
    strip.setPixelColor(i, Wheel( (i) % 48, 16));  
  }
  idx++;
  strip.show();
}

// umlaufen lassen
void rainbow16() {
  if (!dir) shiftLeft1();
  else shiftRight1();
  if (idx++ >= 48) {
    idx = 0;
    count++;
  }  
  strip.show();   // write all the pixels out
  // spn("Rainbow16");
}

// Hilfsfunktion Regenbogen aus LPD 6803-Lib-Examples angepasst
// Input a value 0 to 127 to get a color value.
// The colours are a transition r - g -b - back to r
unsigned int Wheel(byte WheelPos, byte laenge) {
  byte r,g,b,shift = 4;
  int c;
  if (laenge ==32) shift++;
  switch(WheelPos >> shift)
  {
    case 0:
      r=(laenge - 1)- WheelPos % laenge;   //Red down
      g=WheelPos % laenge;      // Green up
      b=0;                  //blue off
      break;
    case 1:
      g=(laenge - 1)- WheelPos % laenge;  //green down
      b=WheelPos % laenge;      //blue up
      r=0;                  //red off
      break;
    case 2:
      b=(laenge - 1)- WheelPos % laenge;  //blue down
      r=WheelPos % laenge;      //red up
      g=0;                  //green off
      break;
  }
  c = Color(r,g,b);
  // sp("Rot: ");sp(r); sp(" Gruen: "); sp(g);
  // sp(" Blau: ");sp(b); sp(" Color: ");spn(c);
  return(c);
}

// Hilfsfunktion Regenbogen aus LPD 6803-Lib-Examples angepasst
// Create a 15 bit color value from R,G,B
unsigned int Color(byte r, byte g, byte b)
{
  //Take the lowest 5 bits of each value and append them end to end
  return( (((unsigned int)r & 0x1F )<<10 | ((unsigned int)g & 0x1F)<<5 | (unsigned int)b & 0x1F) | 0x8000);
}

// Verschieben aller LED
// linksrum ist einfach, weil es der Speicherrichtung entspricht
void shiftLeft1() {
  // Ziel, Quelle (In Array-Elementen!), Länge (in Byte!);
  memmove(buf, buf+1, numLeds*sizeof(uint16_t));
}

void shiftLeftX(uint16_t anzahl) {
  if (anzahl >=numLeds) return; // sinnlos
  memmove(buf, buf + anzahl, numLeds*sizeof(uint16_t));
}

// rechtsrum müssen wir etwas sichern und zurückspielen
void shiftRight1() {
uint16_t temp = buf[numLeds-1];
  memmove(buf+1, buf, (numLeds-1)*sizeof(uint16_t));
  buf[0] = temp;
}

void shiftRightX(uint16_t anzahl) {
// temporärer Puffer auf uint16_t ausgerichtet (wie die internen Strukturen) wegen memmove
#pragma pack (push, 2)
uint16_t temp[50];
#pragma pack (pop)
  if (anzahl >=numLeds) return; // sinnlos
  for(int i=0, j=numLeds -1;i<anzahl ;i++,j--) temp[i]=buf[j];
  memmove(buf+anzahl, buf, (numLeds-anzahl)*sizeof(uint16_t));
  for(int i=0, j=anzahl -1;i<anzahl ;i++,j--) buf[i]=temp[j];
}

// alle aus
void clear() {
uint16_t c = Color(0,0,0);
  for(uint8_t i = 0; i < numLeds; i++) buf[i] = c;
  strip.show();
}

// alle auf eine Farbe
void fillAll(uint16_t c) {
  for(uint8_t i = 0; i < numLeds; i++) buf[i] = c;
}

// zum Debuggen
void printBuf(uint16_t * puffer) {
  for(int i = 0; i < numLeds; i++) {
    sp(puffer[i],HEX); sp(", ");
    if ((i+1)%10 ==0) spn();
  }
  spn();
}
Ebenfalls interessant könnte der Zugriff auf den NTP-Server sein. Die Synchronisation erfolge aller Stunden (das ist mehr als ausreichend).
Code:
#include <TimeLib.h>  // https://github.com/PaulStoffregen/Time

// Die müssen in den Hauptsketch, wenn sie dort verwendet werden sollen
// char lastSyncStr[] = "00:00:00 00.00.0000";
// char actualTime[] = "00:00:00 00.00.0000";

// den 5 gibt es nicht, der ist nur zum Fehlertest drin
static const char ntpServerName[][20] = {"1.de.pool.ntp.org","2.de.pool.ntp.org", "3.de.pool.ntp.org","4.de.pool.ntp.org","5.de.pool.ntp.org"};
time_t lastSyncTime;
time_t prevDisplay = 0; // when the digital clock was displayed
const int timeZone = 1;     // Central European Time
boolean newSync = false;
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets



void timeSetup() {
  spn("Starting UDP");
  Udp.begin(localPort);
  sp("Local port: ");
  spn(Udp.localPort());
  setSyncProvider(getNtpTime);
  setSyncInterval(3600); // einmal pro Stunde
}

void timeActions() {
  if (timeStatus() != timeNotSet) {
    if (newSync) {
      timeToStr(lastSyncTime,lastSyncStr);
      newSync = false;
    }
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      timeToStr(prevDisplay,actualTime);
      if (einStd == hour() && progStatus == 0) { // Einschalten?
        if (config[0].param4 == 0) { // kein LDR-Wert definiert
          progStatus = 3; // Ein
        }
        else {
          progStatus = 2; // Ein, wenn dunkel
        }
      }
      if (ausStd == hour()) progStatus = 0; // aus
      // sp("Time: ");spn(actualTime);sp(" LastSync: ");spn(lastSyncStr);
    }
  }
}

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime(){
  IPAddress ntpServerIP; // NTP server's ip address
  static uint8_t num = 0;  // Nummer des NTP-Pool-Servers 4 für Fehlertest
  
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  spn("Transmit NTP Request");
  // get a random server from the pool
  spn(num);
  WiFi.hostByName(ntpServerName[num], ntpServerIP);
  sp(ntpServerName[num]);
  sp(": ");
  spn(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      spn("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      lastSyncTime = secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
      newSync = true;
      return lastSyncTime;
    }
  }
  spn("No NTP Response :-(");
  num = ++num %4;
  now();
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address){
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

char *timeToStr(time_t t, char * buf) {
int ja;
  buf[0] = (hour(t) / 10) + '0'; // Zehner
  buf[1] = (hour(t) % 10) + '0'; // Einer
  buf[2] = ':';
  buf[3] = (minute(t) / 10) + '0';
  buf[4] = (minute(t) % 10) + '0';
  buf[5] = ':';
  buf[6] = (second(t) / 10) + '0';
  buf[7] = (second(t) % 10) + '0';
  buf[8] = ' '; // die abschließende 0
  buf[9] = (day(t) / 10) + '0'; // Zehner
  buf[10] = (day(t) % 10) + '0'; // Einer
  buf[11] = '.';
  buf[12] = (month(t) / 10) + '0';
  buf[13] = (month(t) % 10) + '0';
  buf[14] = '.';
  ja = year(t);
  buf[15] = (ja / 1000) + '0'; // Tausender
  ja = ja % 1000;             // Rest 3-stellig
  buf[16] = (ja / 100) + '0';  // Hunderter
  ja = ja % 100;              // Rest 2-stellig
  buf[17] = (ja / 10) + '0';   // Zehner
  buf[18] = (ja % 10) + '0';   // Einer
  buf[19] = 0; // die abschließende 0
  return buf;
}
Die anderen Funktionalitäten habe ich hier schon irgendwo veröffentlicht. Die sind dann nur im ZIP enthalten.

Die LPD6803 sind zwar schon etwas älter aber mechanisch für großflächigere Darstellungen gut geeignet. Von FastLED werden sie nicht mehr unterstützt.

Wenn Ihr das evtl. als Anregung für eigene Basteleien sehen wollt, könnt Ihr beliebige Teile Übernehmen.

Gruß Tommy


Angehängte Datei(en)
.zip  wstern.zip (Größe: 22,44 KB / Downloads: 401)

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle von mir veröffentlichten Codes unterliegen der GPL Version 3
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 07:56
Beitrag #2
RE: [Vorstellung] Weihnachtsstern mit LPD6803
WOW Tommy,
da hast dich aber mächtig ins Zeug gelegt bei der Mustergenerierung....das kostet Zeit...
lgbk


An alle Neuankömmlinge hier, wenn ihr Code(Sketch) hier posten wollt dann liest euch bitte diese Anleitung durch.
Und benutzt vor dem Beitrag absenden den "Vorschau" Button.

Ich spreche fließend Schwäbisch, Deutsch das Notwendigste und für die Begriffsstutzigen erprobtes Tacheles mit direkten Hinweisen ohne Schnörkel...

Dont feed the Troll's

1+1 = 10 Angel ...und ich bin hier nicht der Suchmaschinen-Ersatz Dodgy...nur mal so als genereller Tipp..
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 12:55
Beitrag #3
RE: [Vorstellung] Weihnachtsstern mit LPD6803
(26.11.2017 07:56)Bitklopfer schrieb:  WOW Tommy,
da hast dich aber mächtig ins Zeug gelegt bei der Mustergenerierung....das kostet Zeit...
lgbk
Das Schlimmste war die Ideen zu finden. Das geht ja schon mehr ins Künstlerische und das ist nicht so meine Ecke.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle von mir veröffentlichten Codes unterliegen der GPL Version 3
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 15:24
Beitrag #4
RE: [Vorstellung] Weihnachtsstern mit LPD6803
Hallo,
Klasse Arbeit.
Ist das Plexiglas, Acryl oder Macrolon ?
Gruß, Markus

Immer in Stress
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 15:35
Beitrag #5
RE: [Vorstellung] Weihnachtsstern mit LPD6803
(26.11.2017 15:24)Chopp schrieb:  Hallo,
Klasse Arbeit.
Ist das Plexiglas, Acryl oder Macrolon ?
Gruß, Markus
Das ist sogenanntes Hobbyglas 0,2 cm Transparent 50 cm x 50 cm vom OBI für 5,99€. Genauer weiß ich es nicht.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle von mir veröffentlichten Codes unterliegen der GPL Version 3
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 19:02
Beitrag #6
RE: [Vorstellung] Weihnachtsstern mit LPD6803
Hallo Tommy,
sieht sehr schön aus, gefällt mir sehr gut.

Dann kann die Adventszeit ja kommen.
Wo wird der Stern denn hängen ?

Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. Cool
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 19:50
Beitrag #7
RE: [Vorstellung] Weihnachtsstern mit LPD6803
(26.11.2017 19:02)hotsystems schrieb:  Hallo Tommy,
sieht sehr schön aus, gefällt mir sehr gut.

Dann kann die Adventszeit ja kommen.
Wo wird der Stern denn hängen ?
Der hängt im Fenster vom Arbeitszimmer direkt neben meinem Arbeitsplatz.

Gruß Tommy

"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle von mir veröffentlichten Codes unterliegen der GPL Version 3
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
26.11.2017, 20:07
Beitrag #8
RE: [Vorstellung] Weihnachtsstern mit LPD6803
(26.11.2017 15:35)Tommy56 schrieb:  Das ist sogenanntes Hobbyglas 0,2 cm Transparent 50 cm x 50 cm vom OBI für 5,99€. Genauer weiß ich es nicht.

Wie gut läßt sich die 2mm Platte denn verarbeiten ?
( Bohren, Schneiden )
Und ist die eher flexibel, oder ziemlich steif ?

Gruß, markus

Immer in Stress
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  [Vorstellung] ESP8266 Webserver mit AJAX Tommy56 20 26.688 28.11.2019 11:33
Letzter Beitrag: Tommy56

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste