Root » Serveurs » Chauffage » Mon installation » 2020 » Logiciel
L'évolution de mon installation de chauffage central
Le logiciel arduino
Electronique
Quelques points important concernant le lgiciel, et en particulier le fait qu'il n'est pas possible de commander simultanément le servomoteur et l'écran LCD.
-

-

Le logiciel est régulièrement mis à jour et le listing est publié ici: logiciel arduino commande du chauffage.

La communication série
est expliquée ici

Serial ou SoftwareSerial?

Pour communiquer avec un écran LCD il faut établir une communication sérielle. Il y a d'autres possibilités, mais c'est la communication sérielle qui demande le moins de ports: un seul (pour l'envoi des caractères).

L'arduino a un port sériel hardware connecté au port numérique 1, mais il est aussi possible d'utiliser d'autres ports numériques avec la fonction include #include <SoftwareSerial.h>. Une des raisons pour utiliser un port softwareserial c'est qu'on peut communiquer avec plusieurs appareils. Une alternative c'est d'utiliser un commutateur CMOS qui envoie la ligne TX au display correspondant.

Le port sériel software ne peut par contre pas travailler simultanément avec la commande su servomoteur. Les deux routines utilisent une fonction de retard et il semblerait que l'arduino n'ait qu'un seul timer (minuterie). Quand l'arduino est en train d'envoyer du texte à l'écran, la commande du servo-moteur est retardée et le moteur change continuellement de position.

La solution est d'utiliser le port standard (qui est un port hardware qui dispose de son propre processeur), mais cette solution a également des inconvénients. Voyons toutes les possibilités:

  • Logiciel (avec SoftwareSerial)
    Il faut alterner la communication avec le servomoteur et l'écran. Comme l'envoi d'un texte à l'écran dure plus de 100ms (pour remplir complètement l'écran), il faut que les deux fonctions soient suffisamment éloignées dans le temps. Comment réaliser cette séparation en pratique?
    Avec des temps d'attente (delay();)
    Quand il faut déplacer le moteur:
    • On attend 100ms pour être sûr que toutes les données ont été transmises sur le port sériel
    • On envoie un ordre servomotor.attach pour générer les impulsions de commande
    • On attend 100ms pour que le moteur puisse se synchroniser sur les impulsions
    • On envoie la nouvelle position avec un servomotor.write
    • On attend à nouveau 100ms pour que le moteur puisse se positionner
    • On donne un ordre servomotor.detach pour interrompre les impulsions. On peut maintenant à nouveau transmettre des données sérielles
    C'est la transmission de données sérielles pendant que la fonction servomotor.attach est active qui cause régulièrement un délai, qui fait changer la position du moteur. Il faut donc stopper les impulsions pour le servomoteur pendant (et après) qu'on envoie des données sérielles.

    Avec une variable logique
    Il n'est pas nécessaire de faire attendre le programme, on peut simplement bloquer certaines opérations d'écriture de l'écran, puisque le programme travaille en boucle et que les données sont régulièrement raffraichies.
    • S'il faut modifier la position du servo, on met une variable logique sur 1 pendant la première boucle. Tant qu'elle est sur 1, on n'écrit pas à l'écran
    • Lors de la seconde boucle, on controle si la variable est 1. Si c'est le cas, on transmet la position au moteur
    • Lors de la troisième boucle, on stoppe la communication avec le moteur et on remet la variable sur 0.
    • Au 4e passage, la variable est 0 et on peut à nouveau écrire vers l'écran.
    Cette solution est idéale pour des boucles qui contiennent de nombreuses instructions (boucles lentes) ou les boucles qui ont un délai (boucle à parcourir chaque seconde).

    Avec une minuterie
    On peut également travailler avec une minuterie en utilisant la fonction millis().
    • Le compteur est normalement à 0 et on peut écrire vers l'écran
    • Quand il faut déplacer le moteur, on met la minuterie en route
    • A partir de ce moment (timer > 0) il n'est plus autorisé de communiquer avec l'écran
    • Quand le timer dépasse 100ms on envoie un ordre attach
    • Passé 200ms on donne la nouvelle position
    • Passé 300ms on donne l'ordre detach et on stoppe la minuterie. Il est à nouveau possible d'écrire vers l'écran
    Cette procédure est recommandée pour les boucles rapides qui sont constamment effectuées.
    Bien que dans de nombreuses applications la commande du servo a priorité sur l'écriture à l'écran, le moteur n'a pas la priorité. Quand des données sérielles sont transmises, la position du moteur peut être influencée. Il faut donc attendre que les données sérielles sont transmises.

  • Port hardware
    Il est possible d'envoyer des données à l'écran et de commander le moteur sans qu'ils ne s'influencent. Le port hardware dispose d'un petit processeur qui prend le relais.

    Le port est également utilisé quand le port USB fonctionne: quand un nouveau logiciel est envoyé à l'arduino, les données sont également transmises via le port sériel. Quand l'arduino est mis en route, il tente d'établir une communication avec l'ordinateur. Des données binaires sont ainsi envoyée à l'écran et il est possible de bloquer l'écran (modification du logiciel de l'écran, changement du baud rate,...).

    Il n'y a pas vraiment de solution, puisque chaque fois que le port USB fonctionne, les mêmes données sont envoyées sur le port sériel. Généralement cela ne fait apparaitre que des caractères spéciaux, mais cela peut parfois bloquer l'écran ("bricked").


Un exemple quand l'écran s'est mis au mauvais baud rate. T'as de la chance, ce problème peut être résolu assez facilement. Il faut modifier l'application pour travailler à la vitesse de l'écran (par exemple Serial.begin(2400) et tester toutes les vitesses jusqu'à l'obtention de texte normal. Il est alors possible de faire repasser l'écran à sa vitesse normale. Il faut ensuite remettre la vitesse normale dans l'application.


Un bout de logiciel


Le servomoteur peut en théorie déplacer 25kg, mais il ne faut pas tant en pratique. La connection du moteur avec le thermostat est souple pour éviter la destruction du thermostat.

Pourquoi remettre le baud rate sur 9600? C'est tout d'abord un standard: quand l'écran est remis à zéro, c'est la vitesse de communication qui est utilisée. Un écran neuf travaille à cette vitesse. Une vitesse plus basse bloque le processeur plus longtemps, tandis qu'une vitesse plus élevée peut provoquer des erreurs à la transmission.

J'utilise une variable logique servodrive qui est mise sur 1 quand le moteur doit être commandé. Lors du passage de la boucle suivant, la position est modifiée puis la variable est remise sur 0. Tant que la variable est sur 1, il est interdit d'écrire à l'écran.

Le servomoteur effectue des petits pas pour ne pas forcer le thermostat. Pour éviter que l'écran ne soit bloqué, j'alterne une écriture d'écran et une commande du servomoteur. J'utilise pour cela la variable logique blinker (qui a encore d'autres fonctions).

Constantes

Les numéros de ports sont indiqués comme des constantes. Il est ainsi possible de changer de port (par exemple port défectueux) en changeant la valeur de la constante.

Je préfère limiter l'utilisation de constantes, surtout si elles ne sont utilisées que dans une partie de l'application. En cas d'applications complexes, on ne sait plus très bien ce qu'une constante représente.

Variables

J'utilise des variables entières (int) sauf pour les variables qui représentent une valeur continue comme la température. Les températures sont lues en entier (0..1023) et puis converties en float pour calculer la moyenne et la dérivée.

Certains paramètres sont en fait des valeurs entières avec deux chiffres décimaux. Quand elles doivent être utilisées pour des calculs, elles sont transformées en float. Pour visualiser les valeurs float, la procédure inverse est suivie.

Attention: les variables définies en début de programme sont d'application partout (ce sont des variables globales). Les variables définies dans une routine ne sont disponible que localement, même dans loop();

Il vaut mieux utiliser des variables locales, on est ainsi sûr que le même nom n'est pas utilisé pour deux choses différentes.

Les variables doivent être déclarées static, elles ne sont pas initialisées à 0 à l'entrée de la procédure, mais gardent leur valeur à chaque passage de la procédure. Des erreurs très difficiles à localiser peuvent ainsi être produites, parce qu'on croit qu'une variable a gardé la même valeur que celle reçue lors du passage de boucle précédent.

Routines générales

Les séries d'instructions pour écrire l'écran ou commander les leds sont définies comme routines et peuvent être utilisées partout dans l'application. Cela permet aussi de définir la fonction de bloquage de l'écriture à un seul endroit (ou à un nombre d'endroits imités).

Initialisation (setup)

L'initialisation n'est effectuée qu'une seule fois après une remise à zéro. On configure les ports numériques (entrée ou sortie), on définit les tableaux, on lit les valeurs de l'EEPROM,...

Pour donner une valeur de départ à une variable, on peut le faire plus aisément en attribuant la valeur lors de la définition de la variable.

Programme principal (loop)

Après exécution du setup, le programme principal est effectué. Quand il est terminé, il est automatiquement relancé. Faites attention aux variables locales qui sont remises à zéro à chaque passage (sauf variable static).

Links to relevant pages - Liens vers d'autres pages au contenu similaire - Links naar gelijkaardige pagina's

-