Difference between revisions of "Retro-Inge-LCD"

From Electrolab
Jump to: navigation, search
m (=Etape 3 : code arduino de lecture du LCD)
 
(12 intermediate revisions by one user not shown)
Line 1: Line 1:
 
=Exemple de rétro-ingénierie d'un LCD : Balance Téraillon TX6000=
 
=Exemple de rétro-ingénierie d'un LCD : Balance Téraillon TX6000=
 +
Projet réalisé par Limesle : https://www.facebook.com/labigrerie
 +
 
==Contexte==
 
==Contexte==
 
Le but est de pouvoir hacker une balance qui coûte en moyenne 20 euros afin de pouvoir lire directement le poids sur un autre device.
 
Le but est de pouvoir hacker une balance qui coûte en moyenne 20 euros afin de pouvoir lire directement le poids sur un autre device.
 
+
[[File:poids-LCD-LX6000.png|600px|thumb|none]]
 
Les sources d'inspiration sont :  
 
Les sources d'inspiration sont :  
    http://quo.vadis.stojkovic.ch/hacking-a-weighing-scale/
+
*http://quo.vadis.stojkovic.ch/hacking-a-weighing-scale/
    http://troels.leegaard.org/misc/grundtal20047/ <= code final retenu à partir de cette base.
+
*http://troels.leegaard.org/misc/grundtal20047/ <= code final retenu à partir de cette base.
    et surtout celui là pour la compréhension du fonctionnement d'un LCD (pas la partie sur le Zilog) : http://troels.leegaard.org/misc/grundtal20047/lcd-an0162.pdf
+
*et surtout celui là pour la compréhension du fonctionnement d'un LCD (la première partie, pas la partie sur le Zilog) : http://troels.leegaard.org/misc/grundtal20047/lcd-an0162.pdf
  
 
==Etape 1 : comprendre comment fonctionne le LCD==
 
==Etape 1 : comprendre comment fonctionne le LCD==
Line 22: Line 24:
 
   digitalWrite(5, HIGH);
 
   digitalWrite(5, HIGH);
 
     digitalWrite(6, LOW);
 
     digitalWrite(6, LOW);
     delay(20);
+
     delay(15);
 
   digitalWrite(5, LOW);
 
   digitalWrite(5, LOW);
 
     digitalWrite(6, HIGH);
 
     digitalWrite(6, HIGH);
     delay(20);
+
     delay(15);
  
 
Le montage à ça :
 
Le montage à ça :
Line 31: Line 33:
 
[[File:retro-inge-LCD-LX6000.png|700px|thumb|none]]
 
[[File:retro-inge-LCD-LX6000.png|700px|thumb|none]]
  
Il vous faut ensuite faire des essais et en noter le résultat pour reconstituer le cablage du LCD.
+
Il vous faut ensuite faire des essais et en noter le résultat pour reconstituer le câblage du LCD.
 
Pour la balance LX6000 on obtient :
 
Pour la balance LX6000 on obtient :
  
Line 38: Line 40:
 
==Etape 2: souder et remonter la bête==
 
==Etape 2: souder et remonter la bête==
  
Perso j'ai utilisé une vieille nappe de pc que j'ai soudé comme sur la photo. Il reste ensuite à connecter le tout à un arduino. On observe que sur le TX6000 il existe un petit bouton qui est censé controler les unités. Il est très utile car il peut ervir à réveiller la balance de sa torpeur pour lancer une mesure à distance. Sachant que le tarage est fait une fois pour toute à la première mise en route, on peut alors mesurer des charge à distance sans avoir besoin de remettre le tout à 0 et donc d'enlever la charge avant la pesée. Pratique pour une télérelève !
+
Perso j'ai utilisé une vieille nappe de pc que j'ai soudé comme sur la photo. Il reste ensuite à connecter le tout à un arduino. On observe que sur le TX6000 il existe un petit bouton qui est censé contrôler les unités. Il est très utile car il peut servir à réveiller la balance de sa torpeur pour lancer une mesure à distance. Sachant que le tarage est fait une fois pour toute à la première mise en route, on peut alors mesurer des charges à distance sans avoir besoin de remettre le tout à 0 et donc d'enlever la charge avant la pesée. Pratique pour une télé-relève !
 
[[File:retro-inge-SpyNappe-LX6000.png|700px|thumb|none]]
 
[[File:retro-inge-SpyNappe-LX6000.png|700px|thumb|none]]
  
  
==Etape 3 : code arduino de lecture du LCD=
+
==Etape 3 : code arduino de lecture du LCD==
 
