Samedi, juillet 16 2011

Projet DataLogger pour vélo

Encore un projet dans les cartons. Concevoir un petit enregistreur me permettant de stocker sur une carte SD plusieurs paramètres lorsque je fais des sorties à vélo. Je souhaiterai enregistrer:

  • La date / heure
  • La position GPS
  • La vitesse
  • Le cap
  • la cadence de pédalage
  • l’accélération X Y et Z
  • la température
  • Le rythme cardiaque
L’ensemble des données sont récupérées / calculées par un Atmega 328 embarquant du code Arduino. Les données sont ensuite enregistrées sur carte SD et présentées en temps réel sur l’écran.

Voilà un schéma de principe du système. 

Samedi, juillet 9 2011

Utiliser un arduino comme programmeur ISP

L'arduino est devenu le microcontroleur[1](µC) à tout faire. De part sa communauté, de nombreuses bibliothèques et programmes sont proposés et disponibles pour nombre d'utilisations. Nous allons aujourd'hui en découvrir une un peu particulière. Nous allons apprendre à (re)programmer un autre microcontroleur à l'aide d'un arduino.

Charger un programme dans un arduino est très simple, cela grâce au bootloader chargé dans l'ATmega. Basiquement, ce petit programme exécuté au démarrage de votre arduino récupère le code via la liaison usb et programme l'ATmega de la carte[2]. Si rien ne lui est envoyé, alors il démarre le programme déjà présent dans la mémoire flash. Le bootloader ou le programme à exécuter sont stockés dans 2 zones mémoires différentes.

Seulement il peut arriver que ce bootloader soit cassé[3] ou ne soit pas présent[4]. De plus, un certain nombre de µC ne peuvent pas héberger de bootloader. Dans ce cas, il faut les programmer autrement. On utilise alors un programmeur qui se charge de cette tâche.

Les µC d'atmel disposent en général d'une fonction très utile : l'ISP (In-System Programming). Celle-ci permet de les reprogrammer à l'aide de 4 fils, alors qu'ils sont déjà dans un montage. Nous allons utiliser cette fonction pour reprogrammer notre arduino.

Exemple avec un ATtiny45

Commençons par programmer un simple petit ATtiny45 (cible) à l'aide d'un arduino Duemilanove (programmeur).

Il nous faut d'abord utiliser le sketch ArduinoISP présent dans les exemples fournis avec l'IDE de l'arduino. Vous pouvez aussi le télécharger sur le site mega-isp. Compilez le et chargez le dans l'arduino.

Note: par défaut la vitesse utilisée lors de la (future) programmation de la cible est de 19200bps, vous pouvez changer cela dans le code, mais il faudra alors penser à reporter cette valeur dans les commandes de programmation.

Depuis la version Diecimila les arduino intègrent une fonction d'auto-reset qui permet de redémarrer la carte (et donc lancer le bootloader) quand une communication série débute[5]. C'est très utile pour programmer l'arduino, mais cela va nous poser problème ici. Nous devons donc le désactiver. Pour notre version Duemilanove, le plus simple et le moins intrusif est de relier le reset au +5V par une résistance de 120ohms, ce qui maintiendra le reset à l'état haut[6]. Je vous laisse voir le site officiel pour les autres méthodes.

Ensuite, nous relions les différentes pattes nécessaires pour la programmation ISP :

Arduino     ATTiny45  Fonction
  10           1       reset 
  11           5       MOSI
  12           6       MISO
  13           7       SCK

Référez vous à la datasheet de votre µC pour connaitre les pattes à relier.

Enfin, le sketch ArduinoISP utilise 3 leds d'état que vous relierez à la masse via une résistance adéquate[7].

Arduino    led (anode)
   7       jaune: programation en cours
   8       rouge: erreur
   9       vert : heartbeat

Voici le schéma du montage sur plaque à essai :

montage montage

Vous pouvez ignorer la led verte de gauche, elle ne sert qu'a tester le programme chargé.

Enfin, vient le moment tant attendu, vous pouvez connecter l'arduino à l'USB et programmer votre ATtiny en utilisant avrdude :

avrdude -V -p t45 -c avrisp  -b 19200 -P /dev/ttyUSB0 -U flash:w:led.hex

Quelques mots sur les options (voyez la doc pour les détails) :

  • -p t45 : pour dire que l'on programme un ATtiny45
  • -c avrisp : le type de programmeur utilisé
  • -b 19200 : la vitesse de la liaison (à changer éventuellement en fonction du code de ArduinoISP)
  • -P /dev/ttyUSB0 : le port sur lequel est connecté votre arduino
  • -U flash:w:led.hex : on écrit (w) dans la flash le programme compilé led.hex

Et voila, selon votre programme de test, la led devrait commencer à clignoter.

Programmer un arduino à partir d'un arduino

Attention: Pour pouvoir programmer plus de 256 octets (ce qui va être nécessaire pour la suite), il vous faut utiliser ArduinoISP de l'IDE version 22 minimum, ou utiliser les sources prises sur mega-isp vues ci-dessus. C'est un bug connu de l'IDE 21

Nous allons reprogrammer le bootloader de l'arduino. On peut avoir de nombreuses raisons de faire cela: pour le réparer, pour préparer un nouveau µC, pour le remplacer par une version plus efficace. Dans mon cas, c'est cette dernière opération que je veux réaliser. Le bootloader du Duemilanove, empêche l'utilisation du watchdog dans les programmes. On trouve la correction dans des bootloader alternatifs[8] ou dans celui de l'arduino UNO (optiboot). Ce dernier étant compatible avec la majorité des versions précédentes, nous allons donc l'utiliser. Ceci impliquera de choisir Arduino Uno dans le menu Board de l'IDE lors des prochaines programmation, puisque le bootloader sera celui de l'Uno. Je vous conseille d'y coller une étiquette pour ne pas l'oublier.

Notre arduino programmeur sera préparé de la même manière que ci-dessus, c'est-à-dire qu'on lui chargera le sketch ArduinoISP. On le connecte alors vers les pattes ISP de notre arduino cible. On peut utiliser soit le connecteur ICSP soit relier directement aux connecteurs femelle sur lesquels on branche habituellement les shields.

Note: On peut aussi se contenter d'un seul arduino (programmeur) et utiliser une plaque à essai pour simuler le 2ème. Dans ce cas, les différentes options sont décrites sur le site officiel.

Voyez ci-dessous les connexions à établir.

arduino isp to arduino montage

La cible doit être alimentée. Vous pouvez faire cela via l'USB, mais je le déconseille ainsi, vous n'aurez qu'un seul /dev/ttyUSBx et c'est un risque d'erreur en moins. Utilisez plutôt l'entrée VIN de l'arduino à programmer.

Il ne nous reste plus qu'à utiliser l'IDE pour flasher la cible.

  • choisir ce que vous allez programmer dans le menu Tools / Board :
    • UNO pour avoir l'optiboot
    • ou bien duamilanove avec atmega328
    • ou autre chose suivant votre modèle d'arduino
  • puis Tools / Burn Bootloader / w/Arduino as ISP

Note: Si vous avez changé la vitesse dans le sketch ArduinoISP, il vous faudra mettre à jour le paramètre arduinoisp.speed présent dans le fichiers programmers.txt[9], soit directement, soit en le surchargeant via votre fichier preferences.txt[10]

Nous pouvons aussi utiliser avrdude pour faire cela à l'ancienne. il suffit d'enchainer les 3 commandes suivantes, voir de les regrouper en une seule[11]

Vous trouverez les valeurs de fuses et les fichiers de bootloader dans le fichier texte boards.txt de votre installation[12]. Les différents fichiers hex du bootloader sont dans un sous répertoire bootloaders[13]. Rappelons que les commandes suivantes s'appliquent pour programmer un optiboot sur un arduino Duemilanove.

La 1ère action est de débloquer l'accès au bootloader :

avrdude -p m328p -P /dev/ttyUSB0 -c avrisp -b 19200 -e -U lock:w:0x3F:m

Ensuite, il faut flasher le bootloader :

avrdude -p m328p -P /dev/ttyUSB0 -c avrisp -b 19200 -D -U flash:w:optiboot_atmega328.hex

notons que vous pouvez relire le fichier flashé ainsi :

avrdude -p m328p -P /dev/ttyUSB0 -c avrisp -b 19200 -D -U flash:r:read.hex:i

et enfin rebloquer l'accès au bootloader :

avrdude -p m328p -P /dev/ttyUSB0 -c avrisp -b 19200 -U lock:w:0x0F:m

Programmer directement un arduino (Bitbang FT232)

Note: Je n'ai pas personnellement utilisé cette technique, ce que vous vous apprêtez à lire n'est donc que ma compréhension résultant de mes lectures. Cela-dit de nombreux témoignages existent sur sa viabilité et elle est visiblement beaucoup utilisée.

Une autre méthode pour reprogrammer le bootloader de votre arduino est la technique dite BitBang. Elle utilise un mode particulier du chipset FTDI présent sur les arduino. Ce mode permet de jouer directement avec les pattes de sorties du chipset et ainsi de l'utiliser pour simuler un programmeur ISP.

Le principe est donc de relier les pattes du FTDI au connecteur ICSP de l'arduino. pour cela il vous faudra souder une barette sur les trous 1 à 4 nommés X3 sur votre arduino. Puis d'établir les connexions nécessaires avec le connecteur ICSP dont nous avons déjà parlé.

La deuxième étape est de patcher avrdude pour lui ajouter un nouveau programmeur[14]. Et enfin de reprogrammer celui-ci avec avrdude en lui donnant le bon fichier .hex à manger.

L'énorme avantage de cette méthode est bien entendu que vous n'avez besoin que d'un seul arduino, et qu'il peut donc se reprogrammer lui-même. Les inconvénients sont que vous devez souder sur votre arduino et utiliser un autre avrdude que celui fournit avec l'environnement de programmation standard.

Pour plus de détails, je vous renvoi vers les liens suivants :

Un vrai programmeur

Pour autant que ces techniques soient amusantes leur mise en place et utilisation devient vite assez lourde. Cela est très bien pour un besoin ponctuel, mais pour une utilisation régulière, je ne saurais trop vous conseiller d'acheter un vrai programmeur de µC. Pas besoin de dépenser des centaines d'€ pour cela. On trouve facilement des programmeur ISP pour pas cher. Notons en particulier le USBtinyISP de LadyAda[15]. Une simple recherche avec stk500 ou avrisp vous renverra aussi une foultitude de résultats sur un site d'enchères bien connu.

Ainsi, vous économiserez un arduino et vous vous simplifierez la vie. Plus rapides, plus sur et plus transportables, ils ont tout pour plaire. Il ne vous reste alors qu'à prévoir un connecteur ISP sur vos montages et hop. On peut aussi réaliser un petit adaptateur comme ci-dessous pour l'utiliser facilement sur une plaque à essais.

montage

Voila, félicitations aux courageux qui sont arrivés jusqu'ici, et si vous avez des questions ou des remarques, les commentaires sont ouverts[16].

Notes

[1] oui, je sais c'est plus qu'un µC (régulateur, liaison usb ...)

[2] ie: charge le code dans la mémoire fash

[3] par une fausse manip

[4] cas d'un atmega neuf

[5] basé sur le passage de DTR au niveau bas

[6] il est actif à l'état bas, vous l'aurez compris

[7] 330ohms pour mes leds

[8] tel celui de ladyAda

[9] dans /usr/share/arduino/hardware/arduino/ chez moi

[10] dans ~/.arduino

[11] en gardant le même ordre pour les options -U

[12] chez moi dans /usr/share/arduino/hardware/arduino/

[13] soit /usr/share/arduino/hardware/arduino/bootloaders/ chez moi

[14] à utiliser via l'option -c

[15] je vous jure, que je n'ai pas d'actions chez AdaFruit !

[16] Je ne pouvais pas finir sans une dernière note de bas de page :)

Dimanche, juin 19 2011

Horloge multifonction (1ère partie)

Voici un projet qui est dans mes cartons depuis maintenant pas mal de mois et qui arrive enfin à un niveau de finition montrable. Le temps que j’y consacre est inversement proportionnel au temps passé à jouer sur console, ce qui en explique l’avancée laborieuse.

L’idée est d’avoir une horloge autonome multifonction utilisant un double afficheur led de 24x16 … J’avais déjà parlé de ces afficheurs lors d’un post précédent: achetés chez SureElectronics pour une bouchée de pain (14$), ils sont très bien finis, un peu inégaux au niveau de l’intensité des leds, mais globalement d’un excellent rapport qualité/prix.

Du point de vue fonctionnalité de l’horloge, il y a évidemment l’heure, la date mais aussi la température et l’humidité relative.

Je voulais aussi une horloge sympa niveau design qui n’ai pas trop l’air d’être un proto fait sur un breadboard à la va-vite. Je me suis donc procuré une plaque de plexi dans laquelle j’ai découpé une face avant et une arrière. Pour éviter les vis et boulons en façade, je me suis pris un kit de tarauds pour visser les tiges filetées directement dans le plexi sans qu’elles ressortent à l’avant … 

  Je n’avais jamais taraudé avant cela, mais finalement c’est simple et le résultat est très propre et solide. J’ai pris 1m de tige filetée que j’ai découpé pour avoir mon afficheur, le circuit et l’arduino pris en sandwich entre la face avant et la face arrière. La face arrière n’est pas encore placée actuellement, mais voici ce que donne la fixation de l’afficheur sur la face avant :

Pour surélever l’afficheur, j’ai découpé des petites sections de tube en alu afin d’éviter de voir le filetage. De plus, cela me permet d’avoir une distance fixe entre le plexi et le circuit imprimé. J’ai placé en tout 4 fixations par afficheur pour être certain que rien ne bouge au final. 

Pour ce qui est de la partie électronique:

  • un arduino comme élément central.
  • un DS1307 pour assurer une base de temps relativement solide et éviter de perdre l’heure en cas de coupure de courant.
  • un DC-SS500 de chez sure electronics pour la température et l’humidité
  • une photorésistance pour régler l’intensité de l’afficheur en fonction de l’éclairage ambiant.
  • un RFM12B pour la communication externe.

La communication externe n’est pas encore présente actuellement mais la place du chip est réservée sur le circuit. 

L’afficheur led est géré grâce à la librairie de Miles Burton que vous pouvez trouver ici. Son utilisation est simple et peut contrôler jusqu’à 4 afficheurs chaînés. Sur ce projet, je n’en ai que 2 chaînés et 4 fils sont utilisés : clock, data, CS1, CS2 … ainsi que l’alimentation, évidemment. J’ai juste fait quelques ajouts à la librairie pour avoir des fonts de taille double, vu que je compte pouvoir configurer le type d’affichage dans le futur. 

Voici le schéma complet du circuit (cliquez dessus pour l’avoir en plus haute définition) :

 

  Le tout a été monté sur un petit circuit expérimental, mais vu la simplicité du cablage, cela me semblait acceptable comme solution : 

