Page 2 sur 3

Re: Retour vers le Futur

Posté : mar. 27 janv. 2015 14:02
par Veloce
Ah, bien vu, merci.

Veloce

Re: Retour vers le Futur

Posté : mar. 27 janv. 2015 14:08
par Manfraid
Mais de rien ;-)

Re: Retour vers le Futur

Posté : mar. 27 janv. 2015 15:57
par Veloce
Hologe Temps réel

La première chose que j'ai faite, ça a été d'expérimenter le bus I2C avec l'horloge temps réel.
Mais au fait c'est quoi une horloge temps réel, et à quoi ça sert ?

Dans le Raspberry Pi, il y a une horloge système, c'est à dire un composant dans le processeur, qui
compte la date et l'heure depuis la naissance d'Unix, fixée au 1/1/1970. Si on éteint le Raspberry,
il devrait revenir tout seul dans le temps, et afficher une date où je n'étais pas né et où mes parents
portaient des pantalons pattes d'eph et des vestes en peau de mouton :lol:

Sauf que par défaut dans Raspbian il y a un soft qui fixe comme date la dernière date connue au
démarrage du système. Par exemple si j'ai éteint hier à 21h et que je rallume ce matin, il affichera
la date d'hier et l'heure où je l'ai éteint.

De plus, si j'ai une connexion réseau (LAN ou Wi-fi) avec un accès à Internet, Raspbian a un client NTP
qui se connecte sur des serveurs de temps (pool.ntp.org) pour régler la date et l'heure actuelles précises.

Donc, puisque j'ai un dongle Wifi dans mon Raspberry, je n'ai pas besoin d'horloge temps réel: quand mon
Raspberry démarre, il est initialement à la date où je l'ai éteint, puis assez vite il se règle sur l'heure actuelle.
L'avantage de mettre une horloge temps réel, c'est qu'on peut conserver l'heure courante même sans réseau,
par exemple dans une voiture. Or je voulais pouvoir mettre l'horloge dans une voiture, pour voir ce qui se passe
quand on dépasse les 88 mph (140 km/h). Ben en fait ça cligote en bleu, derrière, et puis on rentre à pied.

A noter que dans un montage à base d'Arduino, il est indispensable de mettre une horloge temps réel, puisque
l'Arduino ne dispose pas d'horloge système.

Il y a plusieurs composants utilisables, et celui que j'ai choisi (DS1307) est le plus pourri, mais le moins cher.
Pourri, parce qu'il ne garde pas l'heure précise à la seconde près pendant plusieurs mois, mais ça je m'en fiche
puisque je suis connecté au réseau la plupart du temps.

La platine de chez Adafruit est un kit qu'il faut souder soi-même. Il y a 4 composants, et je crois que c'est mon
fils de 9 ans qui a fait les soudures. Attention, il ne faut surtout pas souder les deux résistances de pull-up sur
la platine, sinon on risque de cramer le Raspberry Pi en envoyant du 5V sur ses lignes I2C qui n'acceptent que du 3,3V.
Il existe d'autres modèles sur le marché que celui d'Adafruit, mais j'ai choici celui-ci parce qu'il y a des tutoriaux sur leur site web:
https://learn.adafruit.com/adding-a-rea ... ng-the-rtc
Tout ce que je sais vient de là, et donc tout ce que je décris ci-dessous.

On relie la platine au Raspberry Pi par 4 fils:
RTC --------------> Raspberry type B
+5V --------------> patte n°2
GND --------------> patte n°6
SDA --------------> patte n°3
SCL --------------> patte n°5

Ensuite, il faut activer le driver qui pilote le bus I2C, puis celui qui pilote les devices, puis celui qui pilote
l'horloge temps réel. Pour ça on modifie le fichier /etc/modules :

Code : Tout sélectionner

sudo nano /etc/modules
et on ajoute les trois modules concernés

Code : Tout sélectionner

i2c-bcm2708 
i2c-dev
rtc-ds1307 
On installe les utilitaires I2C:

Code : Tout sélectionner

sudo apt-get install python-smbus
sudo apt-get install i2c-tools
Puis il faut modifier le fichier rc.local pour qu'il crée le device au démarrage:

