Éclairage à base de ruban à LEDs SK6812-RGBW

De Wiki LOGre
Révision datée du 17 avril 2017 à 20:44 par Ebonet (discussion | contributions) (Mesure de la lumière ambiante : + mesures.)
Aller à : navigation, rechercher


Projet réalisé par : Edgar Bonet.

Le but de ce projet est de faire un éclairage d'appoint pour mon couloir à base d'un ruban à LEDs SK6812-RGBW. Cet éclairage aura deux fonctions:

  • quand on allume la lumière, il s'allume en blanc chaud pour compléter l'éclairage d'origine ;
  • quand il fait noir, il s'allume en rouge sombre, façon veilleuse.

L'éclairage d'appoint sera assuré par un ruban à LEDs SK6812-RGBW. Chaque pixel du ruban comporte, en plus des traditionnelles LEDs RGB, une LED de couleur blanc-chaud qui assure un meilleur rendu des couleurs que la combinaison R+G+B. Il y aura 3 m de ruban à 60 LEDs/m, soit 180 LEDs au total. En plus du ruban à LEDs, le dispositif comportera :

  • un capteur de lumière, pour savoir quand activer l'un des deux modes d'éclairage ;
  • un microcontrôleur ATtiny, probablement un ATtiny13A, pour lire le capteur de lumière et piloter le ruban à LEDs ;
  • une alimentation 5 V, 4 A.

Mesure de la lumière ambiante

Elle est réalisée à l'aide d'une photorésistance en série avec une résistance de tirage de 10 kΩ. La photorésistance est placée tout près de l'ampoule du couloir, de sorte que celle-ci l'éclaire bien plus que la lumière du jour. La luminosité mesurée est alors comparée à deux seuils :

  • au dessus du seuil haut, on considère que la lumière a été allumée, le ruban doit éclairer en blanc ;
  • en dessous du seuil bas, on considère qu'il fait nuit, le ruban doit passer en mode veilleuse.

Afin de déterminer les seuils appropriés, j'ai des mesures pendant trois jours à l'aide d'un Arduino (pour prendre les mesures) et d'un Raspberry Pi (pour les enregistrer dans un fichier). Voici les résultats, exprimés en résistance en fonction du temps :

Sk6812 ldr data-fr.png

On constate sur ce graphique que :

  • la lampe éclaire la photorésistance bien plus que la lumière du jour, ce qui permettra de reconnaître sans ambigüité l'allumage de cette lampe ;
  • l'obscurité nocturne est aussi clairement distinguée de la pénombre qu'on a quand seule une lumière du salon est allumée ;
  • la nuit, la photorésistance affiche plus de 1 MΩ, mais sa valeur est déterminée de façon très imprécise à cause de la discrétisation du convertisseur analogique-numérique qui est proche de la saturation.

Pilotage du ruban à LEDs

Les LEDs SK6812 sont très similaires aux célèbres WS2812 et se pilotent de la même manière. Outre la classique version RGB, elles existent aussi en version RGBW, avec une LED blanche qui permet de faire de l'éclairage avec un meilleur rendu de couleurs qu'en combinant RGB. La version que j'ai est un blanc chaud. Il faut envoyer 32 bits par LED : dans l'ordre vert, rouge, bleu et blanc.

Les bibliothèques pour piloter les WS2812 supportent souvent les SK6812-RGBW, mais elles demandent toutes une grande quantité de RAM (4 octets par LED) pour stocker tous les bits à envoyer. Or je voudrais piloter le ruban de façon minimaliste, avec seulement un ATtiny13A, qui n'a que 64 octets de RAM.

Liens utiles :

En m'inspirant du deuxième lien, j'ai réussi à piloter le ruban avec un ATtiny13A. Ce programme fait progresser une LED bleue le long du ruban dans un sens et une LED rouge dans l'autre sens :

/*
 * Test the SK6812 LED strip.
 * Version running on an ATtiny13A at 9.6 MHz.
 *
 * Data sent through PB0.
 */

#include <avr/io.h>
#include <util/delay.h>

#define LED_COUNT 300

//                 GGRRBBWW
#define LED_OFF  0
#define LED_RED  0x00ff0000
#define LED_BLUE 0x0000ff00

int main(void)
{
    // Clock the CPU @ 9.6 MHz.
    CLKPR = _BV(CLKPCE);  // enable prescaler change
    CLKPR = 0;            // prescaler = 1

    DDRB |= _BV(PB0);
    for (;;) {
        for (int led = 0; led < LED_COUNT; led++) {  // lit led
            for (int i = 0; i < LED_COUNT; i++) {  // addressed LED
                uint32_t val;
                if (i == led)
                    val = LED_BLUE;
                else if (i == LED_COUNT - 1 - led)
                    val = LED_RED;
                else
                    val = LED_OFF;
                for (int j = 0; j < 32; j++) {  // bit index
                    if (val & 0x80000000)       // long pulse
                        asm volatile(
                        "    sbi %[port], %[bit] \n"
                        "    rjmp .              \n"
                        "    rjmp .              \n"
                        "    cbi %[port], %[bit] \n"
                        :: [port] "I" (_SFR_IO_ADDR(PORTB)),
                           [bit]  "I" (PB0));
                    else                        // short pulse
                        asm volatile(
                        "    sbi %[port], %[bit] \n"
                        "    cbi %[port], %[bit] \n"
                        :: [port] "I" (_SFR_IO_ADDR(PORTB)),
                           [bit]  "I" (PB0));
                    val <<= 1;
                }
            }
            _delay_us(60);  // break
        }
    }
}

Mesure du courant consommé

Mesure au multimètre du courant consommé.

J'ai réalisé des mesures de courant consommé en fonction du nombre de LEDs allumées et de leur couleur. Ces mesures sont effectuées sur un ruban de 300 LEDs (5 m et 60 LEDs par mètre). Elles sont limitées à un petit nombre de LEDs allumées car c'est le port USB de mon portable qui sert d'alimentation. Voici les résultats :

Sk6812 power.svg

Une régression linéaire sur ces mesures donne le courant consommé par chaque LED en fonction de sa couleur (R, G, B, W) :

[math]I = 0,72\;\text{mA} + 7,4\;\text{mA} \times \left(\frac{R}{255} + \frac{G}{255} + \frac{B}{255}\right) + 14,8\;\text{mA} × \frac{W}{255}[/math]

À partir de là, on déduit que pour allumer le ruban en blanc seul (RGBW = (0, 0, 0, 255)) il faut

180 × (0,72 mA + 14,8 mA) ≈ 2,8 A

Je me suis décidé sur une alimentation 4 A, ce qui permet d'avoir une petite marge.