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.






jeudi 31 juillet 2014

Deux dés Arduino / Conception / Page 2

Tutoriel pour deux dés

retour conception page 1

Organisation des leds :

Avec 2 dés, il faut gérer l'affichage de 14 leds avec seulement 7 sorties Arduino.
Le dispositif est similaire avec une double connexion des 7 pins sur les leds symétriques des deux dés.

Nous utilisons deux transistors NPN(Explication composant pnp) avec 3 pattes, qui laissent passer le courant aux extrémités lorsque nous envoyons du courant sur la patte centrale. Nous raccordons aux sorties 10 et 11 chacun des transistors. toutes les cathodes (-) d'un dés sont rattachées à une patte extérieur du composant NPN. la patte libre est connectée au GND (-).

Pour afficher un chiffre différent, on éteint un dés et on allume l'autre ensuite on alterne. Ce fonctionnement impose un affichage, continu en alternance de chaque dés.




le script de fonctionnement pour les deux dés est le suivant : 


//organisation des dès avec sorties : 
//     6     4
//     7  5  3
//     8     2
int butPin = 9;    // bouton
int transi1 = 10;  // transistor 1
int transi2 = 11;  // transistor 2

byte dede[8][7] ={
 //2 3 4 5 6 7 8
  {0,0,0,0,0,0,0}, // 0 rien
  {0,0,0,1,0,0,0}, // 1
  {1,0,0,0,1,0,0}, // 2
  {0,0,1,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 tout
};

byte resultatloto[2][30]; // remplissage du résultat des deux dès lancés
int resultdesun=0; 
int resultdesdeux=0;
int attenteboucle = 5; //10 en standard = calcul la vitesse de changement

void setup()
{
  int i;
  for (i=2; i<9; i++) pinMode(i,OUTPUT);   // led pins
  pinMode(transi1,OUTPUT);
  pinMode(transi2,OUTPUT);
  pinMode(butPin,INPUT); 
  digitalWrite(butPin, HIGH); // indispensable pour la lecture du switch proto
  
  //  start/stop button
  turnOnNumber(0);
  randomSeed(analogRead(0));               // initialise le random
  Serial.begin(9600);
}

void loop() 
{
  Lancedes();
}

void Lancedes() 
{
  
 int n,i; 
 int loto1; 
 int loto2; 
 int maxi =15;
 int delay1;
 int resultat = 10;
 int ancienresultat = 10; // empeche deux fois le meme nombre

  // test bouton  si actionné
  if (digitalRead(butPin) == HIGH)
  {
    // Calcul et chargement du résultat dans resultatloto (tableau des resultats)
    randomSeed(analogRead(0));               // initialise le random
    loto1 = random(5,maxi);
    randomSeed(analogRead(1));               // initialise le random
    loto2 = random(5,maxi);

     for (n=0; n < maxi;n++)
      {
        while (resultat == ancienresultat)  resultat=random(1,7);
        ancienresultat=resultat;
        if (n<loto1) resultatloto[0][n]=resultat;
        else resultatloto[0][n]=0;
       }
      // resultat final sur premier dés
       resultdesun = resultatloto[0][loto1-1];

     for (n=0; n < maxi ;n++)
      {
        while (resultat == ancienresultat)  resultat=random(1,7);
        ancienresultat=resultat;
        if (n<loto2) resultatloto[1][n]=resultat;
        else resultatloto[1][n]=0;
      }
      // resultat final sur deuxième dés
       resultdesdeux = resultatloto[1][loto2-1];


     // affichage des résultats
     if (loto1<loto2) maxi = loto2;    // determine la boucle max pour les deux dès
     else maxi = loto1;

    // boucle avec affichage de plus en plus lent
     for (n=0; n<maxi; n++)
     {
         delay1=(n+1) * 2;
         for (i=0;i<delay1;i++)
         {
           if (resultatloto[0][n] != 0) 
           {
             resultdesun = resultatloto[0][n];
            }
           else 
           {
             resultdesun = resultatloto[0][loto1-1];
           }

          if (resultatloto[1][n]!=0) 
          {
            resultdesdeux = resultatloto[1][n];      
          }
          else 
          {
            resultdesdeux = resultatloto[1][loto2-1];
          }
          
//          Serial.println(resultdesun);
 //         Serial.println(resultdesdeux);
          
          digitalWrite(transi1,HIGH);
          digitalWrite(transi2,LOW);
          turnOnNumber(resultdesun);
          delay(attenteboucle);
          digitalWrite(transi2,HIGH);
          digitalWrite(transi1,LOW);
          turnOnNumber(resultdesdeux);
          delay(attenteboucle);
         }
     }
  }
 digitalWrite(transi1,HIGH);
 digitalWrite(transi2,LOW);
 turnOnNumber(resultdesun);
 delay(attenteboucle);
 digitalWrite(transi2,HIGH);
 digitalWrite(transi1,LOW);
 turnOnNumber(resultdesdeux);
 delay(attenteboucle);
}


// ***** set up leds corresponding the number *****
void turnOnNumber(int n)
{
    int i;
    
    for(i=0;i<7;i++) //n en décalage de 1 lié à la gestion tableau qui commence à0 
    {
      if (dede[n][i]==0) digitalWrite(i+2, LOW);     
     else digitalWrite(i+2, HIGH);
   }
}







lundi 28 juillet 2014

Deux dés Arduino / Conception / Page 1

DEUX DES ARDUINO / CONCEPTION


Tutorial pour un dés seul

Organisation des leds :

Un dé est composé de 7 leds. Chaque led est reliée à une sortie Arduino.
Voila à quoi ça ressemble :

Ce dispositif permet d'afficher un dé. Voici l'exemple image et script qui fonctionne avec ce dispositif: 

Dispositif Arduino 1 dé

Sketch Arduino Uno 1 dé

/****************************************************************************************
------------------------------------- Programme 1 dés ---------------------------------------------- 
Déclaration des variables
  ButPin pour le bouton
  etat pour le resultat du bouton
  dede est un tableau contenant les positions 
  des 7 leds pour toutes les combinaisons d'un dés

organisation des dès avec sorties : 
  led-pin relationships:     6     4
                                    7  5  3
                                    8     2
*****************************************************************************************/

int butPin = 9;
int etat =0;
byte dede[8][7] ={
 //2 3 4 5 6 7 8 numéro des pins associés aux leds
  {0,0,0,0,0,0,0}, // 0 rien
  {0,0,0,1,0,0,0}, // 1
  {1,0,0,0,1,0,0}, // 2
  {0,0,1,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 tout
};

// initialisation partie du programme qui s'execute une fois
void setup()
{

  int i; // utilisé pour la boucle qui suit

  // initialisation des pins 2 à 8 pour les leds
  for (i=2; i<9; i++) pinMode(i,OUTPUT);   // led pins
  pinMode(butPin,INPUT);                   //  initialisation du bouton switch

  turnOnNumber(0);                         // extinction des leds
  randomSeed(analogRead(0));               // initialise le random astuce pour avoir un vrai random
  Serial.begin(9600);
}

void loop() 
{
  
 int n; 
 int loto; 
 int resultat = 10;
 int ancienresultat = 10; // empeche deux fois le meme nombre

// lecture du bouton
 etat= digitalRead(butPin);

  if ( etat == HIGH)
  {
    turnOnNumber(7);
    delay(500);
    turnOnNumber(0);
    delay(500);
    
      loto = random(5,30);

      for (n=2; n <loto;n++)
      {
        while (resultat == ancienresultat)  resultat=random(1,7);
        turnOnNumber(resultat);
        ancienresultat=resultat;
        delay(500-((loto-n)*20));
      }
  }
}

// ***** set up leds corresponding the number *****
void turnOnNumber(int n)
{
    int i;
  
    for(i=0;i<7;i++) //n en décalage de 1 lié à la gestion tableau qui commence à0 
    {
      if (dede[n][i]==0) digitalWrite(i+2, LOW);
      else digitalWrite(i+2, HIGH);
    }
} //******************************************* FIN DU PROGRAMME ********************************



La suite affichage de deux dés