Code : Tout sélectionner

sudo nano /etc/rc.local
et on ajoute les deux lignes suivantes:

Code : Tout sélectionner

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device 
sudo hwclock -s
La première crée le device ds1307 sur le bus I2C à l'adresse 68h.
La deuxième synchronise l'horloge système avec l'horloge temps réel.

et on reboote.

Il faut maintenant régler l'heure, sauf si on a un réseau relié à Internet:

Code : Tout sélectionner

date --set "27 JAN 2015 19:20:00"
Et voilà ! Maintenant l'heure est sauvegardée dans l'horloge temps réel, chaque fois que vous
éteignez le Raspberry Pi.
Si ça ne marche pas, reprenez le tutorial d'origine, je me suis peut-être trompé, ou alors il y a une différence
dans votre config par rapport à la mienne :
https://learn.adafruit.com/adafruits-ra ... guring-i2c

Dans un prochain post, j'expliquerai un peu comment marchent les afficheurs 7 segments, et ensuite je
présenterai le démultiplexage qui permet d'adresser 9 afficheurs alors qu'on n'a que 8 adresses.

A bientôt,

Veloce :roll:

Re: Retour vers le Futur

Posté : lun. 2 févr. 2015 11:28
par Veloce
HT16K33

On continue. Avant de parler des afficheurs, je vais parler du composant qui commande ces afficheurs, le HT16K33.

Quand on achète un kit d'afficheur Adafruit, tous les composants SMS sont déjà soudés sur la plaque, et tant mieux,
parce que le HT16K33 fait 28 broches et qu'il faut déjà savoir bien souder pour faire quelque chose de propre.

Vous trouverez un tuto qui décrit le montage, et qui explique comment utiliser le code fourni par Adafruit:
https://learn.adafruit.com/adafruit-led ... t-backpack
Mais, comme je l'ai déjà expliqué, les exemples fournis par Adafruit sont en Python, et moi je ne connais que le C.
Il va donc falloir mettre un peu plus les mains dans le cambouis, et comprendre comment marche le composant.

Ce composant est fait pour piloter, à partir du bus I2C, des matrices de LED (en écriture) et des matrices de touches
(en lecture) pour faire un clavier. Je vous recommande de lire le datasheet sur le site du constructeur :
http://www.holtek.com/english/docum/consumer/16K33.htm

On a 16 lignes de 8 bits donc théoriquement on peut commander 128 LEDs.
Sur le "Backpack" d'Adafruit, on a 5 lignes de 8 bits:
Adresse = Segment
0 = unités des minutes
2 = dizaines des minutes
4 = deux-points
6 = unités des heures
8 = dizaines des heures

Le composant a son propre oscillateur interne, et il passe donc son temps à balayer les lignes et les colonnes pour allumer les LED, comme
les vieux écrans de télévision. Chaque segment est relié à l'intersection d'une ligne et d'une colonne, et on l'allume en écrivant un octet sur une ligne.

Le schéma de branchement est archi-classique, on retrouve la même numérotation sur plein de montages donc on n'est pas trop dépaysés:
Image

Pour écrire un chiffre, il suffit de définir quels segments sont allumés, puis de convertir la séquence de 0 et de 1 en nombre hexadécimal.
Compliqué ? Non, je vais prendre un exemple. On veut faire un "2". Il faut donc allumer les segments a, b, g, e et d.
Si je les remets dans l'ordre, on obtient en binaire:
h-g-f-e-d-c-b-a
0-1-0-1-1-0-1-1
Ce qui donne 5Bh en hexadécimal.

Vous avez compris le principe, c'est comme ça que j'ai défini les codes pour afficher, non seulement tous les chiffres, mais aussi toutes
les lettres de l'alphabet. Bien sûr, j'ai du mal à écrire des lettres comme W, X, ou Z sur 7 segments. Mais c'est assez lisible en fait.

Code : Tout sélectionner