L’arduino et le circuit sont posés sur du tape double face qui les maintiens en place mais surtout les isole des afficheurs.

Actuellement, l’heure est affichée en permanence sur la première ligne de texte, et sur la deuxième ligne, on a le jour/la date, l’humidité et la température en alternance. Le code est encore très expérimental … dès que celui-ci sera un peu plus finalisé, je le posterai.

Une fois la partie RF connectée, je compte faire communiquer l’horloge avec le reste de mes circuits. Je pourrai tracer les variations de température, humidité et luminosité sur mon poste central, et je pourrai aussi envoyer de commandes à l’horloge, telles que : 

  • remise à l’heure
  • changement d’affichage
  • message personnalisé 

A suivre dans un prochain post.

Mardi, juin 14 2011

Lecture de bandes magnétiques

CML'autre jour dans le train, je lisais Open Silicium #2 et j'ai été effaré de lire que le numéro de carte bancaire se retrouvait sur la bande magnétique des billets SNCF. Ni une, ni deux, uns fois mes pénates retrouvées, j'ai voulu en avoir le cœur net !

Ne voulant pas acheter un lecteur de carte, je me suis intéressé à la méthode Batagllia présentée au paragraphe 2.1 Le principe est simple, on utilise une tête de lecture telle qu'on en trouve dans les lecteurs de K7 audio, sur laquelle on soude une prise jack elle-même branchée sur l'entrée micro d'une carte son. Un logiciel se charge alors d'interpréter le signal reçu en données intelligibles. L'auto-radio que j'avais au fond de mes cartons étant un CD, je me suis tourné vers la fausse K7 que j'utilise pour brancher mon lecteur MP3 dans la voiture.

Je ne vais pas détailler le processus entier, je vous renvoi plutôt vers une série de liens en fin d'article, outre bien sur Open Scilicium déjà cité. Vous pouvez aussi regarder la vidéo suivante.

Côté résultats, la lecture de cartes marche plutôt bien. J'ai réussit à lire des données sur toutes celles que j'ai essayés : carte bancaire, tickets de parking, cartes de fidélité, cartes d'accès etc... Il faut quand même attraper le coup de main pour passer la tête de lecture à la bonne vitesse.

CMQuand aux billets de train, j'ai eu plus de mal, plusieurs lectures donnant parfois des résultats différents. J'ai tout de même réussit à voir pas mal d'informations telles que les gares de départ et d'arrivée, le prix, le numéro de train etc...

Par contre, pas de numéro de carte bleue ! Bonne nouvelle ! Soit les données sont déjà perdues (bande LoCo), soit elles ne sont pas présentes sur tous les type de billets. Ceux de mes tests ayant été acheté via internet et livrés à la maison.

Voila, un petit hack simple et facile, mais il est toujours amusant de regarder ce que l'on n'est pas censés voir ;)

Liens

Mercredi, mai 11 2011

Arduino – Un petit SpaceInvader

Hier j’ai reçu un petit shield LCD couleur pour mon Arduino que j’avais commandé. Il s’agit d’un modèle avec un écran nokia de 128x128pixels, et 3 boutons en façade.

Shield LCD pour Arduino

Shield LCD pour Arduino

Comme je suis quelqu’un d’assez impatient, j’ai voulu tester au plus vite ce petit joujou :) . Déjà, point assez agréable, quelqu’un a déjà fourni un travail remarquable et une librairie toute prête permet d’effectuer les affichages de base (pixel, ligne, rectangle, texte, etc…). Vous pourrez la trouver ici.

Mes premières impressions tout d’abord : bah ça reste un écran d’ancienne génération de téléphone portable, avec les défauts qui vont avec : très mauvais rendu des couleurs, angle de vision particulièrement limité, et vitesse…. euhhhh…. lente ;)
Mais bon, pour le prix, ça reste un petit affichage tout à fait correct, et on arrive a faire des petites choses marrantes avec.
Le positionnement des boutons m’as fait penser à une manette de jeux, avec gauche/droite et tir…. ce qui m’a donné envie d’essayer de faire un petit space invader, histoire de voire quelles performances je pouvais tirer d’un arduino pour ce type d’applications.
Au passage, un grand merci à Julien qui m’a permis d’améliorer ma compréhension de la programmation objet, et grâce à qui le code fourni est un peu plus propre ;) (J’ai pas encore tout nettoyé, mais promis la v2 sera plus propre ;) )

Space invader sur arduino

Space invader sur arduino

Le jeu est jouable, aves les ennemis qui bougent et la détection des collisions qui est fonctionnelle. Par contre il manque l’affichage des scores et quelques détails….
A priori, l’arduino arrive à gérér ça sans trop ramer, ce qui permet d’envisager quelques petites améliorations.

Le code source du projet

Ps : le code source est libre (domaine public)

Arduino – Un petit SpaceInvader

Hier j’ai reçu un petit shield LCD couleur pour mon Arduino que j’avais commandé. Il s’agit d’un modèle avec un écran nokia de 128x128pixels, et 3 boutons en façade.

Shield LCD pour Arduino

Shield LCD pour Arduino

Comme je suis quelqu’un d’assez impatient, j’ai voulu tester au plus vite ce petit joujou :) . Déjà, point assez agréable, quelqu’un a déjà fourni un travail remarquable et une librairie toute prête permet d’effectuer les affichages de base (pixel, ligne, rectangle, texte, etc…). Vous pourrez la trouver ici.

Mes premières impressions tout d’abord : bah ça reste un écran d’ancienne génération de téléphone portable, avec les défauts qui vont avec : très mauvais rendu des couleurs, angle de vision particulièrement limité, et vitesse…. euhhhh…. lente ;)
Mais bon, pour le prix, ça reste un petit affichage tout à fait correct, et on arrive a faire des petites choses marrantes avec.
Le positionnement des boutons m’as fait penser à une manette de jeux, avec gauche/droite et tir…. ce qui m’a donné envie d’essayer de faire un petit space invader, histoire de voire quelles performances je pouvais tirer d’un arduino pour ce type d’applications.
Au passage, un grand merci à Julien qui m’a permis d’améliorer ma compréhension de la programmation objet, et grâce à qui le code fourni est un peu plus propre ;) (J’ai pas encore tout nettoyé, mais promis la v2 sera plus propre ;) )

Space invader sur arduino

Space invader sur arduino

Le jeu est jouable, aves les ennemis qui bougent et la détection des collisions qui est fonctionnelle. Par contre il manque l’affichage des scores et quelques détails….
A priori, l’arduino arrive à gérér ça sans trop ramer, ce qui permet d’envisager quelques petites améliorations.

Le code source du projet

Ps : le code source est libre (domaine public)

Dimanche, mai 8 2011

Arduino – Horloge binaire DIY – Part 1

Oui, je sais, ça faisait longtemps que je n’avais pas présenté de schéma. Et pour cause : je me bat avec celui-ci depuis presque 1 mois ! Au point que j’ai décidé de vous le publier en 2 parties ;)
Rassurez vous, la partie que je vais vous présenter est tout à fait fonctionnelle, mais je voulais vous présenter un joli projet fini, sous la forme d’un shield Arduino, (et éventuellement vous proposer un kit), mais je galère pas mal avec les prototypes…. (encore une fois, je me rend compte qu’il ne faut pas négliger les caractéristiques physiques des composants ;) )

Bref, voici donc une horloge à LED binaire fonctionnant avec un arduino

Horloge binaire - prototype

Horloge binaire - prototype

Pour ceux qui ne connaissent pas les horloges binaires, il s’agit de représenter les heures – minutes – secondes sous leurs équivalents en binaire, ce qui permet d’afficher l’heure grace à une rangée de LED.  Concernant l’affichage, il y a deux écoles : soit on affiche directement la conversion binaire pour chaque membre de l’heure, par exemple pour 10:00:45, on afficherais 101101 (soit 45 en binaire) pour les secondes, soit on décompose pour chaque membre les dizaines des unités, ce qui donnerais pour l’exemple précédent 100 et 101 (soit respectivement 4 et 5). C’est cette dernière méthode que j’ai choisi car elle permet de lire l’heure un peu plus simplement.

Je voulais une horloge relativement fiable, je ne me suis donc pas basé sur l’horloge interne de l’arduino, mais plutôt sur une base de temps externe à 1Hz, à base de quartz d’horlogerie.

Schéma horloge binaire

Schéma horloge binaire

R1 = 1Mo
R2 = 220Ko
C1 et c2 = 39pf
C3 = 100pf
Q1 = 32,768 KHz

Voici pour la partie matérielle, je vous met également les sources de mon code Arduino :

Code source horloge binaire

/*
Horloge binaire
Utilise 3 74HC595 pour gérer l’affichage Heure minutes secondes
On gère l’affichage sur colonnes separees pour les dizaines et les unites, afin de faciliter la lecture
*/ 

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;

//Pin recevant les ticks d’horloge (1Hz)
const int Clock = 3;

//Pin boutton poussoir reglage heure
const int BouttonH = 7;
const int BouttonM = 6;

//const int MULTIPLEX = 5; //delai de boucle pour le multiplexage en milliseconde
const int MULTIPLEX = 200;
// On garde l’état précédent de la clock : S’il était à 0 et que la clock est à 1, on est sur un nouveau top, sinon, c’est toujours le même top.
int last_state = 0;
int cur_state = 0; //l’etat actuel de la Clock
int demisec = 0;
int increment = 0; //s’il faut incrémenter le compteur, increment vaut 1.

//On gère les dizaines et les unités séparement car elles ne font pas parties de la meme colonne d’affichage.
int HeureD = 0;
int HeureU = 0;
int MinuteD = 0;
int MinuteU = 0;
int SecondeD = 0;
int SecondeU = 0;

//Variables pour les conversion binaires
int bSecondeD = 0;
int bSeconde = 0;
int bMinuteD = 0;
int bMinute = 0;
int bHeureD = 0;
int bHeure = 0;

//Variables d’etat des boutons
int sBouttonH = 1; //etat du boutton de reglage heure (1 = relache)
int clkBouttonH = 0; //on memorise depuis combien de top est appuyé le bouton
int sBouttonM = 1;
int clkBouttonM = 0;

//variable pour le multiplexage :
// on n’eclaire pas toutes les leds en meme temps, on le fait bloc par blog (HH, puis MM, puis SS)
int multiplex = 0;

//Variable de debug : Si debug = 1, alors on active le port serie.
int debug = 1;

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(Clock, INPUT);
pinMode(BouttonH, INPUT);
if(debug == 1)
Serial.begin(9600);
last_state = digitalRead(Clock);
}

void loop() {

// est-on sur un nouveau top ?
cur_state = digitalRead(Clock);

//est-ce qu’un boutton est appuyé ?
sBouttonH = digitalRead(BouttonH);
if(sBouttonH == 1)//si le boutton H a ete relache, on remet tout a 0
clkBouttonH = 0;
sBouttonM = digitalRead(BouttonM);
if(sBouttonM == 1)//si le boutton M a ete relache, on remet tout a 0
clkBouttonM = 0;

if(debug == 1)
Serial.println(« debut top »);

if((cur_state == 1) && (last_state == 0)) // Si l’horloge viens de passer à 1, on est sur un top
demisec = demisec++;
if(demisec > 1)
//On a besoin de 2 tops pour une seconde
{
increment = 1; // on va donc pouvoir incrementer le compteur
last_state = cur_state; //on met à jour last_state
//Et on en profite pour vérifier depuis combien de temps le bouton est appuyé
if(sBouttonH == 0)
{
clkBouttonH = clkBouttonH++;
//si Le bouton était déjà appuyé la seconde precedente, alors on incremente.
if(clkBouttonH > 2)
{
//on incremente l’heure
if(HeureU < 11)
HeureU = HeureU++;
if(HeureU == 4 && HeureD == 2) //minuit, on remet tout à 0
{
HeureU = 0;
HeureD = 0;
}
else if(HeureU == 10)
{
HeureD = HeureD++;
HeureU = 0;
}
}
}
//idem pour les minutes
if(sBouttonM == 0)
{
clkBouttonM = clkBouttonM++;
//si Le bouton était déjà appuyé la seconde precedente, alors on incremente.
if(clkBouttonM > 2)
{
//on incremente les minutes
if(MinuteU < 11)
MinuteU = MinuteU ++;
if(MinuteU == 10)
{
MinuteD = MinuteD++;
MinuteU = 0;
}
if(MinuteD == 6) //on ne depasse pas les 60 minutes…
{
MinuteD = 0;
}
}
}

}
else
{
last_state = cur_state; //sinon, on se contente de rafraichir last_state
}

/// Si on doit incrémenter l’horloge :
if(increment == 1)
{

if(SecondeU < 11)
SecondeU = SecondeU ++;
if(SecondeU == 10)
{
SecondeD = SecondeD++;
SecondeU = 0;
}
if(SecondeD == 6)
{
SecondeD = 0; //on remet le compteur des secondes à 0;
if(MinuteU < 11)
MinuteU = MinuteU ++;
if(MinuteU == 10)
{
MinuteD = MinuteD++;
MinuteU = 0;
}

if(MinuteD == 6)
{
MinuteD = 0;
if(HeureU < 11)
HeureU = HeureU++;
if(HeureU == 4 && HeureD == 2) //minuit, on remet tout à 0
{
HeureU = 0;
HeureD = 0;
}
else if(HeureU == 10)
{
HeureD = HeureD++;
HeureU = 0;
}
}

}
//on a finit d’incrementer, on repasse donc le flag increment à 0
increment = 0;
//On repasse demisec = 0
demisec = 0;
//on met à jour l’affichage
if(debug == 1)
{
Serial.print(HeureD);
Serial.print(HeureU);
Serial.print(« : »);
Serial.print(MinuteD);
Serial.print(MinuteU);
Serial.print(« : »);
Serial.print(SecondeD);
Serial.println(SecondeU);
}

//on convertis l’affichage en binaire , de maniere a ce que les dizaines et unites tiennent sur 1 octet
bSecondeD = SecondeD << 4; //decalage a gauche de 4 bit pour les dizaines
bSeconde = bSecondeD | SecondeU;  //OU logique pour « assembler » les dizaines et les unites
bMinuteD = MinuteD << 4;
bMinute = bMinuteD | MinuteU;
bHeureD = HeureD << 4;
bHeure = bHeureD | HeureU;
if(debug == 1)
{
Serial.print(« Binaire Heures:Minutes:Secondes  « );
Serial.print(bHeure,BIN);
Serial.print(« : »);
Serial.print(bMinute,BIN);
Serial.print(« : »);
Serial.println(bSeconde,BIN);
Serial.print(« Etat du bouton Heures : »);
Serial.println(sBouttonH);
Serial.print(« Etat du bouton Minutes : »);
Serial.println(sBouttonM);
}
}
////on envoie l’heure sur le 74HC595
digitalWrite(latchPin, LOW);
//on multiplexe l’affichage

if(multiplex == 0)
{
shiftOut(dataPin, clockPin, MSBFIRST, bHeure);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les secondes
}
if(multiplex == 1)
{
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, bMinute);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les secondes
}
if(multiplex == 2)
{
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, bSeconde);//on envoie les secondes
}
multiplex = multiplex++;
if(multiplex>2)
multiplex = 0;
/*
// shift the bytes out:
shiftOut(dataPin, clockPin, MSBFIRST, bHeure);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, bMinute);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, bSeconde);//on envoie les secondes
*/
digitalWrite(latchPin, HIGH);
if(debug == 1)
{

Serial.print(« multiplex : « );
Serial.println(multiplex);
}