Le principe est tout simple : Échantillonner rapidement les sorties des pins et backplane de la balance.  
 
Le principe est tout simple : Échantillonner rapidement les sorties des pins et backplane de la balance.  
  
A chaque lecture on détermine quel backplane est actif (Valeur analogique différentes des autres), on note quels pins sont actifs et on en déduit quels sont les segments actifs. La lecture durant plusieurs secondes, on aura statistiquement des résultats pour tous les couples Backplane/Pin qui sont actifs. On fait une moyenne en divisant par le nombre de lecture validées pour chaque backplane et tout ce qui se rapproche de 1 est considéré comme allumé.
+
A chaque lecture on détermine quel backplane est actif (Valeur analogique différentes des autres), on note quels pins sont actifs et on en déduit quels sont les segments actifs. La lecture durant plusieurs secondes, on aura statistiquement des résultats pour tous les couples Backplane/Pin qui sont actifs. On fait une moyenne en divisant par le nombre de lectures validées pour chaque backplane et tout ce qui se rapproche de 1 est considéré comme allumé.
  
 
On créer ensuite une fonction qui détermine les digits en fonction des segments allumés et on en déduit le poids !
 
On créer ensuite une fonction qui détermine les digits en fonction des segments allumés et on en déduit le poids !
  
'''La lecture doit se faire alors que l'affichage LCD est stabilisé sur le poids final. J'ai donc ajouté un bouton pour déclencher la lecture manuellement une fois la pesée faite et que le poids s'affiche pendant qqs seconde sur la balance.''' Si vous voulez une autre fonctionnalité il faudra développer un autre code avec une temporisation.
+
Voici donc le dernier code développé pour une version complète avec envoi des données sur le réseau Sigfox par la plateforme Akeru de SnootLab et en bonus l'ajout de 2 sondes de température.
 +
*https://codebender.cc/sketch:34727
  
Voici donc le code.
+
Et voici les premières courbes obtenues sur Actoboard de Snootlab avec une image du montage sans les sondes de température :
 +
[[File:resultat-actoboard.png|800px|thumb|none]]
  
  #define bouton 13
+
=Mise en œuvre pour pesée de ruche=
 
+
Résultat appliqué par mise en place d'une balance sous une ruche de production.
  //Initialisation des variables
+
[[File:BeeEyeVe.png|300px|thumb|none]]
  int lcdA=0,lcdB=0,lcdC=0,lcdD=0;
+
  int pa,pb,pc,pd;
+
  bool lcd0,lcd1,lcd2,lcd3,lcd4,lcd5,lcd6,lcd7,lcd8,lcd9;
+
  unsigned int SAn, SBn, SCn, SDDn;
+
  unsigned int SA[10], SB[10], SC[10], SDD[10];
+
  bool A[10], B[10], C[10], D[10];
+
 
+
  int bas=100; // valeur à déterminer en fonction du type de backplane
+
 
+
  // Fonction de lecture des Digits en fonctions des résultats
+
  int getDigit(int i, int j)
+
  {
+
      if ( A[i] &&  A[j] &&  B[i] && !B[j] &&  C[i] &&  C[j] &&  true &&  D[j]) return 0;
+
      if (!A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] &&  true && !D[j]) return 1;
+
      if ( A[i] && !A[j] &&  B[i] &&  B[j] && !C[i] &&  C[j] &&  true &&  D[j]) return 2;
+
      if ( A[i] && !A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  true &&  D[j]) return 3;
+
      if (!A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  true && !D[j]) return 4;
+
      if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] && !C[j] &&  true &&  D[j]) return 5;
+
      if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] &&  C[j] &&  true &&  D[j]) return 6;
+
      if ( A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] &&  true && !D[j]) return 7;
+
      if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] &&  C[j] &&  true &&  D[j]) return 8;
+
      if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  true &&  D[j]) return 9;
+
      return 0;
+
             
+
  }
+
 
+
 
+
  void setup() {
+
 
+
      for (int i=0; i<10; i++) {   
+
      pinMode(i, INPUT);
+
      }
+
      pinMode(A1, INPUT);
+
      pinMode(A2, INPUT);
+
      pinMode(A3, INPUT);
+
      pinMode(A4, INPUT);
+
      pinMode(bouton, INPUT);
+
      Serial.begin(9600);
+
  }
+
 
+
 
+
  void loop()