static const uint charTable[] =
{
        0x3F,   //0
        0x06,   //1
        0x5B,   //2
        0x4F,   //3
        0x66,   //4
        0x6D,   //5
        0x7D,   //6
        0x07,   //7
        0x7F,   //8
        0x6F,   //9
        0x77,   //A
        0x7C,   //b
        0x39,   //C
        0x5E,   //d
        0x79,   //E
        0x71,   //F
        0x3d,   //G
        0x76,   //H
        0x04,   //i
        0x0E,   //j
        0x74,   //k
        0x38,   //L
        0x37,   //M
        0x54,   //n
        0x5c,   //o
        0x73,   //P
        0x67,   //q
        0x50,   //r
        0x6d,   //S
        0x78,   //t
        0x1c,   //u
        0x72,   //V
        0x3e,   //W
        0x52,   //X
        0x6E,   //y
        0x49,   //Z
        0x00    //SPACE
};
Par défaut, le composant se trouve à l'adresse 70h sur le bus I2C, ce qu'on peut vérifier en tapant :

Code : Tout sélectionner

sudo i2cdetect -y 1
(attention c'est bien "un" et pas "L minuscule")
Mais sur le circuit imprimé on a 3 contacts nommés A0 A1 et A2, que l'on peut ponter avec un peu de soudure pour changer l'adresse.
Avec 3 bits on peut compter de 0 à 7, donc on peut avoir jusqu'à 8 composants sur le même bus. Zut, pour notre horloge nous avons
9 composants, donc il va falloir trouver une solution... Que je vous expliquerai la prochaine fois.

Veloce ;)

Re: Retour vers le Futur

Posté : mar. 10 févr. 2015 11:43
par Veloce
Bonjour,

ça fait une semaine que je n'ai pas donné de nouvelles, mais ne vous inquiétez pas, je vais continuer mon tuto. C'est juste que je n'ai pas beaucoup de temps en ce moment, et qu'en plus il manque un composant dans Fritzing pour faire mes schémas. Je vais voir comment on peut en créer un, à priori c'est facile.

à suivre...

Veloce

Re: Retour vers le Futur

Posté : mar. 10 févr. 2015 17:35
par Veloce
74HC138

Ca y est, j'ai refait le schéma. J'ai copié sur celui d'Adafruit : http://blog.adafruit.com/2012/07/02/gre ... ruit-gear/
Mais en corrigeant l'erreur: ils ont interverti les données et l'horloge, tss, tss :roll:

Voilà le schéma correct:
Image

(si l'image est tronquée, cliquez ici : http://imageshack.com/a/img673/2486/F3ZHVh.png)

On voit que la ligne SDA (données) du bus I2C alimente en parallèle tous les afficheurs, et que la ligne SCL (horloge ou clock) va vers le 74HC138,
qui va l'envoyer sur la 1ere ligne (fil rouge), la 2e (fil vert) ou la 3e (fil jaune) selon une adresse définie par les lignes GPIO 0 et GPIO 1.
Attention, la numérotation des GPIO que j'utilise est celle du logiciel (la librairie WiringPi en l'occurence) et pas celle du BCM.
Il me restera donc 6 GPIO de libre, pour commander les 6 leds d'indication matin/après-midi (AM/PM).
Voilà un extrait du code :

Code : Tout sélectionner

        // initialise GPIOs
        wiringPiSetup();
        pinMode (0, OUTPUT);    // line address A0
        pinMode (1, OUTPUT);    // line address A1
        pinMode (2, OUTPUT);    // AM led line 0
        pinMode (3, OUTPUT);    // PM led line 0
        pinMode (4, OUTPUT);    // AM led line 1
        pinMode (5, OUTPUT);    // PM led line 1
        pinMode (6, OUTPUT);    // AM led line 2
        pinMode (7, OUTPUT);    // PM led line 2
Le schéma de principe est plus précis:
Image
http://imageshack.com/a/img661/8860/6aoCSi.png

On voit que les lignes d'adresses A0, A1, A2 servent à sélectionner les sorties /Y0 à /Y7.
A2 est en permanence relié à GND, puisqu'on n'a besoin que de deux bits pour compter de 0 à 2.
La sortie sélectionnée est normalement à l'état haut, et elle tombe à 0 quand /E1=0 et /E2=0 et E3 =1.
Étant donné que E3 est relié à +3,3V, et que /E1 et /E2 sont reliés à SCL, la sortie tombe bien à 0 quand SCL tombe à zéro, ce qui est le but recherché.
Vu le faible nombre de sorties commandées, on aurait sûrement pu faire le même montage avec seulement des portes NAND.
Mais comme j'avais un schéma sous les yeux et pas forcément envie de tâtonner pendant des heures, j'ai copié le modèle.

Un petit rappel, important : les afficheurs, ainsi que le 74HC138, sont alimentés en 3,3V.

L'horloge temps réel, non représentée sur ce schéma, est elle alimentée en 5V, mais non équipée de ses résistances de pull-up.

Parlons un peu logiciel: on a vu que pour sélectionner la ligne, il suffisait d'inscrire son numéro, de 0 à 2, sur les GPIO 0 et 1.
Ensuite, pour adresser le bon écran sur chaque ligne, il faut choisir son adresse I2C. En l’occurrence, de gauche à droite les adresses sont 70h, 71h et 72h.
Enfin, pour choisir le bon caractère il faut sélectionner le bon registre, 0, 2, 4, 6, 8 pour respectivement: les dizaines d'heures, les heures, les deux-points, les dizaines de minutes, les minutes.

Dans mon prochain post j'expliquerai comment on installe la librairie WiringPi, qui permet d'utiliser les GPIO et le bus I2C du Raspberry à partir du langage C, comme on le ferait sur un Arduino. Ensuite je présenterai le code complet de mon programme, puis j'expliquerai comment on le compile, comment on l'exécute.

A suivre...

Veloce ;)

Re: Retour vers le Futur

Posté : ven. 20 févr. 2015 22:16
par Veloce
WiringPi

Alors, résumons les épisodes précédents: nous avons un bus I2C, qui est piloté par un module du noyau.
Un autre module accède sur ce bus I2C à une horloge temps réel DS1302, pour maintenir l'heure du système
lorsqu'on coupe l'alimentation. Pour l'instant on n'a pas une ligne de code à taper.

Sur ce même bus I2C, nous avons nos 9 afficheurs, qui vont devoir être commandés par notre programme.
Nous avons aussi un démultiplexeur 74HC138 qui va nous prendre 2 GPIO, et 6 LEDs qui vont prendre 6 GPIO.

Mais comment notre programme va interagir avec le bus ? Je n'y connais rien, moi en protocoles ?
Et puis pour allumer les leds, il faut connaître les registres internes des composants du Raspberry Pi. :cry:
Ah, si tout était simple comme sur l'Arduino, où on allume une GPIO comme une lampe...

Bon heureusement, un certain Gordon Henderson (Drogon de son pseudo) a écrit une bibliothèque en C pour le Raspberry Pi, qui imite la bibliothèque Wiring de l'Arduino.
Du coup ouf, pas besoin d'apprendre le Python, ni de savoir écrire un driver sous Linux, il suffit d'écrire un programme en C à la manière Arduino.

En fait, c'est tellement pareil qu'un Arduino, que pour apprendre à programmer les afficheurs, j'ai tout simplement récupéré des programmes d'Arduino donnés comme exemple sur le site Adafruit, et je les ai portés sur le Raspberry Pi. Super facile.

Allez, on installe WiringPi !

Nan, d'abord on installe Git. En gros c'est un outil qui permet de recopier toute une arborescence de répertoires depuis le site internet GitHub, jusqu'à un répertoire sur votre Raspberry. Et si le développeur fait une mise à jour, vous pouvez re-synchroniser votre arborescence pour récupérer les mises à jour. Je n'ai pas bien compris l'avantage par rapport à un fichier tar, mais bon, je suis un peu jeune en Linux. :evil:

Code : Tout sélectionner

sudo apt-get install git-core
Puis on synchronise le répertoire de WiringPi:

Code : Tout sélectionner

git clone git://git.drogon.net/wiringPi
Par défaut ça va se copier dans le répertoire /home/pi (ou /home/votre_username)

Et enfin on installe la bibliothèque WirinPi:

Code : Tout sélectionner

cd wiringPi
./build
Voilà, y'a plus qu'à tester avec quelques lignes de commande:

Code : Tout sélectionner

