Arduino WS2811 LEDs mit Schieberegister Kombinieren

Hallo,
ich habe ein Problem mit meinem Code. Normalerweise würde ich selber daran Rum basteln bis es funktioniert. Aber das kann leider auch mal ein paar Wochen dauern und so viel Zeit habe ich nicht. Jetzt zum Thema. Ich möchte meiner Freundin zum Geburtstag (Morgen :confused: ) eine Selbstgemachte Uhr schenken. Praktisch und technisch funktioniert eigentlich schon das meiste. Ich habe ein Uhrmodul RTC DS1307) und möchte damit 4 große 7 Segment anzeigen (mithilfe der Shift-Display Library und zwei 74HC595) ansteuern. Dazu sollen 60 LEDs mit WS2811 Chip quasi den Sekundenzeiger darstellen. Dazu kann man die Uhr mit einer IR Fernbedienung anschalten und die Zeit korrigieren ( hab erst zu spät gemerkt, das der RTC ziemlicher misst ist). Ich habe aber leider noch ein Problem mit der Software. Scheinbar vertragen sich die Schieberegister nicht mit dem WS2811. Alleine funktionieren beide Problemlos, aber wenn ich Code die beide Bauteile ansteuern zusammen laufen lasse blinken die 7 Segment anzeigen nur noch schwach.

Hier mein Code und bitte nicht gleich Zerfleischen bin nicht gut im Programmieren und "klaue" mehr so zusammen. Auch stehe ich Leider unter Zeitdruck da ich natürlich viel zu Spät angefangen habe zu Basteln :wink:

#include <CharacterEncoding.h>
#include <ShiftDisplay.h>


#include <Adafruit_NeoPixel.h>


#include <RTClib.h>
#include <Wire.h>

#include <boarddefs.h>
#include <IRremote.h>
#include <IRremoteInt.h>
#include <ir_Lego_PF_BitStreamEncoder.h>

#define PIXEL_PIN   9    // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 60


// Parameter 1 = number of pixels in strip,  neopixel stick has 8
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream
//   NEO_GRB     Pixels are wired for GRB bitstream, correct for neopixel stick
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); //Initialisierung der LEDs
//-------------------
ShiftDisplay display(6,4,5,COMMON_CATHODE, 4); // Arduino pin 6 connected to shift register latch, pin 4 to clock and pin 5 to data
// common anode display with 4 digits
//----------------


RTC_DS1307 rtc; //Initialisierung des RTC
int minute_correct=0; //Variable für korrigierte Zeit
int time_display=0; // Korrigierte Zeit in hhmm
int MinuteCorrection=0; //Variable für die Zeit Korrektur

//---------------
int RECV_PIN=3;//Initialisierung des IR Empfängers
IRrecv irrecv(RECV_PIN);
decode_results results;

int LED_MODE=0; //Momentaner LED Mode
int Number_LEDModes=2; // Nummer der LED Modes
int start=0;
int i=0;

unsigned long previousMillis = 0;       //Ersatz für Delay im Sekundenzeiger
unsigned long previousMillis2 = 0;        // Ersatz für Delay im LOOP


const long interval = 1000;  // Interval für den Sekundenzeiger

//--------------
void IRReceiver() // Teil für den IR Empfänger
{


  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
  }
  
 

    if( results.value== 0xFF18E7){ //LED Mode +
      if(LED_MODE<Number_LEDModes)
      {
   LED_MODE++;
   Serial.print("LM");
   Serial.println(LED_MODE);
      }
      else
      {
        LED_MODE=0;
      }
    results.value = 0x00000000;
   }
     if( results.value== 0xFF4AB5){ //LED Mode -
      if(LED_MODE>=0)
      {
    LED_MODE=LED_MODE-1;
       Serial.print("LM");
    Serial.println(LED_MODE);
      }
      else
      {
        LED_MODE=Number_LEDModes;
        
      }
    results.value = 0x00000000;
   }
     if( results.value== 0xFF10EF){ //Time Correction +1 Minute
    MinuteCorrection--;
    Serial.println(MinuteCorrection);
    results.value = 0x00000000;
   }
    if( results.value== 0xFF5AA5){ //Time Correction -1 Minute
    MinuteCorrection++;
    Serial.println(MinuteCorrection);
    results.value = 0x00000000;
   }
 
}

void setup() {
  // put your setup code here, to run once:
  strip.begin(); //start für die LEDs
  
  strip.show(); 


  pinMode(RECV_PIN, INPUT);
irrecv.enableIRIn(); // Startet den IR Empfänger


Serial.begin(9600);

display.set(1234, ALIGN_LEFT);//Setzt das Display auf die aktuelle Uhrzeit

}

void loop() {
  // put your main code here, to run repeatedly:

IRReceiver();

if (LED_MODE==0) //Schaltet zwischen den verschiedenen Modi um
{
off();
start=0; 
}
if(LED_MODE==1)
 {
  
  if ( start==0) //Einmalig sollen alle LEDs ausgeschaltet werden, dann startet der "Sekundenzeiger"
  {
    off();
    start++;
  }
  sekunden_LED();

 }
if(LED_MODE==2)
{
  all_red();
  start=0;
}

unsigned long currentMillis2 = millis();

correct_time(); 
   


  if (currentMillis2 - previousMillis2 >= 1000) { //aktuallisiert alle 10 Sekunden das Display
  
    previousMillis2 = currentMillis2;
display.update();
    Serial.println(time_display);

  }

}

void sekunden_LED()// Rote LED "Hüpft" Jede Sekunde eins weiter
{
 
 strip.begin();
  
unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    Serial.println(time_display);
    if ( i<PIXEL_COUNT)
    {
       strip.setPixelColor(i,strip.Color(0,255,0));
       strip.setPixelColor(i-1,strip.Color(0,0,0));
       strip.show();
       i++;
    }
    else
    {
      i=0;
      off();
    }
}
}

void all_red() //Schalte alle LED rot
{
 
  for(int i=0 ; i<PIXEL_COUNT;i++)
  {
    strip.setPixelColor(i,strip.Color(0,255,0));
    strip.show();
  }
  
}

void off() // Schalte alle LEDs aus
{
for (int i=0; i<PIXEL_COUNT;i++)
{
  strip.setPixelColor(i,strip.Color(0,0,0));
  strip.show();
}
}

//----------------------------------------------------------------------

void correct_time() //Korrigiert Zeit vom RTC
{
  DateTime now = rtc.now();

  time_display=(now.hour()*100)+now.minute()+MinuteCorrection;
}

Der RTC ist über i2c Verbunden
Der IR Empfänger hängt an Pin 3
Der LED Strip an PIN 9
Die Schieberegister an Pin 6,4,5

Die Teile für sich funktionieren alle in eigenen Beispielen. Nur Zusammen mögen sie sich nicht. Ich hoffe ihr könnt mir helfen den Geburtstag morgen zu retten. Freue mich über jede Hilfe.

Tech_Nik:
....Nur Zusammen mögen sie sich nicht. Ich hoffe ihr könnt mir helfen den Geburtstag morgen zu retten. Freue mich über jede Hilfe.

Das ist sehr sportlich.

Leider kann ich nicht helfen, da keine Schieberegistererfahrung vorhanden.

Sorry.

Allerdings verstehe ich nicht, warum du die WS2811 per Schieberegister steuern musst.
Die haben doch einen eigenen Controller.

Dann rette mal den Geburtstag und laß die WS2811 weg.

Nicht alle Bibliotheken vertragen sich miteinander. Ich kenne die einzenen Bibliotheken nicht genau aber es kann leicht sein daß mehrere Timer brauchen und so in Konflikt untereinander gehen.

Grüße Uwe

die Schieberegister sind für 7 Segment anzeigen und die WS2811 für die LED Kette drum herum.
Im Anhang ist ein Foto von einer Zeichnung wie es denn Mal aussehen soll.

Tech_Nik:
die Schieberegister sind für 7 Segment anzeigen und die WS2811 für die LED Kette drum herum.
Im Anhang ist ein Foto von einer Zeichnung wie es denn Mal aussehen soll.

Da musst du die einzelnen Libraries prüfen, welche Timer die verwenden.
Wir wissen nicht, welche Libs du einsetzt.
Sobald ein Timer von mehreren Libs verwendet wird, gibt es Probleme.

Hi

Das riecht schwer danach, daß die 7-Segment-ANzeige gemultiplext wird, also den Timer braucht, damit die Ziffern immer korrekt angezeigt werden.
Dagegen die WS28xx, Die ganz gerne ein zeitkritisches Protokoll brauchen, damit die LEDs auch Das mitbekommen, was Sie machen sollen.

Ich befürchte, Beide nutzen den gleichen Timer - und daran wirst Du wohl auch nicht viel ändern können.

Du könntest einen zweiten Arduino dazu missbrauchen, sich um eines der beiden zeitkritischen Dinge zu kümmern - Einer der Beiden macht einen Master, der Andere einen Slave, die Kommunikation zwischen Beiden per I2C, damit der 'Nicht-Uhr-Arduino' auch die korrekte Uhrzeit erfährt (sofern Das für den Stripe nötig ist).

Im Laufe der Zeit solltest Du die RTC gegen eine 3231 tauschen, die ist temperaturkompensiert und läuft deshalb wesentlich genauer, als die 1307, Die 'nur' quarzstabil läuft.

Viel Erfolg hierbei und Spaß beim Feiern

MfG

Eine WS28xx Biblothek verwendet keinen Timer sondern die Datenübertragung erfolgt mittels einer in Maschinensprache geschriebenen Übertragungroutine.

Grüße Uwe

Hi

Unter den Umständen dürfte sich das Multiplexen unsauber zeigen, aber laufen müsste Das.

... muß ich mir so eine WS28xx-Bibliothek doch Mal genauer anschauen - klar, das Timing ist nicht ganz einfach, aber auf 'eine Hand voll NOPs' hätte ich jetzt nicht getippt (also egal, ob per NOP oder anderen Befehlen die genaue Anzahl an Takten verzammelt wird, gibt Da ein schönes ASM-Makro, Welches die Aufrufzeit mit einrechnet, verschachtelte Schleifen und JMPs).