+
  {
+
      // On attend que le bouton soit pressé pour faire la mesure, ce qui nous laisse décider de déclencher quand la balance valide la mesure et reste ensuite avec un affichage fixe du poids
+
      while (digitalRead(bouton)==0){}
+
     
+
      // Mesure de départ qui aide à déterminer si le LCD est actif
+
 
+
          lcdA = analogRead(A1);
+
          lcdB = analogRead(A2);
+
          lcdC = analogRead(A3);
+
          lcdD = analogRead(A4);
+
 
+
 
+
      // Démarrage des mesures
+
      SAn = SBn = SCn = SDDn = 0;
+
      for (int i=0; i<10; i++) {
+
      SA[i] = SB[i] = SC[i] = SDD[i] = 0;
+
      }
+
     
+
      int i=0;
+
     
+
      while (lcdA != 0 || lcdB != 0 || lcdC != 0 || lcdD != 0)
+
      {
+
 
+
          lcdA  = analogRead(A1);
+
          lcdB  = analogRead(A2);
+
          lcdC  = analogRead(A3);
+
          lcdD  = analogRead(A4);
+
          lcd0  = digitalRead(2);
+
          lcd1  = digitalRead(3);
+
          lcd2  = digitalRead(4);
+
          lcd3  = digitalRead(5);
+
          lcd4  = digitalRead(6);
+
          lcd5  = digitalRead(7);
+
          lcd6  = digitalRead(8);
+
          lcd7  = digitalRead(9);
+
          lcd8  = digitalRead(10);
+
          lcd9  = digitalRead(11);
+
 
+
  /* // A utiliser pour un affichage en cours de lecture pour test
+
      Serial.print("A ");
+
      Serial.print(lcdA);
+
      Serial.print(" B ");
+
      Serial.print(lcdB);   
+
      Serial.print(" C ");
+
      Serial.print(lcdC);
+
      Serial.print(" D ");
+
      Serial.print(lcdD);
+
      Serial.print(" - ");
+
      Serial.print(lcd0);
+
      Serial.print(lcd1);
+
      Serial.print(lcd2);
+
      Serial.print(lcd3);
+
      Serial.print(lcd4);
+
      Serial.print(lcd5);
+
      Serial.print(lcd6);
+
      Serial.print(lcd7);
+
      Serial.print(lcd8);
+
      Serial.println(lcd9);
+
      */
+
 
+
 
+
              if (lcdA < bas)
+
              {
+
                  SA[0] += lcd0;
+
                  SA[1] += lcd1;
+
                  SA[2] += lcd2;
+
                  SA[3] += lcd3;
+
                  SA[4] += lcd4;
+
                  SA[5] += lcd5;
+
                  SA[6] += lcd6;
+
                  SA[7] += lcd7;
+
                  SA[8] += lcd8;
+
                  SA[9] += lcd9;
+
                  SAn++;
+
              }
+
              if (lcdB < bas)
+
              {
+
                  SB[0] += lcd0;
+
                  SB[1] += lcd1;
+
                  SB[2] += lcd2;
+
                  SB[3] += lcd3;
+
                  SB[4] += lcd4;
+
                  SB[5] += lcd5;
+
                  SB[6] += lcd6;
+
                  SB[7] += lcd7;
+
                  SB[8] += lcd8;
+
                  SB[9] += lcd9;
+
                  SBn++;
+
              }
+
              if (lcdC <= bas)
+
              {
+
                  SC[0] += lcd0;
+
                  SC[1] += lcd1;
+
                  SC[2] += lcd2;
+
                  SC[3] += lcd3;
+
                  SC[4] += lcd4;
+
                  SC[5] += lcd5;
+
                  SC[6] += lcd6;
+
                  SC[7] += lcd7;
+
                  SC[8] += lcd8;
+
                  SC[9] += lcd9;
+
                  SCn++;
+
              }
+
              if (lcdD <= bas)
+
              {
+
                  SDD[0] += lcd0;
+
                  SDD[1] += lcd1;
+
                  SDD[2] += lcd2;
+
                  SDD[3] += lcd3;
+
                  SDD[4] += lcd4;
+
                  SDD[5] += lcd5;
+
                  SDD[6] += lcd6;
+
                  SDD[7] += lcd7;
+
                  SDD[8] += lcd8;
+
                  SDD[9] += lcd9;
+
                  SDDn++;
+
              }
+
 
+
              i++;
+
              }
+
             
+
      // Un fois que le LCD s'éteind, on détermine les moyennes des mesures pour trier les vrais actifs
+
              if (lcdA==0 && lcdB==0 && lcdC==0  && lcdD==0 && (SA[0]+SA[1]+SA[2]+SA[3]+SA[4]+SA[5]+SA[6]+SA[7]+SA[8]+SA[9]>0)) {
+
              for (int i=0;i<10;i++){
+
              A[i] = (1.0 * SA[i] / SAn >0.5);
+
              B[i] = (1.0 * SB[i] / SBn >0.5);
+
              C[i] = (1.0 * SC[i] / SCn >0.5);
+
              D[i] = (1.0 * SDD[i] / SDDn >0.5);
+
              }
+
             
+
      // decoding
+
          float weight = 100.0*getDigit(8,9) +10.0*getDigit(6,7) + 1.0*getDigit(4,5) + 0.1*getDigit(2,3);
+
         
+
 
+
      // La mesure est maintenant terminée : on affiche sur le port série
+
 
+
      Serial.print("On mesure : ");
+
      Serial.print(weight);
+
      Serial.println(" Kgs");
+
         
+
          weight = 0;
+
 
+
 
+
      delay(2000);
+
         
+
 
+
      }
+
 
+
 
+
 
+
  }