gpio -p write <broche> 1
gpio -p write <broche> 0
gpio -p read <broche>
etc.
(De mémoire il fallait faire sudo, parce que l'utilisateur de base n'a pas accès à ces commandes, enfin je crois)

Si ça n'est pas clair, ou si ça ne marche pas, toute la doc a été traduite par nos amis belges:
http://www.framboise314.fr/la-documenta ... -francais/

On y est presque, la prochaine fois je vous présenterai le code de mon programme, et ensuite je vous parlerai des problèmes que je rencontre pour changer l'heure à partir d'un site web.

A bientôt,

Veloce :roll:

Re: Retour vers le Futur

Posté : dim. 22 févr. 2015 18:29
par Veloce
Code source

Bonjour,

Comme promis voilà mon programme. On a sûrement déjà vu plus propre, mais enfin ça marche.
Vous remarquerez le while(1) dans le programme principal : ce programme ne s'arrête en effet jamais.
C'est une horloge, et donc elle met à jour son affichage toutes les demi-secondes.

J'utilise l'horloge système, ce qui m'évite de devoir fouiller dans les registres de mon horloge temps réel.
En contrepartie, je dois utiliser des structures de type tm, qui sont un peu curieuses.
Les mois sont comptés de 0 à 11, par exemple, et les années sont comptées à partir de 1900.

Il reste quelques printf mis en commentaires, je m'en suis servi pendant le développement et je les ai laissés pour débugger.

J'ai oublié d'expliquer comment on exécute le programme: puisque WiringPi accède aux GPIO, et que c'est interdit si on n'est pas root,
il faut faire :

Code : Tout sélectionner

