Episode 1 – Dans le domaine des bus de transmission série (SPI, 1Wire et autres), le bus I2C est certainement le plus connu. Il se décline sous différentes appellations (I2C, SmBus, 2Wire ou TWI) et, sur le fond, ils se ressemblent tous à quelques variantes près (fréquences ou niveaux de tension). Ces variantes existent principalement pour échapper à la licence I2C et de la redevance associée.
Introduction
Le bus I2C (Inter Integrated Circuit) a été créé dans le début des années 80 par la société Philips (actuellement I2C est pris en charge par NXP). On trouve des centaines de boîtiers différents avec une interface I2C.
On peut classer ces circuits en trois grandes familles (les applications grands publics, les applications professionnelles et les applications à usages généraux).
Quelques exemples de circuits disponibles dans ces domaines :
-
contrôles de tonalité, contrôles de volume, sélecteurs de sources,
-
convertisseurs A/D, convertisseurs D/A,
-
commandes d’amplificateur, fading, compact disc,
-
synthétiseurs de fréquences, PLL, circuits de FI,
-
décodeurs stéréo, RDS,
-
décodeurs PAL / SECAM / NTSC,
-
circuits de réception TV,
-
générateurs DTMF, générateurs de mélodie,
-
mémoires RAM et E2PROM,
-
expandeurs d’entrées / sorties,
-
commandes d’afficheurs LED, LCD, etc…
-
horloges temps réel,
-
etc…
Pour mener à bien notre expérimentation, il nous fallait des composants I2C et de préférence des circuits faciles à mettre en œuvre. Un petit tour dans l’atelier et dans le tiroir circuits intégrés I2C, il n’y avait que l’embarras du choix. Nous avons retenu les candidats suivants :
– une RAM (Random Access Memory) PCF8570,
– une E2PROM ( Electrically-Erasable Programmable Read-Only Memory) PCF8582,
– un capteur de température DS1621.
Vous pouvez utiliser tout ou partie des composants I2C (cela vous donne 7 possibilités).
Le Bus I2C
Nous allons pas vous présenter le BUS I2C, d’autres l’ont très bien fait. En effet, on trouve sur la toile des centaines de pages sur le sujet et il existe des ouvrages entiers consacrés au bus i2c.
Vous pourrez, par exemple, lire l’article WikiPedia, ou bien, l’article du site de Christian Tavernier.
Nota : Pourquoi le site de CT ?
Car c’est à travers ces articles de la presse électronique que j’aie découvert le monde des micro-processeurs (6800, 6809 et autres 68000 de Motorola). A l’époque le clavier était composé d’une vingtaine de boutons poussoirs et de six afficheurs 7 segments (2 pour les données et 4 pour les adresses) et le reste c’était de l’assembleur. Séquence nostalgie !
La figure ci-dessous représente le synoptique de notre base d’expérimentation.
Rappel :
Le bus i2c est un bus de type série, synchrone et half-duplex. Il est composé de trois fils, à savoir :
– SDA (Serial Data Line), transmission des données dans les deux sens,
– SCL (Serial Clock Line), signal d’horloge pour la synchronisation,
– GND (Ground), il faut bien une référence.
Les informations transitent sur un même fil mais jamais en même temps.
Toutes les transmissions (écriture ou lecture) sont initiées par le maître et adressées à un esclave via sont adresse.
C’est un bus lent, à l’origine la fréquence de transmission était fixée à 100 kbits/s (standard mode). Depuis d’autres fréquences de fonctionnement sont apparues 400 kbits/s (fast mode), 1 Mbits/s (fast mode +), 3.4 Mbits/s (high-speed mode) et 5 Mbits/s (Ultra-fast mode). Le mode ultra-fast n’est plus bidirectionnel, le maître ne fait que des écritures.
Configurer le bus I2C
Généralités
En préparant cet article, nous avons consulté nos notes et des sites web pour définir les procédures de configuration du bus i2c. On constate que l’on trouve tout et même parfois n’importe quoi !
Pour clarifier la situation, nous avons utilisé une nouvelle installation de raspbian (2016-05-27-raspbian-jessie.img) sur notre Raspberry Pi et nous avons examiné les différentes étapes de l’installation. Après création de la carte SD, démarrage, paramétrages (extension du fichier système, localisation, fuseau horaire, clavier, région WiFi et accès réseau) et les re-démarrages correspondants, nous avons un système propre et vierge de toutes autres installations et mises à jour.
Si l’on examine les fichiers etc/modules et etc/modprobe.d/raspi-blacklist.conf, nous constatons que le premier contient la ligne :
i2c-dev
Le second est vide (pas d’interdiction de chargement de modules noyau).
En exécutant la commande console :
lsmod
Nous obtenons la liste des modules actifs du noyau :
Module Size Used by ... i2c_dev 5859 0 ...
Le module i2c_dev gère les accès /dev/entries.
On peut obtenir plus d’informations sur le module par la commande :
modinfo i2c_dev
Activation I2C
Mode graphique
Pour activer l’interface i2c, il suffit de faire les opérations suivantes à la souris :
Menu → Préférences → Configuration du Raspberry Pi
Dans la fenêtre affichée, il faut se rendre dans l’onglet Interfaces et cliquer sur le bouton radio «Activé» de la ligne I2C puis sur le bouton Valider.
Pour terminer l’opération, il faut rebooter le Raspberry Pi.
Mode console
Pour activer l’interface i2c, il suffit de saisir dans la console Linux :
sudo raspi-config
Puis il faut sélectionner l’option 9 (Advanced Options) puis A6 (I2C) puis <Oui> et <Ok>. Pour sortir de l’application utilisée <Finish>.
Pour terminer l’opération, il faut rebooter le Raspberry Pi.
Contrôle
Si l’on examine les fichiers etc/modules et etc/modprobe.d/raspi-blacklist.conf, nous constatons que le premier contient la ligne :
i2c-dev
Le second est vide (pas d’interdiction de chargement de modules noyau).
Le contenu des deux fichiers n’a pas changé par rapport à la situation précédente.
En exécutant la commande console :
lsmod
Nous obtenons la liste des modules actifs du noyau :
Module Size Used by ... i2c_bcm2708 4770 0 ... i2c_dev 5859 0 ...
Le module i2c_bcm2708 est le pilote de bas niveau du bus i2c.
On peut obtenir plus d’informations sur le module par la commande :
modinfo i2c_bcm2708
Si l’on regarde les messages du noyau avec la commande :
dmesg | grep i2c
On obtient les informations suivantes :
[ 5.580941] i2c /dev entries driver [ 9.097842] bcm2708_i2c 20804000.i2c: BSC1 Controller at 0x20804000 (irq 77) (baudrate 100000)
On voit que le bus i2c est disponible à la fréquence standard de 100 kbits/s.
Une autre information utile est disponible par la commande :
ls -l /dev/i2c*
On obtient l’information suivante :
crw-rw---- 1 root i2c 89, 1 sept. 2 15:57 /dev/i2c-1
Dans la suite, on se servira du chiffre 1 de /dev/i2c-1 pour l’accès au bus i2c.
Compléments
Vous pouvez ajouter ou retirer des modules du noyau avec les commandes :
sudo modprobe -a [nom_module] sudo modprobe -r [nom_module]
(a comme add et r comme remove).
Ces modifications restent actives tant que le système n’a pas été redémarré ou éteint.
La liste des modules à charger au démarrage se trouve dans le fichier /etc/modules. Chaque ligne représente un module à charger, sauf les lignes vides ou les lignes précédées par un #.
Attention : les modules sont chargés dans l’ordre dans lequel ils sont listés.
Il existe également une liste de modules que le noyau n’a pas le droit de charger qui sont listés dans le fichier /etc/modprobe.d/blacklist.
Nota :
Si l’on explore, un peu, la liste des fichiers de Linux, on constate que pour activer ou désactiver l’interface i2c, il suffit de modifier le fichier /boot/config.txt.
... # Uncomment some or all of these to enable the optional hardware interfaces dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on ...
dtparam=i2c_arm=on #active l'interface i2c dtparam=i2c_arm=off #désactive l'interface i2c
Il faudra rebooter pour que la modification soit prise en compte. Cette procédure est une alternative à la modification via l’interface graphique ou via sudo raspi-config.
On pourra également changer la fréquence du bus i2c en ajoutant dans /boot/config.txt la ligne ci-dessous :
... # Uncomment some or all of these to enable the optional hardware interfaces dtparam=i2c_arm=on dtparam=i2c_baudrate=400000 #dtparam=i2s=on #dtparam=spi=on ...
Avec cette modification, la fréquence du bus devient 400 kbits/s.
Outils
Pour utiliser notre interface i2c, il nous faut des outils que l’on peut installer par les commandes suivantes :
sudo apt-get update sudo apt-get install i2c-tools
On a, maintenant, à notre disposition des commandes pour explorer le bus i2c.
i2cdetect
Syntaxe :
i2cdetect Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST] i2cdetect -F I2CBUS i2cdetect -l I2CBUS is an integer or an I2C bus name If provided, FIRST and LAST limit the probing range.
La première commande que nous utiliserons est i2cdetect avec la syntaxe i2cdetect -y 1.
Pour plus de détail sur la commande, vous pouvez consulter la page i2cdetect
pi@raspberrypi:~ $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
La commande n’a pas détecter d’adresses i2c sur le bus, ce qui est normal, car nous n’avons pas implanter de composants pour l’instant. On constate, également, que la commande n’a pas balayé l’ensemble des adresses du bus (0x03 à 0x77).
En effet, la norme i2c prévoit que certaines adresses sont réservées :
– 0x00 à 0x02 : appel général, CBUS et autres bus
– 0x78 à 0x7B : adressage sur 10 bits
– 0x7C à 0x7F : device ID
Nous disposons ainsi de 117 adresses utilisables pour notre bus i2c donc conforme avec notre plage de balayage de i2cdetect..
Nota :
L’adresse 0x03 (utilisation future) devrait également faire partie des adresses réservées.
Les adresses 0x4 à 0x07 sont utilisées par des composants hautes vitesses.
Si l’on veut scruter l’ensemble des adresses, il faudra utiliser la commande i2cdetect -a 1.
pi@raspberrypi:~ $ i2cdetect -a 1 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-1. I will probe address range 0x00-0x7f. Continue? [Y/n] 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Avertissement : Certaines options de i2cdetec sont à utiliser avec précautions.
On peut, également, obtenir la liste des bus disponibles par i2cdetect -l
pi@rasp10:~ $ i2cdetect -l i2c-1 i2c 20804000.i2c I2C adapter
Ou, sur les fonctionnalités implémentées par i2cdetect -F 1.
pi@rasp10:~ $ i2cdetect -F 1 Functionalities implemented by /dev/i2c-1: I2C yes SMBus Quick Command yes SMBus Send Byte yes SMBus Receive Byte yes SMBus Write Byte yes SMBus Read Byte yes SMBus Write Word yes SMBus Read Word yes SMBus Process Call yes SMBus Block Write yes SMBus Block Read no SMBus Block Process Call no SMBus PEC yes I2C Block Write yes I2C Block Read yes
Mais i2cdetect n’est pas la seule commande disponible, elle est venue avec quelques copines. Nous n’utiliserons que les commandes ci-dessous pour nos tests.
i2cdump
Affiche le contenu d’une zone.
Syntaxe :
i2cdump Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]] I2CBUS is an integer or an I2C bus name ADDRESS is an integer (0x03 - 0x77) MODE is one of: b (byte, default) w (word) W (word on even register addresses) s (SMBus block) i (I2C block) c (consecutive byte) Append p for SMBus PEC
Pour plus de détail sur la commande, vous pouvez consulter la page i2cdump
i2cget
Lecture d’une adresse.
Syntaxe :
i2cget Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]] I2CBUS is an integer or an I2C bus name ADDRESS is an integer (0x03 - 0x77) MODE is one of: b (read byte data, default) w (read word data) c (write byte/read byte) Append p for SMBus PEC
Pour plus de détail sur la commande, vous pouvez consulter la page i2cget
i2cset
Ecriture à une adresse.
Syntaxe :
i2cset Usage: i2cset [-f] [-y] [-m MASK] [-r] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE] I2CBUS is an integer or an I2C bus name ADDRESS is an integer (0x03 - 0x77) MODE is one of: c (byte, no value) b (byte data, default) w (word data) i (I2C block data) s (SMBus block data) Append p for SMBus PEC
Pour plus de détail sur la commande, vous pouvez consulter la page i2cset
Base d’expérimentation
Schéma électronique
Nous avons un schéma un peu plus touffu que les fois précédentes mais rien de bien compliqué.
Toutes les pins SDA et SCL des composants i2c sont reliées à la broche SDA ou SCL de notre Raspberry PI. L’alimentation est également prélevée sur la carte et pour finir toutes les broches gnd sont reliées entre-elles.
Remarque 1 : Les deux résistances de soutirage, entre l’alimentation et les lignes SDA et SCL (ET câblé), nécessaires au fonctionnement du bus ne sont pas prévues sur le schéma car implantées sur la carte Raspberry Pi.
Remarque 2 : Pour éviter d’avoir des phénomènes d’oscillations avec les circuits intégrés numériques, il est préférable de prévoir un condensateur de découplage (100 nF) sur la broche d’alimentation (câblage à faire au plus près du circuit intégré).
Câblage
Pour réaliser notre base d’expérimentation, il nous faut :
– un Raspberry Pi,
– un cobbler avec sa nappe,
– une plaque de prototypage rapide,
– un PCF8570 (RAM),
– un PCF 8582 (E2PROM),
– un DS 1621 (température),
– trois condensateurs 100 nF,
– des fils de liaison mâle/mâle.
Nota : Pour le câblage des adresses des circuits i2c, il faut consulter la documentation technique des composants. Les trois fiches techniques (datasheets) sont jointes dans le zip des sources.
Tests
Il n’y a pas de secret pour exploiter nos composants connectés au bus i2c, il faudra lire et relire des fiches techniques (FT).
Nota :
Il ne faut jamais se contenter de la première page de la datasheet car souvent cela ressemble plus à un publicité, pas toujours très réaliste, qu’à un document technique. Mais c’est juste mon avis !
Composants
DS1621
Le DS1621 est un thermomètre digital et un thermostat permettant des mesures de température dans la plage -55°C et +125°C avec une précision de mesure de 0.5°C (on peut améliorer l’affichage par calcul).
L’alimentation électrique peut se faire dans la plage 2.7V à 5.5V ce qui est dans la plage d’utilisation de notre carte (3.3V).
Les fréquences d’utilisation sont de 100 kHz (standard mode) ou 400 kHz (fast mode) voir FT page 15.
L’adresse sur 7 bits du composant est 1001A2A1A0 soit 0x48 à 0x4F (FT page 8).
Nota :
Pour l’exploitation du composant, on utilise une adresse sur 8 bits sous la forme 1001A2A1A0S (S=0 pour l’écriture ou S=1 pour la lecture).
Information : La fiche technique donne également la procédure et les chronogrammes i2c pour sa mise en œuvre .
PCF8570
Le PCF8570 est une mémoire volatile (RAM) de 256 octets (8 bits).
L’alimentation électrique se fait dans la plage 2.5V et 6.0V.
La fréquence d’utilisation se limite au standard mode, c’est à dire 100 kHz (FT page 10).
L’adresse sur 7 bits du composant est 1010A2A1A0 soit 0x50 à 0x57 (FT page 12).
Information : La fiche technique donne également la procédure et les chronogrammes i2c pour sa mise en œuvre
PCF8582
Le PCF8582 est une mémoire non volatile effaçable et programmable électriquement (EEPROM ou E2PROM) de 256 octets (8 bits).
L’alimentation électrique se fait dans la plage 2.5V et 6.0V.
La fréquence d’utilisation se limite au standard mode, c’est à dire 100 kHz (FT page 11).
L’adresse sur 7 bits du composant est 1010A2A1A0 soit 0x50 à 0x57 (FT page 7).
Le nombre de cycle écriture / effacement est limité à 1.000.000 de cycle (valeur théorique). Cela peut paraître énorme mais dans une boucle infinie cette limite peut être atteinte très rapidement. Alors attention !
Information :La fiche technique donne également la procédure et les chronogrammes i2c pour sa mise en œuvre.
Remarque : Le PCF8570 et PCF8582 ont la même plage d’adressage
i2cdetect
La commande i2cdetect -y 1 nous donne :
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: 50 51 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
La recherche nous donne trois adresses de composants en hexadécimal 0x48, 0x50 et 0x51. Mais qui est qui ?
Pour le DS1621, nous avons pour A2 = 0 (grd), A1 = 0 et A0 = 0 ce qui nous donne une adresse 0b1001000 = 0x48.
Pour le PCF8570, nous avons pour A2 = 0, A1 = 0 et A0 = 0 ce qui nous donne une adresse 0b1010000 = 0x50.
Pour le PCF8582, nous avons pour A2 = 0, A1 = 0 et A0 = 1 (+3.3V) ce qui nous donne une adresse 0b1010001 = 0x51.
Si l’on fait la même manipulation en fixant la vitesse du bus à 400 kbits/sec, nous obtenons le résultat suivant :
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Notre mémoire E2PROM (ad : 0x50) n’est plus détectée. Malgré une vitesse de 400 kbits/s notre RAM est toujours détectée. Par contre, les écritures et les lectures de la RAM s’avèrent être des plus aléatoires.
Pour le capteur de température (DS1621) tout est normal car prévu pour fonctionner à cette vitesse.
i2cdump
La commande i2cdump permet d’afficher le contenu mémoire du composant.
PCF8570
Pour afficher l’ensemble des données de notre RAM, on utilise la commande :
i2cdump -y 1 0x50 b
Le paramètre b signifie que l’affichage se fait sous la forme d’octets.
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 00 04 00 06 00 00 00 82 00 40 00 80 00 04 00 ..?.?...?.@.?.?. 10: 80 00 00 04 00 00 02 00 00 00 00 00 00 01 00 01 ?..?..?......?.? 20: 10 88 00 00 00 00 00 00 00 08 42 00 10 00 00 00 ??.......?B.?... 30: 00 09 00 02 00 80 00 04 00 41 00 00 08 00 00 08 .?.?.?.?.A..?..? 40: 00 00 80 00 00 08 00 00 00 00 00 10 00 00 00 80 ..?..?.....?...? 50: 80 02 00 80 02 00 00 02 00 00 20 00 00 10 09 80 ??.??..?.. ..??? 60: 20 10 20 00 00 00 00 00 00 00 00 00 80 00 00 01 ? .........?..? 70: 00 00 10 20 10 00 00 8c 00 00 20 01 00 10 00 00 ..? ?..?.. ?.?.. 80: 00 04 02 00 00 01 04 00 00 00 01 00 10 00 00 08 .??..??...?.?..? 90: 50 04 00 20 30 00 08 00 00 01 01 00 00 02 00 80 P?. 0.?..??..?.? a0: 00 00 10 00 10 00 00 04 20 01 02 00 08 00 00 00 ..?.?..? ??.?... b0: 02 00 00 00 00 00 00 01 00 02 00 00 28 00 00 00 ?......?.?..(... c0: 40 00 00 00 00 a0 00 00 80 20 00 00 99 00 08 00 @....?..? ..?.?. d0: 10 20 80 00 02 00 00 00 00 10 40 08 00 00 00 10 ? ?.?....?@?...? e0: 00 00 00 02 00 80 00 08 00 00 00 08 30 28 00 10 ...?.?.?...?0(.? f0: 04 00 02 00 22 00 00 80 80 00 00 00 00 20 00 00 ?.?."..??.... ..
A la mise sous tension, le contenu de la RAM est complètement aléatoire.
Pour afficher l’ensemble des données de notre RAM au format word (2 octets), on utilise la commande :
i2cdump -y 1 0x50 w
Le paramètre w signifie que l’affichage se fait sous la forme de word (2 octets).
0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f 00: 0000 0400 0004 0600 0006 0000 0000 8200 08: 0082 4000 0040 8000 0080 0400 0004 8000 10: 0080 0000 0400 0004 0000 0200 0002 0000 18: 0000 0000 0000 0000 0100 0001 0100 1001 20: 8810 0088 0000 0000 0000 0000 0000 0000 28: 0800 4208 0042 1000 0010 0000 0000 0000 30: 0900 0009 0200 0002 8000 0080 0400 0004 38: 4100 0041 0000 0800 0008 0000 0800 0008 40: 0000 8000 0080 0000 0800 0008 0000 0000 48: 0000 0000 1000 0010 0000 0000 8000 8080 50: 0280 0002 8000 0280 0002 0000 0200 0002 58: 0000 2000 0020 0000 1000 0910 8009 2080 60: 1020 2010 0020 0000 0000 0000 0000 0000 68: 0000 0000 0000 8000 0080 0000 0100 0001 70: 0000 1000 2010 1020 0010 0000 8c00 008c 78: 0000 2000 0120 0001 1000 0010 0000 0000 80: 0400 0204 0002 0000 0100 0401 0004 0000 88: 0000 0100 0001 1000 0010 0000 0800 5008 90: 0450 0004 2000 3020 0030 0800 0008 0000 98: 0100 0101 0001 0000 0200 0002 8000 0080 a0: 0000 1000 0010 1000 0010 0000 0400 2004 a8: 0120 0201 0002 0800 0008 0000 0000 0200 b0: 0002 0000 0000 0000 0000 0000 0100 0001 b8: 0200 0002 0000 2800 0028 0000 0000 4000 c0: 0040 0000 0000 0000 a000 00a0 0000 8000 c8: 2080 0020 0000 9900 0099 0800 0008 1000 d0: 2010 8020 0080 0200 0002 0000 0000 0000 d8: 1000 4010 0840 0008 0000 0000 1000 0010 e0: 0000 0000 0200 0002 8000 0080 0800 0008 e8: 0000 0000 0800 3008 2830 0028 1000 0410 f0: 0004 0200 0002 2200 0022 0000 8000 8080 f8: 0080 0000 0000 0000 2000 0020 0000 0000
On peut également afficher une partie du plan mémoire avec la commande :
i2cdump -y -r 0x06-0x2b 1 0x50 b
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 00 82 00 40 00 80 00 04 00 ..?.@.?.?. 10: 80 00 00 04 00 00 02 00 00 00 00 00 00 01 00 01 ?..?..?......?.? 20: 10 88 00 00 00 00 00 00 00 08 42 00 ??.......?B.
PCF8582
Pour afficher l’ensemble des données de notre EEPROM, on utilise la commande :
i2cdump -y 1 0x51 b
Le paramètre b signifie que l’affichage se fait sous la forme d’octets.
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
Nota :
Une mémoire EPROM ou EEPROM est considérée comme vierge lorsque tous ces octets sont à 0xff (tous les bits sont à 1).
DS1621
La même commande pour le capteur de température, vous donnera n’importe quoi car elle n’a pas de signification physique.
i2cset
La commande i2cset permet d’écrire une donnée vers le composant.
PCF8570
Pour écrire une données (octet) 0x46 (caractère F en ascii) à l’adresse mémoire 0x00 du composant 0x50, on utilise la commande :
i2cset -y 1 0x50 0x00 0x46 b
On peut vérifier le résultat avec de l’écriture avec la commande :
i2cdump -y -r 0x00-0x0f 1 0x50 b
Affichage de la plage 0x00 à 0x0f de notre RAM.
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 46 00 04 00 06 00 00 00 82 00 40 00 80 00 04 00 F.?.?...?.@.?.?.
On retrouve bien notre F dans le dump dans les colonnes de droite.
On peut utiliser d’autres bases de numérotation :
i2cset -y 1 0x50 0x01 0162 b
Ecrit en octal à l’adresse 0x01.
i2cset -y 1 0x50 0x02 97 b
Ecrit en décimal à l’adresse 0x02.
De même, il est possible d’écrire plusieurs octets à la suite avec la commande :
i2cset -y 1 0x50 0x03 0x6d 0142 111 0x69 0x73 0x65 0x33 0x31 i
Attention : Il y a un mélange de décimal, d’octal et d’hexadécimal.
Cette commande envoie les octets 0x6d, 0142, 111, 0x69, 0x73, 0x65, 0x33 et 0x31 à partir de l’adresse mémoire 0x03 de la RAM (ad : 0x50). Le caractère i précise que l’on transmet un bloc de données selon le format i2c.
Ce type d’écriture de données est limité à 8 octets.
Une dernière écriture avec la commande :
i2cset -y 1 0x50 0x0b 0x34 b
On peut vérifier le résultat avec i2cdump -y -r 0x00-0x0f 1 0x50 b (affiche la plage 0x00 à 0x0f de notre RAM).
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 46 72 61 6d 62 6f 69 73 65 33 31 34 80 00 04 00 Framboise314?.?.
Avec toutes ces manipulations, nous venons d’écrire Framboise314 (en ascii) dans notre mémoire RAM.
Il est possible d’écrire directement des données sur 2 octets (word au sens i2c) par la commande :
i2cset -y 1 0x50 0x10 0x1680 w
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 46 72 61 6d 62 6f 69 73 65 33 31 34 80 00 04 00 Framboise314?.?. 10: 80 16 00 04 00 00 02 00 00 00 00 00 00 01 00 01 ??.?..?......?.?
On retrouve nos données aux adresses 0x11 et 0x10
Remarque : Si l’on coupe l’alimentation de la RAM toutes les données seront perdues.
Nota :
Vous pouvez stocker en mémoire des valeurs numériques (int, short int ou float) mais il vous faudra décoder la valeur et faire une sauvegarde des différents octets qui composent la valeur. De même, il faudra recomposer les valeurs numériques à partir de ces octets.
PCF8582
Il suffit de faire les mêmes opérations pour l’EEPROM que celles de la RAM en changeant l’adresse 0x50 par 0x51.
On aura finalement dans l’EEPROM les données suivantes :
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 46 72 61 6d 62 6f 69 73 65 20 33 31 34 ff ff ff Framboise 314... 10: 80 16 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ??..............
Par contre, une coupure de l’alimentation ne fera pas perdre les informations.
DS1621
Avant d’envoyer des données vers le DS1621 (thermomètre + thermostat), il faut savoir quoi et où ?
La documentation technique viendra de nouveau à notre secours (page 10) et vous trouverez également page 9 les chronogrammes des différentes lectures / écritures correspondant au DS1621.
Les différents registres
Vous trouverez les différents registres avec leurs descriptions page 10 de la documentation. Les commandes dont nous aurons besoin sont les suivantes :
– Red Temperature (ad : 0xaa) : Registre à lecture seule. Il contient le résultat de la dernière conversion de température. (utilisé dans le paragraphe suivant)
– Access Config (ad : 0xac) : Registre à lecture / écriture. Il définit les conditions de fonctionnement et de contrôle du circuit.
La signification de l’octet à joindre à cette adresse est décrite page 5 de la documentation techniques.
Le seul bit qui nous intéresse est le bit0 ou lsb qui permet la conversion de température en continue ou en coup par coup (0=continue et 1=coup par coup).
Pour nos tests, nous fixerons cet octet de configuration à 0x00.
– Read Counter (ad : 0xa8) : Registre à lecture seule. Il lit la valeur de Count_Remain. Cette valeur est utilisée dans le calcul de la température donnant une approximation supérieur au 1/2 degré.
– Read Slope (ad : 0xa9) : Registre à lecture seule. Il lit la valeur de Count_Per_C. Cette valeur est utilisée dans le calcul de la température donnant une approximation supérieur au 1/2 degré.
– Start Convert T (ad:0xee) : Registre à lecture /écriture. Il déclenche la conversion de la température.
Le temps de conversion de la température est de 750 ms (page 15).
Information : Dans notre application, nous n’utiliserons pas la fonction thermostat.
Commandes
Pour configurer notre thermomètre, il suffit d’envoyer la commande :
i2cset -y 1 0x48 0xac 0x00 b
On écrit 0x00 (mesure en continue) dans le registre 0xac (accès configuration) à l’adresse du composant 0x48.
Pour démarrer les mesure :
i2cset -y 1 0x48 0xee
Nous exploiterons la lecture des données du capteur de température dans le chapitre suivant.
i2cget
La commande i2cget permet de lire une donnée du composant.
DS1621
Comme nous venons de mettre en service notre capteur de température, il ne nous reste plus qu’à lire les données. On obtient la valeur de la température par la commande :
i2cget – y 1 0x48 0xaa w
Un exemple de réponse du DS1621 :
pi@rasp10:~/dev/sagaI2C_01/bash $ i2cget -y 1 0x48 0xaa w 0x8013
A quoi correspondant cette donnée ?
Comme d’habitude nous trouvons la réponse dans la documentation technique page 4. La température est codée sur deux octets. L’octet de poids fort représente la température entière et l’octet de poids faible la température décimale.
0x8013 : 0x13 octet poids fort et 0x80 octet poids faible Octet poids fort Octet poids faible S 2⁶ 2⁵ 2⁴ 2³ 2² 2¹ 2⁰ 2-¹ 2-2 2-3 2-4 2-5 2-6 2-7 2-8 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 ^ Bit de signe 0 = positif ou 1 = négatif Température entière = 2⁴ + 2¹ + 2¹ = 19°C Température décimale = 2-¹ = 0.5°C Température lue = 19.5°C
Si S = 1, les bits 2⁶ à 2⁰ de l’octet de poids fort représentent la valeur de la température en complément à 2.
Le complément à 2 correspond au complément à 1 + 1.
Exemple :
0x00ff: 0xff octet poids fort et 0x00 octet poids faible Octet poids fort = 11111111 Complément à 1 = 00000000 Complément à 2 = 00000000 + 00000001 = 00000001 Soit -1°C
Autres lectures de température :
Température positive
i2cget – y 1 0x48 0xaa w #température i2cget – y 1 0x48 0xa8 b #Count_Remain i2cget – y 1 0x48 0xa9 b #Count_Per_C
Résultats des lectures :
0X8012 #Température 18.5°C 0x07 #Count_Remain soit 7 en décimal 0x10 #Count_Per_C sit 16 en décimal
Avec Count_Remain et Count_Per_C, on peut obtenir température calculée plus fine par la formule :
(Count_Per_C - Count_Remain) Température calculée = température entière lue - 0.25 + ---------------------------- Count_Per_C
Soit une température calculée de 18.3125°C. Tous les chiffres inférieures au dixième de degré n’ont pas de signification physique.
Pour ces mesures, nous retiendrons les valeurs suivantes :
Température lue = 18.5°C Température calculée = 18.3°C
Température négative
i2cget – y 1 0x48 0xaa w #température i2cget – y 1 0x48 0xa8 b #Count_Remain i2cget – y 1 0x48 0xa9 b #Count_Per_C
Résultats des lectures :
0X80e2 #Température -29.5°C 0x01 #Count_Remain soit 1 en décimal 0x10 #Count_Per_C sit 16 en décimal
Température lue = -29.5°C Température calculée = -29.3°C
PCF8570
Avec tout ce que l’on a vu précédemment, nous avons oublié nos deux mémoires.
Pour lire un octet dans la RAM, on peut utiliser la commande :
i2cget -y 1 0x50 0x00 b
Ce qui nous donne :
0x46 #F de Framboise314
PCF8582
Pour lire un octet dans l’EEPROM, on peut utiliser la commande :
i2cget -y 1 0x51 0x00 b
Ce qui nous donne :
0x46 #F de Framboise314
Commentaire
Avec tout ce que nous venons de voir et si vous disposez de la datasheet du composant, vous pouvez exploiter tous les périphériques i2c existants.
I2C et bash
Pour illustrer tout ce que nous venons de voir, nous vous proposons un script bash qui lit la température du DS1621 toutes les secondes et affiche dans la console la température lue ainsi que la température calculée.
Programme
Pour saisir ce programme, il faut saisir dans la console :
nano i2c01.sh
Cette commande ouvre un fichier teste vide appelé i2c01.sh (pour la sauvegarde faire ctrl-o et pour sortir ctrl-x).
Le contenu du programme et ses commentaires sont représentés ci-dessous.
#!/bin/bash #Programme lecture capteur de température DS1621 via bus i2c #nom programme : i2c01.sh #logiciel : bash #cible : raspberry Pi #date de création : 06/09/2016 #date de mise à jour : 08/09/2016 #version : 1.0 #auteur : icarePetibles #référence : #Remarques : Pour fonctionner, il faut être sous super utilisateur # Il faut rendre le fichier exécutable avec # sudo chmod +x i2c01.sh # exécution : ./i2c01.sh # ATTENTE=1 #attente entre 2 mesures #temps de conversion du DS1621 #750 ms LC_NUMERIC=C #définit le séparateur décimal #en . au lieu de , car printf #utilise les paramètres régionaux #Procédure de netoyage et sortie cleanup() #sortie { echo echo Fin script #message de fin exit #sortie } #programme principal echo Début du script #IHM echo Mesure de température avec capteur DS1621 #IHM echo ctrl-c pour sortir de la boucle #IHM echo #Setup pin et direction - Cature Control-C SIGHUP SIGKILL trap "cleanup" SIGHUP SIGINT SIGTERM #capture SIGNAL et lance la #la procédure cleanup #initialisation DS1621 i2cset -y 1 0x48 0xac 0x00 #configuration i2cset -y 1 0x48 0xee #démarre la converssion #traitement des mesures while true #boucle infinie do #faire #lecure des registres du DS1621 lecture=`i2cget -y 1 0x48 0xaa w` #lecture température lecture=$(($lecture)) #pour permettre le calcul counter=`i2cget -y 1 0x48 0xa8 b` #lecture Count_Remain counter=$(($counter)) #pour les calcul slope=`i2cget -y 1 0x48 0xa9 b` #lecture Count_Per_C slope=$(($slope)) #pour le calcul corr=$(echo "scale=3; -0.25+($slope/1-$counter/1)/($slope/1)" | bc -l) #correction pour le calcul #octets de poids faible et valeur décimale de la température lsb=$((($lecture>>8)/128)) #extraction bit 2^7 if [ $lsb -eq 1 ] #si bit poids fort = 1 then decimal=0.5 #partie décimale = 0.5°C else decimal=0.0 #partie décimale = 0.0°C fi #octet de poids fort, test >0 ou <0 et valeur entière de la température entier=$(($lecture&0x00ff)) #pour le calcul signe=$(($entier/128)) #extraction bit 2^7 if [ $signe -eq 1 ] #si = 1 alors température <0 then entier=$(($entier^0xff)) #complément à 1 par xor entier=$(echo "scale=0; ($entier+1)*(-1)" | bc -l) #complément à 2 fi temp_lue=$(echo "scale=1; $entier/1+$decimal/1" | bc -l) #calcul température lue #calcul la valeur de la température à partir de |temp_lue|, counter et slope if [ $entier -eq 0 ] #température = 0 then temp_cal=0 #init temp_cal=$(($temp_cal)) #pour le calcul temp_cal=${temp_cal/.*} #conversion float to int else #température <> 0 if [ $lecture -eq 33023 ] #cas particulier de 0x80FF then #pb de float to int temp_cal=0 #init temp_cal=$(($temp_cal)) #pour le calcul temp_cal=${temp_cal%.*} #float to int else #tous les autres cas temp_cal=${temp_lue%.*} #valeur entière de temp_lue fi fi temp_cal=$(echo "scale=1; $temp_cal/1+$corr/1" | bc -l) #température corrigée par calcul #affichage des données printf "Température lue : %.1f °C\n" $temp_lue printf "Température calculée : %.1f °C\n" $temp_cal #nécessaire pour afficher #correctement les nbres entre #-0.9 et 0.9 echo #saut de ligne sleep $ATTENTE #attente done #fin do #Fin du script
Les commentaires du script sont auto-suffisants à la compréhension.
Exécution du programme
Pour exécuter ce script bash, il faut le rendre exécutable avec la commande :
sudo chmod +x i2c01.sh
Et pour l’exécuter :
./i2c01.sh
Pour sortir de la boucle de mesure, il suffit de faire ctrl-c au clavier.
Quelques copies d’écrans
Un peu d’habillage
Tous les programmes de la série « saga » affichaient leurs résultats dans la console Linux en mode texte. Ce type d’affichage n’est pas très « sexy », pour remédier à cette situation nous allons mettre en œuvre tput qui est disponible par défaut dans la distribution Raspbian.
tput
Programme
Pour saisir ce programme, il faut saisir dans la console :
nano i2c06.sh
Cette commande ouvre un fichier teste vide appelé i2c06.sh (pour la sauvegarde faire ctrl-o et pour sortir ctrl-x).
Le contenu du programme et ses commentaires sont représentés ci-dessous.
#!/bin/bash #Programme lecture capteur de température DS1621 via bus i2c #nom programme : i2c06.sh #logiciel : bash #cible : raspberry Pi #date de création : 06/09/2016 #date de mise à jour : 08/09/2016 #version : 1.0 #auteur : icarePetibles #référence : #Remarques : Pour fonctionner, il faut être sous super utilisateur # Il faut rendre le fichier exécutable avec # sudo chmod +x i2c06.sh # exécution : ./i2c06.sh # echo -e "\e[8;12;40t" #fenêtre terminal 12x40 ATTENTE=1 #attente entre 2 mesures #temps de conversion du DS1621 #750 ms # LC_NUMERIC=C #définit le séparateur décimal # en . au lieu de , car printf #utilise les paramètres régionaux #affichage écran tput smcup #sauve screen clear #efface écran tput civis #curseur invisible tput cup 1 5 #curseur lig 1 col 6 tput setaf 4 #écrire en bleu tput bold #écrire en gras echo "MESURE TEMPERATURE AVEC DS1621" #IHM tput sgr0 #annule attributs tput cup 4 5 #lig 4 col 5 echo -e "Température lue : \c" #IHM tput cup 5 5 #lig 5 col 5 echo -e "Température calculée : \c" #IHM tput cup 8 10 #lig 8 col 10 echo -e "Tapez \c" #IHM tput setaf 5 #écrire en magnenta tput bold #écrire en gras echo -e "q\c" #IHM tput sgr0 #annule les attributs tput setaf 0 #écrire en noir echo -e " pour quitter\c" #IHM #initialisation DS1621 i2cset -y 1 0x48 0xac 0x00 #configuration i2cset -y 1 0x48 0xee #démarre la converssion #traitement des mesures while true #boucle infinie do #faire #lecure des registres du DS1621 lecture=`i2cget -y 1 0x48 0xaa w` #lecture température lecture=$(($lecture)) #pour permettre le calcul counter=`i2cget -y 1 0x48 0xa8 b` #lecture Count_Remain counter=$(($counter)) #pour le calcul slope=`i2cget -y 1 0x48 0xa9 b` #lecture Count_Per_C slope=$(($slope)) #pour le calcul corr=$(echo "scale=3; -0.25+($slope/1-$counter/1)/($slope/1)" | bc -l) #correction pour le calcul #octets de poids faible et valeur décimale de la température lsb=$((($lecture>>8)/128)) #pour le calcul if [ $lsb -eq 1 ] #si bit poids fort = 1 then decimal=0.5 #partie décimale = 0.5°C else decimal=0.0 #partie décimale = 0.0°C fi #octet de poids fort, test >0 ou <0 et valeur entière de la température entier=$(($lecture&0x00ff)) #pour le calcul signe=$(($entier/128)) #extraction bit 2^7 if [ $signe -eq 1 ] #si = 1 alors température <0 then entier=$(($entier^0xff)) #complément à 1 par xor entier=$(echo "scale=0; ($entier+1)*(-1)" | bc -l) #complément à 2 fi temp_lue=$(echo "scale=1; $entier/1+$decimal/1" | bc -l) #calcul température lue #calcul la valeur de la température à partir de |temp_lue|, counter et slope if [ $entier -eq 0 ] #température = 0 then temp_cal=0 #init temp_cal=$(($trmp_cal)) #pour le calcul temp_cal=${temp_cal/.*} #conversion float to int else #température <> 0 if [ $lecture -eq 33023 ] #cas particulier de 0x80FF then #pb de float to int temp_cal=0 #init temp_cal=$(($temp_cal)) #pour le calcul temp_cal=${temp_cal%.*} #float to int else #tous les autres cas temp_cal=${temp_lue%.*} #valeur entière de temp_lue fi fi temp_cal=$(echo "scale=1; $temp_cal/1+$corr/1" | bc -l) #température corrigée par calcul tput cup 4 28 #lig 4 col 28 tput setaf 1 #écrire en rouge tput bold #gras printf '%.1f' $temp_lue #affiche temp_lue avec format #nécessaire pour afficher #correctement les nbres entre #-0.9 et 0.9 tput sgr0 #annule attributs tput el #efface jusqu'à la fin de ligne tput cup 4 33 #curseur lig 4 col 33 echo -e " °C\c" #IHM tput cup 5 28 #lig 5 col 28 tput setab 7 #fond blanc printf "%.1f" $temp_cal #affiche temp_cal avec format tput sgr0 #annule attributs tput el #efface jusqu'à la fin de ligne tput cup 5 33 #curseur lig 5 col 33 echo -e " °C\c" #IHM tput cup 8 0 #curseur lig 8 col 0 read -n 1 -t $ATTENTE -s saisie #saisie clavier 1 carc, time out # ^ ^ ^ et non visible # | | n'affiche pas le caractère saisie # | time out en cas de non saisie, utiliser pour l'attente entre # | 2 mesures du DS1621 # saisie 1 caractère if [ "$saisie" = "q" ] #si q then break #sortie boucle infinie fi done #fin do echo tput cnorm #curseur visible tput rmcup #restaure screen echo -e "\e[8;25;90t" #taille fenêtre 25x90 #à adapter à votre taille de #fenêtre terminal console echo #saut de ligne #Fin du script
Le programme de lecture et de calcul est le même que dans l’exemple précédent, les modifications portent uniquement sur l’affichage.
Exécution
Pour exécuter ce script bash, il faut le rendre exécutable avec la commande :
sudo chmod +x i2c06.sh
Et pour l’exécuter :
./i2c06.sh
Pour sortir de la boucle de mesure, il suffit de faire q au clavier.
Quelques copies d’écrans
Ne juger pas le côté design des fenêtres, mais elles montrent juste quelques possibilités de gestion semi-graphique de tput. Pour plus d’informations sur le programme tput, une recherche sur la toile avec votre butineur favori vous fournira toutes les options possibles.
tput et banner
Une autre possibilité d’affichage de nos résultats de mesure peut se faire par l’utilisation du logiciel banner. Banner affiche le texte passé en paramètre sous forme de bannière.
Le logiciel banner n’est pas présent dans la distribution Raspbian. Dans cette distribution, il s’appelle sysvbanner et pour l’installer il faut faire :
sudo apt-get update sudo apt-get install sysvbanner
Programme
Pour saisir ce programme, il faut saisir dans la console :
nano i2c08.sh
Cette commande ouvre un fichier teste vide appelé i2c08.sh (pour la sauvegarde faire ctrl-o et pour sortir ctrl-x).
Le contenu du programme et ses commentaires sont représentés ci-dessous.
#!/bin/bash #Programme lecture capteur de température DS1621 via bus i2c #nom programme : i2c08.sh #logiciel : bash #cible : raspberry Pi #date de création : 06/09/2016 #date de mise à jour : 08/09/2016 #version : 1.0 #auteur : icarePetibles #référence : #Remarques : Pour fonctionner, il faut être sous super utilisateur # Il faut rendre le fichier exécutable avec # sudo chmod +x i2c08.sh # exécution : ./i2c08.sh # echo -e "\e[8;25;90t" #taille écran 25x90 ATTENTE=10 #attente entre 2 mesures #temps de conversion du DS1621 #750 ms LC_NUMERIC=C #définit le séparateur décimal #en . au lieu de , car printf #utilise les paramètres régionaux mesure(){ #lecture data DS1621 #lecure des registres du DS1621 lecture=`i2cget -y 1 0x48 0xaa w` #lecture température lecture=$(($lecture)) #pour permettre le calcul counter=`i2cget -y 1 0x48 0xa8 b` #lecture Count_Remain counter=$(($counter)) #pour les calcul slope=`i2cget -y 1 0x48 0xa9 b` #lecture Count_Per_C slope=$(($slope)) #pour le calcul corr=$(echo "scale=3; -0.25+($slope/1-$counter/1)/($slope/1)" | bc -l) #correction pour le calcul #octets de poids faible et valeur décimale de la température lsb=$((($lecture>>8)/128)) #extraction bit 2^7 if [ $lsb -eq 1 ] #si bit poids fort = 1 then decimal=0.5 #partie décimale = 0.5°C else decimal=0.0 #partie décimale = 0.0°C fi #octet de poids fort, test >0 ou <0 et valeur entière de la température entier=$(($lecture&0x00ff)) #pour le calcul signe=$(($entier/128)) #extraction bit 2^7 if [ $signe -eq 1 ] #si = 1 alors température <0 then entier=$(($entier^0xff)) #complément à 1 par xor entier=$(echo "scale=0; ($entier+1)*(-1)" | bc -l) #complément à 2 fi temp_lue=$(echo "scale=1; $entier/1+$decimal/1" | bc -l) #calcul température lue #calcul la valeur de la température à partir de |temp_lue|, counter et slope if [ $entier -eq 0 ] #température = 0 then temp_cal=0 #init temp_cal=$(($temp_cal)) #pour le calcul temp_cal=${temp_cal/.*} #conversion float to int else #température <> 0 if [ $lecture -eq 33023 ] #cas particulier de 0x80FF then #pb de float to int temp_cal=0 #init temp_cal=$(($temp_cal)) #pour le calcul temp_cal=${temp_cal%.*} #float to int else #tous les autres cas temp_cal=${temp_lue%.*} #valeur entière de temp_lue fi fi temp_cal=$(echo "scale=1; $temp_cal/1+$corr/1" | bc -l) #température corrigée par calcul } BG_BLUE="$(tput setab 4)" #commande couleur arrière plan FG_WHITE="$(tput setaf 7)" #commande couleur écriture #lit la taille de la fenêtre terminal terminal_size(){ terminal_cols="$(tput cols)" #nbre col fenêtre terminal terminal_rows="$(tput lines)" #nbre lig fenêtre terminal } #calcul la taille de la bannière (banner) banner_size(){ banner_cols=0 #initialisation banner rows=0 #initialisation while read do [[ ${#REPLY} -gt $banner_cols ]] && banner_cols=${#REPLY} # ^ ^ REPLY = contenu de read si l'on # | >(supérieur) affecte pas la valeur saisie à une # nbre de caractères de REPLY variable ((++banner_rows)) #incrémente banner_rows done < <(banner "100.0^C") #structure type de la température # ^ ^ # | envoie résultat du processus # redirection } #affiche la température à l'écran display_temp(){ local row=$temp_row #variable locale while read do tput cup $row $temp_col #coordonnées du curseur echo -n "$REPLY" #affiche le contenu de REPLY # ^ # sans retour à la ligne ((++row)) #incrémente row done < <(banner "$temp_ban") #différentes lignes de la température # ^ ^ # | envoie résultat du processus # redirection } #efface l'écran par remplissage de blancs clear_screen(){ tput home #curseur position 0, 0 (haut gauche) echo -n "$blank_screen" #rempli l'écran avec des spaces } #calcul de la colonne d'affichage cal_coord(){ if [[ ${#temp_ban} -eq 7 ]] #si nbre carac de température = 7 then temp_col=$(($temp_colB)) #valeur pour la structure type tput cup $temp_row $temp_col #position curseur elif [[ ${#temp_ban} -eq 6 ]] #si nbre carac de température = 6 then temp_col=$(($temp_colB + 4)) #correction car < à la tructure de base tput cup $temp_row $temp_col #position curseur elif [[ ${#temp_ban} -eq 5 ]] #si nbre carac de température = 5 then temp_col=$(($temp_colB + 8)) #correction car < à la structure de base tput cup $temp_row $temp_col #position curseur fi #ces corrections permettent d'avoir un } #affichage centré #sortie de la boucle infinie par ctrl-c trap 'tput sgr0; tput cnorm; tput rmcup || clear; exit 0' SIGINT # ^ ^ ^ ^ ^ # | | | efface écran Ctrl-c # | | restaure contenu écran # | curseur normal # désactive tous les attributs #sauve le contenu de l'écran et rend le curseur invisible tput smcup; tput civis # ^ ^ # | curseur invisible # sauve contenu écran terminal_size #lit taille fenêtre terminal banner_size #calcul taille banner temp_row=$(((terminal_rows - banner_rows) / 2)) #centrage pour les lignes temp_colB=$(((terminal_cols - banner_cols) / 2)) #centrage pour les colonnes blank_screen='' #création variable for ((i=0; i < (terminal_cols * terminal_rows); ++i)) do blank_screen+=" " #espace pour remplir l'écran done echo -n ${BG_BLUE}${FG_WHITE} #fixe couleurs avant et arrière plan #programme principal #initialisation DS1621 i2cset -y 1 0x48 0xac 0x00 #configuration i2cset -y 1 0x48 0xee #démarre la converssion #boucle infinie while true do mesure #lit et calcul les températures clear_screen #efface écran tput cup 1 38 #curseur lig 1 col 38 echo -n "Capteur DS1621" #IHM temp_ban=$(printf "%.1f^C" $temp_cal) #température à afficher en #bannière via banner cal_coord #position bannière display_temp #affiche la température #calculée en bannière tput cup 23 1 printf "Température mesurée : %.1f°C" $temp_lue tput cup 23 69 echo -n "<ctrl-c pour sortir>" sleep $ATTENTE #attente done #fin do #Fin du script
Le programme de lecture et de calcul est le même que dans l’exemple précédent mais il est regroupé dans un sous-programme mesure(). Certaines subtilités utilisées dans le script sont commentées dans le programme.
Exécution
Pour exécuter ce script bash, il faut le rendre exécutable avec la commande :
sudo chmod +x i2c08.sh
Et pour l’exécuter :
./i2c08.sh
Pour sortir de la boucle de mesure, il suffit de faire ctrl-c au clavier.
Quelques copies d’écrans
Banner n’est pas en mesure d’afficher le signe ° (il n’est pas dans les caractères de base du code ASCII), nous avons utilisé le symbole ^ pour palier à ce petit défaut. Il existe d’autres logiciels similaires à banner mais nous n’avons pas fait de tests avec ceux-ci.
Conclusion
Nous arrivons à la fin de l’épisode 1 de la saga I2C qui portait sur la découverte du bus I2C, son activation ainsi que la mise en œuvre d’un capteur de température, d’une RAM et d’une EEPROM. La mise en forme de l’affichage sous forme semi-graphique nous a permis d’avoir une présentation plus agréable des résultats.
Le prochain épisode portera sur l’utilisation du capteur DS1621 sous une forme similaire mais avec les langages Python et C/C++.
A tous présents et à venir. Salut !
Sources
Vous pouvez télécharger les sources et la documentation :
http://psl.ibidouille.net/Images_forum/raspberryPi/sagaI2C_01.zip
Liens
Bus I2C
Manuel de l’utilisateur i2c
Autres articles de la série saga
Saga Blink – saison 1
Saga Blink – saison 2
Saga Push Button