D’abord un peut de théorie
Généralité sur le Bus 1-Wire
Le bus 1-Wire (ou OneWire) est un bus conçu par Dallas Semiconductor. Il permet de connecter et de faire dialoguer entre eux des circuits sur un seul fil. Il fonctionne suivant le principe maître / esclave. Il y a donc un seul maître, qui pourra dialoguer avec un ou plusieurs esclaves.
Le niveau de tension normalisé sur ce bus est +5V (Standard TTL). Ce bus supporte une topologie de réseau1 en série, parallèle ou étoile.
Dans le cas des composants Dallas la tension du bus doit être comprise entre 3 et 5V. Cela permet de les utiliser dans aucune adaptation complémentaire, aussi bien sur des Arduino UNO en 5V, qu’avec des Arduino Mini en 3,3V comme pour les Raspberry-Pi qui travaillent aussi en 3,3V pour les GPIO.
Sur le schéma ci-dessus, on voit que le bus 1-wire est relié au +3,3 V par une résistance de tirage de 4,7 kΩ. En fonction de la longueur des fils de liaison, il sera parfois nécessaire d’ajuster sa valeur. Tous les appareils sont branchés en parallèle sur le bus et c’est en mettant (ou pas) leur sortie à la masse qu’ils envoient les données au maître.
La topologie d’un réseau correspond à son architecture physique. En ce sens ou leur structure détermine leur type.
Raccordement au Filaire au Bus OneWire en mode Standard :
L’avantage de ce bus est qu’il peut être utilisé en mode « parasite » (alimentation à partir du fil de données). Cela permet d’utiliser seulement 2 fils (et non un seul comme le nom le laisse supposer), un fil de données et un fil de masse.
Raccordement des abonnés du Bus OneWire en mode Parasite :
Dans le mode parasite, l’esclave est connecté en reliant ses broches d’alimentation ensemble et en les reliant à la masse. Il n’y a plus besoin dans ce cas que de deux fils pour assurer la liaison avec les esclaves connectés au bus 1-wire.
Lorsque le bus est au niveau 1, un condensateur interne au composant esclave est chargé, et c’est lui qui assurera l’alimentation du composant pendant que le niveau du bus sera bas.
Chaque circuit possède une adresse physique unique, gravée dans la puce à la fabrication. C’est une des raisons expliquant la réticence de Dallas à permettre la création d’esclave 1-Wire autres que ceux qu’il produit : avoir la maîtrise de l’identification des esclaves du bus.
Généralement utilisé pour des mesures de températures, il existe une gamme complète de composants compatibles.
Principe du protocole 1-Wire
La communication sur le bus 1-Wire est caractérisée par un ensemble de « pulse » ou changement d’état. L’état par défaut de la ligne data est +5V, ce qui permet d’alimenter les différents composants à partir de la ligne data en mode parasite.
Avant toute communication, le maître met le bus à l’état bas (0V) pendant 480 μs pour faire une initialisation (reset) des composants connectés. Après un délai de 15 à 60 μs, le ou les esclaves connectés, forcent le bus à l’état bas pendant 60 à 240 μs pour signaler leur présence. Le maître est alors informé des esclaves connectés sur le bus.
Chaque circuit possède une adresse physique unique, gravée dans la puce à la fabrication. Cette adresse est constituée de 64 bits soit 8 octets. Le premier octet détermine le type de famille auquel appartient le circuit. Les 6 octets suivants, constituent le code propre du circuit. Le dernier octet est le CRC. C’est un octet de contrôle calculé à partir des 56 bits précédents.
Toute transaction entre un maître et un ou plusieurs esclaves, débute par une initialisation, constituée par l’envoi du pulse de Reset par le maître. Le maître doit ensuite envoyer une commande de type ROM qui est propre au protocole 1-Wire, et que tous les circuits de ce type vont reconnaître. Cela va permettre entre autre de sélectionner un circuit parmi les différents esclaves qui ont répondu présents au pulse de Reset. Le dialogue et l’échange de données pourra ensuite commencer, entre le maître et l’esclave sélectionné.
Pour émettre un bit sur le bus, le maître force le bus à « 0 » pendant 1 à 15 μs. L’esclave va lire le bus entre 15 et 45 μs après le front descendant ( valeur typique 30 μs).
Si on veut émettre un « 1 », il faut repasser le bus à « 1 » immédiatement, et ne plus rien faire jusqu’à t = 60 μs.
Pour émettre un « 0 » il faut laisser le bus à « 0 » jusqu’à t = 60 μs, puis repasser le bus à « 1 ».
La durée total d’un bit est donc de 60us, ce qui donne une vitesse de communication maximale de 16kbits/s.
Après la réception d’une commande du maître, l’esclave peut renvoyer des données. Pour lire les données de l’esclave, le maître force le bus à « 0 » pendant au moins 1 μs. Si l’esclave veut émettre un « 1 », il laisse le bus libre, donc tiré à « 1 ». Pour émettre un « 0 », l’esclave doit tirer le bus à « 0 » pendant 15 μs au minimum.
Le maître devra donc dans tous les cas lire le bus 15 μs maximum après avoir tiré le bus à « 0 » pendant 1 μs. L’état du bus donnera alors le bit transmis par l’esclave.
Ceci est une description assez sommaire du protocole 1-Wire. Il faut ensuite se reporter à la datasheet de chaque composant 1-Wire pour connaître les fonctions qui sont supportées et les zones de données qui peuvent être lues pour obtenir les températures, niveaux de tensions…
Pour allez plus loin :
Sur la compréhension détaillé du bus 1-Wire, notamment sur le calcul du CRC j’invite les intéressé à consulter le document pdf de Daniel Menesplier, qui ma servi à faire cette introduction.
Le DS18B20 a une gamme de mesure qui s’étend de -55 °C à +125 °C. Il transmet sa mesure directement en degrés Celsius, codée sur 16 bits. Sa précision est de ±0,5 °C entre -10 °C et +85 °C.
Avec une plage de tension d’alimentation allant de 3v à 5,5v, le DS18B20 est un candidat idéal pour utiliser un Arduino, utilisant soit une tension de fonctionnement de 3,3V comme les Arduino Pro-Mini ou un plus classique 5V utilisé par les Arduino Uno.
Pour ma part j’ai plutôt opté pour un Arduino Pro-Mini de 3.3V, dans le but d’une future utilisation « portable » alimentée par une batterie Li-Po de 3,7V. (Forme de thermomètre mobile et autonome)
Le montage avec l’Arduino Pro-Mini
Pour cette phase de « programmation » dans l’environnement Arduino.
Nous allons avoir besoin de :
L’ environnement de programmation Arduino adapté à votre plate-forme (Mac OS, Windows, Linux…), à télécharger ici, pour ceux qui ne l’aurait pas encore installé.
La librairie OneWire disponible ici. A décompresser dans votre répertoire < Arduino >/Librairies/ .
La librairie Dallas Temperature Control – DTC – disponible ici. Idem à décompresser dans votre répertoire < Arduino >/Librairies/ .
L’autre méthode pour l’installation des librairies, consiste à ouvrir l’IDE Arduino, puis sous le menu ‘Croquis->Inclure une bibliothèque->Ajouter la bibliothèque .ZIP’ sélectionner le fichier Compressé .ZIP .
La prise en compte sera effective au prochain démarrage de l’IDE.
Une foi les 2 librairies installées, le programme utilisé est le suivant :
#include <OneWire.h> #include <DallasTemperature.h> // On utilise la Pin #2 pour connecter le DS18B20 #define ONE_WIRE_BUS 2 // Initialisation de la librairie OneWire OneWire oneWire(ONE_WIRE_BUS); // Lien avec la librairie Dallas Temperature Control DallasTemperature sensors(&oneWire); void setup(void) { // On initialise le port série Serial.begin(9600); Serial.println("Démonstration de prise de température avec le DS18B20"); // On initialise la librairie DTC sensors.begin(); } void loop(void) { // On réalise un appel pour tous les "esclaves" connectés Serial.print(" Demande de température en cours..."); sensors.requestTemperatures(); // Envoi de la demande Serial.println("DONE"); // Confirmation de l'envoi de la demande Serial.print("La temperature pour le DS18B20 est de: "); Serial.print(sensors.getTempCByIndex(0)); // Le 0 corresponant au premier esclave trouvé (nous n'en avons qu'un). delay(1000); // On attend une seconde avant la prochaine mesure }
Rien de particulier à signaler dans ce code si ce n’est l’utilisation de nos deux librairies.
J’ai inseré un délai d’une seconde entre chaque mesure mais que dans la pratique l’opération de conversion prenant environ 750 ms, il se passe ainsi presque 2 secondes (1,75s pour être précis) entre chaque affichage sur le moniteur série.
Vous pouvez désormais compiler ce code et lancer la programmation de votre Arduino après avoir pris soin de sélectionner le bon type de carte et le port série associé.
En activant le moniteur série, vous devriez désormais voir apparaître les informations suivantes:
Démonstration de prise de température avec le DS18B20 Demande de température en cours...DONE La temperature pour le DS18B20 est de: 19.81 Demande de température en cours...DONE La temperature pour le DS18B20 est de: 19.87 Demande de température en cours...DONE La temperature pour le DS18B20 est de: 19.87 Demande de température en cours...DONE La temperature pour le DS18B20 est de: 19.94 Demande de température en cours...DONE La temperature pour le DS18B20 est de: 19.94 Demande de température en cours...DONE
Cela clos cette première utilisation, de la sonde de température DS18B20, avec un Arduino.
Je vous propose d’entrer un peut plus loin dans le détail de la librairie OneWire :
Étude de la librairie OneWire :
Méthodes et utilisation :
OneWire myWire(pin);
Déclare un objet du type OneWire sur la broche « pin », il est possible de déclarer plusieurs objets OneWire sur la même broche étant donnée qu’il s’agit d’un bus.
myWire.search(addrArray) ;
Cherche des modules compatible OneWire sur le bus.
Si un module est trouvé la fonction renvoi True et l’adresse du module est placé dans « addrArray » (addrArray qui correspond à un tableau de 8 byte), si aucun module n’est trouvé elle retourne False.
(Ps: C’est une fonction de recherche « glissante », cela signifie que si plusieurs module Dallas sont présent, il faudra appeler la fonction autant de fois qu’il y a de modules sur le bus)
myWire.reset_search() ;
Fait repartir la recherche de zéro, utile pour rescanner tous les modules présent sur le bus.
myWire.reset() ;
Relance le bus 1-Wire, obligatoire avant de communiquer avec la plupart des modules Dallas.
myWire.select(addrArray) ;
Sélectionne un module d’adresse addrArray afin de pouvoir communiquer avec lui.
Toutes les communications réalisées jusqu’au prochain reset se feront avec ce module.
myWire.skip() ;
Permet d’outre passer la sélection du module avec qui communiquer.
Utile dans le cas ou il n’y a qu’un module Dallas sur le bus et où, par conséquent, faire une recherche serait inutilement lourd.
(ne fonctionne QUE s’il n’y a qu’un module Dallas sur le bus)
myWire.write(valeur) ;
Écrit un octet « valeur » sur le bus.
(Note: bien prendre le temps de lire le datasheet du module utilisé, la plupart possède un « scratchpad » qui sert de mémoire tampon entre la mémoire physique et une mémoire ram virtuelle.
Si les données contenu dans le « scratchpad » ne sont pas transférées dans la mémoire physique en suivant la procédure qui va bien elle ne seront tout simplement pas sauvegardées)
myWire.write(valeur, 1) ;
Écrit un octet « valeur » sur le bus, mais conserve l’alimentation sur le bus à la fin de la transmission.
(utile dans le cas d’un câblage en mode parasite)
myWire.read();
Lit un octet depuis le bus.
myWire.crc8(dataArray, length) ;
Calcul la checksum (CRC8) du tableau « dataArray » de taille « length », très utile pour savoir si les données reçu sont corrompu ou non.
Passons maintenant au Raspberry-PI / Odroid pour un usage un peut similaire.
Montage avec un Raspberry-Pi
Linux n’est pas Temps Réel (RT)
Nous avons vu que l’utilisation du Bus OneWire exige une gestion temporelle très précise de l’ordre de quelque µS.
Si les µContrôleur comme l’Arduino ou ses semblables sont bien taillé pour de telles performances, c’est qu’il ne fonctionnent pas dans un mode Multitâche préemptif, où voir pire en mode collaboratif.
Cette caractéristique de fonctionner dans un mode séquentiel monotâche, garantie une temporalité du programme exécutés. Il n’y en à qu’un et il n’est pas interrompu.
Pour un Système Multitâche préemptif, comme Linux sur le Rasberry-Pi, le contrôle d’un bus séquencé par une horloge externe n’est pas possible sans adaptations particulière.
Il est indispensable, lors des phases de dialogues (le contrôle du bus), d’avoir la maîtrise du temps d’exécution du processeur. Pour ce faire il faut pouvoir ‘geler’ temporairement, la capacité de l’OS à préempter, notre tache de dialogue sur le bus OneWire.
Rassurez-vous une tel gestion est prévus par le noyau de Linux. Il faut donc pouvoir intervenir au niveau du noyau, c’est le rôles des modules de noyau complémentaire.
Les fonctions de gestion du bus OneWire ne seront donc pas, comme c’était le cas pour l’Arduino, de simples librairies (extensions fonctionnelles du langage), mais des modules du noyau de Linux. Qui auront en charge de bloquer le mode préemptif de Linux pendant l’exécution de ces routines particulières.
Pour résumer :
Pour que le noyau Linux sache gérer le composant OneWire DS18B20, il faut lui adjoindre un module pour la gestion du OneWire, et un module pour la gestion des composants de la famille 28h, capteurs de température.
Cela parait très simple, mais en réalité le travail à exécuter …. Bref d’autres l’on considérablement simplifié pour nous.
Passons maintenant au concret !
Quels modules noyaux et comme les ajouter ?
Les modules en question sont :
Comment installer ces modules au noyau ?
Ce n’est pas l’objectif, que de faire un cours sur la gestion du noyau Linux et des modules de périphériques (pilotes).
Toutefois quelques notions me sembles importantes à préciser.
Généralement ignoré, les modules noyaux sont sont au cœur du système, globalement chargés d’interfacer un matériel avec le noyau Linux.
Les modules noyaux existent sous 2 formes :
Soit ils ont été compilé au sein même du noyau, on dit parfois compilé “en dur”,
Soit ils ont été compilé sous forme de modules externes.
Vous aurez devinez que dans notre cas, on va utiliser des modules externes. Dans le cas d’une distribution Debian, qui se trouve être la distribution principal utilisé sur le Raspberry-Pi et nommé dans ce cas “Raspbian”.
Deux façons de monter un module :
en mode direct
Charger les modules du kernel pour prendre en charge le capteur. w1-gpio est le module pour les capteurs avec un seul fil, w1-therm est celui pour les sondes de température.
modprobe w1-gpio
modprobe w1-therm
Par configuration:
Les modules externes sont définis dans le fichier :
/etc/ modules
Il suffit d’éditer, avec votre éditeur de fichier préféré en mode root, puis de compléter ce fichier avec les lignes suivantes :
w1-therm w1-gpio pullup=1
Votre fichier de modules devrait ressembler un peut à ceci :
# /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. # Parameters can be specified after the module name. i2c-dev i2c-bcm2708 spi-bcm2708 snd-bcm2835 w1-therm w1-gpio pullup=1
La prise en charge par le noyau, de cette nouvelle configuration, se fait au plus simple par un redémarrage.
Schéma de raccordement de la sonde DS18B20 au Raspberry-Pi
Pour une sonde en boîtier industriel.
En mode labo sur un Breadboard
Lecture de la température de notre sonde DS18B20
Dans un premier temps vérifions, après notre petit montage, que le système a bien reconnu la sonde :
>pi@rasphil $ cd /sys/bus/w1/devices >pi@rasphil /sys/bus/w1/devices $ ls 28-0000054c2ec2 w1_bus_master1
Ma sonde a effectivement été détectée. Elle porte le numéro 28-0000054c2ec2 (numéro unique au monde, je vous le rappelle). Le système a créé un répertoire à son nom et c’est dans ce dossier que nous allons trouver les informations qui nous intéressent.
Dans un premier temps, et pour bien comprendre comment le système (l’OS) gère la sonde, on va effectuer cette lecture directement en ligne de commande.
Remarque :
il n’y à pas réellement d’autre manière de communiquer directement avec un périphérique sous Linux. En effet tout périphérique dialogue avec un fichier d’interface disponible dans le répertoire des ‘devices’.
Un programme sous python ou autre ne fera rien d’autre que d’invoquer ce même fichier pour communiquer avec la sonde.
Il est donc intéressant d’étudier ce mécanisme au travers de notre exemple de lecture la sonde DS18B20.
Allons directement sous le répertoire de notre sonde :
>cd /sys/bus/w1/devices/28-0000054c2ec2
>ls -la driver id name power subsystem uevent w1_slave
Lecture du fichier ‘w1_slave’
>cat w1_slave 7c 01 4b 46 7f ff 04 10 09 : crc=09 YES 7c 01 4b 46 7f ff 04 10 09 t=23750
Le fichier w1_slave contient sur la première ligne le code correspondant au numéro de la sonde, avec son CRC qui a été vérifié (YES), et sur la deuxième ligne la température en hexadécimal (peu utilisable) mais aussi en milièmes de degrés Celsius.
Il suffira de diviser par 1000 pour obtenir la température réelle. On peut arrondir à un chiffre après la virgule sans vergogne, puisque la précision n’est que de ±0,5 °C.
Une topologie de réseau est en informatique une définition de l’architecture d’un réseau. Elle donne une certaine disposition des différents postes informatiques du réseau et une hiérarchie de ces postes. ↩