sudo ./run
(Mon exécutable s'appelle run, j'aurais aussi pu l'appeler outatime)
C'est un peu embêtant de faire tourner un programme en root, notamment en termes de sécurité, mais je n'ai pas le choix.

Sinon, les commentaires sont en anglais, c'est parce que je pensais publier mon programme sur Instructables ou autre.
Enfin si vous avez des questions vous savez où me trouver...

Code : Tout sélectionner

#include <stdio.h>
#include <stdlib.h>
#include <time.h>                       //required for localtime, struct tm, etc
#include <wiringPi.h>           // library for GPIOs
#include <wiringPiI2C.h>    // library for I2C management


/*********************************************************
 *            Doc Brown's TIME MACHINE
 *                                For Raspberry Pi
 *                      Using 9 Adafruit's LED Backpacks
 *                      and a 74HC138 DMUX for addressing
 *                      written by Laurent Sineux
 *                      Inspired by Adafruit and movie "Back to the Future"
 *
 * *******************************************************/


/*************************************************************
 *  setUp
 *
 *  Starts internal oscillator of HT16K33
 *      (not advised with address DMUX, can stall chip)
 *
 *      input variables:
 *              int fd                  handle to I2C device
 *
 *      returns 0 if OK
 *************************************************************/

int setUp (int fd)
        {
                int result;
                result = wiringPiI2CWrite (fd, 0x21);
                return result;
        }


/*************************************************************
 *  setBrightness
 *
 *  set by PWM in the HT16K33
 *
 *      input variables:
 *              int fd                  handle to the I2C device
 *              int bness               brightness
 *                      correct values 0-15
 *                      PWM ratio = (bness+1)/16
 *
 *      returns 0 if OK
 *************************************************************/

int setBrightness (int fd, int bness)
        {
                int result;
                result = wiringPiI2CWrite (fd, 0xE0 | bness);
                return result;
        }

/*************************************************************
 *  setBlink
 *
 *  defines blink rate
 *  & turns display on/off
 *
 *      input variables:
 *              int fd                  handle for the I2C device
 *              int br                  blink rate
 *                      correct values:
 *                      0               no blinking
 *                      2               2Hz
 *                      4               1Hz
 *                      6               0.5 Hz
 *
 *      returns 0 if OK
 *************************************************************/
// first we define the commnds for the I2C led drivers
#define HT16K33_BLINK_CMD               0x80
#define HT16K33_BLINK_DISPLAYON 0x01
#define HT16K33_BLINK_OFF               0x00
#define HT16K33_BLINK_2HZ               0x02
#define HT16K33_BLINK_1HZ               0x04
#define HT16K33_BLINK_0HZ5              0x06

int setBlink (int fd, int br)
        {
                int result;
                result = wiringPiI2CWrite (fd, HT16K33_BLINK_CMD \
                | HT16K33_BLINK_DISPLAYON | br);
                return result;
        }

/*************************************************************
 *  writeBuffer
 *
 *  Writes a character to the display
 *      input variables:
 *              int fd                  handle to the I2C device
 *              int pos                 position of the digit
 *                      correct values:
 *                      0               digit n°1 (leftmost)
 *                      2               digit n°2
 *                      4               colon (:)
 *                      6               digit n°3
 *                      8               digit n°4 (rightmost)
 *              int value
 *                      correct values:
 *                      0-9             digits
 *                      10-35   characters
 *                      36              space (clear digit)
 *
 *      note: send value || 0xF0 to light the decimal point
 *
 * returns 0 if OK, error code otherwise
 *************************************************************/
// mapping of digits and characters to corresponding 7 segments
static const uint charTable[] =
{
        0x3F,   //0
        0x06,   //1
        0x5B,   //2
        0x4F,   //3
        0x66,   //4
        0x6D,   //5
        0x7D,   //6
        0x07,   //7
        0x7F,   //8
        0x6F,   //9
        0x77,   //A
        0x7C,   //b
        0x39,   //C
        0x5E,   //d
        0x79,   //E
        0x71,   //F
        0x3d,   //G
        0x76,   //H
        0x04,   //i
        0x0E,   //j
        0x74,   //k
        0x38,   //L
        0x37,   //M
        0x54,   //n
        0x5c,   //o
        0x73,   //P
        0x67,   //q
        0x50,   //r
        0x6d,   //S
        0x78,   //t
        0x1c,   //u
        0x72,   //V
        0x3e,   //W
        0x52,   //X
        0x6E,   //y
        0x49,   //Z
        0x00    //SPACE
};

# define DECIMAL_POINT 0x80


int writeBuffer (int fd, int pos, int value)
        {
                int result;
                result = wiringPiI2CWriteReg8 (fd, pos, 0xFF & value);
                return result;
        }

/*************************************************************
 *      selectLine
 *
 *      sets address to the 74HC138 for selected line
 *
 *      input variables:
 *              int line         (0, 1 or 2)
 *
 * ***********************************************************/
int selectLine(int line)
{
        if ((line < 0) || (line > 2)) return -1;
        digitalWrite (0, line & 1);
        digitalWrite (1, (line/2)&1 );
        return 0;
}

/*************************************************************
 *      displayDate
 *
 *      Displays a date on a given line
 *
 *      input variables:
 *              struct tm *ptrDate              pointer to the date to print
 *              int *dhArray            pointer to the device handle array
 *              int line                        line number concerned
 *
 *
 * ***********************************************************/
int displayDate (struct tm *ptrDate, int dhArray[], int line)
{
        int month, day, year, hour, min, ampm, pin;

//      printf("month.day       year    ampm    hour:minute\n");
//      printf("%d.%d           %d      %d      %d:%d\n", ptrDate->tm_mon+1, \
        ptrDate->tm_mday, ptrDate->tm_year+1900, ptrDate->tm_isdst, \
        ptrDate->tm_hour,ptrDate->tm_min);

        selectLine(line);                       //select line address

        // write month
        month = ptrDate->tm_mon+1;
        // device n°0 (left display)
        // digits n°0 and 2
        // don't forget to OR the decimal point
        // write 10's of the month
        writeBuffer(dhArray[0], 0, charTable[month / 10 % 10]);
        // write units of the month (+OR decimal point)
        writeBuffer(dhArray[0], 2, charTable[month % 10]|DECIMAL_POINT);

        // write day
        day = ptrDate->tm_mday;
        // device n°0 (left display)
        // digits n°6 and 8 (4 being the colon)
        // write 10's of the day
        writeBuffer(dhArray[0], 6, charTable[day / 10 % 10]);
        // write units of the day
        writeBuffer(dhArray[0], 8, charTable[day %10]);

        //write year
        // device n°1 (middle display)
        // digits 0, 2, 6, 8 (4 being the colon)
         // years are relative from 1900
         year = ptrDate->tm_year+1900;
        // write 1000's of the year
        writeBuffer(dhArray[1], 0, charTable[year / 1000 % 10]);
        // write 100's of the year
        writeBuffer(dhArray[1], 2, charTable[year / 100 % 10]);
        // write 10's of the year
        writeBuffer(dhArray[1], 6, charTable[year / 10 % 10]);
        // write units of the year
        writeBuffer(dhArray[1], 8, charTable[year % 10]);

        //write hour
        // device n°2 (right display)
        hour = ptrDate->tm_hour;
        // set ampm (morning/afternoon) flag
        if (hour >= 12)
        {
                ampm = 1;
        }
        else
        {
                ampm = 0;
        }
        // convert 24h to 12h
        if (hour > 12) hour -= 12;
        // write 10's of the hour
        writeBuffer(dhArray[2], 0, charTable[hour / 10 % 10]);
        // write units of the year
        writeBuffer(dhArray[2], 2, charTable[hour % 10]);

        //write min
        // device n°2 (right display)
        min = ptrDate->tm_min;
        // write 10's of the min
        writeBuffer(dhArray[2], 6, charTable[min / 10 % 10]);
        // write units of the min
        writeBuffer(dhArray[2], 8, charTable[min % 10]);

        //set AM/PM LEDS
        // line         Pins:   AM              PM
        // 0                            2               3
        // 1                            4               5
        // 2                            6               7
        pin = (line+1)*2; // which goes 2, 4, 6
        // AM led is on if ampm = 0 (ie is false)
        digitalWrite (pin, !ampm);
        // PM led is on if ampm = 1 (ie is true)
        pin++;  // which goes 3, 5, 7
        digitalWrite (pin, ampm);


//      printf("%d.%d           %d      %d      %d:%d\n", month, day, year,\
         ampm, hour, min);


        return 0;
}
/**************************************************************
 * blinkColon
 *
 * switches colon between hours and minutes
 * input variables
 *              int *dhArray            pointer to the device handle array
 *              int value                       (1 = on, 0 = off)
 *
 *************************************************************/
