dimanche 17 mai 2015

Dé Attiny 85 en CharliePlexing moulé en résine Crystal




le résultat : gauche dernière version, à droite première version (démoulée trop tôt).
les images de ce tuto sont issues de plusieurs expériences autour du même sujet. Le sketch et les indications de montages sont le résultat des derniers essais. 


Inventaire : 

  • Leds 5 mm (acheté par 1000 ebay chine)
  • tilt sensor ebay
  • Attiny85 + support ebay
  • support pile bouton CR2432 ebay
  • 4 Resistances 39 ohms
  • Resine Crystal
  • un gloss ultra brillant pour résine (amazon)
  • moule 3x3x3 cube silicone
  • de la pâte Playdoh
Les trucs qui n'ont pas fonctionné :
  • l'interrupteur (bloqué par la résine)
  • le random standard

Les étapes importantes du montage : 


1. Le CharliePlexing
voir le wiki : http://en.wikipedia.org/wiki/Charlieplexing
Dans notre cas nous avons 7 leds à piloter, le nombre de pins nécessaires est de 4. la règle avec 4 pins on peut piloter : (4*4)-4 = 12 pins. 
le schéma pins <-> leds est le suivant : 

Schéma Charlieplexing

2. Souder les leds et respecter la forme finale.

Afin de respecter la forme finale, j'utilise une plaquette en bois percée en 5 mm.  Utilisation de pâte Play-Doh pour maintenir les composants. Sur la led 4 faire attention aux croisements, le vernis à ongle peut être utilisé pour isoler. Tester et valider qu'il n'y a pas de faux contacts.


Positionner les leds à souder

3. Souder l'Attiny 85 avec son support

Evitez les erreurs en dessinant l'Attiny85


Raccordement des leds



Les pins 1, 2, 3 et 4 sont reliés à des résistances de 39 ohms, reliées aux 4 brins  issues des leds. Le mapping avec le schéma initial est : 
bleu = 1
vert = 2
rouge = 3
noir = 4

Raccordement Attiny 85 et Tilt Sensor
Le tilt sensor est utilisé comme interrupteur. il est composé de deux pins : l'un raccordé au (+) de la pile bouton et l'autre au (+) de l'Attiny. pour comprendre le tilt sensor voir :   http://www.learningaboutelectronics.com/Articles/Tilt-sensor-circuit.php
Le (-) de la pile bouton est relié au GND de l'Attiny.


Souder la pile bouton

C'est la dernière étape de soudure, le système complet doit tenir dans le moule (à glaçon) prévu pour le dé. Il s'agit d'un moule à glaçon de 3x3x3 cm en silicone.



Les étapes de la programmation :

  1. chargement du programme sur Attiny
  2. Programmation du charlieplexing
  3. Programmation du random (différent sur Attiny et pas fiable en standard).
  4. Programmer le lancement

1) le chargement du programme sur Attiny

Le meilleur tuto sur le sujet est sur le lien suivant : http://highlowtech.org/?p=1695
et faire le test avec un programme simple (voir blink).
Pour ma part, j'utilise un arduino pour programmer l'Attiny.

il s'agit d'un shield arduino, connecté pour charger l'attiny.
A savoir, la vitesse par défaut 1mhz de l'Attiny n'est pas suffisante pour un affichage fluide.















A 8 mhz c'est parfait. pour changer la vitesse, il faut choisir l'attiny 85 à 8mhz.
avant de téléverser le programme, il faut graver la sequence d'initialisation pour changer la vitesse :


2) Programmation Charlieplexing


les indispensables
une table pour identifier chaque led : (1 pour pole +, 2 pour -, 3 pour inactif).
On initialise un tableau d'équivalence pour piloter chaque led.

// 1= output high
// 2= output low
// 3= input low
int tabled[7][4] ={
  //row 1 2 3 4
  {1,2,3,3}, //led 1
  {2,1,3,3}, //led 2
  {1,3,2,3}, //led 3
  {3,1,2,3}, //led 4
  {3,3,1,2}, //led 5
  {3,3,2,1}, //led 6
  {3,2,3,1}, //led 7
};  

l'affichage d'une led se fait en déterminant la polarité des pins : 