//on attend quelques millisecondes, pour pas saturer l’arduino (surtout utile en cas d’utilisation du port serie)
delay(MULTIPLEX);

}

Arduino – Horloge binaire DIY – Part 1

Oui, je sais, ça faisait longtemps que je n’avais pas présenté de schéma. Et pour cause : je me bat avec celui-ci depuis presque 1 mois ! Au point que j’ai décidé de vous le publier en 2 parties ;)
Rassurez vous, la partie que je vais vous présenter est tout à fait fonctionnelle, mais je voulais vous présenter un joli projet fini, sous la forme d’un shield Arduino, (et éventuellement vous proposer un kit), mais je galère pas mal avec les prototypes…. (encore une fois, je me rend compte qu’il ne faut pas négliger les caractéristiques physiques des composants ;) )

Bref, voici donc une horloge à LED binaire fonctionnant avec un arduino

Horloge binaire - prototype

Horloge binaire - prototype

Pour ceux qui ne connaissent pas les horloges binaires, il s’agit de représenter les heures – minutes – secondes sous leurs équivalents en binaire, ce qui permet d’afficher l’heure grace à une rangée de LED.  Concernant l’affichage, il y a deux écoles : soit on affiche directement la conversion binaire pour chaque membre de l’heure, par exemple pour 10:00:45, on afficherais 101101 (soit 45 en binaire) pour les secondes, soit on décompose pour chaque membre les dizaines des unités, ce qui donnerais pour l’exemple précédent 100 et 101 (soit respectivement 4 et 5). C’est cette dernière méthode que j’ai choisi car elle permet de lire l’heure un peu plus simplement.

Je voulais une horloge relativement fiable, je ne me suis donc pas basé sur l’horloge interne de l’arduino, mais plutôt sur une base de temps externe à 1Hz, à base de quartz d’horlogerie.

Schéma horloge binaire

Schéma horloge binaire

R1 = 1Mo
R2 = 220Ko
C1 et c2 = 39pf
C3 = 100pf
Q1 = 32,768 KHz

Voici pour la partie matérielle, je vous met également les sources de mon code Arduino :

Code source horloge binaire

/*
Horloge binaire
Utilise 3 74HC595 pour gérer l’affichage Heure minutes secondes
On gère l’affichage sur colonnes separees pour les dizaines et les unites, afin de faciliter la lecture
*/ 

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;

//Pin recevant les ticks d’horloge (1Hz)
const int Clock = 3;

//Pin boutton poussoir reglage heure
const int BouttonH = 7;
const int BouttonM = 6;

//const int MULTIPLEX = 5; //delai de boucle pour le multiplexage en milliseconde
const int MULTIPLEX = 200;
// On garde l’état précédent de la clock : S’il était à 0 et que la clock est à 1, on est sur un nouveau top, sinon, c’est toujours le même top.
int last_state = 0;
int cur_state = 0; //l’etat actuel de la Clock
int demisec = 0;
int increment = 0; //s’il faut incrémenter le compteur, increment vaut 1.

//On gère les dizaines et les unités séparement car elles ne font pas parties de la meme colonne d’affichage.
int HeureD = 0;
int HeureU = 0;
int MinuteD = 0;
int MinuteU = 0;
int SecondeD = 0;
int SecondeU = 0;

//Variables pour les conversion binaires
int bSecondeD = 0;
int bSeconde = 0;
int bMinuteD = 0;
int bMinute = 0;
int bHeureD = 0;
int bHeure = 0;

//Variables d’etat des boutons
int sBouttonH = 1; //etat du boutton de reglage heure (1 = relache)
int clkBouttonH = 0; //on memorise depuis combien de top est appuyé le bouton
int sBouttonM = 1;
int clkBouttonM = 0;

//variable pour le multiplexage :
// on n’eclaire pas toutes les leds en meme temps, on le fait bloc par blog (HH, puis MM, puis SS)
int multiplex = 0;

//Variable de debug : Si debug = 1, alors on active le port serie.
int debug = 1;

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(Clock, INPUT);
pinMode(BouttonH, INPUT);
if(debug == 1)
Serial.begin(9600);
last_state = digitalRead(Clock);
}