+

Latest revision as of 11:56, 9 June 2014

Exemple de rétro-ingénierie d'un LCD : Balance Téraillon TX6000

Projet réalisé par Limesle : https://www.facebook.com/labigrerie

Contexte

Le but est de pouvoir hacker une balance qui coûte en moyenne 20 euros afin de pouvoir lire directement le poids sur un autre device.

Poids-LCD-LX6000.png

Les sources d'inspiration sont :

Etape 1 : comprendre comment fonctionne le LCD

Il faut déjà savoir qu'il est actionné par un courant alternatif de l'ordre de 50 htz et 2.3 V

Si jamais on l'actionne avec du DC trop longtemps, les cristaux liquides vont se coller à l'une des électrode et le LCD est foutu !!

Ensuite, le LCD de la LX6000 est en fait constitué de plages d'affichage qui sont multiplexées. Chaque segment est une plage, les points ou unités aussi.

Il faut donc faire des essais pour connaître les "coordonnées" de chaque segment. Maintenant que l'on sait tout ça, on démonte la bête et on injecte du courant directement dans le LCD grâce au code et montage ci-après.

Pour cela on utilise un Arduino avec 2 pins en digitalWrite de façon alternative. Le code ressemble à ça :

 digitalWrite(5, HIGH);
   digitalWrite(6, LOW);
   delay(15);
 digitalWrite(5, LOW);
   digitalWrite(6, HIGH);
   delay(15);

Le montage à ça :

Retro-inge-LCD-LX6000.png

Il vous faut ensuite faire des essais et en noter le résultat pour reconstituer le câblage du LCD. Pour la balance LX6000 on obtient :

Cablage-LCD-LX6000.png

Etape 2: souder et remonter la bête

Perso j'ai utilisé une vieille nappe de pc que j'ai soudé comme sur la photo. Il reste ensuite à connecter le tout à un arduino. On observe que sur le TX6000 il existe un petit bouton qui est censé contrôler les unités. Il est très utile car il peut servir à réveiller la balance de sa torpeur pour lancer une mesure à distance. Sachant que le tarage est fait une fois pour toute à la première mise en route, on peut alors mesurer des charges à distance sans avoir besoin de remettre le tout à 0 et donc d'enlever la charge avant la pesée. Pratique pour une télé-relève !

Retro-inge-SpyNappe-LX6000.png


Etape 3 : code arduino de lecture du LCD

Le principe est tout simple : Échantillonner rapidement les sorties des pins et backplane de la balance.

A chaque lecture on détermine quel backplane est actif (Valeur analogique différentes des autres), on note quels pins sont actifs et on en déduit quels sont les segments actifs. La lecture durant plusieurs secondes, on aura statistiquement des résultats pour tous les couples Backplane/Pin qui sont actifs. On fait une moyenne en divisant par le nombre de lectures validées pour chaque backplane et tout ce qui se rapproche de 1 est considéré comme allumé.

On créer ensuite une fonction qui détermine les digits en fonction des segments allumés et on en déduit le poids !

Voici donc le dernier code développé pour une version complète avec envoi des données sur le réseau Sigfox par la plateforme Akeru de SnootLab et en bonus l'ajout de 2 sondes de température.

Et voici les premières courbes obtenues sur Actoboard de Snootlab avec une image du montage sans les sondes de température :

Resultat-actoboard.png

Mise en œuvre pour pesée de ruche

Résultat appliqué par mise en place d'une balance sous une ruche de production.

BeeEyeVe.png