MfG

Danke für die Vielen Antworten. Ja das Multiplexing funktioniert. Nur ist die Datenübertragung für die WS2811 immer wieder dazwischen gefunkt. Ich habe den Code jetzt stark vereinfacht und alle Spiellerei rausgeschmissen.
wenn ich nur selten neue Daten an die LEDs Schicke klappt alles wunderbar auch wenn die Übertragung an 60 LEDs eine kurze Zeit brauch.

Momentan sieht es vielversprechend aus. Morgen schwänze ich noch die Uni und dann wird es hoffentlich ein Erfolg.

Hier noch der aktuelle Code:

#include <CharacterEncoding.h>
#include <ShiftDisplay.h>
#include <Adafruit_NeoPixel.h>
#include <RTClib.h>
#include <Wire.h>
#include <boarddefs.h>


#define PIXEL_PIN   9    // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 60


// Parameter 1 = number of pixels in strip,  neopixel stick has 8
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream
//   NEO_GRB     Pixels are wired for GRB bitstream, correct for neopixel stick
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); //Initialisierung der LEDs
//-------------------
ShiftDisplay display(6,4,5,COMMON_CATHODE, 4); // Arduino pin 6 connected to shift register latch, pin 4 to clock and pin 5 to data
// common anode display with 4 digits
//----------------


RTC_DS1307 rtc; //Initialisierung des RTC
int minute_correct=0; //Variable für korrigierte Zeit
int time_display=0; // Korrigierte Zeit in hhmm
int MinuteCorrection=0; //Variable für die Zeit Korrektur

//---------------

int i=0;

unsigned long previousMillis = 0;       //Ersatz für Delay im Sekundenzeiger
unsigned long previousMillis2 = 0;        // Ersatz für Delay im LOOP


const long interval = 1000;  // Interval für den Sekundenzeiger

//--------------


void setup() {
  // put your setup code here, to run once:

  strip.begin(); //start für die LEDs
  strip.show(); 



  Serial.begin(9600);


}

void loop() {
   display.set(time_display, ALIGN_RIGHT);//Setzt das Display auf die aktuelle Uhrzeit
  // put your main code here, to run repeatedly:
  display.update();


  sekunden_LED();
    

  unsigned long currentMillis2 = millis();

 
 
  if (currentMillis2 - previousMillis2 >= 10000) { //aktuallisiert alle 10 Sekunden die Zeit  
    previousMillis2 = currentMillis2;
  
    DateTime now = rtc.now();
    time_display=(now.hour()*100)+now.minute()+MinuteCorrection;
    Serial.println(time_display);
  }
}

void sekunden_LED() { // Rote LED "Hüpft" Jede Sekunde eins weiter
 
  strip.begin();
  
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    if ( i<PIXEL_COUNT) {
      strip.setPixelColor(i,strip.Color(0,255,0));
      strip.setPixelColor(i-1,strip.Color(0,0,0));
      strip.show();
      i++;
    } else {
      i=0;
      off();
    }
  }
}

void all_red() { //Schalte alle LED rot
 
 
  for(int i=0 ; i<PIXEL_COUNT; i++) {
    strip.setPixelColor(i,strip.Color(0,255,0));
    strip.show();
  
}

}

void off() { // Schalte alle LEDs aus

  
  for (int i=0; i<PIXEL_COUNT; i++) {
    strip.setPixelColor(i,strip.Color(0,0,0));
    strip.show();
  }
   
   
}

//----------------------------------------------------------------------

Die Daten an die WS2811/12 werden mit 800kHz (1,25µS) gesendet.
Die Decodierung von 0 und 1 erfolgt durch unterschiedliche Länge der HIGH und LOW Teil einer Periode. Die Zeiten müssen auf 150nS genau eingehalten werden. Das sind bei 16MHz Takt und einer Periode von 62,5nS ca 3 Takte. Darum ist die Übertragungsroutine in Assembler geschrieben und alle Interrups abgeschaltet.
Bei 60 LED und 24 bit pro WS2811/12 beansprucht die Datenübertragung ca 1,9µS

Darum funktioniert ein Timergesteuertes Multiplexing nicht korrekt..

Grüße Uwe

Mittlerweile Funktioniert es (hoffentlich). Ich habe den meisten Schnickschnack entfernt und jetzt wird nur noch einmal die Sekunde ein Befehl an die WS2811 geschickt. damit wird das Multiplexing nur kurz aber kaum Merklich unterbrochen. Mein Fehler war es dauerhaft im Loop Daten an die LEDs zu schicken, da konnte der Arduino dann natürlich auch nicht multiplexen.

Es läuft alles. Die Uhr ist nach einer langen Nacht rechtzeitigt fertig geworden. Danke an alle die Geholfen haben!
Im Anhang ein Bild von der fertigen Uhr.

Hi

Sauber und schöne Arbeit!
Danke für das Feedback - hoffe, die Uhr erhält bei der Empfängerin ähnliches Ansehen :wink:

MfG

Sehr schöne Uhr, wirglich sauber gearbeitet.