Je travaille depuis deux ans sur la domotisation de mon chauffage, basé sur une pompe à chaleur air-air. Le projet est bien avancé. Pour info, mon installation comporte un arduino uno relié à
6 sondes DS18B20 et une sonde NTC préconditionnée par un pont et ampli-op
un capteur de rotation de ventilateur construit sur le principe d'un micro de guitare électrique (bobinage autour d'un aimant)
un compteur électrique envoyant des tops tous les 0.5Wh
un relai de commande d'une résistance de chauffage dans un bac à condensats
un transformateur de courant pour mesurer la fréquence de l'alimentation du compresseur
une led infrarouge pour piloter le climatiseur
un raspberry Pi, relié par I2C
D'autre part, le raspberry récupère des enregistrements, les stocke dans une base de donnée pour avoir un historique des températures, consommations, rendement etc... et permet de programmer le chauffage à distance via une page web.
Par ailleurs il y a un deuxième micro-contrôleur qui sert à mesurer la consommation électrique de tout l'appartement dans le style du OpenEnergyMonitor, et qui est aussi sur le bus I2C.
Tout cela fonctionne à peu près de façon fiable mais j'ai un problème de fond avec l'I2C.
L'implémentation du protocole I2C du raspberry est buggée (c'est un bug hardware, voir par exemple ici: BNO005 and the Raspberry Pi I2C bug | Details | Hackaday.io). Ce bug a pour effet que les périphériques esclaves reliés au rasberry en I2C ne peuvent pas utiliser de façon fiable le clock stretching et doivent donc impérativement répondre sans délai aux requêtes du RPI.
Or l'émetteur IR et les DS18B20 nécessitent un timing précis qui oblige à désactiver temporairement les interruptions. Donc, pendant ce temps, les communications I2C sont inopérantes.
Pour l'instant, j'ai contourné le problème en réduisant fortement (10kHz) la fréquence d'horloge de l'I2C et en déclenchant depuis le RPi la lecture des sondes et l'émission IR (donc le RPi sait qu'il ne faut rien envoyer dans les 5 secondes qui suivent car l'arduino est occupé.
Ce n'est pas satisfaisant car j'aimerais à terme que l'arduino puisse gérer le chauffage de façon autonome si le RPI plante ou et débranché. J'ai étudié d'autres moyens de communiquer:
port série: le problème est le même que pour I2C: l'arduino doit être constamment à l'écoute et réagir instantanément au risque de perdre des infos. De plus j'ai un autre microcontroleur branché au RPI, que j'aurais bien mis sur le même bus pour simplifier.
port usb + communication série: j'ai constaté sur de petits programmes de tests que la communication série s'interrompt au bout d'un certain temps. Je n'ai pas creusé la question pour savoir si ça vient de l'usb ou du code arduino qui finit par déborder en mémoire, toujours est-il que ça ne me semble pas très fiable, en plus il faut débrancher la fonctionnalité de reboot automatique de l'arduino ce n'est pas très pratique pour le développement.
Sans fil NRF24L01: c'est séduisant car cela résout le pb des niveaux de tension différents, c'est sans fil et il y a un buffer qui permet à l'arduino de ne pas être constamment à l'écoute des communications. C'est aussi un moyen que j'envisage pour d'autres applications mais... j'ai lu ici ou là qu'il y a des problèmes de fiabilité intrinsèque (le module s'arrête de fonctionner et il faut rebooter) et j'avoue que parfois le wifi ne fonctionne plus chez moi, j'ai peur que certains voisins soient assez bruyants sur cette bande de fréquence...
il reste une solution bourrin: utiliser un deuxième arduino (nano par exemple) pour faire un pont usb<->i2C. ça oblige à une gymnastique d'encapsulation de protocoles et rend l'écriture du code sur le RPi pas très simple....
deuxième option encore plus bourrin, remplacer le rpi par un ordinateur possédant un bus I2C qui ne soit pas buggé.
Ma question est: étant donné le contexte, quel moyen de communication choisiriez vous ?
les périphériques esclaves reliés au rasberry en I2C ne peuvent pas utiliser de façon fiable le clock stretching et doivent donc impérativement répondre sans délai aux requêtes du RPI
Bonjour,
il y a une petite méprise là : le délai en question n'est pas dans la réponse à donner au RP mais dans la célérité à accepter la question, nuance !
je ne vois pas pourquoi l'arduino doit répondre "instantanément" ?
il doit pouvoir lire un message, le traiter, répondre, puis passer au suivants, même s'il a plusieurs messages dans son buffer
ton réseau I2C doit avoir l'arduino comme maître
car c'est lui qui doit pouvoir être autonome
car c'est lui qui doit pouvoir se consacrer à des taches "non-interruptibles", donc gérer le temps à sa guise. Cela éviterait notamment de devoir utiliser en même temps les fonctions "1wire", I2C, voire "software serial", ce qui te pose problème
ne laisse aucune initiative au RP, oblige-le à répondre à l'arduino après requète de celui-ci cad. quand l'arduino est 100% disposé à recevoir la réponse
Et bien.. certes ça fait le job... mais ça ne m'arrange pas parce que j'aimerais aussi profiter du bus i2c pour mettre un deuxième microcontrôleur qui est un compteur d'énergie sur le réseau électrique... puis un troisième pour piloter les volets, etc...
De plus, philosophiquement parlant, ce serait un peu bizarre que le RPi soit l'esclave dans ce système, de plus c'est lui qui fournit le pull-up 3.3V (si c'est arduino je fais griller le RPi). D'autre part, le clock stretching est justement fait pour gérer ce genre de problème où un esclave n'est pas très véloce...
Pour être honnête la solution backup qui me plaît le plus est celle d'ajouter un pont USB<->i2C. Cela me permet éventuellement de brancher n'importe quel pc sur mon système, pas seulement un RPi.... mais la solution NRF24L me plaît bien aussi, sauf que je suis inquiet pour la robustesse des communications.
.. et sur la célérité à accepter la question il y a un problème: le clock stretching du RPi ne fonctionne que dans un seul cas bien précis, et ce cas ne couvre pas l'envoi par le RPi d'un message multi-octets qui n'attend pas de réponse immédiate... me semble-t-il. Donc sur un message mult-byte impossible de garantir que l'arduino récupèrera bien tous les octets.
ce serait un peu bizarre que le RPi soit l'esclave dans ce système, de plus c'est lui qui fournit le pull-up 3.3V (si c'est arduino je fais griller le RPi).
Cela ne va pas fonctionner sans changement de niveau.
La bibliothèque "Wire" active les "pull-up" sans fournir aucune information.
Il te faudrait commencer par modifier la bibliothèque.
C'est faisable facilement mais il y a un autre écueil : les niveaux I2C des micros avr.
Pour la détection 1 ou 0, l'atmega a un seuil sensiblement centré sur Vcc/2 avec un hystérésis de 0,5V.
Pour l'I2C c'est différent. L'I2C est gérée dans le micro par une zone d'électronique numérique pure et cette zone est conforme aux niveaux CMOS.
Si tu prend la datasheet du 328p, selon mon édition chap 29.7 Two Wire Serial Interface Characteristics
tu peux lire Vih >= 0,7 Vcc soit si Vcc = 5V --> 3,5V
J'ai testé et sur l'exemplaire que j'avais la limite était plutôt 0,8*Vcc (limite trouvée à 3,85 V).
C'est normal dans la connexion réelle entre deux circuits intégrés il y a toujours des pertes.
Cela ne colle pas avec la logique 3,3V.
On trouve facilement maintenant des modules interface avec circuit intégré dédié qui seront de meilleur qualité que les modules à base de transistors discrets et au même prix.
Personnellement j'ai un grand nombre de capteurs, afficheurs et actionneurs équipés de modules NRF24L01 et la fiabilité est très bonne.
Attention toutefois avec la tension d'alimentation de ce module, prévu pour pour être alimenté entre 2.9V et 3.6V. Il est possible pour cela d'utiliser la sortie 3.3V disponible sur la plupart des cartes ARDUINO.
Il est toutefois tolérant au 5V sur ses entrées, ce qui dispense d'utiliser des adaptateurs de niveau.
Du point de vue WIFI, dans le cas de distances importantes ou de murs épais à contourner, il est possible de trouver des modules équipés de vraies antennes. Exemple. J'utilise ce module comme passerelle centrale de communication.
En fait cela fonctionne actuellement dans mon installation et ça semble plutôt robuste, mais en effet, ce n'est pas carré au niveau des niveaux Je n'ai eu aucun plantage depuis plus de six mois sur ce système. Sur l'autre système (compteur d'énergie), j'ai perdu la communication i2c quatre ou cinq fois, et ça semble corrélé avec des reboot de l'autre micro-controleur.
En revanche je n'utilise pas la librairie Wire, j'ai codé moi-même une interruption pour être le plus rapide possible pour répondre aux requetes i2c du raspberry... et donc je n'ai pas mis de pullup du côté arduino.
Je suis loin de tout maitriser sur les spécifications électriques ttl et cmos mais a priori une commutation à 0.8V ne me semble pas incompatible avec des niveaux hauts à 3.3V... Comme la ligne est courte, le niveau high est très proche de 3.3V et le niveau bas très proche de zéro, que ce soit le RPi ou l'avr qui tire vers le bas. De ma compréhension, ce qui pourrait poser problème c'est si ViL (qui est de 0.3V) ne pouvait pas être atteint par le pullLow du RPi ou de l'AVR.
Je veux bien en discuter mais d'un autre côté je suis certain que le fait d'intercaler un level-shifter ne va pas du tout résoudre mon problème de départ...
Benoit
EDIT: erreur de ma part. 0.7 Vcc, pas 0.7V. Cela fait 3.5V... en effet, théoriquement, ça ne devrait pas fonctionner ! et pourtant ça marche !?
A hbachetti,
Merci pour ce retour sur le NRF2401. Savez-vous s'il existe une limite légale ou non écrite sur le débit de messages de ces modules. Pour le LoRa par exemple le nombre de messages par jour est limité. Sur la bande des 433MHz, tout va bien la plupart du temps parce que les gens n'émettent pas en permanence mais mon système poserait problème si je communiquais sur cette bande: un message de quelques dizaines d'octets toutes les secondes pour le compteur d'énergie par exemple. Un autre gros message toutes les 5 secondes pour la clim...
Benoit
Le post de 68tjs me fait penser que quoi qu'il arrive je vais devoir changer de mode de communication entre le RPi et les AVR si je veux un système robuste...