Luciole numérique

L’idée

Projet de luciole basé sur plusieurs projets dont une démo de @asthrolab rencontré à l’OpenBidouilleCamp de Montreuil (déc. 2013).

luciole NE555© 2013 par Asthrolab

Après recherche, c’est un classique de l’électronique personnelle dont on retrouve des références de par le monde, comme chez David DARTS (aussi à l’origine du concept de la PirateBox) et la LEDfirefly.

De tous ces exemples, j’ai conservé les points suivants :

  • un minimum de composants (une pile, un chip et une led) ;
  • un minimum de consommation électrique pour que la pile dure le plus longtemps possible.

Le résultat

luciole jaune Ça reste très compact malgré l’utilisation du support. La tension de 3v de la pile rend l’utilisation d’une résistance avec la led inutile.

Il vous faudra donc :

  • 1 led ;
  • micro-contrôleur Atmel ATtiny 13, 25, 45, 85 (ou) ;
  • une pile 3v (CR2032) ;
  • l’application Luciole dispo sur mon GitHub ;
  • un fer à souder, de la soudure et quelques straps.

Comment ça marche ?

Bien, merci !

L’application qui est chargée dans le micro-contrôleur ne fait que 2 choses :

  1. Flasher la led ;
  2. Attendre un temps aléatoire d’environ 30 secondes, et recommencer.

1. Flasher la led

Le principe du flash consiste à faire une phase d’allumage progressif puis une phase d’extinction progressive mais avec une pente plus douce et donc un temps d’extinction plus grand.

La gamme des ATtiny comporte un (ou plusieurs suivant le modèle) générateurs de signaux PWM (Pulse Width Modulation : Modulation en largeur de pulsation). Je ne reviens pas sur le principe qui consiste à produire un signal carré de rapport cyclique variable afin de compenser l’absence de convertisseur Numérique / Analogique dans ces composants. Suivi par un filtre passe-bas, le signal tout-ou-rien devient un signal analogique variable entre 0 à la tension d’alimentation avec, dans notre cas, un pas de 1/255ème. Ici, le signal carré est directement appliqué à la diode et c’est notre œil qui se charge de faire la moyenne, puisque la fréquence de clignotement est bien supérieure à la persistance rétinienne.

Implémentation

Dans la suite, je me limite à la configuration pour l’ATtiny13, pour les autres contrôleurs, les noms des registres peuvent changer légèrement.

8-bit Timer/Counter Block Diagram

Dans l’ATtiny13, on a accès au « 8-bits Timer/Counter0 with PWM » (page 58). On va pouvoir utiliser deux fonctions simultanées de ce composant, à savoir :

  1. Le générateur d’onde « Waveform Generation » configuré en mode « Fast PWM Mode = 3 », le compteur tourne indéfiniment de 0 à 0xFF. Lors du passage à la valeur de référence, il génère un évènement de changement de status de la sortie. A l’arrivée à 0xFF, il génère une interruption de dépassement (TOV0) et recommence à 0.
    Avec le « Compare Output Mode = 3 », le signal de sortie est activé lors du passage de la valeur de référence et désactivé à l’arrivée à la valeur maximum (0xFF).
    On utilisera le compteur à sa fréquence maximum donc sans division de l’horloge interne.
    Les différents registres à spécifier sont :

    • WGM02:0 = 3 (Fast PWM ; TOP = 0xFF ; Update OCRx at TOP ; TOV Flag set on MAX)
    • COM0A1:0 = 3 (Set OC0A on Compare Match, clear OC0A at TOP)
    • CS02:0 = 1 (No prescaling)
    • OCR0A = 0 (initialisation led éteinte)

    Il suffit de faire varier directement la valeur du registre OCR0A, sans même en conserver une copie et d’attendre la prochaine itération du compteur avant de faire à nouveau évoluer. On passe donc de 0 à 255, puis de 255 à 0 en faisant varier le nombre d’itérations du compteur entre chaque incrémentation/décrémentation de la valeur de référence afin de contrôler les pentes d’allumage et d’extinction.

  2.  On profite de la génération de l’interruption TOV pour réveiller la CPU de son sommeil. L’économie d’énergie n’est pas très importante car seule la CPU est éteinte, mais de toute façon à côté de la consommation de la led (env. 10mA), il n’est pas utile de se lancer dans des économies plus complexe. De plus , cette période de d’allumage de la led est relativement plus courte que la phase d’attente.

Quand la phase du flash est terminée, on éteint simplement le timer en désactivant son horloge.

2. Attendre une durée aléatoire

Dans cette phase, on doit faire face à deux problématiques que sont le calcule de la valeur de l’attente qui sera donc aléatoire suivant une loi normale de moyenne et de dispersion précisées. Il faudra d’autre part mettre le contrôleur en sommeil profond (consommation quasi-nulle) et le réveiller régulièrement.

  1. Pour calculer une période aléatoire, j’ai commencé par utiliser la fonction rand()  disponible nativement dans les API Arduino en faisant une boucle comme suit :
    while (rand() < RAND_MAX / 16) {
        delay(1000);
    }
    

    Malheureusement, si la réponse donne bien une moyenne de 16 s, la distribution ressemble à p(x) = 1/x, ce qui n’est du tout une loi normale. D’autre part, le code binaire généré est simplement énorme avec environ 500 octets sur les 1 ko disponibles.
    Après quelques recherches, j’ai fini par trouver une astuce pour obtenir une pseudo-distribution normale de nombres pseudo-aléatoires (Generating Normal (Gaussian) Distributed Random Numbers). Mais cette fonction a encore besoin d’un générateur de nombres aléatoires (Random Number Generator – RNG) sur un intervalle. Sur le blog de Brad Forschinger on trouve des exemples de code de RNGs de grande période basés sur le travail  de George Marsaglia sur les « Xorshift RNGs ».
    Après quelques adaptations, ces algorithmes me permettent d’obtenir des nombres entiers suivant une distribution normale avec une qualité bien suffisante ici. Et en plus le code généré est bien plus efficace.

  2. Pour faire dormir profondément un ATtiny, il y a une astuce qui fonctionne bien quand la précision temporelle n’est pas importante, c’est d’utiliser le Watchdog (chien de garde). C’est un composant interne qui, lorsqu’il est activé, permet de rebooter le contrôleur lorsque son programme part dans une boucle infinie. On définit un intervalle de temps maximum au bout duquel un « Reset » est généré et d’autre part l’application doit régulièrement réinitialiser ce compteur pour éviter cette génération. Quand le contrôle du programme est perdu, on peut supposer que la réinitialisation du compteur ne se fait plus et donc qu’au bout d’un certain temps le « Reset » a lieu et remet le contrôleur dans une situation connue. Cette fonction est particulièrement appréciée dans les systèmes automatiques autonomes.
    Dans notre cas, on va utiliser le watchdog pour générer une interruption qui va réveiller tout le composant après une mise en sommeil profond qui inclut l’arrêt de l’horloge interne, le watchdog ayant sa propre horloge fonctionnant à basse fréquence et très peu consommatrice d’énergie.

Et voilà tout ça tient dans l’ATtiny13 et ses 1ko de programme et il reste encore un peu de place pour d’autres fonctionnalités.

Pour peaufiner la consommation électrique, on peut encore prendre soin d’éteindre toutes les fonctions inutiles et atteindre un courant résiduel de l’ordre de 7µA !

TODO

Ben oui, parce qu’il reste encore quelques centaines d’octets libres dans le ATtiny13, on pourrait implémenter une mesure de luminosité afin de ne faire clignoter la luciole qu’à la nuit tombée.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *