Overblog
Suivre ce blog Administration + Créer mon blog
8 juin 2012 5 08 /06 /juin /2012 21:58

Ce soir en rentrant du boulot j'a fait les câbles en nappe avec Hervé.

J'étais impatient de faire un essai grandeur nature.

Et le résultat n'est pas satisfaisant:

  • Ca manque beaucoup de luminosité
  • Le calque du dessous est moins bien imprimé que celui du dessus et ça ce voit trop à mon goût.

De toutes façons, il faut que je refasse le cadran car il sera mieux avec le caractère "fen" (minutes).

 

J'ai augmenté l'intensité lumineuse et ré-étalonné la LDR.

C'est un peu mieux mais encore trop sombre. Je dois pouvoir encore augmenter le courant dans les LED sans risque.

 

Je vais aussi voir si une seule couche de calque ne serait pas suffisante.

 

Voilà ce que ça donne, c'est un peu mieux en photo qu'en vrai je trouve!

Il est 21h52:

2012 06 08 4262

 

Partager cet article
Repost0
3 juin 2012 7 03 /06 /juin /2012 22:12

J'ai pas mal avancé la matrice de LED ces derniers jours.

 

J'ai commencé par coller une feuille de papier imprimée avec le cadran sur le fond de la matrice.

Ensuite j'y ai tracé l'emplacement des futures alvéoles, puis les points de perçage pour les led:

 

matricePercée

 

 

Il m'a fallu quelques heures de travail pour découper et coller les alvéoles à la colle chaude.

Surtout que je m'étais trompé de 5mm de hauteur...j'ai dû enlever 5mm alors que j'avais 2/5 des alvéoles construites...

C'est pas très joli à voir, mais ça fonctionne bien.

J'ai passé un coup de ponceuse pour égaliser la surface, puis testé qu'il n'y avait pas de fuite de lumière entre les alvéoles:

 

matriceAlvéoles

 

Les LED sont en place, y'a plus qu'à les souder:

 

matriceLedsASouder

 

Enfin la matrice terminée, et testée, toutes les LED fonctionnent:

matriceLedComplete

 

Reste à percer le passage du câble en nappe.

 

Prochaine étape: la mise en place du capteur de mouvement et des boutons capacitifs.

Partager cet article
Repost0
25 mai 2012 5 25 /05 /mai /2012 22:28

Voici les 2 modes de démo de l'horloge qui s'enchainent: cycle des heures suivi d'un cycle des minutes:

 

 


 
Partager cet article
Repost0
23 mai 2012 3 23 /05 /mai /2012 22:00

Après avoir expériementé avec les sleep modes avec plus ou moins de succès (j'en reparlerai bientôt) je me suis dit que ça serait sympa que l'horloge affiche un message d'accueil à la mise sous tension.

J'ai donc décidé de lui faire afficher un 你好 (ni hao) autrement dit "bonjour" scrollant de droite à gauche en utilisant chaque caractère de la matrice comme un point lumineux.

Encore un truc qui m'a rappelé des souvenirs de jeunesse!

Je m'amusais à faire des scrollings en assembleur Z80 en rentrant du collège quand j'étais en cinquième (ça plantait souvent et fallait recharcher l'assembleur depuis une cassette à chaque plantage!).

 

Donc comment faire ça avec un Arduino et un MAX7219.

Eh bien encore une fois la librairie LedControl simplifie énormément la tâche puisqu'elle permet entre autre un pilotage ligne par ligne avec un bit par led.

 

J'ai donc commencé par tracer le message à afficher sur un papier quadrillé sur une hauteur de 5 cases. Pas facile!

Ensuite, j'ai découpé la longueur en blocs de 8 cases (mes futurs octets) et j'ai utilisé ce dessin pour créer un tableau de 5*6 octets pour le stocker.

Voilà ce que ça donne:

//message d'accueil scrollant "ni hao"
const static int text[5][6]={
  {0,B00101111,B10001000,B01111100,0,0},
  {0,B01010000,B10001000,B00001000,0,0}, 
  {0,B11000010,B00011111,B00111100,0,0},
  {0,B01001010,B10000100,B00010000,0,0},
  {0,B01000010,B00001010,B00010000,0,0},
};

 

Au début j'ai un caractère vide pour permettre d'introduire le premier caractère progressivement.

Et à la fin j'ai deux caractères vides pour l'effacement progressif du dernier caractère.

Chaque bit à 1 est un "pixel" de mon message.

 

L'astuce pour faire scroller ça c'est d'avoir un "pointeur" qui va indiquer sur quel bit des 5*8 bits formant les cololonnes doit commencer l'affichage.

Ensuite on sait que notre matrice fait 8 bits de long (par 5 de haut), on va donc copier 8 bits à partir de cette position dans le tableau qui représente la matrice d'affichage.

Comme on va commencer par lire un bit situé à n'importe quel endroit d'un octet on doit jouer avec des décalages de bits pour prendre les bits à afficher dans les bons octets et les décaler pour les placer là où ils doivent être dans la matrice d'affichage à un instant donné.

Une fois qu'on a fait ça pour les 5 lignes à afficher, y'a plus qu'à transférer tout ça au Max7219 via LedControl.

 

Voilà ce que ça donne niveau implémentation :

/*
* Message d'accueil
*/
void greet(){
  int i; //bit à partir duquel on commence à afficher
  int b; //octet suivant celui en cours d'affichage
  int r; //ligne
  int octet=0; //octet en cours d'affichage
  int offset=0; //nombre de bits à prendre dans l'octet suivant
 
  for(i=0;i<32;i++){ //on a 32 bits à afficher
        octet = i / 8; //octet de départ
        offset = i % 8; //nombre de bits à prendre dans l'octet suivant
        for(r=0;r<5;r++){ //pour chaque ligne de la matrice
          row[r]=0;

//on transfert dans la matrice l'octet de départ décalé de l'offset (on décale le caractère

//de N crans vers la  droite de la matrice)

          row[r] |= text[r][octet] << offset;

//si on n'est pas sur le premier bit d'un octet il faut prendre les bits qui restent à

//afficher dans l'octet suivant
          if(offset>0){
            b = text[r][octet+1];
            row[r] |=  b >> (8-offset)  ;
          }
        }

//on a calculé la matrice à afficher, reste plus qu'à la transférer ligne par ligne

//dans le Max7219
        for(r=0;r<5;r++){
          lc.setRow(0,r,row[r]);     
        }
        delay(70);
   }
}

 

Et comme un bon dessin, en l'occurence une vidéo, vaut mieux qu'un long discours, voici ce qu'elle affiche à la mise sous tension:

 

 

 


 

 

 

 

Elle va aussi afficher une fois "ni hao" lors du premier allumage de la journée à la sortie de veille (c'est une horloge polie ). Pour un peu je la ferais parler mais je sens que ça risque m'énerver à la longue.

 

Partager cet article
Repost0
21 mai 2012 1 21 /05 /mai /2012 23:05

J'ai bien bossé ce soir:

-J'ai testé le détecteur de mouvement sans sa lentille de fresnel et en position presque finale dans mon salon.

J'ai aussi fini par trouver la doc de ce modèle exact de capteur (elle n'est pas à jour chez Adafruit) et j'ai vu que j'avais réglé la sensibilité au minimum, pensant la régler au maximum...

Avec le bon réglage, même sans lentille le résultat est très satisfaisant, même si l'angle de vue est un peu plus réduit.

 

-J'ai débuggué le code de calcul de la matrice de led. Y'avait des caractères affichés quand il ne faut pas.

 

-J'ai câblé les 2 capteurs capacitifs et implémenté les 2 modes de démonstration via un appui simultané sur les 2 capteurs. Ca fonctionne parfaitement. Reste à implémenter le réglage manuel de l'heure via ces boutons (demain soir je pense).

 

-J'ai débuggué un problème de réglage auto de la luminosité (borne basse inférieure à celle paramétrée dans la fonction map() ce qui fait passer la valeur retournée à 65535! A mon avis y'a comme un bug dans cette fonction de la lib Arduino!).

 

-J'ai implémenté le mode veille pour le Max 7219 (pilote des LED).

 

-Reste à modifier l'alimentation du récepteur DCF77 et terminer la nouvelle gestion de la synchro de l'heure et les deux états de mode veille. Après ça le soft devrait être terminé.

 

Voilà le prototype complet. Le morceau de plastique noir en bas à droite est une maquette des deux capteurs capacitifs (faits d'un sandwich de feuilles d'alu et papier de 5cm de côté)

P1060976

Partager cet article
Repost0
21 mai 2012 1 21 /05 /mai /2012 11:56

Juste pour donner une idée de comment l'allumage des LED est fait en fonction de l'heure, voici le code de calcul de la matrice (avec le cadrant V3):

 

//matrice calculée. Chaque byte est une ligne de la matrice.

//Chaque bit est une LED de la ligne.

byte row[8];

 

/*

* calcul de la matrice h: heures, m:minutes, s:secondes (inutilisé)

*/

void calcMatrix(byte h, byte m, byte s){
  boolean cha=false;
  for(byte r=0;r<8;r++){
     row[r]=0;
  }
 
  //dian (heure)
  if(!(m==0 && (h==0 || h==12))){
    row[2] |= B00001000;  
  }  
 
  //cha (moins)
  if(m==45 || m==50 || m==55){
    row[2] |= B00000001;
    h++;
    if(h==24){
        h=0;
    }        
    cha=true;
  }

  //yeli (la nuit)
  if(h>=1 && h < 5){
    row[0] |= B00000011;
  }
 
  //zaoshang (tôt le matin)
  if(h>=5 && h < 8){
    row[0] |= B10100000;
  }
  //shangwu (tard le matin)
if(h>=8 && h <= 11){
    row[0] |= B00100100;
  }  
  //zhongwu (midi)
  if(h>=12 && h<14){
    row[0] |= B00001100;
  }    
  //xiawu (après-midi)
  if(h>=14 && h<18){
    row[0] |= B00010100;
  }
  //wanshang (soir)
  if(h>18){
    row[0] |= B01100000;
  }
  //wuye (minuit)
  if(h==0){
    row[0] |= B00000110;
  }
  //10h
  if((h>=10 && h < 12) ||(h>=22)){
    row[1] |= B01000000;
  }
  //0h
  if(h==0){
    row[1] |= B10000000;
  }
  //1h
  if(h==1 || h==11 | h==13 || h == 23){
    row[1] |= B00010000;
  }
  //2h
  if(h==2 || h==14){
    row[1] |= B00001000;
  }
   //3h
  if(h==3 || h==15){
    row[1] |= B00000100;
  }
  //4h
  if(h==4 || h==16){
    row[1] |= B00000010;
  }
  //5h
  if(h==5 || h==17){
    row[1] |= B00000001;
  }
  //6h
  if(h==6 || h==18){
    row[2] |= B10000000;
  }
  //7h
  if(h==7 || h==19){
    row[2] |= B01000000;
  }
  //8h
  if(h==8 || h==20){
    row[2] |= B00100000;
  }
  //9h
  if(h==9 || h==21){
    row[2] |= B00010000;
  }
 
  //zhong (heure pile)
  if(m==0 && h!=0 && h!=12){
    row[2] |= B00000100;
  }
  //ban (demi-heure)
  if(m == 30){
    row[2] |= B00000010;
  }
 
  //minutes

  //shi (dizaines de minutes)
  if((m>=10 && m!=15 && m!=45 && m!=30 && m!=50 && m!=55) || (m==50 && cha)){
   row[3] |= B00000010;
  }
  //d1
  if(m==45 || m==15){
    row[3] |= B10000000;
  }
  //d2
  if(m>=20 && m<30){
    row[3] |= B01000000;
  }
  //d3
  if(m>=30 && m<40 && m!=30){
    row[3] |= B00100000;
  }  
  //d4
  if(m>=40 &&  m!=45 && m<50){
    row[3] |= B00001000;
  }
  //d5
  if(m>50 && m != 55){
    row[3] |= B00000100;
  }
 
  //ke (quart d'heure)
  if(m==15 || m==45){
    row[3] |= B00010000;
  }
  //1
  if(m%10 == 1){
    row[3] |= B00000001;
  }
  //2
  if(m%10 == 2){
    row[4] |= B10000000;
  }
  //3
  if(m%10 == 3){
    row[4] |= B01000000;
  }
  //4
  if(m%10 == 4 && m!=45){
    row[4] |= B00100000;
  }
  //5
  if((m%10 == 5 && m!=15 && m!=45 && m!=55) ||(m==55 && cha)){
    row[4] |= B00010000;
  }
  //6
  if(m%10 == 6){
    row[4] |= B00001000;
  }
  //7
  if(m%10 == 7){
    row[4] |= B00000100;
  }
  //8
  if(m%10 == 8){
    row[4] |= B00000010;
  }
  //9
  if(m%10 == 9){
    row[4] |= B00000001;
  }  
}

Partager cet article
Repost0
20 mai 2012 7 20 /05 /mai /2012 22:50

J'ai profité d'une semaine de 3 jours de boulot pour bien avancer l'horloge.

J'avais hâte d'essayer l'afffichage.

J'ai dû commencer par déterminer le brochage de la mini-matrice BL-M07C881 car manifestement il ne correspond pas à la datasheet!

Comme je l'ai indiqué sur le forum d'Adafruit, le brochage déterminé manuellement  est, avec la matrice (LED) faisant face à l'utilisateur:

Cx: colonne x

Lx: ligne x

 

C8 C7 L2 C1 L4 C6 C4 L1


L5 L7 C2 C3 L8 C5 L6 L3
(face imprimée en bas)

J'ai câblé cette matrice sur une autre breadboard et sorti 2 connecteurs pour respectivement les colonnes et les lignes (cathodes).

Restait plus qu'à câbler le Max7219

 

Aujourd'hui j'ai passé une bonne partie de la journée à développer le code qui tranforme une heure en une série de LED allumées.

Pour cela j'utilise la fantastique librairie LedControl.

Le plus gros du travail consiste alors à déterminer les règles d'allumage de chaque LED.

J'initialise un tableau de 8 bytes (même si je n'utlise que 5 lignes sur 8 pour mon horloge).