switch (tabled[numled][i]) {
case 1 :
  pinMode(pin_switch + i, OUTPUT);
  break;
case 2 :
  pinMode(pin_switch + i, OUTPUT);
  break;
case 3 : 
  pinMode(pin_switch + i, INPUT);
  break;
default : 
  break;

switch (tabled[numled][i]) {
case 1 :
  digitalWrite(pin_switch + i, HIGH);
  break;
case 2 :
  digitalWrite(pin_switch + i, LOW);
  break;
case 3 : 
  digitalWrite(pin_switch + i, LOW);
  break;
default : 
  break;

3) La programmation du random

La fonction randomSeed avec la lecture du port analogique retourne la même série de valeurs.
j'ai utilisé deux techniques pour m'assurer un random parfait :

  • l'excellente librairie Entropy
  • la sauvegarde du nombre de la série randomSeed dans l'eprom via la librairie EPROM. l'utilisation du tilt comme interrupteur fait que nous ne pouvons pas utiliser une simple variable pour sauver le dernier nombre utilisé. 

4) Le programme 


Chaque chiffre du dé correspond à un ensemble de leds allumées. la clé est une table décrivant cette correspondance.
 
/* Charliplexing 7 LEDs
dice description : 
  1      5
  2  4   6
  3      7
--------------------------------------------------------------------------------
Row 1 (R1): Arduino Pin 10 or ATTINY Pin 1
Row 2 (R2): Arduino Pin 11 or ATTINY Pin 2
Row 3 (R3): Arduino Pin 12 or ATTINY Pin 3
Row 4 (R4): Arduino Pin 13 or ATTINY Pin 4
See pin_switch var Arduino vs Attiny
--------------------------------------------------------------------------------
variable    pinMode      state
 L           OUTPUT       LOW 
 H           OUTPUT       HIGH
 Z           INPUT        LOW
---------------------------------------------------------------------------------
*/

#define ATTINY_MODE 1    // Comment for ARDUINO
//#define TEST_MODE 1      // Comment for production version

//#define ATTINYfd_1   1      //Attiny à 1 mhz
#define ATTINYfd_8   1      //Attiny à 8 mhz
//#define ATTINYfd_20  1      //Attiny à 20 mhz

// Library 
#include < EEPROM.h >      // save data for random
#include < Entropy.h >  // GNU random

const int coef = 5;

#if !defined (ATTINY_MODE) //ARDUINO
  const int temps_affiche =   500; //display refresh rate = 500 for arduino 150 for ATTINY
  const int temps_une_led =   30;  // display repet light per led = 30 for arduino and 5 for ATTINY
  const int pin_switch =      10;      // match pin between ATTINY and arduino 
#endif

#if defined(ATTINYfd_1)
  const int temps_affiche =   150; //display refresh rate = 500 for arduino 150 for ATTINY
  const int temps_une_led =   24;    // display repet light per led = 30 for arduino and 5 for ATTINY
  const int pin_switch =      1;      // match pin between ATTINY and arduino
#endif
#if defined(ATTINYfd_8)
  const int temps_affiche =   300; //display refresh rate = 500 for arduino 150 for ATTINY
  const int temps_une_led =   100;    // display repet light per led = 30 for arduino and 5 for ATTINY
  const int pin_switch =      1;      // match pin between ATTINY and arduino
#endif



// dice number To led matrix
byte dede[8][7] ={
 //3 4 5 6 7 8 9
  {0,0,0,0,0,0,0}, // 0 nothing
  {0,0,0,1,0,0,0}, // 1
  {0,0,1,0,1,0,0}, // 2
  {1,0,0,1,0,0,1}, // 3
  {1,0,1,0,1,0,1}, // 4
  {1,0,1,1,1,0,1}, // 5
  {1,1,1,0,1,1,1}, // 6
  {1,1,1,1,1,1,1}, // 7 all
}; 

// 1= output high
// 2= output low
// 3= input low
int tabled[7][4] ={
  //row 1 2 3 4
  {1,2,3,3}, //led 1
  {2,1,3,3}, //led 2
  {1,3,2,3}, //led 3
  {3,1,2,3}, //led 4
  {3,3,1,2}, //led 5
  {3,3,2,1}, //led 6
  {3,2,3,1}, //led 7
};  


void setup() 
{
    uint8_t random_byte;
    unsigned int id = EEPROM.read(0);
   
   Entropy.Initialize();

  if (Entropy.available()) {
    randomSeed(id);
    id = Entropy.random();
  }
    EEPROM.write(0, id);
  
#if !defined (ATTINY_MODE)    
    Serial.begin (115200);
    Serial.println ("setup");
    Serial.println ("id : ");
    Serial.print (id+1);
    Serial.println("");
#endif 

#if !defined (TEST_MODE)
  Lancedes();
#endif
}