int blinkColon (int dhArray[], int value)
{
        int line;
        for (line = 0; line < 3; line ++)
        {
                selectLine(line);       // set line address in mux
                writeBuffer(dhArray[2], 4, value);
/*              printf("line = %d device = %d value = %d\n",line,dhArray[2]\
                ,value);
*/
        }
        return 0;
}


/*************************************************************
 *  main
 *
 *
 *************************************************************/
// table of addresses for the I2C display devices
static const int device[] =
{
        0x70,
        0x71,
        0x72
};

int main (void)
{
        int dh[3];                      // I2C device handles
        int result;                     // return from functions
        int i,j;                        // counters
        int row, line;
        int colon=0;
        struct tm toTime, *ptrToTime;
        struct tm nowTime, *ptrNowTime;
        struct tm fromTime, *ptrFromTime;

        // initialise GPIOs
        wiringPiSetup();
        pinMode (0, OUTPUT);    // line address A0
        pinMode (1, OUTPUT);    // line address A1
        pinMode (2, OUTPUT);    // AM led line 0
        pinMode (3, OUTPUT);    // PM led line 0
        pinMode (4, OUTPUT);    // AM led line 1
        pinMode (5, OUTPUT);    // PM led line 1
        pinMode (6, OUTPUT);    // AM led line 2
        pinMode (7, OUTPUT);    // PM led line 2

        // create device handles for the 3 rows
        selectLine(0);  // select first line
        for (row=0; row<3; row++)
        {
                if((dh[row]=wiringPiI2CSetup(device[row]))<0)
                        {
                                printf("No device at address %X\n",device[row]);
                                exit (-1);
                        }
                else
                        {
//                              printf("device #%i at address %X\n",dh[row],device[row]);
                        }
        }

// initialise all display devices
// line by line
        for (line = 0; line < 3; line ++)
        {
                selectLine(line);       // set line address in mux
                // row by row
                for (row = 0; row < 3; row ++)
                {
                        result = setUp(dh[row]); // start oscillator
                        result = setBrightness(dh[row], 8); // average brightness
                        result = setBlink(dh[row], HT16K33_BLINK_OFF); // no blink
                        // digit by digit
                        for (i=0;i<5;i++)
                        {
                        result = writeBuffer(dh[row], i*2, 0x00);       // clear digit
                        }
                }
        }


        while (1)
        {
                        time_t t = time (NULL);
//                      printf("month.day       year    ampm    hour:minute\n");

                        toTime.tm_mon   =  11-1;
                        toTime.tm_mday  = 5;
                        toTime.tm_year  = 1955-1900;
                        toTime.tm_hour  = 06;
                        toTime.tm_min   = 00;
                        toTime.tm_sec   = 0;
                        toTime.tm_isdst = 0;
                        result=displayDate(&toTime, dh, 0);

                        ptrNowTime = localtime (&t);
                        nowTime = *ptrNowTime;
                        result=displayDate(&nowTime, dh, 1);

                        fromTime.tm_mon         = 10-1;
                        fromTime.tm_mday        = 26;
                        fromTime.tm_year        = 1985-1900;
                        fromTime.tm_hour        = 01;
                        fromTime.tm_min         = 20;
                        fromTime.tm_isdst       = 0;
                        result=displayDate(&fromTime, dh, 2);
                        blinkColon(dh, colon);
                        if(colon == 0)
                                {
                                        colon = 0xFF;
                                }
                        else
                                {
                                        colon = 0x00;
                                }
                        delay(500);
        }


    return 0;
}
La prochaine évolution consistera à développer une application web permettant de modifier la ligne "Destination Time" et la ligne "Last Time Departed".
Dans le principe, c'est tout simple, je dois développer une page html avec un formulaire, et un tout petit programme en C qui traite ce formulaire et que je mets dans le répertoire CGI. Sauf que ce programme exécuté à chaque envoi du formulaire doit communiquer avec mon programme d'horloge, qui lui tourne en boucle.