Chaque byte est une ligne de la matrice.

Mes règles d'affichage font des OR pour mettre à 1 les bits correspondants aux LED à allumer selon l'heure.

Une fois la matrice calculée j'ai une boucle qui pour chaque ligne appelle la fonction setRow(0,row,value) de LedControl.

Simple!

 

D'ailleurs c'est en codant mes règles d'allumage de LED que je me suis aperçu que mon cadrant avait un problème: il y manquait 'minuit'! J'ai donc remplacé les 2 caractères inutilisés qui indiquaient le nom de l'horloge, par ceux utilisés pour dire minuit (les 2 premiers caractères de la seconde ligne, et ça se lit 'banne yé', littérallement, "le milieu de la nuit').

 

L'intégration du code de pilotage de la matrice de LED au reste du code de l'horloge est en cours et j'ai pas mal de changements par rapports à mes projets initiaux, mais ça commence à fonctionner.

Voici par exemple une photo prise à 9h37 du soir.

La première ligne indique "il est, le soir", la troisième "9 heures", la quatrième "30" et la cinquième "7":

P1060974.JPG

 

Le Max7219 brouille complètement la réception DCF77!

Je vais voir de combien je dois éloigner le circuit pour que ça fonctionne.

Sinon, comme me l'a suggéré une personne rencontrée sur le forum Arduino dont j'aurai certainement l'occasion de reparler je n'activerais la réception DCF77 que lorsque l'horloge sera en mode veille.

 

Je pilote l'intensité des LED depuis l'info de luminosité captée par la LDR.

L'étalonnage a l'air pas trop mal. Faudra affiner une fois la vraie matrice construite et en condition d'éclairage réelles (c'est à dire dans mon salon).

 

J'ai aussi intégré le détecteur de mouvement à infra-rouge.

Il permet d'éteindre l'horloge (et plus tard de mettre le micro-contrôleur en sommeil) quand aucun mouvement n'a été détecté dans la pièce pendant un certain temps.

 

J'ai fait une petite vidéo pour montrer l'affichage en action.

C'est avec la première version du mini-cadrant, celle qui m' a permis de détecter qu'il y manquait 'minuit'.

La vidéo montre à une cadence accélérée (.5s pour 1s) les heures entre 12h et 13h:

http://www.youtube.com/watch?v=2WQThQBpPCY


 
Partager cet article
Repost0
17 mai 2012 4 17 /05 /mai /2012 22:12

Aujourd'hui j'ai assemblé le kit d'horloge RTC reçu de chez Adafruit.

J'utilise la librairie RTClib recommandée, et ça marche tout seul.

 

Restait à utiliser l'heure reçue via le module DCF77 pour mettre à l'heure l'horloge.

Ca n'a pas posé trop de problème, si ce n'est des includes et symboles à définir pour le compilateur C (les mêmes que pour le compilateur C++) car la librairie RTCLib utilise Wire, qui elle-même dépend d'un morceau écrit en C.

 