void loop()
{
#if defined (TEST_MODE)
    afficheled(0,temps_affiche*coef);
    afficheled(1,temps_affiche*coef);
    afficheled(2,temps_affiche*coef);
    afficheled(3,temps_affiche*coef);
    afficheled(4,temps_affiche*coef);
    afficheled(5,temps_affiche*coef);
    afficheled(6,temps_affiche*coef);
    affichede(1, temps_affiche);
    affichede(2, temps_affiche);
    affichede(3, temps_affiche);
    affichede(4, temps_affiche);
    affichede(5, temps_affiche);
    affichede(6, temps_affiche);
#endif
}
// ***** affiche led *****
void afficheled(int numled,int temps)
{    int i,j;
  //boucle de repetition nombre de temps
  //par defaut 1
 if (numled > 6 || numled < 0) affiche_erreur (1);
 
      for(i=0;i < 4;i++) // changement des pins arduino  
      {
        
        switch (tabled[numled][i]) {
          case 1 :
            pinMode(pin_switch + i, OUTPUT);
             break;
          case 2 :
            pinMode(pin_switch + i, OUTPUT);
            break;
          case 3 : 
            pinMode(pin_switch + i, INPUT);
            break;
         default : 
            break;
        }
      }

  if (temps ==0) temps=1;

     for (j=0;j < temps;j++)
    {
      for(i=0;i < 4;i++) // changement des pins arduino  
      {
        
        switch (tabled[numled][i]) {
          case 1 :
            digitalWrite(pin_switch + i, HIGH);
            break;
          case 2 :
            digitalWrite(pin_switch + i, LOW);
            break;
          case 3 : 
            digitalWrite(pin_switch + i, LOW);
            break;
         default : 
            break;
      }
      }
  }
}

// ***** set up leds corresponding the number *****
void affichede(int n ,int temps)
{    int i,j;   
     int tp_led , tp_boucle;
     
     if (n > 6 || n < 1) affiche_erreur (2);
     
     tp_led = temps_une_led / n;
     tp_boucle= temps;

  //boucle de repetition nombre de temps
  //par defaut 1
  if (tp_boucle ==0) tp_boucle=1;
  for (j=0;j < tp_boucle;j++)
  {
    for(i=0;i < 7;i++) if (dede[n][i]==1) afficheled(i,tp_led);
  }
}

void affiche_erreur(int erreur)
{
  int i,j;
  
    switch (erreur) {
      case 1 : // erreur affiche led
        for (i=0;i < 10;i++) for (j=1;j < 8;j++) afficheled(j,temps_affiche);
        break;
      case 2 : // erreur affichede
        for (i=0;i < 10;i++) for (j=1;j < 4;j++) afficheled(j,temps_affiche);
        break;
     default : 
        break;
    }
}
  

void Lancedes() 
{
  
 int n,i; 
 int loto1;                // résultat random du nombre de tour de dès avant résultat
 int maxi =15;             // maxi du random du nombre de tour de dès avant résultat
 int mini = 5;             // mini du random du nombre de tour de dès avant résultat
 int delay1;               // temps d'affichage entre deux tours avant final
 int resultat = 10;        // résultat intermediaire
 int ancienresultat = 10;  // empeche deux fois le meme nombre
 

  loto1 = Entropy.random(mini,maxi);

 for (n=0; n < loto1;n++)
  {
     while (resultat == ancienresultat)  resultat=Entropy.random(1,7);      
     ancienresultat=resultat;
     delay1=(temps_affiche)/(loto1-n);
     affichede(resultat,delay1);
   }

#if !defined (ATTINY_MODE)
    Serial.print ("resultat final :");
    Serial.print(resultat);
    Serial.print(" nb resul inter : ");
    Serial.println(loto1);
#endif
 affichede(resultat,temps_affiche*100);
 
}



Le moulage en résine : 

Avant de mouler l'ensemble, il faut protéger l'emplacement de la pile bouton pour pouvoir la changer.
j'utilise la pâte Playdoh, mais le résidu n'est pas évident à retirer après.

Le séchage est long > 3 jours, 1 semaine est recommandé. il est important de ne pas démouler avant l'heure.


Après séchage, si le dé n'est pas entièrement transparent, utilisez le vernis Gloss.






1 commentaire:

  1. cool le concept de dés avec Attiny, ça donne envie de se lancer, Bravo !
    "Une once de pratique vaut mieux que des tonnes de discours." – Mahatma Gandhi

    RépondreSupprimer