Comment faire pour les faire communiquer ? J'ai bien pensé écrire un fichier texte sur le disque, qui est écrit par le programme web, et lu par mon programme horloge, mais d'une part je vais cramer ma carte SD en un rien de temps, et d'autre part je vais avoir des conflits si les deux programmes essaient d'accéder au même moment.

La solution, ce serait d'utiliser un sémaphore pour signaler à mon horloge que la page web a des données à lui communiquer, et puis d'envoyer les données à travers un pipe. Je suis en train de lire un chouette bouquin qui explique tout ça : http://www.advancedlinuxprogramming.com/

Mais il va encore me falloir un peu de temps pour comprendre comment on traite un formulaire web, puis comment faire communiquer mes deux programmes.

Si vous avez des idées ou des questions je suis preneur. Enfin si quelqu'un a lu jusque là.
Parce que, des fois j'ai l'impression d'être tout seul.


Euh, y'a quelqu'un ? Hého ?

Veloce :(

Re: Retour vers le Futur

Posté : dim. 22 févr. 2015 19:33
par vague nerd
Oui, oui, il y a moi !
Vous pouvez aussi utiliser une pile fifo...
Je pense que tout se passe en ram (à vérifir), et que la sd n'est pas impactée...
Cdt.

Re: Retour vers le Futur

Posté : dim. 22 févr. 2015 22:00
par Veloce
Ah ben oui c'est un excellent exemple de pipe, merci.

Par contre, il faut que je sache que j'ai des données à lire. Alors soit je peux consulter régulièrement la pile pour voir si j'ai quelque chose à lire, soit il faut que l'émetteur m'envoie un signal pour me dire que j'ai un truc à lire.

Bon, en même temps mon programme ne fait rien de ses journées : il doit travailler pendant 10ms pour mettre à jour son affichage, puis il roupille pendant 1/2 seconde. Alors il peut regarder la longueur des données dans la fifo, et puis si la longueur est nulle, eh ben c'est qu'il n'y a rien dedans... :roll:

Mouais, ça pourrait bien marcher ton truc: Je vais regarder quand j'aurai du temps.

Merci !

Veloce ;)