Il me faut maintenant modifier le logiciel pour affiner tout ça, et en particulier ajouter une source d'interruption toutes les secondes (via le Timer 2) qui va gérer la mise à jour de l'affichage et la synchro de l'horloge.

 

La breadboard se remplit peu à peu:

2012 05 17 4198

Partager cet article
Repost0
16 mai 2012 3 16 /05 /mai /2012 22:11

Un récepteur DCF77 se trouve pour une dizaine d'euros, plus frais de port.

J'avais lu quelque part qu'on peut trouver chez les soldeurs des horloges radio-pilotées pour moins cher que ça et en récupérer le récepteur DCF77.

 

Je suis donc passé chez un soldeur et j'y ai trouvé une "station météo", enfin une horloge-thermomètre radio-pilotée, pour 7€, soit moins que le prix d'un récepteur DCF77!

Bon je dirais "thermomètre" avec des guillemets car il y a 1° d'écart entre la sonde intérieure et extérieure quand elles sont côte à côte, et autant avec un autre thermomètre de référence... Bref un truc qui vaut le prix qu'il coûte!

 

J'ai donc ouvert la chose et:

 

2012 05 15 4016

Je ne pouvais espérer mieux. Le récepteur DCF77 est sur une breakout-board et le brochage est même indiqué sur le circuit imprimé!

 

Un petit coup de pompe à dessouder plus tard, et le circuit est sur ma breadboard:

 

2012 05 16 4015

C'est là que les choses se compliquent.

 

Après avoir essayé 3 librairies de décodage du signal DCF77 j'opte pour Funkurh.

Elle a l'avantage d'utiliser les interruptions (mais pas tout à fait comme je le souhaiterais).

J'essaie différents trucs, rien à faire...

Heureusement je trouve cet article qui propose un mini-oscilloscope pour vérifier la réception du signal DCF77.

Je vois que la réception est effectivement très dépendante de l'oritentation de l'antenne!

Après avoir trouvé le bon réglage et fait quelques modification à la librairie Funkurh, j'obtiens enfin l'heure transmise!

Il faut plusieurs minutes pour recevoir une trame correcte, mais ça marche.

 

J'ai dû modifier la librairie pour ne pas inverser le signal d'entrée (le récepteur utilisé par le développeur de la librairie nécessite un transistor pour amplifier le signal de sortie, ce qui l'inverse au passage).

 

Je l'ai aussi modifiée pour:

-Utiliser l'interruption INT0 non seulement pour détecter les fronts du signal reçu, mais aussi pour le décoder. Ce décodage est inialement fait dans la fonction getTime et je ne souhaite l'appeler que quand j'en ai besoin, et non toutes les millisecondes ou presque.

-J'ai aussi supprimé l'utilisation du TIMER 2 car d'une part j'ai besoin de ce timer pour un autre usage, et d'autre part je n'ai pas besoin de connaitre les secondes (et si j'en ai besoin j'ai une horloge RTC).

 

Voilà pour le radio-pilotage.

Prochaine étape, l'intégration de l'horloge RTC.

Partager cet article
Repost0
8 mai 2012 2 08 /05 /mai /2012 21:28

L'horloge a pas mal avancé depuis deux jours.

J'ai fait des essais de capteurs capacitifs sans contact, très concluants, qui feront l'objet d'un billet plus tard.

 

J'ai aussi reçu les leds, commandées en gros pour pas cher du tout sur ebay, et avant de construire la matrice j'ai voulu faire un essai pour voir ce que ça donnait, avec une seule cellule de la future matrice. Et bien m'en a pris.

 

Ces leds sont très lumineuses, mais hélas bien trop directrices, et le résultat n'est pas vraiment joli avec un point rouge très lumineux:

 

2012 05 08 4011

 

J'ai essayé plusieurs couches de papier calque, en vain. Reste une solution: rendre les leds diffusantes en les dépolissant.

Direction la perceuse à colonne:

2012 05 08 4013C'est très efficace et en y allant doucement en une petite minute on arrive à une led couleur d'opale.

 

Le résultat est infiniment mieux, avec une lumière bien plus homogène:

2012 05 08 4012

Bien! Plus que 39 leds à dépolir.

 

J'ai dû mettre 3 couches de transparent pour avoir un fond noir suffisamment opaque, mais une impression par un pro devrait me permettre de n'avoir qu'une ou deux couches.

 

Y'a plus qu'à terminer le traçage de la matrice de leds et entammer la construction.

Partager cet article
Repost0