void loop() {

// est-on sur un nouveau top ?
cur_state = digitalRead(Clock);

//est-ce qu’un boutton est appuyé ?
sBouttonH = digitalRead(BouttonH);
if(sBouttonH == 1)//si le boutton H a ete relache, on remet tout a 0
clkBouttonH = 0;
sBouttonM = digitalRead(BouttonM);
if(sBouttonM == 1)//si le boutton M a ete relache, on remet tout a 0
clkBouttonM = 0;

if(debug == 1)
Serial.println(« debut top »);

if((cur_state == 1) && (last_state == 0)) // Si l’horloge viens de passer à 1, on est sur un top
demisec = demisec++;
if(demisec > 1)
//On a besoin de 2 tops pour une seconde
{
increment = 1; // on va donc pouvoir incrementer le compteur
last_state = cur_state; //on met à jour last_state
//Et on en profite pour vérifier depuis combien de temps le bouton est appuyé
if(sBouttonH == 0)
{
clkBouttonH = clkBouttonH++;
//si Le bouton était déjà appuyé la seconde precedente, alors on incremente.
if(clkBouttonH > 2)
{
//on incremente l’heure
if(HeureU < 11)
HeureU = HeureU++;
if(HeureU == 4 && HeureD == 2) //minuit, on remet tout à 0
{
HeureU = 0;
HeureD = 0;
}
else if(HeureU == 10)
{
HeureD = HeureD++;
HeureU = 0;
}
}
}
//idem pour les minutes
if(sBouttonM == 0)
{
clkBouttonM = clkBouttonM++;
//si Le bouton était déjà appuyé la seconde precedente, alors on incremente.
if(clkBouttonM > 2)
{
//on incremente les minutes
if(MinuteU < 11)
MinuteU = MinuteU ++;
if(MinuteU == 10)
{
MinuteD = MinuteD++;
MinuteU = 0;
}
if(MinuteD == 6) //on ne depasse pas les 60 minutes…
{
MinuteD = 0;
}
}
}

}
else
{
last_state = cur_state; //sinon, on se contente de rafraichir last_state
}

/// Si on doit incrémenter l’horloge :
if(increment == 1)
{

if(SecondeU < 11)
SecondeU = SecondeU ++;
if(SecondeU == 10)
{
SecondeD = SecondeD++;
SecondeU = 0;
}
if(SecondeD == 6)
{
SecondeD = 0; //on remet le compteur des secondes à 0;
if(MinuteU < 11)
MinuteU = MinuteU ++;
if(MinuteU == 10)
{
MinuteD = MinuteD++;
MinuteU = 0;
}

if(MinuteD == 6)
{
MinuteD = 0;
if(HeureU < 11)
HeureU = HeureU++;
if(HeureU == 4 && HeureD == 2) //minuit, on remet tout à 0
{
HeureU = 0;
HeureD = 0;
}
else if(HeureU == 10)
{
HeureD = HeureD++;
HeureU = 0;
}
}

}
//on a finit d’incrementer, on repasse donc le flag increment à 0
increment = 0;
//On repasse demisec = 0
demisec = 0;
//on met à jour l’affichage
if(debug == 1)
{
Serial.print(HeureD);
Serial.print(HeureU);
Serial.print(« : »);
Serial.print(MinuteD);
Serial.print(MinuteU);
Serial.print(« : »);
Serial.print(SecondeD);
Serial.println(SecondeU);
}

//on convertis l’affichage en binaire , de maniere a ce que les dizaines et unites tiennent sur 1 octet
bSecondeD = SecondeD << 4; //decalage a gauche de 4 bit pour les dizaines
bSeconde = bSecondeD | SecondeU;  //OU logique pour « assembler » les dizaines et les unites
bMinuteD = MinuteD << 4;
bMinute = bMinuteD | MinuteU;
bHeureD = HeureD << 4;
bHeure = bHeureD | HeureU;
if(debug == 1)
{
Serial.print(« Binaire Heures:Minutes:Secondes  « );
Serial.print(bHeure,BIN);
Serial.print(« : »);
Serial.print(bMinute,BIN);
Serial.print(« : »);
Serial.println(bSeconde,BIN);
Serial.print(« Etat du bouton Heures : »);
Serial.println(sBouttonH);
Serial.print(« Etat du bouton Minutes : »);
Serial.println(sBouttonM);
}
}
////on envoie l’heure sur le 74HC595
digitalWrite(latchPin, LOW);
//on multiplexe l’affichage

if(multiplex == 0)
{
shiftOut(dataPin, clockPin, MSBFIRST, bHeure);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les secondes
}
if(multiplex == 1)
{
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, bMinute);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les secondes
}
if(multiplex == 2)
{
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, 0);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, bSeconde);//on envoie les secondes
}
multiplex = multiplex++;
if(multiplex>2)
multiplex = 0;
/*
// shift the bytes out:
shiftOut(dataPin, clockPin, MSBFIRST, bHeure);//on envoie les heures
shiftOut(dataPin, clockPin, MSBFIRST, bMinute);//on envoie les minutes
shiftOut(dataPin, clockPin, MSBFIRST, bSeconde);//on envoie les secondes
*/
digitalWrite(latchPin, HIGH);
if(debug == 1)
{

Serial.print(« multiplex : « );
Serial.println(multiplex);
}

//on attend quelques millisecondes, pour pas saturer l’arduino (surtout utile en cas d’utilisation du port serie)
delay(MULTIPLEX);

}

- page 1 de 13