Sylvain Mahé Le site Web Retour à l'accueil Principes Partager mes idées et mes projets librement et gratuitement. Thématiques Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté. Contact ✆ Téléphone : 06.45.49.96.98
✉ E-mail : contact@sylvainmahe.site
✎ Site Web : sylvainmahe.site
Écriture de la page : Sylvain Mahé
Le site Web Je vous propose ici l'intégralité de la programmation (code source) de ce présent site Web (cette page y compris, sauf les fichiers présentés ci-dessous, auquel cas il y aurait redondance infinie), ce qui comprend les fichiers de feuille de style en cascade (.css), les fichiers de script (.js), les fichiers de langage de balisage d'hypertexte, autrement dit, les pages de contenu HTML (.html), et les fichiers de langage de préprocesseur d'hypertexte (.php). En effet dans cette philosophie de partage de mon travail avec le plus grand nombre, tout est libre de droits d'auteur (voir dans la section "Licence officielle" en page d'accueil), ainsi les fichiers sources (programmation notamment) sont tous ouverts et modifiables (open source). Tout le site Web est écrit à l'aide d'un simple éditeur de texte (gedit) pourvu uniquement de la coloration syntaxique. Libre à vous de récupérer par exemple des parties (ou la totalité) de mes fichiers de programmation .css, .js, .html, et .php afin de créer votre propre site Web. Fichier style.css : html { font-family: sans-serif; } body { margin: 0px; background-color: #ffffff; } name { z-index: 1; display: inline-block; position: fixed; margin-left: 320px; margin-top: 40px; padding-left: 24px; padding-right: 24px; padding-top: 6px; padding-bottom: 6px; border-top-right-radius: 8px; border-bottom-right-radius: 8px; background-color: #f5f5f5; font-size: 28px; color: #2c3e50; } function { z-index: 1; display: inline-block; position: fixed; margin-left: 320px; margin-top: 90px; padding-left: 24px; padding-right: 24px; padding-top: 6px; padding-bottom: 6px; border-top-right-radius: 8px; border-bottom-right-radius: 8px; background-color: #f5f5f5; font-size: 14px; color: #496479; } side { z-index: 1; display: inline-block; position: fixed; width: 256px; height: 100%; padding-left: 32px; padding-right: 31px; padding-top: 31px; padding-bottom: 32px; border-width: 1px; border-style: solid; border-color: #dddddd; border-top-right-radius: 32px; border-left: none; border-bottom: none; background-color: #f5f5f5; } side underline { display: inline-block; position: relative; width: 256px; height: 1px; background-color: #dddddd; } side title { display: inline-block; position: relative; width: 256px; margin-top: 24px; font-size: 22px; color: #2c3e50; letter-spacing: 2px; } side text { display: inline-block; position: relative; width: 256px; margin-top: 10px; font-size: 12px; color: #496479; } side text bold { font-weight: bold; } side img { display: inline-block; position: relative; width: 224px; height: 224px; padding: 15px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; } side navigation { display: inline-block; position: relative; width: 223px; margin-top: 6px; padding-left: 10px; padding-right: 16px; padding-top: 5px; padding-bottom: 5px; border-left-width: 6px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; font-size: 12px; color: #e74c3c; text-decoration: underline; } side navigation bold { font-weight: bold; } page { display: inline-block; position: absolute; width: 768px; margin-top: 8px; padding-left: 384px; padding-right: 64px; padding-top: 32px; padding-bottom: 32px; border-top-right-radius: 64px; box-shadow: 0px 0px 64px #e0e0e0; } page header { display: inline-block; position: relative; float: right; width: 768px; font-size: 10px; color: #b0b8c0; text-align: right; } page separator { display: inline-block; position: relative; width: 768px; height: 66px; } page underline { display: inline-block; position: relative; width: 768px; height: 1px; background-color: #dddddd; } page line { display: inline-block; position: relative; width: 768px; height: 1px; margin-top: 18px; background-color: #dddddd; } page title { display: inline-block; position: relative; width: 768px; margin-top: 54px; font-size: 28px; color: #2c3e50; letter-spacing: 2px; } page text { display: inline-block; position: relative; width: 768px; margin-top: 18px; font-size: 16px; color: #496479; } page text bold { font-weight: bold; } page code { display: inline-block; position: relative; width: 704px; margin-top: 18px; padding: 31px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; font-size: 14px; color: #000000; white-space: pre; overflow-x: auto; } page code green { font-weight: bold; color: #2e8b57; } page code red { font-weight: bold; color: #b32a2a; } page code pink { color: #ff1bff; } page code purple { color: #7820f0; } page code blue { color: #1900ff; } page quote { display: inline-block; position: relative; width: 704px; margin-top: 18px; padding-left: 26px; padding-right: 32px; padding-top: 18px; padding-bottom: 18px; border-width: 6px; border-style: solid; border-color: #358ccb; border-radius: 2px; border-right: none; border-top: none; border-bottom: none; background-color: #f5f5f5; font-size: 18px; font-style: italic; color: #496479; } page quote bold { font-weight: bold; } page caution { display: inline-block; position: relative; width: 704px; margin-top: 18px; padding-left: 26px; padding-right: 32px; padding-top: 18px; padding-bottom: 18px; border-width: 6px; border-style: solid; border-color: #e74c3c; border-radius: 2px; border-right: none; border-top: none; border-bottom: none; background-color: #f5f5f5; font-size: 18px; font-style: italic; color: #496479; } page caution bold { font-weight: bold; } page valid { display: inline-block; position: relative; width: 704px; margin-top: 18px; padding-left: 26px; padding-right: 32px; padding-top: 18px; padding-bottom: 18px; border-width: 6px; border-style: solid; border-color: #2e8b57; border-radius: 2px; border-right: none; border-top: none; border-bottom: none; background-color: #f5f5f5; font-size: 18px; font-style: italic; color: #496479; } page valid bold { font-weight: bold; } page img { display: inline-block; position: relative; float: left; width: 328px; height: 219px; margin-left: 16px; margin-top: 18px; padding: 15px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; } page video { display: inline-block; position: relative; width: 704px; height: 352px; margin-left: 16px; margin-top: 18px; padding: 15px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; } page download { display: inline-block; position: relative; width: 704px; margin-top: 6px; padding-left: 26px; padding-right: 32px; padding-top: 10px; padding-bottom: 10px; border-width: 6px; border-style: solid; border-color: #dddddd; border-radius: 2px; border-right: none; border-top: none; border-bottom: none; background-color: #f5f5f5; font-size: 16px; color: #e74c3c; text-decoration: underline; } page download bold { font-weight: bold; } page input[type=text] { display: inline-block; position: relative; width: 768px; margin-top: 6px; padding: 6px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; font-family: sans-serif; font-size: 14px; font-style: italic; color: #496479; overflow-x: auto; } page textarea { display: inline-block; position: relative; width: 768px; height: 128px; margin-top: 6px; padding: 6px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; background-color: #f5f5f5; font-family: sans-serif; font-size: 14px; font-style: italic; color: #496479; resize: none; } page input[type=submit] { display: inline-block; position: relative; width: 768px; padding: 6px; border-width: 1px; border-style: solid; border-color: #dddddd; border-radius: 2px; font-family: sans-serif; font-size: 16px; color: #2c3e50; text-align: center; } page footer { display: inline-block; position: relative; float: right; width: 768px; margin-top: 64px; font-size: 10px; color: #b0b8c0; text-align: right; } Fichier script.js : function scrolling() { var tagName = document.getElementById ("name"); var tagFunction = document.getElementById ("function"); var opacityName = 1 - (window.scrollY / 256); var opacityFunction = 1 - (window.scrollY / 128); if (opacityName >= 0.1) { tagName.style.visibility = "visible"; tagName.style.opacity = opacityName; } else { tagName.style.visibility = "hidden"; } if (opacityFunction >= 0.1) { tagFunction.style.visibility = "visible"; tagFunction.style.opacity = opacityFunction; } else { tagFunction.style.visibility = "hidden"; } } window.addEventListener("scroll", scrolling); scrolling(); Fichier complementaryToolOfModule.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#complementaryToolOfModule"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les outils complémentaires du projet MODULE</title> <underline></underline> <text>En programmation C++ pour les microcontrôleurs de marque Microchip comme l'ATmega48P, l'ATmega88P, l'ATmega168P, l'ATmega328P, l'ATmega164P, l'ATmega324P, l'ATmega644P, ou l'ATmega1284P dont il est question ici, des outils de compilation et de programmation de la puce performants et standards existent.</text> <text>Ces outils sont disponibles pour les systèmes <bold>Linux</bold>, <bold>macOS</bold>, ou <bold>Windows</bold>.</text> <text><bold>Outils pour Linux :</bold> <br/>Pour Linux vous devez installer les paquets <bold>gcc-avr</bold>, <bold>avr-libc</bold>, <bold>avrdude</bold> et <bold>binutils</bold> afin de programmer les microcontrôleurs implantés sur mes automates programmables MODULABLE 20 ou MODULABLE 32. Pour ma part j'utilise le système d'exploitation Linux (qui est largement utilisé de nos jours).</text> <text>En exemple voici la ligne de commande à écrire dans le terminal pour télécharger et installer les paquets nécessaires sur Linux :</text> <code>sudo apt-get install gcc-avr avr-libc avrdude binutils -y</code> <text><bold>Outils pour macOS :</bold> <br/>Pour macOS une procédure légèrement différente est requise, en premier vous devez installer un gestionnaire de paquets avec la commande suivante à écrire dans le terminal :</text> <code>ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"</code> <text>Puis, il vous faut indiquer le dépôt à utiliser pour pouvoir installer avr-libc et avrdude :</text> <code>brew tap osx-cross/avr</code> <text>Après quoi vous pouvez installer avr-libc :</text> <code>brew install avr-libc</code> <text>Puis installer avrdude avec le support de l'USB :</text> <code>brew install avrdude --with-usb</code> <text><bold>Outils pour Windows :</bold> <br/>Pour Windows plusieurs solutions sont possibles, la plus simple est de télécharger et installer un programme qui se nomme <bold>WinAVR</bold>, ce programme contient les mêmes outils que sur Linux mais ici en version pour Windows :</text> <a href="http://winavr.sourceforge.net/download.html"><download>Site Web de <bold>WinAVR</bold></download></a> <caution>Ne possédant pas Windows il m'est difficile de tester nativement ce logiciel, je pense que le problème qui peut se poser avec WinAVR est son obsolescence, en effet il n'est pas régulièrement mis à jour, et la version que vous allez télécharger est probablement trop ancienne...</caution> <text>C'est pourquoi <bold>je recommande vivement la procédure suivante</bold>, téléchargez manuellement l'archive (.zip) correspondant à la version de votre système d'exploitation Windows, c'est-à-dire soit en version 32 bits ou en version 64 bits disponible sur le site Web de <bold>Zak Kemble</bold> ici :</text> <a href="http://blog.zakkemble.co.uk/avr-gcc-builds/"><download>Site Web de <bold>Zak Kemble</bold></download></a> <text>Une fois la bonne archive téléchargée (version 32 bits ou 64 bits), vous devez extraire son contenu dans le répertoire de votre choix.</text> <text>En conséquence, pour que ma routine <bold>Compiler uploader.bat</bold> (que je propose avec le programme MODULE) fonctionne avec les fichiers de Zak Kemble que vous venez de télécharger, il est nécessaire de légèrement modifier son contenu, soit le renommage des différents appels aux programmes <bold>avr-gcc</bold>, <bold>avr-objcopy</bold>, <bold>avrdude</bold>, et <bold>avr-size</bold> respectivement comme suit :</text> <quote>c:\avr-gcc-7.2.0-x86-mingw\bin\avr-gcc.exe <br/>c:\avr-gcc-7.2.0-x86-mingw\bin\avr-objcopy.exe <br/>c:\avr-gcc-7.2.0-x86-mingw\bin\avrdude.exe <br/>c:\avr-gcc-7.2.0-x86-mingw\bin\avr-size.exe</quote> <text>Le renommage montré ci-dessus <bold>est un exemple à adapter</bold> selon l'archive de Zak Kemble que vous avez téléchargé en version 32 bits ou 64 bits, et en fonction du chemin d'accès où cette archive a été extraite. Dans l'exemple on voit que j'ai téléchargé l'archive en version <bold>32 bits</bold>, et que je l'ai extraite à la racine du disque dur <bold>c:\</bold>.</text> <title>Le programmateur :</title> <underline></underline> <text>Le programmateur est une petite carte qui fait l'interface entre votre ordinateur personnel et le microcontrôleur, ce qui permet d'envoyer votre programme dans ce circuit intégré. Vous pouvez fabriquer un programmateur vous-même, ou utiliser une carte toute faite. Pour ma part j'ai essayé les deux.</text> <a href="photo/dsc08195.jpg"><img src="thumbnail/dsc08195.jpg"></img></a> <text>Je vous conseille d'utiliser le programmateur <bold>USBasp</bold> qui est très performant et robuste, disponible à l'achat ici :</text> <a href="http://www.google.fr/search?tbm=shop&q=usbasp+6+pin+header"><download>Recherche Google pour acheter le programmateur <bold>USBasp</bold></download></a> <text>La documentation du programmateur <bold>USBasp</bold> est disponible sur le site Web officiel :</text> <a href="http://www.fischl.de/usbasp/"><download>Site Web du programmateur <bold>USBasp</bold></download></a> <quote>Le programmateur <bold>USBasp</bold> est équipé d'un <bold>port USB</bold>, à connecter directement à un port USB de votre ordinateur personnel, et à l'autre extrémité d'un <bold>port ISP</bold> (programmation in-situ) dédié à la programmation du microcontrôleur (c'est un port SPI avec alimentation +5V), à connecter via une nappe adaptée (généralement fournie) sur le port nommé <bold>ISP</bold> de l'automate programmable (qui lui-même alimente en +5V la totalité de l'automate programmable et est relié en SPI au microcontrôleur).</quote> <a href="photo/dsc07984.jpg"><img src="thumbnail/dsc07984.jpg"></img></a> <text><bold>À noter que la programmation ISP a plusieurs avantages par rapport à l'USB :</bold> <br/>- Évite de contenir dans la mémoire Flash du microcontrôleur un chargeur d'amorçage (bootloader). <br/>- De ce fait, évite un délai au démarrage du microcontrôleur. <br/>- Minimise le nombre de composants embarqués sur la carte électronique. <br/>- En conséquence, dispense d'équiper la carte électronique d'un composant permettant de faire la traduction USB/USART vers le chargeur d'amorçage (qui sur certains systèmes concurrents cause des problèmes d'impédance sur les entrées/sorties RXD et TXD du microcontrôleur).</text> <a href="photo/dsc08346.jpg"><img src="thumbnail/dsc08346.jpg"></img></a> <a href="photo/dsc08121.jpg"><img src="thumbnail/dsc08121.jpg"></img></a> <title>Compiler et téléverser votre programme dans l'automate programmable :</title> <underline></underline> <text>Pour compiler et téléverser votre programme dans l'automate programmable via le programmateur USBasp, il vous suffit d'exécuter les routines contenues dans le répertoire <bold>example</bold> situé dans l'archive du programme MODULE (téléchargeable en page d'accueil de mon site Web dans la section "Téléchargements") nommées <bold>Compiler uploader.sh</bold> si vous utilisez un système d'exploitation Linux ou macOS, ou <bold>Compiler uploader.bat</bold> si vous utilisez un système d'exploitation Windows.</text> <quote>À l'exécution, ces routines (Compiler uploader.sh et Compiler uploader.bat) compileront et téléverseront dans l'automate programmable (connecté en ISP via le programmateur USBasp à votre ordinateur personnel) <bold>tous les fichiers avec l'extension .cpp</bold> (fichiers C++) situés dans le répertoire courant.</quote> <caution>Attention, pour que l'opération de téléversement fonctionne lors de l'exécution des routines exprimées ci-dessus, selon le système d'exploitation il est nécessaire d'appliquer les procédures décrites ci-dessous. Dans le cas contraire la communication par USB avec l'USBasp ne pourra pas s'effectuer.</caution> <text><bold>Procédure pour Linux :</bold> <br/>Sur certaines versions anciennes de Linux, il convient d'écrire quelques lignes dans le terminal afin d'ouvrir un fichier qui permettra de spécifier quelques règles utiles pour pouvoir communiquer avec l'USBasp :</text> <code>sudo gedit /etc/udev/rules.d/99-USBasp.rules</code> <text>Cette ligne ouvre l'éditeur de texte <bold>Gedit</bold>, ensuite il suffit de copier la ligne suivante dans cet éditeur de texte :</text> <code>SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", GROUP="plugdev", MODE="0666"</code> <text>Une fois ceci effectué, vous enregistrez le fichier, et vous pouvez quitter Gedit.</text> <quote>Pour simplifier, il est également possible d'automatiser la procédure décrite ci-dessus en créant une routine (bash) ayant l'extension <bold>.sh</bold> que vous pourrez exécuter.</quote> <text>Cette routine (.sh) contient le programme suivant :</text> <code>#!/bin/bash echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"16c0\", ATTRS{idProduct}==\"05dc\", GROUP=\"plugdev\", MODE=\"0666\"" | sudo tee /etc/udev/rules.d/99-USBasp.rules read exit 0</code> <text><bold>Procédure pour Windows :</bold> <br/>Sur Windows le pilote de l'USBasp n'est pas présent par défaut sur ce système. Par conséquent vous devez le télécharger et l'installer vous-même.</text> <text>Il existe nombre de pilotes pour le fonctionnement de l'USB sur Windows, mais l'auteur de l'USBasp recommande d'utiliser un outil qui se nomme <bold>Zadig</bold> qui permet de rechercher et installer automatiquement ce pilote. Personnellement je n'ai jamais essayé (ne possédant pas Windows) mais vu la qualité de son travail je pense que cela est de bon conseil. Ce logiciel est disponible en version pour <bold>Windows 7</bold> (ou supérieur) et également en versions plus anciennes pour <bold>Windows XP</bold> (voir dans la page "Other versions" de la section "Download" de son site Web) :</text> <a href="http://zadig.akeo.ie/"><download>Site Web de <bold>Zadig</bold></download></a> <text>Lors de l'utilisation de ce logiciel, il vous faut spécifier le programmateur utilisé (l'USBasp), ainsi que le pilote, en l'occurrence il se nomme <bold>libusb</bold>. Ce dernier est en fait une bibliothèque, que vous pouvez télécharger séparément si vous le souhaitez :</text> <a href="http://libusb.info/"><download>Site Web de <bold>libusb</bold></download></a> <title>Les fusibles du microcontrôleur :</title> <underline></underline> <text>Quand vous achetez un microcontrôleur neuf n'ayant jamais été programmé, les fusibles qui permettent de définir des paramètres comme la vitesse de téléversement, l'utilisation d'un quartz externe ou encore le verrouillage du SPI (et bien d'autres paramètres fondamentaux pour le microcontrôleur) sont définis par défaut par le constructeur de la puce.</text> <text>Les routines décrites ci-dessus (Compiler uploader.sh et Compiler uploader.bat) s'occupent de modifier automatiquement les valeurs des fusibles.</text> <caution>Les valeurs des fusibles que j'ai indiqué dans les routines sont les <bold>plus optimisées pour les automates programmable MODULABLE 20 et MODULABLE 32</bold> que j'ai développé (dont les plans de fabrication sont disponibles dans les sections "Fabrications et diverses réalisations" et "Téléchargements" en page d'accueil de mon site Web).</caution> <text>Si jamais vous souhaitez programmer avec MODULE sans utiliser les routines que je propose, sachez que cette opération sur les fusibles est à effectuer une seule fois dans deux cas précis, lorsque vous recevez un <bold>microcontrôleur neuf n'ayant jamais été programmé</bold>, ou lorsque vous récupérez un microcontrôleur qui possiblement dans sa mémoire contient un chargeur d'amorçage (bootloader), ou des paramètres de fusibles inadaptés pour l'architecture de l'automate programmable et le fonctionnement des périphériques.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationAnalogRead.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationAnalogRead"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Lire un potentiomètre avec la classe AnalogRead</title> <underline></underline> <text>La classe <bold>AnalogRead</bold> permet de lire la <bold>tension analogique</bold> (0V à +5V) des GPIO connectées à l'ADC (pour "Analog to Digital Converter" ou convertisseur analogique/numérique) du microcontrôleur.</text> <quote>Cette tension analogique de 0V à +5V est convertie en binaire par l'ADC avec une résolution sur 10 bits (de 0 à 1023 en base 10).</quote> <text><bold>Exemple d'utilisation de la classe AnalogRead :</bold></text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <green>int</green> main() { AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); <red>while</red> (<red>true</red>) { myPotentiometer.read(); <blue>//myPotentiometer.value est la valeur lue :</blue> <red>if</red> (myPotentiometer.value > <pink>511.5</pink>) { <blue>//effectuer une action si la tension lue est supérieure à +2.5V</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myPotentiometer</bold> de type <bold>AnalogRead</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>25</bold> de l'automate programmable en entrée, puis cet objet <bold>myPotentiometer</bold> appelle la fonction <bold>read</bold> ce qui permet de lire l'entrée analogique concernée, et donc de mettre à jour la variable <bold>value</bold> attachée à cet objet.</text> <text>Puis aux lignes suivantes, si cette variable est supérieure à <bold>511.5</bold> (+2.5V), le déroulement du programme rentre dans la condition logique.</text> <text><bold>Ports des automates programmables concernés par l'ADC :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 15 (PC0) = ADC0 (analog to digital converter 0) <br/>- Port GPIO 16 (PC1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 17 (PC2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 18 (PC3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 19 (PC4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 20 (PC5) = ADC5 (analog to digital converter 5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 25 (PA7) = ADC7 (analog to digital converter 7) <br/>- Port GPIO 26 (PA6) = ADC6 (analog to digital converter 6) <br/>- Port GPIO 27 (PA5) = ADC5 (analog to digital converter 5) <br/>- Port GPIO 28 (PA4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 29 (PA3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 30 (PA2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 31 (PA1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 32 (PA0) = ADC0 (analog to digital converter 0)</caution> <text>Note importante concernant l'impédance de votre montage :</text> <caution>Le circuit de conversion analogique/numérique du microcontrôleur est optimisé pour fonctionner avec une impédance en entrée de <bold>10kΩ</bold>, et peut fonctionner correctement de <bold>1kΩ</bold> à <bold>100kΩ</bold>. Avec MODULE, le multiplexeur du microcontrôleur fonctionne à une fréquence de <bold>500kHz</bold> car le pré-diviseur d'horloge est réglé sur 32 et la fréquence du microcontrôleur est de 16MHz, la période est donc de <bold>2µs</bold>, sachant que la capacité de la ligne vers le convertisseur analogique/numérique est de <bold>14pF</bold>, le temps pour la charger à <bold>5τ</bold> (soit 99%) avec une impédance d'entrée de <bold>10kΩ</bold> (valeur conseillée) est donc de : <br/>10kΩ * 14pF * 5τ = <bold>700ns</bold> <br/> <br/>Ceci est largement inférieur à <bold>2µs</bold> (la période du multiplexage), ce qui signifie qu'avec une impédance d'entrée de <bold>10kΩ</bold>, la capacité de la ligne aura le temps de se charger au-delà de 99% sans problème. <br/> <br/>Un autre calcul permet de connaître l'impédance maximale admissible dans cette configuration : <br/>2µs / (14pF * 5τ) ≈ <bold>28.571kΩ</bold> <br/> <br/>Avec MODULE il est fortement déconseillé de dépasser une impédance d'entrée de ≈ <bold>28.571kΩ</bold>, car dans ce cas la capacité de la ligne égale à <bold>14pF</bold> n'aurait pas le temps de se charger au moins à 99% dans la période de <bold>2µs</bold>.</caution> <title>Détection d'un niveau de batterie faible :</title> <underline></underline> <text>Avec une entrée analogique disponible et un montage en <bold>pont diviseur de tension</bold>, il vous est possible aisément de détecter si votre batterie d'alimentation est déchargée.</text> <text>Imaginons le cas suivant, vous disposez comme alimentation électrique d'une batterie avec une <bold>tension maximale de +12V</bold>. Une précaution d'usage s'impose alors :</text> <caution>Ne mettez jamais sur un port GPIO de l'automate programmable une tension supérieure à <bold>+5V</bold>, vous risqueriez d'endommager irrémédiablement le microcontrôleur !</caution> <text>Le but est donc de diviser cette tension pour qu'elle ne soit jamais supérieure à +5V <bold>accumulateur complètement chargé</bold> + <bold>tolérances de sécurité</bold>.</text> <text>Pour faire un pont diviseur de tension, vous devez connecter une résistance sur le <bold>pôle positif</bold> de la batterie (cathode), une autre sur le <bold>pôle négatif</bold> de la batterie (masse/anode), et relier les autres extrémités encore non connectées des deux résistances entres elles, puis relier le tout sur une broche connectée au convertisseur analogique/numérique du microcontrôleur qui va servir à mesurer et convertir cette tension.</text> <text><bold>Calcul du pont diviseur de tension :</bold></text> <quote><bold>Constantes :</bold> <br/>Tension maximale de la batterie = <bold>12V</bold> <br/>Tension niveau de batterie faible = <bold>6V</bold> <br/>Tension d'alimentation du microcontrôleur = <bold>5V</bold> <br/>Résistance connectée à la cathode de la batterie = <bold>10kΩ ± 1%</bold> <br/>Résistance connectée à l'anode de la batterie = <bold>2kΩ ± 1%</bold></quote> <quote><bold>Calcul des tolérances minimales et maximales de la résistance connectée à la cathode de la batterie :</bold> <br/>Résistance minimale = 10kΩ - ((10kΩ / 100) * 1%) = 9.9kΩ <br/>Résistance maximale = 10kΩ + ((10kΩ / 100) * 1%) = 10.1kΩ <br/> <br/><bold>Calcul des tolérances minimales et maximales de la résistance connectée à l'anode de la batterie :</bold> <br/>Résistance minimale = 2kΩ - ((2kΩ / 100) * 1%) = 1.98kΩ <br/>Résistance maximale = 2kΩ + ((2kΩ / 100) * 1%) = 2.02kΩ</quote> <caution><bold>Valeurs maximales en sortie du pont diviseur de tension (lorsque la batterie d'alimentation est pleinement chargée) :</bold> <br/>Tension maximale = (2.02kΩ / (9.9kΩ + 2.02kΩ)) * 12V ≈ <bold>2.033V</bold> <br/>Intensité maximale = 12V / (9.9kΩ + 1.98kΩ) ≈ <bold>1.01mA</bold> <br/> <br/><bold>Valeurs minimales en sortie du pont diviseur de tension (lorsque le niveau de batterie faible est atteint) :</bold> <br/>Tension minimale = (1.98kΩ / (10.1kΩ + 1.98kΩ)) * 6V ≈ <bold>0.983V</bold> <br/>Intensité minimale = 6V / (10.1kΩ + 2.02kΩ) ≈ <bold>0.495mA</bold> <br/> <br/><bold>Valeur à indiquer en programmation pour le niveau de batterie faible :</bold> <br/>Tension nominale = (2kΩ / (10kΩ + 2kΩ)) * 6V = <bold>1V</bold> <br/>Pour ADC 10 bits = 1024 / (5V / ((2kΩ / (10kΩ + 2kΩ)) * 6V)) ≈ <bold>204</bold></caution> <text>Avec ce montage, la tension entre la masse et l'entrée analogique du microcontrôleur n'excédera pas ≈ <bold>+2.033V</bold>, et l'intensité ne pourra être supérieure à ≈ <bold>1.01mA</bold> lorsque la batterie d'alimentation sera pleinement chargée à <bold>+12V</bold>. Dans un autre cas, lorsque le niveau de batterie faible de <bold>+6V</bold> sera atteint, la tension entre la masse et l'entrée analogique du microcontrôleur sera au minimum de ≈ <bold>+0.983V</bold>, et l'intensité ne pourra être inférieure à ≈ <bold>0.495mA</bold>, ce qui garantit une tension et une intensité suffisante en entrée du convertisseur analogique/numérique au moment ou la batterie sera considérée comme déchargée. <text>Dans le code source de votre projet, le seuil de niveau de batterie faible à indiquer en programmation sera de <bold>204</bold> en base 10 pour ADC 10 bits, ce qui donne le programme suivant :</text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <green>int</green> main() { AnalogRead myVoltage = AnalogRead (<pink>25</pink>); <red>while</red> (<red>true</red>) { myVoltage.read(); <blue>//si la tension de la batterie est inférieure à +6V :</blue> <red>if</red> (myVoltage.value < <pink>204</pink>) { <blue>//niveau de batterie faible</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Ensuite, si la tension de votre source d'alimentation fluctue de façon importante, il vous est possible de lisser la valeur à l'aide de la classe <bold>Filter</bold>, comme le montre l'exemple suivant :</text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Filter.h></pink> <green>int</green> main() { AnalogRead myVoltage = AnalogRead (<pink>25</pink>); Filter myFilter = Filter (<pink>1000</pink>, <red>false</red>); <red>while</red> (<red>true</red>) { myVoltage.read(); myFilter.set (myVoltage.value); <blue>//si la tension filtrée de la batterie est inférieure à +6V :</blue> <red>if</red> (myFilter.value < <pink>204</pink>) { <blue>//niveau de batterie faible</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Dans ce présent cas, le filtre va effectuer une moyenne sur l'équivalent de <bold>1000 échantillons</bold>, la tension récupérée sera alors débarrassée des fluctuations dues aux variations de la puissance consommée et au bruit électrique.</text> <caution>Maintenant, au lieu d'indiquer la valeur de <bold>204</bold> dans la condition logique, ce qui n'est pas très parlant dans le programme, il est possible d'indiquer directement le seuil de <bold>+6V</bold> à ne pas dépasser en effectuant simplement un changement d'échelle de la valeur de <bold>0</bold> à <bold>1023</bold> retournée par le convertisseur analogique/numérique. Ceci mobilise la fonction <bold>curve</bold> de la classe <bold>Math</bold>.</caution> <quote>Afin de renseigner les paramètres de la fonction curve, il nous faut calculer la tension maximale d'alimentation avec toujours la même configuration en pont diviseur de tension (voir les constantes énoncées plus haut), soit le calcul suivant : <br/>5V / (2kΩ / (10kΩ + 2kΩ)) = <bold>30V</bold></quote> <text>En indiquant <bold>+30V</bold> dans la fonction <bold>curve</bold>, nous pouvons à présent renseigner <bold>+6V</bold> dans la condition logique :</text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Filter.h></pink> <purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { AnalogRead myVoltage = AnalogRead (<pink>25</pink>); Filter myFilter = Filter (<pink>1000</pink>, <red>false</red>); <red>while</red> (<red>true</red>) { myVoltage.read(); myFilter.set (Math::curve (<pink>0</pink>, myVoltage.value, <pink>1023</pink>, <pink>0</pink>, <pink>30</pink>, <pink>0</pink>)); <blue>//si la tension filtrée de la batterie est inférieure à +6V :</blue> <red>if</red> (myFilter.value < <pink>6</pink>) { <blue>//niveau de batterie faible</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, il est plus aisé de pouvoir fixer un seuil de tension en Volt sans avoir la contrainte de devoir tout recalculer manuellement à chaque fois.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>unsigned int</green> value = <pink>0</pink>; AnalogRead (<green>const unsigned char</green> PIN_ANALOG); <green>void</green> read();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationAverage.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationAverage"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les moyennes avec la classe Average</title> <underline></underline> <text>Contrairement à un filtre non prédictif, la moyenne de valeurs n'induit pas de délais (ou lissage temporel) dans l'obtention des résultats justes. Ainsi avec la classe <bold>Average</bold> vous pouvez effectuer des moyennes sur un nombre d'échantillons prédéfini à l'avance.</text> <text><bold>Exemple d'utilisation de la classe Average :</bold></text> <code><purple>#include</purple> <pink><Average.h></pink> <purple>#include</purple> <pink><AnalogRead.h></pink> <green>int</green> main() { Average myAverage = Average (<pink>50</pink>); AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); <red>while</red> (<red>true</red>) { myPotentiometer.read(); myAverage.set (myPotentiometer.value); <blue>//myAverage.value est la moyenne effectuée sur 50 échantillons de la valeur retournée par le potentiomètre</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myAverage</bold> de type <bold>Average</bold> est déclaré, en paramètre est indiqué d'effectuer une moyenne sur <bold>50</bold> échantillons. Puis un objet <bold>myPotentiometer</bold> de type <bold>AnalogRead</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>25</bold> de l'automate programmable en entrée.</text> <text>Dans la boucle, cet objet <bold>myPotentiometer</bold> appelle la fonction <bold>read</bold> ce qui permet de lire l'entrée analogique concernée, et donc de mettre à jour la variable <bold>value</bold> attachée à cet objet, variable qui est envoyée en paramètre à la fonction <bold>set</bold> de l'objet <bold>myAverage</bold> à la ligne suivante, et fonction qui se charge d'effectuer la moyenne.</text> <quote>Ainsi la variable <bold>value</bold> de l'objet <bold>myAverage</bold> est la <bold>moyenne effectuée sur 50 échantillons</bold> de la valeur retournée par le potentiomètre.</quote> <text>L'exemple ci-dessus montre comment facilement effectuer une moyenne sur 50 échantillons d'un nombre provenant d'une source analogique, <bold>nombre obtenu une seule fois à chaque tour de boucle</bold>. Dans ce cas de figure, il est évident que vous ne pourrez pas obtenir les 50 échantillons immédiatement et donc effectuer une moyenne sur la quantité spécifiée en paramètre à la première itération :</text> <caution>La classe <bold>Average</bold> permet de palier à cette problématique en <bold>effectuant progressivement la moyenne</bold> demandée lors du démarrage du procédé, soit dans cet exemple, lors des 49 premiers tours de la boucle de calcul, ceci <bold>tout en restant juste</bold>, et ce jusqu'à ce que les 50 premiers tours de boucle soient effectués, après quoi la moyenne s'effectue normalement (sur 50 valeurs).</caution> <text>Pour finir, d'autres fonctions utiles existent :</text> <quote>- <bold>amount</bold> : permet de modifier à tout moment le nombre d'échantillons sur lesquels la moyenne s'effectue. <br/>- <bold>reset</bold> : permet de réinitialiser la moyenne, donc lors des prochains appels à la fonction <bold>set</bold> la valeur moyenne résultante prendra effet sur de nouvelles valeurs envoyées en paramètre à cette fonction (comme si les précédentes données avaient été effacées).</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> value = <pink>0</pink>; Average (<green>const unsigned char</green> AMOUNT); <green>void</green> set (<green>const float</green> VALUE); <green>void</green> amount (<green>const unsigned char</green> AMOUNT); <green>void</green> reset();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationDelay.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationDelay"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les délais simplifiés avec la classe Delay</title> <underline></underline> <text>Créer une condition logique qui s'exécute de façon périodique n'a jamais été aussi simple à l'aide de la classe <bold>Delay</bold>.</text> <text><bold>Exemple d'utilisation de la classe Delay :</bold></text> <code><purple>#include</purple> <pink><Delay.h></pink> <green>int</green> main() { Delay myDelay = Delay (<pink>1000</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { myDelay.state(); <red>if</red> (myDelay.update == <red>true</red>) { <blue>//tâche à effectuer toutes les 1000ms</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myDelay</bold> de type <bold>Delay</bold> est déclaré, le 1er paramètre <bold>1000</bold> fixe la durée du délai indiqué en millisecondes, et le 2ème paramètre <bold>true</bold> permet d'initialiser à vrai la valeur de la variable <bold>update</bold> qui va suivre. Plus loin dans la boucle, l'appel à la fonction <bold>state</bold> permet de mettre à jour la variable <bold>update</bold> périodiquement en fonction de la durée précédemment indiquée.</text> <text>Si vous souhaitez que la variable <bold>update</bold> soit égale à vrai après le premier appel à la fonction <bold>state</bold> dans la boucle, indiquez <bold>true</bold> (vrai) en paramètre lors de la création de l'objet myDelay, dans le cas contraire indiquez <bold>false</bold> (faux) :</text> <quote>Le paramètre sur <bold>true</bold> aura pour effet de faire rentrer l'exécution dans la condition logique au démarrage du programme, alors qu'une valeur sur <bold>false</bold> (dans cet exemple) fera attendre 1000 millisecondes avant d'exécuter le contenu de la condition logique.</quote> <caution>Il est important de comprendre que la valeur de la variable <bold>update</bold> est un <bold>événement monostable</bold> (en opposition à un événement bistable ou astable), qui prend l'état vrai une seule fois après le passage par la fonction <bold>state</bold>, après quoi il reprendra l'état <bold>faux</bold> aux prochains passages (en attendant que la durée spécifiée est de nouveau atteinte).</caution> <title>Faire clignoter une del périodiquement :</title> <underline></underline> <text>Même si la classe <bold>Delay</bold> est vouée à une utilisation plus poussée si nous le souhaitons, une façon aisée d'apprendre à l'utiliser est de reprendre l'exemple ci-dessus pour simplement commuter une del toutes les secondes.</text> <text><bold>Exemple de clignotement d'une del avec la classe Delay :</bold></text> <code><purple>#include</purple> <pink><GpioWrite.h></pink> <purple>#include</purple> <pink><Delay.h></pink> <green>int</green> main() { GpioWrite myLed = GpioWrite (<pink>1</pink>); Delay myDelay = Delay (<pink>1000</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { myDelay.state(); <red>if</red> (myDelay.update == <red>true</red>) { myLed.toggle(); } } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple est de lui-même explicite, la valeur de la variable <bold>update</bold> change d'état périodiquement et permet à la del de commuter toutes les 1000 millisecondes. La valeur sur <bold>true</bold> (vrai) à la déclaration de l'objet de type <bold>Delay</bold> se chargera de commuter la del (de l'allumer) dès le démarrage du programme, c'est-à-dire au premier tour de la boucle <bold>while</bold>.</text> <quote>D'autres fonctions existent si besoin est, notamment <bold>duration</bold> qui permet d'indiquer une durée différente que celle initialisée lors de la déclaration de l'objet (utile en cours de programme si vous souhaitez changer la périodicité), et <bold>reset</bold> qui réinitialise le temps écoulé, de sorte que la durée indiquée devra de nouveau être atteinte à partir de ce moment.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>bool</green> update = <red>false</red>; Delay (<green>const unsigned long long</green> DURATION, <green>const bool</green> NO_START_DELAY); <green>void</green> state(); <green>void</green> duration (<green>const unsigned long long</green> DURATION); <green>void</green> reset();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationEeprom.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationEeprom"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Lire et écrire dans la mémoire du microcontrôleur avec la classe Eeprom</title> <underline></underline> <text>Sauvegarder les valeurs de certaines variables dans la mémoire interne du microcontrôleur lorsque celui-ci est <bold>coupé de son alimentation électrique</bold> est essentiel dans de nombreux projets. La mémoire EEPROM du microcontrôleur est dédiée à cette tâche car elle est <bold>non volatile</bold> et autorise de nombreux cycles de lecture/écriture.</text> <text>Cette mémoire est accessible très simplement à l'aide des fonctions <bold>read</bold>, <bold>write</bold>, et <bold>erase</bold> de la classe <bold>Eeprom</bold>.</text> <text>Le nombre d'emplacements mémoire disponibles et accessibles via la classe <bold>Eeprom</bold> correspond à la quantité d'octets de mémoire EEPROM disponibles et dépend donc du microcontrôleur utilisé :</text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- EEPROM du microcontrôleur ATmega48P = 256 octets (0.25Kio) <br/>- EEPROM du microcontrôleur ATmega88P = 512 octets (0.5Kio) <br/>- EEPROM du microcontrôleur ATmega168P = 512 octets (0.5Kio) <br/>- EEPROM du microcontrôleur ATmega328P = 1024 octets (1Kio) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- EEPROM du microcontrôleur ATmega164P = 512 octets (0.5Kio) <br/>- EEPROM du microcontrôleur ATmega324P = 1024 octets (1Kio) <br/>- EEPROM du microcontrôleur ATmega644P = 2048 octets (2Kio) <br/>- EEPROM du microcontrôleur ATmega1284P = 4096 octets (4Kio)</caution> <text>Par exemple le microcontrôleur <bold>ATmega1284P</bold> dispose de <bold>4096</bold> emplacements mémoire.</text> <quote>Il est essentiel de ce référer à la note ci-dessus afin de ne pas dépasser la mémoire disponible pour un microcontrôleur donné (éviter de vouloir accéder à un emplacement mémoire qui n'existe pas).</quote> <title>Lire la mémoire EEPROM :</title> <underline></underline> <text>La lecture de la mémoire EEPROM du microcontrôleur ne demande pas beaucoup d'opérations.</text> <text><bold>Exemple de lecture de la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { <green>unsigned char</green> myData = <pink>0</pink>; myData = Eeprom::read (<pink>1</pink>, <pink>8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple la fonction statique <bold>read</bold> est appelée prenant en 1er paramètre <bold>1</bold>, l'emplacement mémoire demandé (soit la lecture du 1er octet de la mémoire).</text> <text>Puis la fonction prend en 2ème paramètre <bold>8</bold>, le nombre de bits à lire. Ce paramètre peut prendre les valeurs possibles <bold>8</bold>, <bold>16</bold>, et <bold>32</bold> :</text> <quote>- <bold>8</bold> : 8 bits de mémoire seront lus sur l'emplacement mémoire 1. <br/>- <bold>16</bold> : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2. <br/>- <bold>32</bold> : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.</quote> <text>Et également les valeurs <bold>-8</bold>, <bold>-16</bold>, et <bold>-32</bold> (voir plus bas : "Lecture et interprétation des nombres négatifs") :</text> <quote>- <bold>-8</bold> : 8 bits de mémoire seront lus sur l'emplacement mémoire 1. <br/>- <bold>-16</bold> : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2. <br/>- <bold>-32</bold> : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.</quote> <caution>Bien entendu le nombre de bits indiqué en paramètre doit être cohérent avec ce que vous souhaitez lire, de même avec la taille de donnée de destination (myData dans l'exemple), sauf si ces transformations sont nécessaires et trouvent une logique dans le fonctionnement de votre programme.</caution> <title>Lecture et interprétation des nombres négatifs :</title> <underline></underline> <text>Si vous souhaitez lire en mémoire EEPROM un nombre signé tout en conservant son interprétation correcte, il convient de renseigner le 2ème paramètre de la fonction statique <bold>read</bold> comme étant négatif.</text> <text><bold>Exemple de lecture d'un nombre négatif de 8 bits dans la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { <green>signed char</green> myData = <pink>0</pink>; myData = Eeprom::read (<pink>1</pink>, <pink>-8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le 2ème paramètre de la fonction statique <bold>read</bold> prend la valeur <bold>-8</bold>, ce qui force le format retourné sur <bold>8 bits signés</bold>.</text> <text><bold>Exemple de lecture d'un nombre négatif de 32 bits dans la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { <green>signed long</green> myData = <pink>0</pink>; myData = Eeprom::read (<pink>1</pink>, <pink>-32</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Ici le 2ème paramètre de la fonction statique <bold>read</bold> prend la valeur <bold>-32</bold>, ce qui force le format retourné sur <bold>32 bits signés</bold>.</text> <title>Écrire dans la mémoire EEPROM :</title> <underline></underline> <text>La fonction d'écriture reprend les mêmes principes que la fonction de lecture, soit un certain nombre d'emplacements disponibles et une certaine taille de donnée.</text> <text><bold>Exemple d'écriture d'un octet dans la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { Eeprom::write (<pink>1</pink>, <pink>135</pink>, <pink>8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>La fonction statique <bold>write</bold> est appelée prenant en 1er paramètre l'emplacement mémoire demandé, en 2ème paramètre la donnée à écrire dans la mémoire EEPROM, et en 3ème paramètre le nombre de bits qui seront écrits dans la mémoire.</text> <quote>Ici c'est le nombre <bold>135</bold> qui est écrit dans la mémoire à l'emplacement <bold>1</bold>. Ce nombre occupe <bold>8</bold> bits de mémoire, soit 1 octet.</quote> <text><bold>Exemple d'écriture de deux octets dans la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { Eeprom::write (<pink>1</pink>, <pink>6950</pink>, <pink>16</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus c'est le nombre <bold>6950</bold> qui est écrit dans la mémoire à partir de l'emplacement <bold>1</bold>. Il est indiqué que ce nombre occupe <bold>16</bold> bits de mémoire, soit 2 octets. Il s'étend donc jusqu'à l'emplacement <bold>2</bold> de la mémoire.</quote> <text><bold>Exemple d'écriture de quatre octets dans la mémoire EEPROM du microcontrôleur :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { Eeprom::write (<pink>101</pink>, <pink>-125000</pink>, <pink>-32</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le nombre <bold>-125000</bold> est écrit dans la mémoire à partir de l'emplacement <bold>101</bold>. Ce nombre occupe <bold>32</bold> bits de mémoire, soit 4 octets. Il s'étend donc jusqu'à l'emplacement <bold>104</bold> de la mémoire.</quote> <quote>La fonction statique <bold>write</bold> n'est pas sujette à la contrainte des nombres négatifs comme l'est la fonction statique <bold>read</bold>, vous pouvez donc renseigner indifféremment le paramètre <bold>LENGTH</bold> comme étant positif ou négatif (dans l'exemple ci-dessus 32 ou -32).</quote> <title>Effacer la mémoire EEPROM :</title> <underline></underline> <text>Pour effacer la totalité de la mémoire EEPROM, autrement dit remettre tous les bits à 0, il suffit d'appeler la fonction statique <bold>erase</bold> comme le montre l'exemple ci-dessous.</text> <text><bold>Exemple pour effacer la totalité de la mémoire EEPROM :</bold></text> <code><purple>#include</purple> <pink><Eeprom.h></pink> <green>int</green> main() { Eeprom::erase(); <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus la fonction statique <bold>erase</bold> est appelée, ce qui efface toute la mémoire EEPROM du microcontrôleur.</text> <caution>À noter que les fonctions d'écriture comme <bold>write</bold> ou d'effacement comme <bold>erase</bold> (qui est une écriture de 0) offrent l'avantage d'économiser les cycles d'écriture pour <bold>garantir la meilleure durée de vie de la mémoire EEPROM</bold>. En effet ces fonctions lisent la mémoire avant d'y écrire, de sorte que l'écriture n'intervient que lorsque nécessaire.</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code><green>static signed long</green> read (<green>const unsigned int</green> ADDRESS, <green>const signed char</green> LENGTH); <green>static void</green> write (<green>const unsigned int</green> ADDRESS, <green>const signed long</green> DATA, <green>const signed char</green> LENGTH); <green>static void</green> erase();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationFilter.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationFilter"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Filtrer des valeurs avec la classe Filter</title> <underline></underline> <text>Le filtrage de données brutes provenant de sources analogiques bruitées est essentiel dans beaucoup de projets, ainsi que l'obtention de moyennes <bold>en temps réel ou avec progressivité dans le temps</bold> afin par exemple d'en stabiliser la visualisation sur des affichages.</text> <text>La classe <bold>Filter</bold> est un filtre linéaire non prédictif très performant qui automatise cette tâche et offre l'avantage de pouvoir effectuer des moyennes soit sur l'équivalent d'un certain nombre d'échantillons, soit sur une certaine durée paramétrable, ce qui dans ce dernier cas est très intéressant car cette fonction rend les moyennes effectuées <bold>complètement indépendantes de la vitesse d'exécution du programme</bold>.</text> <quote>L'intérêt de lisser des valeurs fluctuantes sur un temps bien défini permet de <bold>faire abstraction des temps d'exécution des boucles de calculs</bold>. Ceci est utile pour maintenir la même capacité à calculer en temps réel quel que soit la complexité des algorithmes mis en œuvre dans vos programmes.</quote> <text><bold>Exemple de filtrage sur 50 échantillons :</bold></text> <code><purple>#include</purple> <pink><Filter.h></pink> <purple>#include</purple> <pink><AnalogRead.h></pink> <green>int</green> main() { Filter myFilter = Filter (<pink>50</pink>, <red>false</red>); AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); <red>while</red> (<red>true</red>) { myPotentiometer.read(); myFilter.set (myPotentiometer.value); <blue>//myFilter.value est un filtrage effectué sur l'équivalent de 50 échantillons de la valeur retournée par le potentiomètre</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myFilter</bold> de type <bold>Filter</bold> est déclaré : <br/>- Le 1er paramètre indique d'effectuer un filtrage sur l'équivalent de <bold>50</bold> échantillons ou sur une durée de <bold>50</bold> millisecondes (selon l'état du paramètre suivant). <br/>- Le 2ème paramètre <bold>false</bold> spécifie un filtrage sur l'équivalent d'un certain nombre d'échantillons.</text> <caution>Si vous souhaitez effectuer un filtrage sur une durée plutôt que sur l'équivalent d'un certain nombre d'échantillons, indiquez <bold>true</bold> en paramètre.</caution> <text>Ensuite un objet <bold>myPotentiometer</bold> de type <bold>AnalogRead</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>25</bold> de l'automate programmable en entrée. Dans la boucle, cet objet <bold>myPotentiometer</bold> appelle la fonction <bold>read</bold> ce qui permet de lire l'entrée analogique concernée, et donc de mettre à jour la variable <bold>value</bold> attachée à cet objet, variable qui est envoyée en paramètre à la fonction <bold>set</bold> de l'objet <bold>myFilter</bold> à la ligne suivante, et fonction qui se charge d'effectuer le filtrage.</text> <quote>Ainsi la variable <bold>value</bold> de l'objet <bold>myFilter</bold> est un filtrage effectué sur l'équivalent de <bold>50</bold> échantillons de la valeur retournée par le potentiomètre.</quote> <caution>Plus l'amplitude du filtre est élevée, plus les valeurs sont lissées.</caution> <text><bold>Exemple de filtrage sur 50 millisecondes :</bold></text> <code><purple>#include</purple> <pink><Filter.h></pink> <purple>#include</purple> <pink><AnalogRead.h></pink> <green>int</green> main() { Filter myFilter = Filter (<pink>50</pink>, <red>true</red>); AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); <red>while</red> (<red>true</red>) { myPotentiometer.read(); myFilter.set (myPotentiometer.value); <blue>//myFilter.value est un filtrage effectué sur une durée de 50 millisecondes de la valeur retournée par le potentiomètre</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Le seul changement ici par rapport au précédent exemple est le 2ème paramètre passé de <bold>false</bold> à <bold>true</bold> à la déclaration de l'objet <bold>myFilter</bold>.</text> <text>Pour comprendre le filtrage indépendant de la vitesse d'exécution :</text> <caution>Si la durée du filtrage est spécifiée à <bold>1000 millisecondes</bold>, et qu'entre 2 itérations, soit 2 appels à la fonction <bold>set</bold>, un temps de <bold>8 millisecondes</bold> s'est écoulé, alors le filtre effectuera à cet instant l'équivalent d'une moyenne sur <bold>125 échantillons</bold>, car : <br/>1000ms / 8ms = <bold>125 échantillons</bold> <br/> <br/>En mode de filtrage temporel, la durée qui précède le dernier appel à la fonction <bold>set</bold> est intégré dans les calculs de la moyenne, de sorte d'effectuer un filtrage indépendamment des vitesses d'exécution du code, ce qui est fondamental pour garder une homogénéité dans le comportement des données filtrées.</caution> <text>Pour finir, d'autres fonctions utiles existent :</text> <quote>- <bold>amount</bold> : permet de modifier à tout moment l'amplitude du filtrage. <br/>- <bold>reset</bold> : permet de réinitialiser le filtre, donc lors du prochain appel à la fonction <bold>set</bold> la valeur filtrée résultante prendra effet sur de nouvelles valeurs envoyées en paramètre à cette fonction (comme si les précédentes données avaient été effacées).</quote> <text>Le filtrage est généralement indispensable dans la majorité des projets, ne serait-ce que pour pouvoir visualiser sur des affichages numériques des valeurs stables. La classe <bold>Filter</bold> est un bon complément en association avec la classe <bold>Hysteresis</bold> dans le but de produire des informations exploitables pour l'utilisateur.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> value = <pink>0</pink>; Filter (<green>const unsigned long</green> AMOUNT, <green>const bool</green> TIME_COMPENSATION); <green>void</green> set (<green>const float</green> VALUE); <green>void</green> amount (<green>const unsigned long</green> AMOUNT); <green>void</green> reset();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationGpioRead.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationGpioRead"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Lire l'état d'un bouton avec la classe GpioRead</title> <underline></underline> <text>La classe <bold>GpioRead</bold> permet de lire <bold>l'état 0 ou 1</bold> (0V ou +5V) d'un ou plusieurs ports GPIO de l'automate programmable avec la possibilité d'utiliser une <bold>résistance de rappel interne au microcontrôleur</bold>, et d'avoir un système <bold>anti-rebonds</bold> bien pratique pour filtrer les rebonds et autres parasites provoquées par les boutons et interrupteurs.</text> <quote>GPIO (pour "General Purpose Input/Output" ou entrée/sortie pour un usage général) est le nom que l'on donne aux ports d'entrée/sortie génériques (c'est-à-dire sans fonctions particulières) principalement dans le monde des microcontrôleurs.</quote> <text><bold>Exemple d'utilisation de la classe GpioRead :</bold></text> <code><purple>#include</purple> <pink><GpioRead.h></pink> <green>int</green> main() { GpioRead myButton = GpioRead (<pink>1</pink>, <red>true</red>, <pink>10</pink>); <red>while</red> (<red>true</red>) { myButton.read(); <red>if</red> (myButton.monostable == <red>true</red>) { <blue>//allumer une del (état momentané)</blue> } <red>if</red> (myButton.bistable == <red>true</red>) { <blue>//allumer une del (état continu)</blue> } <red>else</red> { <blue>//éteindre une del (état continu)</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myButton</bold> de type <bold>GpioRead</bold> est déclaré : <br/>- Le 1er paramètre indique l'utilisation du port GPIO numéro <bold>1</bold> de l'automate programmable en entrée. <br/>- Le 2ème paramètre <bold>true</bold> permet d'utiliser une <bold>résistance de rappel interne</bold>.</text> <caution>La résistance de rappel interne (ou externe) est importante car elle permet de <bold>fixer la tension</bold> et donc l'état 0 ou 1 du port du microcontrôleur. Comprendre que si le bouton connecté à ce port est ouvert et n'utilise pas de résistance de rappel, la broche du microcontrôleur est dans ce cas laissée en l'air, et est sujette à capter le bruit électromagnétique environnant, ce qui correspond à un état indéfini (ce qui n'est pas souhaité).</caution> <text>- Le 3ème paramètre <bold>10</bold> est le <bold>temps en millisecondes</bold> pour filtrer les rebonds.</text> <quote>A noter que <bold>10ms</bold> est une valeur qui fonctionne bien pour filtrer la plupart des boutons. Plus votre bouton ou interrupteur sera d'une qualité médiocre, plus il faudra augmenter cette valeur.</quote> <text>Plus loin cet objet <bold>myButton</bold> appelle la fonction <bold>read</bold> dans une boucle ce qui permet de lire l'état du port GPIO concerné.</text> <text>Cet état <bold>0</bold> ou <bold>1</bold> est stocké dans deux variables, <bold>monostable</bold> et <bold>bistable</bold> : <br/>- monostable signifie que si le bouton est appuyé, <bold>la variable est égale à vrai au premier appel à la fonction read</bold>, mais <bold>qu'elle est égale à faux aux appels suivants</bold> (aux tours de boucle suivants généralement), en attendant que le bouton soit relâché puis par la suite de nouveau appuyé. <br/>- bistable signifie que <bold>tant que le bouton est appuyé, cette variable est égale à vrai</bold>.</text> <caution>Cet état monostable (momentané) permet d'appeler des blocs de code une seule fois lorsqu'un bouton est pressé (sans être relâché immédiatement), c'est un événement <bold>monostable</bold> (en opposition à un événement bistable ou astable), cela peut être utile pour réaliser par exemple des incréments de valeurs, ou bien encore des signaux sonores lorsqu'on presse des boutons, etc...</caution> <text>Bien entendu vous pouvez utiliser cette classe pour d'autres applications (lire autre chose que des boutons ou interrupteurs).</text> <text><bold>Ports des automates programmables concernés par la GPIO :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) <br/>- Port GPIO 2 (PD1) <br/>- Port GPIO 3 (PD2) <br/>- Port GPIO 4 (PD3) <br/>- Port GPIO 5 (PD4) <br/>- Port GPIO 6 (PD5) <br/>- Port GPIO 7 (PD6) <br/>- Port GPIO 8 (PD7) <br/>- Port GPIO 9 (PB0) <br/>- Port GPIO 10 (PB1) <br/>- Port GPIO 11 (PB2) <br/>- Port GPIO 12 (PB3) <br/>- Port GPIO 13 (PB4) <br/>- Port GPIO 14 (PB5) <br/>- Port GPIO 15 (PC0) <br/>- Port GPIO 16 (PC1) <br/>- Port GPIO 17 (PC2) <br/>- Port GPIO 18 (PC3) <br/>- Port GPIO 19 (PC4) <br/>- Port GPIO 20 (PC5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>bool</green> monostable = <red>false</red>; <green>bool</green> bistable = <red>false</red>; GpioRead (<green>const unsigned char</green> PIN, <green>const bool</green> PULL_UP_INTERNAL, <green>const unsigned char</green> DEBOUNCING); <green>void</green> read();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationGpioWrite.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationGpioWrite"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Allumer une del avec la classe GpioWrite</title> <underline></underline> <text>C'est la classe la plus simple à utiliser de MODULE et la première à avoir été écrite. Elle permet de mettre à <bold>l'état 0 ou 1</bold> (0V ou +5V) un ou plusieurs ports GPIO de l'automate programmable.</text> <text><bold>Exemple d'utilisation de la classe GpioWrite :</bold></text> <code><purple>#include</purple> <pink><GpioWrite.h></pink> <green>int</green> main() { GpioWrite myLed = GpioWrite (<pink>1</pink>); myLed.on(); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myLed</bold> de type <bold>GpioWrite</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>1</bold> de l'automate programmable en sortie, puis cet objet <bold>myLed</bold> appelle la fonction <bold>on</bold> ce qui permet de mettre à l'état <bold>1</bold> le port GPIO concerné. Ainsi une diode électroluminescente connectée à ce port s'allumerait.</text> <text>D'autres fonctions existent, <bold>off</bold> pour passer le port à l'état <bold>0</bold>, et <bold>toggle</bold> pour changer l'état du port quel que soit sont état initial (0 ou 1).</text> <caution>Attention, le microcontrôleur <bold>ne peut pas fournir beaucoup de puissance</bold> sur ses broches en sortie !</caution> <text>Il est donc indispensable de piloter un transistor de puissance pour la partie puissance de votre montage. Néanmoins, si il s'agit de quelques 10ènes de milliampères comme dans le cas d'une del ou d'un buzzer, il n'y aura aucun risque à l'alimenter de cette façon.</text> <text><bold>Ports des automates programmables concernés par la GPIO :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) <br/>- Port GPIO 2 (PD1) <br/>- Port GPIO 3 (PD2) <br/>- Port GPIO 4 (PD3) <br/>- Port GPIO 5 (PD4) <br/>- Port GPIO 6 (PD5) <br/>- Port GPIO 7 (PD6) <br/>- Port GPIO 8 (PD7) <br/>- Port GPIO 9 (PB0) <br/>- Port GPIO 10 (PB1) <br/>- Port GPIO 11 (PB2) <br/>- Port GPIO 12 (PB3) <br/>- Port GPIO 13 (PB4) <br/>- Port GPIO 14 (PB5) <br/>- Port GPIO 15 (PC0) <br/>- Port GPIO 16 (PC1) <br/>- Port GPIO 17 (PC2) <br/>- Port GPIO 18 (PC3) <br/>- Port GPIO 19 (PC4) <br/>- Port GPIO 20 (PC5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code>GpioWrite (<green>const unsigned char</green> PIN); <green>void</green> toggle(); <green>void</green> on(); <green>void</green> off();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationHysteresis.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationHysteresis"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Créer des seuils avec la classe Hysteresis</title> <underline></underline> <text>La classe <bold>Hysteresis</bold> permet de fixer les états d'une variable cible via la création automatique de seuils hauts et bas différents suivant l'évolution positive ou négative d'une variable source, et ainsi d'éviter des fluctuations non souhaitées.</text> <text>Imaginons un menu pouvant prendre différentes positions entières de 1 à 10 (soit 10 nombres entiers) navigable à l'aide d'un potentiomètre analogique. La tension de 0V à 5V retournée par le curseur du potentiomètre (qui est un pont diviseur de tension) est traduite par le convertisseur analogique/numérique du microcontrôleur en nombres entiers accessibles en programmation pouvant varier de 0 à 1023.</text> <text><bold>Programmons ce montage comme l'exemple suivant :</bold></text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); <green>unsigned char</green> myMenu = <pink>1</pink>; <red>while</red> (<red>true</red>) { myPotentiometer.read(); myMenu = Math::round (Math::curve (<pink>0</pink>, myPotentiometer.value, <pink>1023</pink>, <pink>1</pink>, <pink>10</pink>, <pink>0</pink>)); <blue>//myMenu est la position dans le menu (de 1 à 10) en fonction de la valeur retournée par le potentiomètre</blue> } <red>return</red> <pink>0</pink>; }</code> <caution>Dans cet exemple, dès que le potentiomètre approche après calcul une valeur se situant à mi-chemin entre deux positions du menu, plus il y a de chances que <bold>le menu saute d'une position à une autre d'une façon tout à fait erratique</bold>, et ce d'autant plus que le bruit analogique du potentiomètre est important.</caution> <text>Pour palier à ce problème, il convient d'introduire un <bold>cycle d'hystérésis</bold> dans le calcul afin que le chemin emprunté par la variation qui anime le menu soit différent selon l'évolution positive ou négative de la valeur du potentiomètre, ce qui créé naturellement une zone delta, comme le montre l'exemple ci-dessous.</text> <text><bold>Exemple d'utilisation de la classe Hysteresis :</bold></text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Math.h></pink> <purple>#include</purple> <pink><Hysteresis.h></pink> <green>int</green> main() { AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); Hysteresis myMenu = Hysteresis(); <red>while</red> (<red>true</red>) { myPotentiometer.read(); myMenu.set (Math::curve (<pink>0</pink>, myPotentiometer.value, <pink>1023</pink>, <pink>1</pink>, <pink>10</pink>, <pink>0</pink>)); <blue>//myMenu.value est la position dans le menu (de 1 à 10) en fonction de la valeur retournée par le potentiomètre</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus, un objet <bold>myPotentiometer</bold> de type <bold>AnalogRead</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>25</bold> de l'automate programmable en entrée. La ligne suivante est différente de l'exemple précédent, puisque c'est un objet <bold>myMenu</bold> de type <bold>Hysteresis</bold> qui est déclaré (ne prenant aucun paramètre).</text> <text>Puis dans la boucle, l'objet <bold>myPotentiometer</bold> appelle la fonction <bold>read</bold> ce qui permet de lire l'entrée analogique concernée, et donc de mettre à jour la variable <bold>value</bold> attachée à cet objet, variable utilisée en paramètre de la fonction statique <bold>curve</bold> de la classe <bold>Math</bold> afin de changer l'échelle de 0 à 1023 (la sortie du convertisseur analogique/numérique) vers 1 à 10 (la valeur souhaitée du menu).</text> <text>Cette valeur pouvant varier de 1 à 10, sortie de la fonction statique <bold>curve</bold>, est un nombre décimal. C'est ce nombre décimal qui est donné en paramètre à la fonction <bold>set</bold> de l'objet <bold>myMenu</bold> :</text> <quote>Il est important de comprendre que le fonctionnement de la classe <bold>Hysteresis</bold> est basé sur l'exploitation des décimales des nombres (en virgule flottante) envoyés en paramètre à la fonction <bold>set</bold>, décimales à partir desquelles la classe <bold>Hyseresis</bold> produit des nombres entiers finis avec hystérésis.</quote> <text>À présent le menu est doté d'un hystérésis et est débarrassé des sauts imprévisibles provoqués par les imperfections inhérentes à l'utilisation de signaux analogiques. La valeur exploitable du menu est accessible via la variable <bold>value</bold> attachée à l'objet <bold>myMenu</bold>.</text> <caution>Dans tous les cas pour que l'hystérésis fonctionne, il convient de s'assurer que la quantité de bruit analogique généré par le potentiomètre soit (largement) inférieure à l'hystérésis souhaité, ce qui est complètement dépendant de la qualité du potentiomètre, du circuit qui l'asservi, et de la plage de valeurs finales (de 1 à 10 dans les exemples) par rapport à la plage de valeurs en sortie du convertisseur analogique/numérique du microcontrôleur (de 0 à 1023).</caution> <text>Un autre exemple d'application du cycle d'hystérésis pourrait être l'allumage et l'extinction d'une chaudière qui devrait être en marche en dessous d'une température, et éteinte au dessus de cette même température. Imaginons une température consigne de 15 degrés Celcius en dessous de laquelle une chaudière démarre. La température initiale est supérieure à 15 degrés Celcius, la chaudière est éteinte et la température baisse progressivement. Dès que la température est inférieure à 15 degrés Celcius, c'est-à-dire 14.999... degrés Celcius, la chaudière démarre. Au bout de quelques secondes la température augmente et passe au dessus de 15 degrés Celcius, immédiatement la chaudière s'éteint alors, la température redescends, puis la chaudière redémarre à nouveau, et ainsi de suite.</text> <text>Dans ce montage la chaudière démarrerait et s'éteindrait d'une façon intempestive, ce qui n'est pas souhaité pour une question pratique, ergonomique, d'économie d'énergie, et d'usure prématurée des composants mis en œuvre. C'est également ici qu'intervient le cycle d'hystérésis, comme le montre l'exemple ci-dessous.</text> <text><bold>Autre exemple d'utilisation de la classe Hysteresis :</bold></text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Math.h></pink> <purple>#include</purple> <pink><Hysteresis.h></pink> <green>int</green> main() { AnalogRead mySensor = AnalogRead (<pink>25</pink>); Hysteresis myTemperature = Hysteresis(); <green>bool</green> myBoilerState = <red>false</red>; <red>while</red> (<red>true</red>) { mySensor.read(); myTemperature.set (Math::curve (<pink>0</pink>, mySensor.value, <pink>1023</pink>, <pink>0</pink>, <pink>100</pink>, <pink>0</pink>)); <red>if</red> (myTemperature.value < <pink>15</pink>) { myBoilerState = <red>true</red>; } <red>else</red> { myBoilerState = <red>false</red>; } <blue>//myBoilerState est l'état de la chaudière (à l'arrêt ou en marche)</blue> } <red>return</red> <pink>0</pink>; }</code> <text>L'hystérésis créé une zone delta de 1 degrés Celcius. Dans ce montage, selon si la température est dans une phase d'augmentation ou de diminution, la chaudière peut être dans un état de marche (true) ou d'arrêt (false) dans cette zone delta.</text> <text>L'hystérésis est donc indispensable dans la majorité des projets afin de faire fonctionner des systèmes correctement et avec fiabilité, ou encore ne serait-ce que pour pouvoir visualiser sur des affichages numériques des valeurs stables. À ce propos, la classe <bold>Hysteresis</bold> est un bon complément en association avec la classe <bold>Filter</bold> dans le but de produire des informations exploitables pour l'utilisateur.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>signed long</green> value = <pink>0</pink>; Hysteresis(); <green>void</green> set (<green>const float</green> VALUE);</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationInterruptRead.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationInterruptRead"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les interruptions avec la classe InterruptRead</title> <underline></underline> <text>Les interruptions permettent <bold>d'interrompre le déroulement normal d'un programme</bold> afin d'effectuer une tâche à un moment précis, puis de continuer l'exécution du programme là où il s'était arrêté.</text> <text>La classe <bold>InterruptRead</bold> permet de détecter un <bold>front montant et/ou descendant</bold> (passage de 0V à +5V ou inversement) sur les broches du microcontrôleur concernées par les interruptions.</text> <text><bold>Ports des automates programmables concernés par les interruptions :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 3 (PD2) = INT0 (interrupt 0) <br/>- Port GPIO 4 (PD3) = INT1 (interrupt 1) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 3 (PB2) = INT2 (interrupt 2) <br/>- Port GPIO 11 (PD2) = INT0 (interrupt 0) <br/>- Port GPIO 12 (PD3) = INT1 (interrupt 1)</caution> <text>L'utilité d'un tel système est de pouvoir <bold>déceler un changement d'état d'un port du microcontrôleur au moment même où il se produit</bold>. Il n'est alors plus nécessaire d'attendre une lecture de l'état du port concerné au sein même d'une boucle de vérification, comme c'est le cas avec la classe <bold>GpioRead</bold> (cette dernière solution produisant une latence suivant la vitesse d'exécution totale de votre boucle de calcul).</text> <quote>Grâce aux interruptions de programme, il vous est par exemple possible de quantifier en nombre et mesurer la périodicité d'un phénomène physique externe qui changerait spontanément d'état (dans les limites techniques imposées par le logiciel et le matériel bien entendu).</quote> <text><bold>Exemple d'utilisation de la classe InterruptRead :</bold></text> <code><purple>#include</purple> <pink><InterruptRead.h></pink> <green>void</green> myEvent() { <blue>//un front montant a été détecté</blue> } <green>int</green> main() { InterruptRead myInterrupt = InterruptRead (<pink>3</pink>); myInterrupt.start (myEvent, <red>true</red>, <red>false</red>); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myInterrupt</bold> de type <bold>InterruptRead</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>3</bold> de l'automate programmable en entrée, puis afin de démarrer la lecture du port concerné, cet objet <bold>myInterrupt</bold> appelle la fonction <bold>start</bold> prenant plusieurs paramètres : <br/>- Le 1er paramètre <bold>myEvent</bold> est le nom de la fonction déclarée en amont qui va servir à exécuter du code quand l'interruption interviendra. <br/>- Le 2ème paramètre <bold>true</bold> permet de détecter les fronts montants sur le port GPIO. <br/>- Le 3ème paramètre <bold>false</bold> indique de ne pas détecter les fronts descendants sur le port GPIO.</text> <quote>Même si vous n'avez pas besoin d'exécuter des instructions dans la boucle <bold>while</bold>, cette dernière reste importante car elle permet au microcontrôleur de continuer l'exécution du code (soit l'écoute des interruptions).</quote> <caution>Dans le cas contraire, l'exécution terminerait après <bold>return 0;</bold>, et le microcontrôleur s'arrêterait là de sorte que plus aucune interruption ne pourrait être exécutée !</caution> <text>Autre fonction disponible :</text> <quote>Cette classe dispose également d'une fonction <bold>stop</bold> qui permet de stopper la lecture des fronts montants et/ou descendants sur le port GPIO concerné.</quote> <text>De nombreuses applications et montages sont possibles avec les interruptions de programme, pour ne citer qu'un exemple, c'est avec ce principe que je détecte la fermeture du tube sur mon compteur Geiger, ce qui permet ensuite d'extrapoler facilement et d'estimer la radioactivité en rapport au temps écoulé entre deux interruptions...</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code>InterruptRead (<green>const unsigned char</green> PIN); <green>void</green> start (<green>void</green> functionJump(), <green>const bool</green> RISING, <green>const bool</green> FALLING); <green>void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationIteration.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationIteration"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Incrémenter des nombres avec la classe Iteration</title> <underline></underline> <text>L'incrémentation et la décrémentation de nombres en programmation est généralement très aisée, mais la classe <bold>Iteration</bold> intègre quelques automatismes qui vous aideront lors d'utilisations un peu plus élaborées.</text> <text>En effet avec la classe <bold>Iteration</bold> il est facile et transparent pour le programmeur <bold>d'incrémenter en boucle</bold> un nombre entier avec une valeur d'incrément égale ou différente de 1 dans un intervalle à ne pas dépasser, soit des limites minimale et maximale, le tout dans une plage positive et/ou négative.</text> <text><bold>Exemple d'utilisation de la classe Iteration :</bold></text> <code><purple>#include</purple> <pink><Iteration.h></pink> <green>int</green> main() { Iteration myIteration = Iteration (<pink>1</pink>, <pink>9</pink>, <pink>10</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { <blue>//incrément de 3 :</blue> myIteration.increment (<pink>3</pink>); <blue>//myIteration.value est la valeur incrémentée, lors de cette première itération elle est égale à 2</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Comme le montre l'exemple ci-dessus, si la limite minimale est de <bold>1</bold> (1er paramètre MIN), la valeur de départ de <bold>9</bold> (2ème paramètre START), la limite maximale de <bold>10</bold> (3ème paramètre MAX), et que la boucle est autorisée avec <bold>true</bold> (4ème paramètre LOOP), alors un incrément de <bold>3</bold> donne après calcul la valeur résultante de <bold>2</bold>, car ((<bold>9</bold> + <bold>3</bold>) - (<bold>10</bold> - <bold>1</bold>)) - 1 = <bold>2</bold>.</text> <text>Comme montré dans cet exemple, les limites minimale et maximale peuvent être bloquantes ou passantes, ce qui autorise la boucle de la valeur incrémentée :</text> <quote>La boucle tient compte de la différence restante entre respectivement la valeur incrémentée et la limite maximale, ou la valeur décrémentée et la limite minimale.</quote> <text>À noter que ces paramètres sont flexibles :</text> <caution>Les valeurs indiquées en paramètre peuvent <bold>indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres</bold>, les fonctions implémentées sont prévues à cet effet.</caution> <text>Également dans un soucis de robustesse et de transparence pour le programmeur, la fonction d'incrémentation permet d'indiquer des valeurs <bold>supérieures à l'intervalle spécifié en paramètre</bold> (limites minimales et maximales), de sorte qu'un modulo est effectué donnant dans tous les cas un résultat juste.</text> <text>Pour finir, un incrément négatif est une <bold>décrémentation</bold>.</text> <text><bold>Exemple de décrémentation avec la classe Iteration :</bold></text> <code><purple>#include</purple> <pink><Iteration.h></pink> <green>int</green> main() { Iteration myIteration = Iteration (<pink>1</pink>, <pink>9</pink>, <pink>10</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { <blue>//décrément de 3 :</blue> myIteration.increment (<pink>-3</pink>); <blue>//myIteration.value est la valeur décrémentée, lors de cette première itération elle est égale à 6</blue> } <red>return</red> <pink>0</pink>; }</code> <text>D'autres fonctions existent :</text> <quote>- <bold>min</bold> : redéfini la limite inférieure. <br/>- <bold>set</bold> : redéfini (ou force) la valeur de la variable <bold>value</bold>. <br/>- <bold>max</bold> : redéfini la limite supérieure. <br/>- <bold>loop</bold> : redéfini la possibilité d'incrémenter et de décrémenter en boucle. <br/>- <bold>reset</bold> : réinitialise la valeur de la variable <bold>value</bold> à sa valeur de départ (initiée avec le paramètre START), ceci dans les limites imposées par l'intervalle spécifié.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>signed long</green> value = <pink>0</pink>; Iteration (<green>const signed long</green> MIN, <green>const signed long</green> START, <green>const signed long</green> MAX, <green>const bool</green> LOOP); <green>void</green> increment (<green>const signed long</green> INCREMENT); <green>void</green> min (<green>const signed long</green> MIN); <green>void</green> set (<green>const signed long</green> VALUE); <green>void</green> max (<green>const signed long</green> MAX); <green>void</green> loop (<green>const bool</green> LOOP); <green>void</green> reset();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationMath.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationMath"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les fonctions mathématiques avec la classe Math</title> <underline></underline> <text>En électronique numérique embarquée qui met en œuvre des calculateurs programmables, et plus largement en programmation générale C++ (le langage utilisé pour écrire les fonctions énoncées ici), la logique pure est généralement accompagnée de calculs arithmétiques pour mener à bien la plupart des projets. Pour se faire, les calculateurs utilisés (soit les microcontrôleurs) sont équipés chacun d'une <bold>unité arithmétique et logique</bold>, partie du circuit intégré dédiée à de telles opérations, mais ce matériel ne permet pas d'effectuer des opérations arithmétiques autres que les calculs élémentaires, soit les additions, les soustractions, les multiplications, ou les divisions :</text> <quote>Comprendre que des opérations plus complexes comme par exemple <bold>sinus</bold> ou <bold>cosinus</bold> (que l'on retrouve habituellement dans les calculatrices modernes), <bold>ne sont pas câblées dans ce type de circuit intégré</bold> (comme c'est le cas dans la majorité des microcontrôleurs).</quote> <text>En conséquence, les opérations mathématiques plus élaborées doivent être écrites manuellement lors de la programmation logicielle, ceci en utilisant un certain nombre d'instructions logiques de base (structures conditionnelles, comparaisons, décalages) et d'instructions arithmétiques simples (additions, soustractions, multiplications, et divisions), seules disponibles dans les architectures matérielles des microcontrôleurs.</text> <text>Cette recherche et construction logicielle effectuée, toutes les opérations (dont les ensembles constituent les algorithmes) qui œuvrent dans le fonctionnement intime de <bold>sinus</bold> ou <bold>cosinus</bold> (pour reprendre l'exemple) peuvent pour une question pratique de lisibilité et portabilité du programme être <bold>encapsulées dans des fonctions autonomes dédiées</bold>, autrement-dit regroupées dans des blocs de code distincts contenant chacun toutes les opérations nécessaires à leur fonctionnement interne, de sorte de pouvoir à posteriori en faire usage facilement en un minimum de lignes de programmation, ceci sans avoir besoin de ressources annexes externes. C'est ce que permet la classe <bold>Math</bold>.</text> <text><bold>Descriptif des fonctions de la classe Math :</bold></text> <quote>- <bold>floor</bold> : arrondit un nombre décimal à l'entier inférieur. <br/>- <bold>round</bold> : arrondit un nombre décimal à l'entier le plus proche. <br/>- <bold>ceil</bold> : arrondit un nombre décimal à l'entier supérieur. <br/>- <bold>curve</bold> : créé des interpolations linéaires ou non-linéaires de courbes. <br/>- <bold>wurve</bold> : créé des interpolations linéaires ou non-linéaires symétriques ou dissymétriques de courbes. <br/>- <bold>range</bold> : cadre une valeur dans un intervalle. <br/>- <bold>center</bold> : calcule la moyenne de deux valeurs. <br/>- <bold>pow</bold> : calcule la puissance d'un nombre. <br/>- <bold>sqrt</bold> : calcule la racine carrée d'un nombre. <br/>- <bold>fact</bold> : calcule la factorielle d'un nombre. <br/>- <bold>sin</bold> : trouve le sinus d'un angle. <br/>- <bold>cos</bold> : trouve le cosinus d'un angle. <br/>- <bold>tan</bold> : trouve la tangente d'un angle. <br/>- <bold>arcsin</bold> : trouve l'angle à partir d'un sinus. <br/>- <bold>arccos</bold> : trouve l'angle à partir d'un cosinus. <br/>- <bold>arctan</bold> : trouve l'angle à partir d'une tangente. <br/>- <bold>arctan2</bold> : trouve l'angle à partir de la tangente de deux arguments x et y.</quote> <text>Il est important d'appréhender que les fonctions mathématiques implémentées dans la classe <bold>Math</bold> ne sont qu'une des façons possibles d'effectuer les calculs et résoudre les fonctions énoncées, ceci dans un certain langage de programmation (le C++), et d'une manière subjective avec une approche et une résolution des problématiques tout à fait singulière et arbitraire, modeste expression partagée libre et ouverte de son auteur.</text> <caution>Si vos applications requièrent des fonctions mathématiques qui ne sont pas présentes dans la classe <bold>Math</bold>, libre à vous d'en ajouter si besoin !</caution> <title>Arrondir des nombres décimaux :</title> <underline></underline> <text>Des calculs complexes en virgule flottante (comprenez en nombres décimaux) sont parfois nécessaires afin de <bold>conserver la précision tout au long des opérations arithmétiques</bold>. Mais la finalité de ces opérations se retrouveront souvent dans un but de faire fonctionner des systèmes prenant en entrée uniquement des nombres entiers. Il est donc nécessaire d'arrondir le résultat en toute fin du calcul.</text> <text><bold>Exemple pour arrondir un nombre décimal à l'entier inférieur :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::floor (<pink>14.6</pink>); <blue>//la fonction retourne la valeur 14</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, la fonction statique <bold>floor</bold> est appelée, elle prend en paramètre <bold>14.6</bold>, le nombre décimal à arrondir à l'entier inférieur, et retourne (dans ce cas de figure) le nombre entier <bold>14</bold>.</text> <text><bold>Exemple pour arrondir un nombre décimal à l'entier le plus proche :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::round (<pink>23.7</pink>); <blue>//la fonction retourne la valeur 24</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple la fonction statique <bold>round</bold> est appelée, elle prend en paramètre <bold>23.7</bold>, le nombre décimal à arrondir à l'entier le plus proche, et retourne le nombre entier <bold>24</bold>.</text> <text><bold>Exemple pour arrondir un nombre décimal à l'entier supérieur :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::ceil (<pink>5.12</pink>); <blue>//la fonction retourne la valeur 6</blue> <red>return</red> <pink>0</pink>; }</code> <text>Ici la fonction statique <bold>ceil</bold> est appelée, elle prend en paramètre <bold>5.12</bold>, le nombre décimal à arrondir à l'entier supérieur, et retourne le nombre entier <bold>6</bold>.</text> <title>Créer des interpolations de courbes :</title> <underline></underline> <text>Avec les fonctions de courbes que je propose il est très simple de changer des valeurs d'échelle, soit l'interpolation de courbes vers d'autres domaines linéaires ou non-linéaires, de façon symétrique ou dissymétrique.</text> <text><bold>Exemple pour créer une interpolation linéaire d'une courbe :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::curve (<pink>-25</pink>, <pink>50</pink>, <pink>100</pink>, <pink>1</pink>, <pink>10</pink>, <pink>0</pink>); <blue>//la fonction retourne la valeur 6.4</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, la fonction statique <bold>curve</bold> est appelée prenant plusieurs paramètres : <br/>- Le 1er paramètre <bold>-25</bold> est le point initial de la courbe. <br/>- Le 2ème paramètre <bold>50</bold> est le point courant de la courbe. <br/>- Le 3ème paramètre <bold>100</bold> est le point final de la courbe. <br/>- Le 4ème paramètre <bold>1</bold> est le point initial de l'interpolation souhaitée. <br/>- Le 5ème paramètre <bold>10</bold> est le point final de l'interpolation souhaitée. <br/>- Le 6ème paramètre <bold>0</bold> défini le type d'interpolation (0 = linéaire) à partir du point initial vers le point final.</text> <quote>Le résultat du calcul est <bold>6.4</bold>.</quote> <caution>À noter que les valeurs indiquées en paramètre peuvent <bold>indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres</bold>, la fonction statique <bold>curve</bold> est prévue à cet effet.</caution> <text><bold>Exemple pour créer une interpolation non-linéaire d'une courbe :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::curve (<pink>-25</pink>, <pink>50</pink>, <pink>100</pink>, <pink>1</pink>, <pink>10</pink>, <pink>40</pink>); <blue>//la fonction retourne la valeur ≈ 1.317 (valeur arrondie)</blue> <red>return</red> <pink>0</pink>; }</code> <text>L'exemple est identique au précédent, sauf le 6ème paramètre <bold>40</bold> (différent de 0 donc non-linéaire) qui permet une interpolation non-linéaire positive, plus ce nombre est élevé, plus la courbe est prononcée. Un nombre négatif produit une non-linéarité négative, c'est-à-dire non pas une interpolation qui évolue doucement proche du point initial de la courbe, mais plutôt évoluant rapidement proche du point initial pour terminer doucement à l'approche du point final.</text> <quote>Le résultat du calcul est maintenant ≈ <bold>1.317</bold> (valeur arrondie).</quote> <text><bold>Exemple pour créer une interpolation linéaire dissymétrique d'une courbe :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::wurve (<pink>0</pink>, <pink>50</pink>, <pink>70</pink>, <pink>0</pink>, <pink>9</pink>, <pink>10</pink>, <pink>0</pink>, <pink>0</pink>); <blue>//la fonction retourne la valeur ≈ 9.428 (valeur arrondie)</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus la fonction statique <bold>wurve</bold> est appelée, voici le détail des paramètres (similaires à la fonction statique curve) : <br/>- Le 1er paramètre <bold>0</bold> est le point initial de la courbe. <br/>- Le 2ème paramètre <bold>50</bold> est le point courant de la courbe. <br/>- Le 3ème paramètre <bold>70</bold> est le point final de la courbe. <br/>- Le 4ème paramètre <bold>0</bold> est le point initial de l'interpolation souhaitée. <br/>- Le 5ème paramètre <bold>9</bold> est le point central de l'interpolation souhaitée. <br/>- Le 6ème paramètre <bold>10</bold> est le point final de l'interpolation souhaitée. <br/>- Le 7ème paramètre <bold>0</bold> défini le type d'interpolation (0 = linéaire) à partir du point central vers le point initial. <br/>- Le 8ème paramètre <bold>0</bold> défini le type d'interpolation (0 = linéaire) à partir du point central vers le point final.</text> <quote>Le résultat du calcul est ≈ <bold>9.428</bold> (valeur arrondie).</quote> <caution>À l'instar de la fonction statique <bold>curve</bold>, les valeurs indiquées en paramètre avec la fonction statique <bold>wurve</bold> peuvent <bold>indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres</bold>.</caution> <text><bold>Exemple pour créer une interpolation non-linéaire symétrique d'une courbe :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::wurve (<pink>0</pink>, <pink>473</pink>, <pink>1023</pink>, <pink>1000</pink>, <pink>1500</pink>, <pink>2000</pink>, <pink>20</pink>, <pink>20</pink>); <blue>//la fonction retourne la valeur ≈ 1498.069 (valeur arrondie)</blue> <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus la fonction statique <bold>wurve</bold> prend en entrée la valeur d'un potentiomètre pouvant varier de <bold>0</bold> à <bold>1023</bold>, c'est la courbe à interpoler, les valeurs d'interpolation vont de <bold>1000</bold> à <bold>2000</bold> en passant par un centre à <bold>1500</bold>, ce centre sert à créer une double courbe non-linéaire centrée sur <bold>1500</bold> ayant des valeurs de <bold>20</bold> (non-linéaire positive) de part et d'autre de ce point central (ou neutre).</text> <quote>Le résultat du calcul est ≈ <bold>1498.069</bold> (valeur arrondie).</quote> <caution>Cette simple expression pourrait servir à transposer un ordre analogique via un potentiomètre (d'intervalle 0 à 1023 après conversion analogique/numérique) vers une modulation de la largeur d'impulsion (d'intervalle 1000 à 2000 microsecondes) dans le but d'asservir un servo-moteur avec la volonté d'augmenter la précision de pilotage autour du neutre.</caution> <text>Beaucoup de mes projets utilisent les fonctions de courbes car elles permettent de transposer facilement des valeurs d'un domaine vers un autre.</text> <title>Cadrer une valeur dans un intervalle :</title> <underline></underline> <text>Il peut être utile de solliciter une fonction dédiée lorsque nous souhaitons qu'une valeur ne sorte pas d'un certain intervalle, sans être obligé de rajouter les conditions logiques nécessaires à cette fonctionnalité dans notre programme (si inférieur ou égal à, si supérieur ou égal à, etc...), ce qui permet de diminuer le nombre d'instructions visibles et d'augmenter la lisibilité du code source.</text> <text><bold>Exemple pour cadrer une valeur dans un intervalle :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::range (<pink>-10</pink>, <pink>23</pink>, <pink>10</pink>); <blue>//la fonction retourne une valeur qui ne sortira jamais de l'intervalle -10 à 10</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, la fonction statique <bold>range</bold> limite l'intervalle que peut prendre le nombre <bold>23</bold>, ceci dans un cadre <bold>-10</bold> à <bold>10</bold>. La fonction retourne alors le nombre <bold>10</bold>.</text> <caution>Les valeurs indiquées en paramètre peuvent <bold>indifféremment être positives ou négatives et inférieures ou supérieures les unes par rapport aux autres</bold>, la fonction statique <bold>range</bold> est implémentée à cet effet.</caution> <title>Calculer la moyenne de deux valeurs :</title> <underline></underline> <text>De même que la fonction présentée ci-dessus, une fonction pour trouver la moyenne de deux nombres (ou centre) semble facultative, néanmoins elle reste bien pratique !</text> <text><bold>Exemple pour calculer la moyenne de deux valeurs :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::center (<pink>125</pink>, <pink>85.3</pink>); <blue>//la fonction retourne la valeur 105.15</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus la fonction statique <bold>center</bold> prend en paramètre les nombres <bold>125</bold> et <bold>85.3</bold>, elle retourne donc la moyenne de ces deux nombre, soit <bold>105.15</bold>.</text> <caution>L'ordre des nombres indiqués en paramètre à la fonction statique <bold>center</bold> peuvent être permutés indifféremment.</caution> <title>Calculer la puissance d'un nombre :</title> <underline></underline> <text>La puissance d'un nombre est le résultat de la multiplication répétée (via un exposant) de ce nombre avec lui même.</text> <text><bold>Exemple pour calculer la puissance d'un nombre :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::pow (<pink>5</pink>, <pink>4</pink>); <blue>//la fonction retourne la valeur 625</blue> <red>return</red> <pink>0</pink>; }</code> <text>Ici le nombre <bold>5</bold> représente le nombre à multiplier avec lui-même, <bold>4</bold> est l'exposant, soit le calcul <bold>5 x 5 x 5 x 5 = 625</bold>.</text> <caution>Le nombre à multiplier avec lui même ainsi que l'exposant <bold>peuvent être positifs, nuls, ou négatifs</bold>.</caution> <title>Calculer la racine carrée d'un nombre :</title> <underline></underline> <text>Le résultat de la racine carrée d'un nombre, est un nombre qui, multiplié par lui-même, donne le radicande (soit le nombre entré en paramètre à la fonction).</text> <text><bold>Exemple pour calculer la racine carrée d'un nombre :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::sqrt (<pink>25</pink>); <blue>//la fonction retourne la valeur 5</blue> <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus le nombre <bold>25</bold> est le résultat du nombre <bold>5</bold> multiplié par lui-même (5 x 5 = 25), la fonction retourne donc le nombre <bold>5</bold>.</text> <title>Calculer la factorielle d'un nombre :</title> <underline></underline> <text>La factorielle d'un nombre est le produit des nombres entiers strictement positifs inférieurs ou égaux à ce nombre. Cet algèbre permet d'effectuer des approches du nombre Pi, de faire converger des équations pour obtenir le sinus, le cosinus, etc...</text> <text><bold>Exemple pour calculer la factorielle d'un nombre :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::fact (<pink>7</pink>); <blue>//la fonction retourne la valeur 5040</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus la factorielle du nombre <bold>7</bold> entré en paramètre donne le résultat <bold>5040</bold>, car <bold>1 x 2 x 3 x 4 x 5 x 6 x 7 = 5040</bold>.</text> <quote>Par convention la factorielle du nombre <bold>0</bold> est <bold>1</bold>.</quote> <title>Les fonctions sinus, cosinus, et tangente :</title> <underline></underline> <text>Les fonctions trigonométriques élémentaires comme sinus, cosinus, ou encore tangente s'avèrent utiles dans le domaine des automates programmables afin d'obtenir la position angulaire d'un robot, calculer la trajectoire d'un objet à l'aide d'un gyroscope, etc...</text> <caution>Attention, mes fonctions trigonométriques <bold>sin</bold> (sinus), <bold>cos</bold> (cosinus), et <bold>tan</bold> (tangente) prennent en entrée un <bold>angle en degrés</bold> (et non pas en radians).</caution> <text><bold>Exemple pour calculer le sinus d'un angle :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::sin (<pink>30</pink>); <blue>//la fonction retourne la valeur 0.5</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le sinus de l'angle <bold>30</bold> degrés est <bold>0.5</bold>.</text> <text><bold>Exemple pour calculer le cosinus d'un angle :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::cos (<pink>45</pink>); <blue>//la fonction retourne la valeur ≈ 0.707 (valeur arrondie)</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, le cosinus de l'angle <bold>45</bold> degrés est ≈ <bold>0.707</bold> (valeur arrondie).</text> <text><bold>Exemple pour calculer la tangente d'un angle :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::tan (<pink>45</pink>); <blue>//la fonction retourne la valeur 1</blue> <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus la tangente de l'angle <bold>45</bold> degrés est <bold>1</bold>.</text> <title>Les fonctions réciproques arc sinus, arc cosinus, arc tangente, et arc tangente 2 :</title> <underline></underline> <text>En complément des fonctions sinus, cosinus, et tangente, il est fort utile de disposer des fonctions réciproques comme arc sinus, arc cosinus, arc tangente, et arc tangente 2.</text> <caution>Attention, mes fonctions trigonométriques <bold>arcsin</bold> (arc sinus), <bold>arccos</bold> (arc cosinus), <bold>arctan</bold> (arc tangente), et <bold>arctan2</bold> (arc tangente à partir de deux arguments x et y) retournent en sortie un <bold>angle en degrés</bold> (et non pas en radians).</caution> <text><bold>Exemple pour trouver l'angle à partir d'un sinus :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::arcsin (<pink>0.5</pink>); <blue>//la fonction retourne la valeur 30</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, un sinus de <bold>0.5</bold> correspond à un angle de <bold>30</bold> degrés.</text> <text><bold>Exemple pour trouver l'angle à partir d'un cosinus :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::arccos (<pink>0.707</pink>); <blue>//la fonction retourne la valeur ≈ 45.008 (valeur arrondie)</blue> <red>return</red> <pink>0</pink>; }</code> <text>Avec la fonction statique <bold>arccos</bold>, on trouve qu'un cosinus de <bold>0.707</bold> correspond à un angle de ≈ <bold>45.008</bold> degrés (valeur arrondie).</text> <text><bold>Exemple pour trouver l'angle à partir d'une tangente :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::arctan (<pink>1</pink>); <blue>//la fonction retourne la valeur 45</blue> <red>return</red> <pink>0</pink>; }</code> <text>Une tangente de <bold>1</bold> correspond à un angle de <bold>45</bold> degrés.</text> <text><bold>Exemple pour trouver l'angle à partir de la tangente de deux arguments x et y (ou fonction circulaire réciproque à quatre cadrans) :</bold></text> <code><purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { Math::arctan2 (<pink>0.5</pink>, <pink>0.5</pink>); <blue>//la fonction retourne la valeur 45</blue> <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, une tangente à partir de deux arguments x égal à <bold>0.5</bold> et y égal à <bold>0.5</bold> correspond à un angle de <bold>45</bold> degrés.</text> <quote>La classe <bold>Math</bold> simplifie grandement la mise en œuvre de nombreuses applications logicielles, vous pouvez combiner les fonctions entres-elles et obtenir des résultats très élaborés.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code><green>static signed long</green> floor (<green>const float</green> VALUE); <green>static signed long</green> round (<green>const float</green> VALUE); <green>static signed long</green> ceil (<green>const float</green> VALUE); <green>static float</green> curve (<green>const float</green> POSITION_START, <green>const float</green> POSITION_CURRENT, <green>const float</green> POSITION_END, <green>const float</green> INTERPOLATION_START, <green>const float</green> INTERPOLATION_END, <green>const float</green> CURVE); <green>static float</green> wurve (<green>const float</green> POSITION_START, <green>const float</green> POSITION_CURRENT, <green>const float</green> POSITION_END, <green>const float</green> INTERPOLATION_START, <green>const float</green> INTERPOLATION_CENTER, <green>const float</green> INTERPOLATION_END, <green>const float</green> CURVE_START, <green>const float</green> CURVE_END); <green>static float</green> range (<green>const float</green> RANGE_START, <green>const float</green> VALUE_CURRENT, <green>const float</green> RANGE_END); <green>static float</green> center (<green>const float</green> VALUE_START, <green>const float</green> VALUE_END); <green>static float</green> pow (<green>const float</green> NUMBER, <green>const unsigned long</green> EXPONENT); <green>static float</green> sqrt (<green>const float</green> RADICAND); <green>static unsigned long long</green> fact (<green>const unsigned long</green> INTEGER); <green>static float</green> sin (<green>const float</green> ANGLE); <green>static float</green> cos (<green>const float</green> ANGLE); <green>static float</green> tan (<green>const float</green> ANGLE); <green>static float</green> arcsin (<green>const float</green> SINUS); <green>static float</green> arccos (<green>const float</green> COSINUS); <green>static float</green> arctan (<green>const float</green> TANGENT); <green>static float</green> arctan2 (<green>const float</green> X, <green>const float</green> Y);</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationPeriod.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationPeriod"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Mesurer une période avec la classe Period</title> <underline></underline> <text>La classe <bold>Period</bold> permet en un minium de lignes de programmation d'effectuer des mesures avec une relative précision (pour le microcontrôleur utilisé) du temps écoulé entre chaque appels à une fonction, qui en interne se charge de <bold>soustraire le temps écoulé courant par rapport au temps écoulé précédent</bold>. La seule contrainte technique pour vos projets est la suivante :</text> <caution>La durée de la période doit être supérieure au temps d'exécution des fonctions mises en œuvre dans le programme (nous ne sommes pas en matériel pur, mais bien en logiciel).</caution> <text><bold>Exemple d'utilisation de la classe Period :</bold></text> <code><purple>#include</purple> <pink><Period.h></pink> <green>int</green> main() { Period myPeriod = Period(); <red>while</red> (<red>true</red>) { myPeriod.state(); <blue>//myPeriod.s est la période mesurée en secondes</blue> <blue>//myPeriod.ms est la période mesurée en millisecondes</blue> <blue>//myPeriod.us est la période mesurée en microsecondes</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, un objet <bold>myPeriod</bold> de type <bold>Period</bold> est déclaré, ne prenant aucun paramètre, il sert uniquement à stocker et calculer des temps écoulés.</text> <text>Plus loin dans la boucle <bold>while</bold>, la fonction <bold>state</bold> de l'objet <bold>myPeriod</bold> est appelée ce qui permet d'initialiser une première fois le temps courant, celui-ci devenant le temps précédent aux tours de boucle suivants en étant soustrait à de nouveaux temps courants pour en déduire la période. Tout ceci est invisible au programmeur, et a pour effet de mettre à jour les variables <bold>s</bold> (secondes), <bold>ms</bold> (millisecondes), et <bold>us</bold> (microsecondes) que vous pourrez utiliser par la suite dans votre programme.</text> <quote>L'exemple présenté ici avec la classe <bold>Period</bold> est simple, peut être effectué via quelques calculs à l'aide de la classe <bold>Timer</bold>, mais dans ce cas présent offre l'avantage d'avoir ce principe intégré dans son fonctionnement ce qui simplifie la programmation.</quote> <text>Pour mesurer la périodicité d'un phénomène il est vivement recommandé d'utiliser les interruptions de programme. En effet, la spontanéité du principe même des interruptions (quelques cycles d'horloges tout au plus) permet de mesurer avec une relative précision (pour le microcontrôleur utilisé) un phénomène périodique.</text> <text><bold>Exemple de mesure d'un phénomène périodique avec les interruptions :</bold></text> <code><purple>#include</purple> <pink><InterruptRead.h></pink> <purple>#include</purple> <pink><Period.h></pink> Period _myPeriod = Period(); <green>void</green> myEvent() { _myPeriod.state(); } <green>int</green> main() { InterruptRead myInterrupt = InterruptRead (<pink>3</pink>); myInterrupt.start (myEvent, <red>true</red>, <red>false</red>); <red>while</red> (<red>true</red>) { <blue>//_myPeriod.s est la période mesurée en secondes</blue> <blue>//_myPeriod.ms est la période mesurée en millisecondes</blue> <blue>//_myPeriod.us est la période mesurée en microsecondes</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple la fonction <bold>state</bold> de l'objet <bold>_myPeriod</bold> est appelée dans la fonction <bold>myEvent</bold> exécutée lors d'une interruption. Comme l'exemple précédent, ceci mettra à jour les variables <bold>s</bold> (secondes), <bold>ms</bold> (millisecondes), et <bold>us</bold> (microsecondes) que vous pourrez utiliser par la suite dans votre programme.</text> <quote>En exemple d'application, ce programme pourrait être associé à un capteur à effet Hall connecté au port GPIO 3 de l'automate programmable, ce qui permettrait par exemple de mesurer la période de rotation d'un moteur pour en déduire le nombre de tours par minute.</quote> <text>Autre fonction disponible :</text> <quote>Une fonction supplémentaire <bold>reset</bold> permet de réinitialiser les variables <bold>s</bold>, <bold>ms</bold>, et <bold>us</bold>, ainsi que le dernier temps (précédent) calculé en interne dans le fonctionnement de la classe, ceci ayant pour but une remise à zéro, ou retour aux conditions initiales des mesures périodiques effectuées.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>unsigned long long</green> s = <pink>0</pink>; <green>unsigned long long</green> ms = <pink>0</pink>; <green>unsigned long long</green> us = <pink>0</pink>; Period(); <green>void</green> state(); <green>void</green> reset();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationPwmRead.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationPwmRead"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Lire les voies PWM d'un récepteur de modélisme avec la classe PwmRead</title> <underline></underline> <text>L'une des utilisations possibles de la classe <bold>PwmRead</bold> est la lecture des sorties PWM d'un récepteur de modélisme standard afin de piloter un modèle radiocommandé. Bien d'autres applications sont possibles, mais c'est celle-ci qui fera l'objet d'un exemple ici.</text> <text>La <bold>modulation de la largeur d'impulsion</bold> (PWM) est un moyen pratique de communication entre deux (ou plusieurs) périphériques, ce principe ne demande qu'un seul fil de liaison.</text> <quote>La classe <bold>PwmRead</bold> permet de mesurer la largeur d'impulsion PWM avec une <bold>résolution d'1 microseconde</bold>.</quote> <text><bold>Exemple d'utilisation de la classe PwmRead :</bold></text> <code><purple>#include</purple> <pink><PwmRead.h></pink> <green>int</green> main() { PwmRead myChannelThrottle = PwmRead (<pink>1</pink>, <red>true</red>); PwmRead myChannelPitch = PwmRead (<pink>2</pink>, <red>true</red>); PwmRead myChannelRoll = PwmRead (<pink>3</pink>, <red>true</red>); PwmRead myChannelYaw = PwmRead (<pink>4</pink>, <red>true</red>); PwmRead myChannelCut = PwmRead (<pink>5</pink>, <red>true</red>); PwmRead::start(); <red>while</red> (<red>true</red>) { myChannelThrottle.read(); myChannelPitch.read(); myChannelRoll.read(); myChannelYaw.read(); myChannelCut.read(); <blue>//si l'interrupteur de coupure moteur est activé :</blue> <red>if</red> (myChannelCut.us < <pink>1500</pink>) { <blue>//coupure des gaz</blue> } <red>else</red> { <blue>//sinon, utilisation des valeurs pour piloter le modèle radiocommandé :</blue> <blue>//myChannelThrottle.us (gaz)</blue> <blue>//myChannelPitch.us (tangage)</blue> <blue>//myChannelRoll.us (roulis)</blue> <blue>//myChannelYaw.us (lacet)</blue> } } <red>return</red> <pink>0</pink>; }</code> <text>Cet exemple montre un peu comment organiser un programme pour pouvoir lire les voies PWM d'un récepteur de modélisme standard afin de piloter un modèle radio-commandé.</text> <text>Au début du code, 5 objets de type <bold>PwmRead</bold> sont déclarés : <br/>- Le 1er paramètre indique le numéro du port GPIO de l'automate programmable en entrée qui va servir à lire le signal PWM, respectivement les ports GPIO numéro <bold>1</bold>, <bold>2</bold>, <bold>3</bold>, <bold>4</bold>, et <bold>5</bold> dans l'exemple.</text> <caution>Avec la classe <bold>PwmRead</bold>, ce sont <bold>tous les ports GPIO de l'automate programmable</bold> qui peuvent servir à la lecture de signaux PWM.</caution> <text>- Le 2ème paramètre <bold>true</bold> permet de définir que la lecture du PWM débute par un <bold>front montant</bold>, et termine par un front descendant (le cas le plus courant), ou inversement si le paramètre était indiqué à <bold>false</bold>.</text> <quote>Ce paramètre n'a pas d'utilité dans le cadre de la lecture de sorties PWM type récepteurs de modélisme standards, où l'on s'attends toujours à un front montant lorsque le signal débute. En revanche, cette fonctionnalité peut être utile voir indispensable pour d'autres applications.</quote> <text>Ensuite, la lecture PWM est démarrée en appelant la fonction statique <bold>start</bold>.</text> <text>À la suite du programme dans la boucle, les 5 objets de type <bold>PwmRead</bold> appellent leurs fonctions <bold>read</bold> respectives, ce qui permet de mettre à jour les variables <bold>us</bold> (largeur d'impulsion en microsecondes) relatives aux objets déclarés, et de s'en servir pour piloter le modèle radiocommandé.</text> <text><bold>Une sécurité dans le cas d'un récepteur de modélisme partiellement défaillant :</bold> <br/>La lecture PWM s'effectuant de manière <bold>séquentielle dans l'ordre de déclaration des objets</bold>, imaginez le cas extrême d'une défaillance de l'une des voies de votre récepteur de modélisme, cas ou la lecture de la voie deviendrait impossible. Il serait alors judicieux de considérer que si au bout d'un certain temps, le signal PWM ne peut être mesuré, la lecture passe à l'objet suivant (à la voie suivante) sans mettre à jour la variable <bold>us</bold> relative à l'objet considéré. C'est ce que permet la classe <bold>PwmRead</bold> :</text> <caution>En effet si les fronts attendus (montant puis descendant ou descendant puis montant) ne sont pas obtenus dans un délai de <bold>100 millisecondes</bold> maximum par canal, alors la lecture du PWM de la voie courante est considérée comme échouée pour cause d'une défaillance en amont, à la suite de quoi <bold>la lecture PWM passe à la voie suivante automatiquement</bold>.</caution> <text>Autre fonction disponible :</text> <quote>La fonction statique <bold>stop</bold> permet d'arrêter la lecture des signaux PWM sur tous les ports GPIO utilisés par la classe <bold>PwmRead</bold>, un nouvel appel à la fonction statique <bold>start</bold> permet de redémarrer la lecture de manière séquentielle (ports après ports, dans l'ordre de déclaration des objets).</quote> <text><bold>Ports des automates programmables concernés par la lecture du PWM :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) = PCINT16 (pin change interrupt 16) <br/>- Port GPIO 2 (PD1) = PCINT17 (pin change interrupt 17) <br/>- Port GPIO 3 (PD2) = PCINT18 (pin change interrupt 18) <br/>- Port GPIO 4 (PD3) = PCINT19 (pin change interrupt 19) <br/>- Port GPIO 5 (PD4) = PCINT20 (pin change interrupt 20) <br/>- Port GPIO 6 (PD5) = PCINT21 (pin change interrupt 21) <br/>- Port GPIO 7 (PD6) = PCINT22 (pin change interrupt 22) <br/>- Port GPIO 8 (PD7) = PCINT23 (pin change interrupt 23) <br/>- Port GPIO 9 (PB0) = PCINT0 (pin change interrupt 0) <br/>- Port GPIO 10 (PB1) = PCINT1 (pin change interrupt 1) <br/>- Port GPIO 11 (PB2) = PCINT2 (pin change interrupt 2) <br/>- Port GPIO 12 (PB3) = PCINT3 (pin change interrupt 3) <br/>- Port GPIO 13 (PB4) = PCINT4 (pin change interrupt 4) <br/>- Port GPIO 14 (PB5) = PCINT5 (pin change interrupt 5) <br/>- Port GPIO 15 (PC0) = PCINT8 (pin change interrupt 8) <br/>- Port GPIO 16 (PC1) = PCINT9 (pin change interrupt 9) <br/>- Port GPIO 17 (PC2) = PCINT10 (pin change interrupt 10) <br/>- Port GPIO 18 (PC3) = PCINT11 (pin change interrupt 11) <br/>- Port GPIO 19 (PC4) = PCINT12 (pin change interrupt 12) <br/>- Port GPIO 20 (PC5) = PCINT13 (pin change interrupt 13) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 1 (PB0) = PCINT8 (pin change interrupt 8) <br/>- Port GPIO 2 (PB1) = PCINT9 (pin change interrupt 9) <br/>- Port GPIO 3 (PB2) = PCINT10 (pin change interrupt 10) <br/>- Port GPIO 4 (PB3) = PCINT11 (pin change interrupt 11) <br/>- Port GPIO 5 (PB4) = PCINT12 (pin change interrupt 12) <br/>- Port GPIO 6 (PB5) = PCINT13 (pin change interrupt 13) <br/>- Port GPIO 7 (PB6) = PCINT14 (pin change interrupt 14) <br/>- Port GPIO 8 (PB7) = PCINT15 (pin change interrupt 15) <br/>- Port GPIO 9 (PD0) = PCINT24 (pin change interrupt 24) <br/>- Port GPIO 10 (PD1) = PCINT25 (pin change interrupt 25) <br/>- Port GPIO 11 (PD2) = PCINT26 (pin change interrupt 26) <br/>- Port GPIO 12 (PD3) = PCINT27 (pin change interrupt 27) <br/>- Port GPIO 13 (PD4) = PCINT28 (pin change interrupt 28) <br/>- Port GPIO 14 (PD5) = PCINT29 (pin change interrupt 29) <br/>- Port GPIO 15 (PD6) = PCINT30 (pin change interrupt 30) <br/>- Port GPIO 16 (PD7) = PCINT31 (pin change interrupt 31) <br/>- Port GPIO 17 (PC0) = PCINT16 (pin change interrupt 16) <br/>- Port GPIO 18 (PC1) = PCINT17 (pin change interrupt 17) <br/>- Port GPIO 19 (PC2) = PCINT18 (pin change interrupt 18) <br/>- Port GPIO 20 (PC3) = PCINT19 (pin change interrupt 19) <br/>- Port GPIO 21 (PC4) = PCINT20 (pin change interrupt 20) <br/>- Port GPIO 22 (PC5) = PCINT21 (pin change interrupt 21) <br/>- Port GPIO 23 (PC6) = PCINT22 (pin change interrupt 22) <br/>- Port GPIO 24 (PC7) = PCINT23 (pin change interrupt 23) <br/>- Port GPIO 25 (PA7) = PCINT7 (pin change interrupt 7) <br/>- Port GPIO 26 (PA6) = PCINT6 (pin change interrupt 6) <br/>- Port GPIO 27 (PA5) = PCINT5 (pin change interrupt 5) <br/>- Port GPIO 28 (PA4) = PCINT4 (pin change interrupt 4) <br/>- Port GPIO 29 (PA3) = PCINT3 (pin change interrupt 3) <br/>- Port GPIO 30 (PA2) = PCINT2 (pin change interrupt 2) <br/>- Port GPIO 31 (PA1) = PCINT1 (pin change interrupt 1) <br/>- Port GPIO 32 (PA0) = PCINT0 (pin change interrupt 0)</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>unsigned long</green> us = <pink>0</pink>; PwmRead (<green>const unsigned char</green> PIN, <green>const bool</green> RISING); <green>static void</green> start(); <green>void</green> read(); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationPwmWrite.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationPwmWrite"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les servo-moteurs avec la classe PwmWrite</title> <underline></underline> <text>Comme pour les autres classes de MODULE, <bold>PwmWrite</bold> n'est pas dédiée à une application en particulier (bien que l'exemple qui suit concerne les servo-moteurs). J'utilise notamment la génération de signaux <bold>PWM</bold> pour faire varier la luminosité des diodes électroluminescentes (voir l'exemple plus bas : "Faire varier la luminosité d'une del").</text> <caution>Avec la classe <bold>PwmWrite</bold>, ce sont <bold>tous les ports GPIO de l'automate programmable</bold> qui peuvent servir à la génération de signaux PWM (voir plus loin : "Le choix du PWM matériel ou logiciel").</caution> <text>L'exemple suivant permet de faire fonctionner un servo-moteur sur le port GPIO numéro <bold>1</bold> de l'automate programmable à une fréquence PWM de <bold>50Hz</bold>. Dans la boucle, le palonnier du servo-moteur se positionnera à <bold>1000μs</bold>, puis 3 secondes plus tard, se positionnera à <bold>2000μs</bold>, pour ensuite attendre de nouveau 3 secondes à cette position, après quoi le programme bouclera.</text> <text><bold>Exemple d'utilisation de la classe PwmWrite :</bold></text> <code><purple>#include</purple> <pink><PwmWrite.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { PwmWrite myServo = PwmWrite (<pink>1</pink>); PwmWrite::start (<pink>50</pink>); <red>while</red> (<red>true</red>) { myServo.us (<pink>1000</pink>); Timer::pause (<pink>3000</pink>); <blue>//pause de 3 secondes</blue> myServo.us (<pink>2000</pink>); Timer::pause (<pink>3000</pink>); <blue>//pause de 3 secondes</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Un objet <bold>myServo</bold> de type <bold>PwmWrite</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>1</bold> de l'automate programmable en sortie. Puis la fonction statique <bold>start</bold> est appelée prenant en paramètre la fréquence du PWM, ce qui démarre la génération PWM à la fréquence de <bold>50Hz</bold> dans cet exemple.</text> <caution>La fréquence PWM indiquée en paramètre avec la fonction statique <bold>start</bold> sera toujours appliquée à l'ensemble des ports choisis.</caution> <text>Ensuite dans la boucle, dans un premier temps l'objet <bold>myServo</bold> appelle la fonction <bold>us</bold> qui prend en paramètre <bold>1000</bold>, la largeur d'impulsion en microsecondes, ce qui vient positionner le palonnier du servo-moteur à cet endroit. Puis 3000ms (3 secondes) plus tard, positionne le servo-moteur à <bold>2000μs</bold>.</text> <caution>Il vous est possible d'appeler la fonction <bold>us</bold> avant ou après avoir démarré et choisi la fréquence du PWM avec la fonction statique <bold>start</bold>. Ceci n'a en effet aucune incidence sur le fonctionnement puisque la fonction <bold>us</bold> retient les valeurs indiquées en paramètre lorsque le PWM n'est pas encore démarré.</caution> <text>La fonction <bold>us</bold> attend en paramètre un <bold>nombre décimal</bold> (float), ou entier si vous le souhaitez. Libre à vous de déterminer dans vos montages électroniques si vous avez besoin de générer des signaux PWM avec une largeur d'impulsion précise à la fraction de microseconde (c'est le cas de certains servo-moteurs ou contrôleurs de moteurs sans charbons).</text> <quote>À noter que la largeur d'impulsion des objets créés est à une valeur par défaut de <bold>0 microseconde</bold> si aucun changement de rapport cyclique n'a encore été effectué avec la fonction <bold>us</bold>.</quote> <text>Ce programme est simple, mais il permet en quelques lignes de comprendre facilement les fonctions de la classe <bold>PwmWrite</bold>.</text> <quote>Si besoin est, une fonction statique <bold>stop</bold> existe et permet d'arrêter la génération de signaux PWM sur tous les ports GPIO utilisés par la classe <bold>PwmWrite</bold>, un nouvel appel à la fonction statique <bold>start</bold> permet de redémarrer la génération la ou elle s'était arrêtée (elle garde en mémoire les dernières valeurs de largeur d'impulsion indiquées en paramètre).</quote> <title>Faire varier la luminosité d'une del :</title> <underline></underline> <text>L'exemple suivant va vous montrer comment modifier la luminosité d'une del grâce au changement de la largeur d'impulsion d'un signal PWM.</text> <text>En effet, notre rétine étant sensible à la persistance rétinienne, une simple <bold>variation du temps d'exposition à la lumière</bold> à une fréquence supérieure au rafraîchissement de la rétine, sera perçue par le cerveau comme une <bold>variation de la luminosité</bold>.</text> <text><bold>Exemple de variation de la luminosité d'une del avec un potentiomètre :</bold></text> <code><purple>#include</purple> <pink><PwmWrite.h></pink> <purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { PwmWrite myLed = PwmWrite (<pink>13</pink>); AnalogRead myPotentiometer = AnalogRead (<pink>25</pink>); PwmWrite::start (<pink>1000</pink>); <red>while</red> (<red>true</red>) { myPotentiometer.read(); myLed.us (Math::curve (<pink>0</pink>, myPotentiometer.value, <pink>1023</pink>, <pink>0</pink>, <pink>1000</pink>, <pink>0</pink>)); } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple, la fréquence du PWM est de <bold>1000Hz</bold> (bien plus rapide que le rafraîchissement de la rétine), ce qui donne un rapport cyclique (largeur d'impulsion) pouvant varier de <bold>0μs</bold> (0%) à <bold>1000μs</bold> (100%).</text> <text>La fonction statique <bold>curve</bold> de la classe <bold>Math</bold> permet d'interpoler la valeur 10 bits (0 à 1023) du potentiomètre en valeurs de <bold>0μs</bold> à <bold>1000μs</bold>. À une valeur de <bold>500μs</bold> (rapport cyclique de 50%), la del éclairerait à une luminosité d'environ 50%.</text> <title>Le choix du PWM matériel ou logiciel :</title> <underline></underline> <text><bold>Tous les ports GPIO de l'automate programmable</bold> peuvent générer des signaux PWM sur une résolution théorique de 16 bits avec la classe <bold>PwmWrite</bold> (ce qui offre une grande souplesse d'utilisation), mais la façon dont ils sont générés (purement matérielle, ou partiellement logicielle) ainsi que les limites techniques (fréquence et résolution) seront <bold>différentes suivant les ports que vous utiliserez</bold>.</text> <text><bold>Ports des automates programmables concernés par la génération purement matérielle du PWM :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 10 (PB1) = OC1A (output compare 1A) <br/>- Port GPIO 11 (PB2) = OC1B (output compare 1B) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 13 (PD4) = OC1B (output compare 1B) <br/>- Port GPIO 14 (PD5) = OC1A (output compare 1A) <br/> <br/><bold>Spécificité pour le microcontrôleur ATmega1284P :</bold> <br/>- Port GPIO 7 (PB6) = OC3A (output compare 3A) <br/>- Port GPIO 8 (PB7) = OC3B (output compare 3B) <br/>- Port GPIO 13 (PD4) = OC1B (output compare 1B) <br/>- Port GPIO 14 (PD5) = OC1A (output compare 1A)</caution> <quote>La sélection d'un autre port GPIO que ceux indiqués ci-dessus passera la génération PWM en mode <bold>logiciel</bold>.</quote> <text>En mode <bold>logiciel</bold>, la génération de signaux PWM s'effectuant de manière <bold>séquentielle</bold> (ports après ports, dans l'ordre de déclaration des objets), <bold>la fréquence PWM choisie</bold> ainsi que <bold>le nombre de ports utilisés</bold> permettent de déterminer la largeur d'impulsion maximale possible avec une telle configuration.</text> <text><bold>Exemple de calcul du rapport cyclique maximum suivant la fréquence et le nombre de signaux PWM à générer en mode logiciel :</bold></text> <quote>Fréquence du PWM = <bold>1000Hz</bold> <br/>Nombre de signaux PWM à générer (ports utilisés) = <bold>4 ports</bold> <br/> <br/><bold>Limites maximales :</bold> <br/>Rapport cyclique = 1000000μs / (1000Hz * 4 ports) = <bold>250μs</bold> (max)</quote> <text>Dans cette configuration, la <bold>largeur d'impulsion maximale</bold> qui pourra être générée sera de <bold>250 microsecondes</bold> (rapport cyclique de 25%). Si vous indiquez un rapport cyclique supérieur à 250μs, ceci n'aura aucun impact sur le bon fonctionnement du PWM (celui-ci sera bloqué à 250μs par port utilisé dans tous les cas).</text> <text>De façon matérielle, la classe <bold>PwmWrite</bold> permet de générer des signaux PWM à des fréquences très élevées (supérieures à 1MHz), mais vous devez prendre conscience que le nombre d'états possibles (soit la résolution) à de telles fréquences sera plus faible qu'à des fréquences inférieures. Ceci est dû aux contraintes même du matériel, en particulier du compteur 16 bits, de la fréquence d'horloge de 16MHz, et des diviseurs d'horloge du microcontrôleur.</text> <text><bold>Exemple de calcul du rapport cyclique maximum suivant la fréquence PWM choisie en mode matériel :</bold></text> <quote>Fréquence du PWM = <bold>1000Hz</bold> <br/> <br/><bold>Limites maximales :</bold> <br/>Rapport cyclique = 1000000μs / 1000Hz = <bold>1000μs</bold> (max)</quote> <text>En mode matériel, la largeur d'impulsion maximale n'est pas dépendante du nombre de ports utilisés.</text> <quote>À noter que la classe <bold>PwmWrite</bold> calculera <bold>le diviseur d'horloge du microcontrôleur le plus adapté</bold> en rapport avec la fréquence PWM choisie avec la fonction statique <bold>start</bold>, ceci afin de garantir une résolution de la largeur d'impulsion <bold>la plus élevée possible</bold> (soit un nombre de pas ou d'états disponibles le plus important dans toutes les situations).</quote> <text>Cette résolution de 16 bits théorique maximum est bien entendu égale et valable pour les deux méthodes de génération du PWM (matérielle et logicielle). Seul des limites de fréquences maximales ou de largeur d'impulsion maximale possible distinguent l'une ou l'autre méthode.</text> <caution>Rappelez-vous que c'est la classe <bold>PwmWrite</bold> qui par vos choix en matière de ports utilisés, <bold>sélectionne automatiquement pour vous</bold> le mode de génération PWM matériel ou logiciel.</caution> <text>Dans tous les cas, si un problème ou une limitation vient à se poser à vous (fréquence maximale, largeur d'impulsion maximale possible, ou résolution de la largeur d'impulsion), il convient alors avant toute chose de comprendre et de s'interroger sur la logique matérielle du composant (largeur des registres, cycles d'horloge, profondeur combinatoire, etc...), et de relire ce que j'ai indiqué plus haut afin d'en maîtriser les contraintes et les limites techniques (ceci ne doit en aucun cas être un frein à vos projets).</text> <text><bold>Ports des automates programmables concernés par la génération du PWM :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) <br/>- Port GPIO 2 (PD1) <br/>- Port GPIO 3 (PD2) <br/>- Port GPIO 4 (PD3) <br/>- Port GPIO 5 (PD4) <br/>- Port GPIO 6 (PD5) <br/>- Port GPIO 7 (PD6) <br/>- Port GPIO 8 (PD7) <br/>- Port GPIO 9 (PB0) <br/>- Port GPIO 10 (PB1) <br/>- Port GPIO 11 (PB2) <br/>- Port GPIO 12 (PB3) <br/>- Port GPIO 13 (PB4) <br/>- Port GPIO 14 (PB5) <br/>- Port GPIO 15 (PC0) <br/>- Port GPIO 16 (PC1) <br/>- Port GPIO 17 (PC2) <br/>- Port GPIO 18 (PC3) <br/>- Port GPIO 19 (PC4) <br/>- Port GPIO 20 (PC5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code>PwmWrite (<green>const unsigned char</green> PIN); <green>static void</green> start (<green>const float</green> FREQUENCY); <green>void</green> us (<green>const float</green> US); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationRandom.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationRandom"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Générer des nombres aléatoires avec la classe Random</title> <underline></underline> <text>Par définition, l'électronique numérique dans sa conception même est un environnement complètement <bold>déterministe</bold>, ce qui exclut le hasard. Éventuellement, une suite de nombres dits <bold>pseudo-aléatoires</bold> (appelés ainsi de part leurs caractères difficilement prédictibles) peuvent être générés via des calculs plus ou moins élaborés, mais ils n'en restent pas moins entièrement déterminés.</text> <text>Pour effectuer de l'aléatoire avec un microcontrôleur déterministe, il convient donc d'y introduire une variable extérieure dont l'évolution est imprévisible et incalculable. Une bonne solution consiste à laisser en l'air une broche, soit physiquement connectée à rien en externe, mais reliée en interne au convertisseur analogique/numérique du microcontrôleur, ceci dans le but de capter le bruit électromagnétique provenant de l'extérieur (et du composant lui même finalement), pour ainsi générer des véritables nombres aléatoires.</text> <text>La classe <bold>Random</bold> propose l'option d'utiliser un port de l'automate programmable relié au convertisseur analogique/numérique du microcontrôleur comme source d'approvisionnement en bruit analogique, mais également dispose d'un générateur de bruit artificiel (pseudo aléatoire) lorsqu'un port inapproprié est utilisé, ou lorsque le bruit analogique est identique sur plusieurs mesures consécutives (et par conséquent rejeté de l'équation), ce qui en fait un algorithme très robuste.</text> <text><bold>Exemple d'utilisation de la classe Random :</bold></text> <code><purple>#include</purple> <pink><Random.h></pink> <green>int</green> main() { Random::seed (<pink>25</pink>); Random::integer (<pink>1</pink>, <pink>6</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple la fonction statique <bold>seed</bold> est appelée prenant en seul paramètre l'utilisation du port GPIO numéro <bold>25</bold> de l'automate programmable relié en interne au convertisseur analogique/numérique (l'ADC) du microcontrôleur. Ce port doit être physiquement laissé libre (en l'air) car il sert au système de génération de nombres aléatoires qui lorsqu'un port approprié est sélectionné, utilise du bruit analogique pour générer de l'aléatoire. Si vous ne souhaitez pas utiliser de bruit analogique pour le système de génération de nombres aléatoires, indiquez <bold>0</bold> en paramètre, dans ce cas seul le générateur de bruit artificiel (pseudo aléatoire) sera utilisé.</text> <caution>Le bruit analogique extérieur permet au système de génération de nombres aléatoires de la classe <bold>Random</bold> d'obtenir la probabilité la plus linéaire et naturelle possible. Afin de conserver cette qualité opérationnelle, il est vivement conseillé de sélectionner un port approprié (voir la liste ci-dessous).</caution> <text><bold>Ports des automates programmables concernés par l'ADC :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 15 (PC0) = ADC0 (analog to digital converter 0) <br/>- Port GPIO 16 (PC1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 17 (PC2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 18 (PC3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 19 (PC4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 20 (PC5) = ADC5 (analog to digital converter 5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 25 (PA7) = ADC7 (analog to digital converter 7) <br/>- Port GPIO 26 (PA6) = ADC6 (analog to digital converter 6) <br/>- Port GPIO 27 (PA5) = ADC5 (analog to digital converter 5) <br/>- Port GPIO 28 (PA4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 29 (PA3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 30 (PA2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 31 (PA1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 32 (PA0) = ADC0 (analog to digital converter 0)</caution> <text>Puis la fonction statique <bold>integer</bold> est appelée prenant en paramètres l'intervalle de nombres aléatoires souhaitée (de 1 à 6 dans l'exemple), ceux-ci peuvent être indifféremment plus petits ou plus grands l'un par rapport à l'autre (de 6 à 1). Après calculs, cette fonction retourne un nombre entier aléatoire que vous pouvez utiliser dans votre programme.</text> <quote>À noter que ce sont <bold>chaque bit du nombre aléatoire généré</bold> dans l'intervalle de nombres demandé qui <bold>fera l'objet d'un calcul et d'un traitement distinct</bold> via le bruit analogique récupéré et le générateur de bruit artificiel, ce qui garanti une probabilité la plus linéaire et naturelle possible.</quote> <text>Une autre fonction existe :</text> <quote>Une fonction statique <bold>boolean</bold> permet de générer et retourner un état binaire <bold>false</bold> (faux) ou <bold>true</bold> (vrai) aléatoire.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code><green>static void</green> seed (<green>const unsigned char</green> PIN_ANALOG); <green>static bool</green> boolean(); <green>static signed long</green> integer (<green>const signed long</green> MIN, <green>const signed long</green> MAX);</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationSoundWrite.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationSoundWrite"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Jouer des sons avec la classe SoundWrite</title> <underline></underline> <text>Lorsque l'on développe un projet demandant une interface entre l'homme et la machine, il est généralement indispensable de pouvoir <bold>communiquer des informations à l'utilisateur à l'aide d'une interface sonore</bold> via un buzzer ou un haut-parleur, c'est ce que permet d'effectuer la classe <bold>SoundWrite</bold>.</text> <a href="photo/dsc08129.jpg"><img src="thumbnail/dsc08129.jpg"></img></a> <text>Avec la classe <bold>SoundWrite</bold> il est possible très simplement de générer des sons de la <bold>fréquence</bold> et de la <bold>durée</bold> souhaitée, ainsi que de <bold>créer des mélodies</bold> grâce au principe d'ajout séquentiel de notes dans ce qui s'apparente à une partition.</text> <text><bold>Exemple pour jouer un son avec la classe SoundWrite :</bold></text> <code><purple>#include</purple> <pink><SoundWrite.h></pink> <green>int</green> main() { SoundWrite::pin (<pink>1</pink>); SoundWrite::play (<pink>440</pink>, <pink>1000</pink>); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, l'instance de la classe <bold>SoundWrite</bold> appelle la fonction statique <bold>pin</bold>, qui prend en paramètre <bold>1</bold>, le numéro du port GPIO de l'automate programmable sur lequel est connecté un périphérique audio (buzzer, haut-parleur, etc...).</text> <text>À la suite la fonction statique <bold>play</bold> est appelée, elle prend un 1er paramètre <bold>440</bold> qui est le choix de la fréquence en Hertz du son qui va être joué (ici un "la" conventionnel à 440Hz), et un 2ème paramètre <bold>1000</bold> qui défini la durée de lecture de cette sonorité exprimée en millisecondes.</text> <quote>À noter que la classe <bold>SoundWrite</bold> calculera <bold>le diviseur d'horloge du microcontrôleur le plus adapté</bold> en rapport avec la fréquence sonore choisie pour chaque appel à la fonction statique <bold>play</bold>, <bold>add</bold>, et <bold>modulate</bold>, ceci afin de garantir une résolution de 20Hz à 20000Hz <bold>la plus élevée possible</bold> (soit un nombre de pas ou d'états disponibles le plus important dans toutes les situations).</quote> <quote>Même si vous n'avez pas besoin d'exécuter des instructions dans la boucle <bold>while</bold>, cette dernière reste importante car elle permet au microcontrôleur de continuer l'exécution du code qui met en fonctionnement l'oscillateur piloté par la classe <bold>SoundWrite</bold>.</quote> <caution>Dans le cas contraire, l'exécution terminerait après <bold>return 0;</bold>, et le microcontrôleur s'arrêterait là de sorte qu'aucun son n'aurait le temps d'être entendu !</caution> <text><bold>Ports des automates programmables concernés par la génération de sons :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) <br/>- Port GPIO 2 (PD1) <br/>- Port GPIO 3 (PD2) <br/>- Port GPIO 4 (PD3) <br/>- Port GPIO 5 (PD4) <br/>- Port GPIO 6 (PD5) <br/>- Port GPIO 7 (PD6) <br/>- Port GPIO 8 (PD7) <br/>- Port GPIO 9 (PB0) <br/>- Port GPIO 10 (PB1) <br/>- Port GPIO 11 (PB2) <br/>- Port GPIO 12 (PB3) <br/>- Port GPIO 13 (PB4) <br/>- Port GPIO 14 (PB5) <br/>- Port GPIO 15 (PC0) <br/>- Port GPIO 16 (PC1) <br/>- Port GPIO 17 (PC2) <br/>- Port GPIO 18 (PC3) <br/>- Port GPIO 19 (PC4) <br/>- Port GPIO 20 (PC5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <title>Jouer une mélodie :</title> <underline></underline> <text>Comme évoqué plus haut, il est possible avec la classe <bold>SoundWrite</bold> de jouer une <bold>suite séquentielle de sonorités</bold> par le simple ajout de notes à une partition virtuelle.</text> <text><bold>Exemple pour créer et jouer une mélodie avec la classe SoundWrite :</bold></text> <code><purple>#include</purple> <pink><SoundWrite.h></pink> <green>int</green> main() { SoundWrite::pin (<pink>1</pink>); SoundWrite::add (<pink>200</pink>, <pink>250</pink>); SoundWrite::add (<pink>400</pink>, <pink>250</pink>); SoundWrite::add (<pink>800</pink>, <pink>250</pink>); SoundWrite::add (<pink>1200</pink>, <pink>250</pink>); SoundWrite::add (<pink>0</pink>, <pink>500</pink>); SoundWrite::add (<pink>800</pink>, <pink>500</pink>); SoundWrite::add (<pink>400</pink>, <pink>500</pink>); SoundWrite::play (<pink>0</pink>, <pink>0</pink>); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>Dans la même logique que l'exemple précédent, après avoir défini le numéro du port GPIO (à l'aide de la fonction statique pin) qui sera utilisé pour générer des sons, une fonction statique <bold>add</bold> est appelée autant de fois qu'il est nécessaire d'ajouter des sons (ou notes), et prend les mêmes paramètres que la fonction statique <bold>play</bold> (fréquence et durée), seul la finalité est différente. En effet avec <bold>play</bold> le son est immédiatement joué, alors qu'avec <bold>add</bold> les sons sont stockés les uns à la suite des autres, après quoi la partition ainsi créée sera jouée en appelant la fonction statique <bold>play</bold> avec en paramètres une fréquence et une durée égales à 0.</text> <caution>À noter qu'un <bold>maximum de 64 notes consécutives</bold> (avant l'appel à la fonction statique play) peuvent être créées, ce qui pourra répondre au besoin de la majorité des projets.</caution> <text>Il est possible de créer des <bold>blancs</bold> (temps morts), c'est-à-dire des moments dans la mélodie où aucune sonorité n'est jouée. Pour se faire il suffit simplement d'indiquer une <bold>fréquence égale à 0</bold> lors de l'appel à la fonction statique <bold>add</bold>.</text> <quote>Il existe également une fonction statique <bold>modulate</bold>, permettant de moduler la fréquence du son en cours de lecture (pour créer un son d'une durée non définie avec la fonction statique play, indiquez une durée égale à 0), et également une fonction statique <bold>stop</bold>, qui a pour but d'arrêter la lecture des sons immédiatement et de vider la partition virtuelle.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code><green>static void</green> pin (<green>const unsigned char</green> PIN); <green>static void</green> play (<green>const float</green> FREQUENCY, <green>const unsigned int</green> DURATION); <green>static void</green> add (<green>const float</green> FREQUENCY, <green>const unsigned int</green> DURATION); <green>static void</green> modulate (<green>const float</green> FREQUENCY); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationSpi25aa1024.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationSpi25aa1024"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Lire et écrire dans une mémoire externe de 1Mio avec la classe Spi25aa1024</title> <underline></underline> <text>Une mémoire EEPROM externe plus importante que celle interne au microcontrôleur peut être indispensable pour des projets qui demandent l'enregistrement de beaucoup de données, quelques exemples :</text> <quote>- Sauvegarder une partition de musique. <br/>- Sauvegarder des acquisitions périodiques de valeurs de capteurs. <br/>- Sauvegarder les pixels d'une image.</quote> <text>La classe <bold>Spi25aa1024</bold> permet très aisément de communiquer avec le composant <bold>25AA1024</bold> qui est une mémoire EEPROM de <bold>1Mio</bold>. Les échanges s'effectuent via le bus <bold>SPI</bold> à la vitesse de 4MHz avec le microcontrôleur (l'automate programmable).</text> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text>Comme toutes les mémoires EEPROM, la mémoire 25AA1024 offre les caractéristiques suivantes :</text> <quote>- Autorise de nombreux cycles de lecture/écriture. <br/>- Est non volatile, cela signifie que la rétention de données perdure même quand celle-ci est coupée de son alimentation électrique.</quote> <text>Les 1048576 octets de la mémoire sont représentés par des emplacements mémoire accessibles à l'aide des fonctions <bold>read</bold> et <bold>write</bold> de la classe Spi25aa1024.</text> <title>Lire la mémoire 25AA1024 :</title> <underline></underline> <text>La lecture de la mémoire 25AA1024 ne demande pas beaucoup d'opérations.</text> <text><bold>Exemple de lecture de la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); <green>unsigned char</green> myData = <pink>0</pink>; myData = myExternalMemory.read (<pink>1</pink>, <pink>8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myExternalMemory</bold> de type <bold>Spi25aa1024</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>5</bold> de l'automate programmable pour sélectionner l'esclave (slave select) sur le bus <bold>SPI</bold>.</text> <quote>Par habitude en SPI, je connecte la sélection de l'esclave au port de l'automate programmable relié à la fonction SS (slave select) du microcontrôleur quand je le peux, <bold>ce qui permet de regrouper tout le câblage relatif au SPI</bold>. <br/> <br/>Mais en réalité, cette entrée/sortie n'est en fait un port SS à la fonction spécifique que lorsque le SPI est configuré en <bold>mode esclave</bold>, ce qui n'arrive jamais avec MODULE. Vous pouvez donc choisir l'esclave sur la sortie SS du microcontrôleur, ou tout autre port d'entrée/sortie disponible (sauf MISO qui même inutilisé doit rester comme une entrée libre lorsque le SPI est en fonctionnement).</quote> <text>Puis la fonction <bold>read</bold> de l'objet <bold>myExternalMemory</bold> est appelée prenant en 1er paramètre <bold>1</bold>, l'emplacement mémoire demandé (soit la lecture du 1er octet de la mémoire). Le 2ème paramètre <bold>8</bold> est le nombre de bits à lire. Ce paramètre peut prendre les valeurs possibles <bold>8</bold>, <bold>16</bold>, et <bold>32</bold> :</text> <quote>- <bold>8</bold> : 8 bits de mémoire seront lus sur l'emplacement mémoire 1. <br/>- <bold>16</bold> : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2. <br/>- <bold>32</bold> : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.</quote> <text>Et également les valeurs <bold>-8</bold>, <bold>-16</bold>, et <bold>-32</bold> (voir plus bas : "Lecture et interprétation des nombres négatifs") :</text> <quote>- <bold>-8</bold> : 8 bits de mémoire seront lus sur l'emplacement mémoire 1. <br/>- <bold>-16</bold> : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2. <br/>- <bold>-32</bold> : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.</quote> <caution>Bien entendu le nombre de bits indiqué en paramètre doit être cohérent avec ce que vous souhaitez lire, de même avec la taille de donnée de destination (myData dans l'exemple), sauf si ces transformations sont nécessaires et trouvent une logique dans le fonctionnement de votre programme.</caution> <title>Lecture et interprétation des nombres négatifs :</title> <underline></underline> <text>Si vous souhaitez lire en mémoire EEPROM un nombre signé tout en conservant son interprétation correcte, il convient de renseigner le 2ème paramètre de la fonction <bold>read</bold> comme étant négatif.</text> <text><bold>Exemple de lecture d'un nombre négatif de 8 bits dans la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); <green>signed char</green> myData = <pink>0</pink>; myData = myExternalMemory.read (<pink>1</pink>, <pink>-8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le 2ème paramètre de la fonction <bold>read</bold> prend la valeur <bold>-8</bold>, ce qui force le format retourné sur <bold>8 bits signés</bold>.</text> <text><bold>Exemple de lecture d'un nombre négatif de 32 bits dans la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); <green>signed long</green> myData = <pink>0</pink>; myData = myExternalMemory.read (<pink>1</pink>, <pink>-32</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Ici le 2ème paramètre de la fonction <bold>read</bold> prend la valeur <bold>-32</bold>, ce qui force le format retourné sur <bold>32 bits signés</bold>.</text> <title>Écrire dans la mémoire 25AA1024 :</title> <underline></underline> <text>La fonction d'écriture reprend les mêmes principes que la fonction de lecture, soit 1048576 emplacements disponibles et une certaine taille de donnée.</text> <text><bold>Exemple d'écriture d'un octet dans la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); myExternalMemory.write (<pink>1</pink>, <pink>135</pink>, <pink>8</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Après la déclaration de l'objet <bold>myExternalMemory</bold> de type <bold>Spi25aa1024</bold>, la fonction <bold>write</bold> instanciée à cet objet est appelée prenant en 1er paramètre l'emplacement mémoire demandé, en 2ème paramètre la donnée à écrire dans la mémoire EEPROM, et en 3ème paramètre le nombre de bits qui seront écrits dans la mémoire.</text> <quote>Ici c'est le nombre <bold>135</bold> qui est écrit dans la mémoire à l'emplacement <bold>1</bold>. Ce nombre occupe <bold>8</bold> bits de mémoire, soit 1 octet.</quote> <text><bold>Exemple d'écriture de deux octets dans la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); myExternalMemory.write (<pink>1</pink>, <pink>6950</pink>, <pink>16</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus c'est le nombre <bold>6950</bold> qui est écrit dans la mémoire à partir de l'emplacement <bold>1</bold>. Il est indiqué que ce nombre occupe <bold>16</bold> bits de mémoire, soit 2 octets. Il s'étend donc jusqu'à l'emplacement <bold>2</bold> de la mémoire.</quote> <text><bold>Exemple d'écriture de quatre octets dans la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); myExternalMemory.write (<pink>101</pink>, <pink>-125000</pink>, <pink>-32</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le nombre <bold>-125000</bold> est écrit dans la mémoire à partir de l'emplacement <bold>101</bold>. Ce nombre occupe <bold>32</bold> bits de mémoire, soit 4 octets. Il s'étend donc jusqu'à l'emplacement <bold>104</bold> de la mémoire.</quote> <quote>La fonction <bold>write</bold> n'est pas sujette à la contrainte des nombres négatifs comme l'est la fonction <bold>read</bold>, vous pouvez donc renseigner indifféremment le paramètre <bold>LENGTH</bold> comme étant positif ou négatif (dans l'exemple ci-dessus 32 ou -32).</quote> <title>Effacer la mémoire 25AA1024 :</title> <underline></underline> <text>Pour effacer la totalité de la mémoire 25AA1024, autrement dit remettre tous les bits à 0, il suffit d'appeler la fonction <bold>erase</bold> comme le montre l'exemple ci-dessous.</text> <text><bold>Exemple pour effacer la totalité de la mémoire 25AA1024 :</bold></text> <code><purple>#include</purple> <pink><Spi25aa1024.h></pink> <green>int</green> main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (<pink>5</pink>); myExternalMemory.erase(); <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus la fonction <bold>erase</bold> attachée à l'objet <bold>myExternalMemory</bold> est appelée, ce qui efface toute la mémoire EEPROM.</text> <caution>À noter que les fonctions d'écriture comme <bold>write</bold> ou d'effacement comme <bold>erase</bold> (qui est une écriture de 0) offrent l'avantage d'économiser les cycles d'écriture pour <bold>garantir la meilleure durée de vie de la mémoire EEPROM</bold>. En effet ces fonctions lisent la mémoire avant d'y écrire, de sorte que l'écriture n'intervient que lorsque nécessaire.</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code>Spi25aa1024 (<green>const unsigned char</green> PIN_SS); <green>signed long</green> read (<green>const unsigned long</green> ADDRESS, <green>const signed char</green> LENGTH); <green>void</green> write (<green>const unsigned long</green> ADDRESS, <green>const signed long</green> DATA, <green>const signed char</green> LENGTH); <green>void</green> erase();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationSpiMax7219.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationSpiMax7219"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Afficher des caractères avec la classe SpiMax7219</title> <underline></underline> <text>La classe <bold>SpiMax7219</bold> permet d'utiliser des afficheurs à diodes électroluminescences (digits et matrice) pilotées par le composant <bold>MAX7219</bold>, ce dernier communique en <bold>SPI</bold> à la vitesse de 4MHz avec le microcontrôleur (l'automate programmable) :</text> <a href="photo/dsc08181.jpg"><img src="thumbnail/dsc08181.jpg"></img></a> <a href="photo/dsc08368.jpg"><img src="thumbnail/dsc08368.jpg"></img></a> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text><bold>Exemple pour afficher un nombre entier :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.integer (<pink>256</pink>, <pink>1</pink>, <pink>8</pink>, <red>true</red>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myDisplay</bold> de type <bold>SpiMax7219</bold> est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro <bold>5</bold> de l'automate programmable pour sélectionner l'esclave (slave select) sur le bus <bold>SPI</bold>.</text> <quote>Par habitude en SPI, je connecte la sélection de l'esclave au port de l'automate programmable relié à la fonction SS (slave select) du microcontrôleur quand je le peux, <bold>ce qui permet de regrouper tout le câblage relatif au SPI</bold>. <br/> <br/>Mais en réalité, cette entrée/sortie n'est en fait un port SS à la fonction spécifique que lorsque le SPI est configuré en <bold>mode esclave</bold>, ce qui n'arrive jamais avec MODULE. Vous pouvez donc choisir l'esclave sur la sortie SS du microcontrôleur, ou tout autre port d'entrée/sortie disponible (sauf MISO qui même inutilisé doit rester comme une entrée libre lorsque le SPI est en fonctionnement).</quote> <text>Puis la fonction <bold>integer</bold> de l'objet <bold>myDisplay</bold> est appelée : <br/>- Le 1er paramètre <bold>256</bold> est le nombre entier à afficher (sur 32 bits maximum). <br/>- Le 2ème paramètre <bold>1</bold> indique la position ou commence l'affichage de ce nombre (position 1). <br/>- Le 3ème paramètre <bold>8</bold> indique la position ou termine l'affichage de ce nombre (position 8). <br/>- Le 4ème paramètre <bold>true</bold> permet de caler le nombre affiché à droite (false pour le caler à gauche) dans l'intervalle de positions sélectionnée (positions 1 à 8).</text> <caution>Dans cet exemple, le nombre à afficher (256) comporte seulement <bold>3 digits</bold>, l'intervalle de positions qui lui est accordé pour être affiché comporte <bold>8 digits</bold> (positions 1 à 8) c'est-à-dire <bold>la totalité de l'afficheur</bold>. En conséquence, le 4ème paramètre (calage) est effectif lorsque le nombre à afficher prend moins de place que l'intervalle sélectionnée (ceci permet de caler le nombre sur la partie gauche ou droite de l'intervalle choisie).</caution> <title>Autres fonctions utiles :</title> <underline></underline> <text>D'autres fonctions existent, comme l'affichage des nombres décimaux, l'affichage de texte, de points ou lignes sur une matrice à dels, ou encore le réglage de la luminosité (par PWM), etc...</text> <text><bold>Exemple pour afficher un nombre décimal :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.decimal (<pink>2.56</pink>, <pink>3</pink>, <pink>7</pink>, <pink>1</pink>, <red>false</red>); <red>return</red> <pink>0</pink>; }</code> <text>Paramètres de la fonction <bold>decimal</bold> de l'objet <bold>myDisplay</bold> : <br/>- Le 1er paramètre <bold>2.56</bold> est le nombre décimal à afficher (en virgule flottante 32 bits). <br/>- Le 2ème paramètre <bold>3</bold> indique la position ou commence l'affichage de ce nombre (position 3). <br/>- Le 3ème paramètre <bold>7</bold> indique la position ou termine l'affichage de ce nombre (position 7). <br/>- Le 4ème paramètre <bold>1</bold> indique le nombre de chiffres à afficher après la virgule. <br/>- Le 5ème paramètre <bold>false</bold> permet de caler le nombre affiché à gauche (true pour le caler à droite) dans l'intervalle de positions sélectionnée (positions 3 à 7).</text> <text><bold>Exemple pour afficher un nombre entier et décimal l'un à coté de l'autre :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.integer (<pink>256</pink>, <pink>1</pink>, <pink>4</pink>, <red>true</red>); myDisplay.decimal (<pink>1.28</pink>, <pink>5</pink>, <pink>8</pink>, <pink>1</pink>, <red>true</red>); <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, le nombre entier <bold>256</bold> sera affiché dans l'intervalle de positions <bold>1</bold> à <bold>4</bold> et <bold>calé à droite</bold> dans son intervalle de positions.</text> <text>Le nombre décimal qu'en à lui sera affiché dans l'intervalle de positions <bold>5</bold> à <bold>8</bold>, avec <bold>1 chiffre après la virgule</bold>, et à l'instar du nombre décimal il sera <bold>calé à droite</bold> dans son intervalle de positions sur l'afficheur.</text> <caution>Le nombre entier affiché en premier ne sera pas effacé tant que des caractères ne viendront pas écraser les positions (intervalles) qu'il occupe. Si vous souhaitez effacer tout ce qui est affiché sur l'afficheur, utilisez la fonction <bold>clearDevice</bold>.</caution> <text><bold>Exemple pour afficher du texte :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.word (<pink>"hello"</pink>); <red>return</red> <pink>0</pink>; }</code> <text>La fonction <bold>word</bold> de l'objet <bold>myDisplay</bold> prend en paramètre un ou plusieurs caractères alphanumériques. Ici c'est le mot <bold>hello</bold> qui est affiché (sur l'afficheur à digits ou le mini afficheur à digits).</text> <text>Il est également possible d'afficher des nombres avec cette fonction, pour cela il suffit d'écrire en paramètre par exemple <bold>"123.45"</bold>, ou bien encore d'afficher les lettres avec leurs points (virgules) correspondants (en suffixe) en écrivant <bold>"..hel.l.o"</bold>. Ici les deux <bold>l.</bold> s'afficheront avec un point en dessous.</text> <quote>Un caractère à la fonction spécifique existe, c'est la barre oblique <bold>/</bold>. Celle-ci permet de terminer le rafraîchissement de l'affichage à cet endroit, et par conséquent de ne pas écraser les digits suivants, car en effet avec la fonction word, <bold>par défaut c'est l'intégralité de l'affichage qui est mis à jour</bold>.</quote> <text><bold>Exemple pour régler la luminosité de l'affichage :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.brightness (<pink>4</pink>); <red>return</red> <pink>0</pink>; }</code> <text>La fonction <bold>brightness</bold> est appelée et prend en paramètre un nombre entier de <bold>1</bold> à <bold>16</bold> (16 étant la luminosité maximale).</text> <quote>Vous pouvez réaliser des effets complexes avec toutes les fonctions qui vous sont proposées dans cette classe, libre à vous de composer votre affichage d'une manière harmonieuse !</quote> <title>Affichage en cascade sur le bus SPI :</title> <underline></underline> <text>Il est possible aisément de connecter plusieurs afficheurs sur le bus SPI via la définition de broches SS (slave select) qui peuvent être communes à plusieurs périphériques.</text> <text><bold>Exemple pour connecter plusieurs afficheurs en cascade et/ou en parallèle sur le bus SPI :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDigitDisplay = SpiMax7219 (<pink>5</pink>); SpiMax7219 myMatrixDisplay = SpiMax7219 (<pink>5</pink>); SpiMax7219 myWordDisplay = SpiMax7219 (<pink>4</pink>); myDigitDisplay.integer (<pink>256</pink>, <pink>1</pink>, <pink>8</pink>, <red>true</red>); myMatrixDisplay.dot (<pink>7</pink>, <pink>2</pink>); myMatrixDisplay.dot (<pink>8</pink>, <pink>1</pink>); myWordDisplay.word (<pink>"hello "</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Explication des connexions : <br/>- La broche SS (slave select) de l'afficheur relatif à l'objet <bold>myDigitDisplay</bold> est connectée au port GPIO <bold>5</bold> de l'automate programmable, il est le <bold>1er périphérique en cascade</bold> sur le bus SPI, étant l'objet déclaré en premier. <br/>- La broche SS de l'afficheur relatif à l'objet <bold>myMatrixDisplay</bold> est également connectée au port GPIO <bold>5</bold> de l'automate programmable, donc cet afficheur est défini comme étant le <bold>2ème périphérique en cascade</bold> sur le bus SPI, car déclaré en deuxième et sur le même port que le précédent. <br/>- Le 3ème afficheur, relatif à l'objet <bold>myWordDisplay</bold>, voit sa broche SS connectée à un autre port que les deux afficheurs précédents, le port GPIO <bold>4</bold> de l'automate programmable, il est donc en parallèle par rapport aux autres, et est placé comme étant le seul périphérique sur cette partie du bus SPI.</text> <caution>L'ordre de positionnement en cascade des afficheurs <bold>suit l'ordre de déclaration des objets de type SpiMAX7219</bold>, si plusieurs afficheurs utilisent un port en commun de l'automate programmable pour connecter leur broches SS respectives, <bold>ils seront en cascade dans l'ordre chronologique des déclarations</bold>.</caution> <quote>Si votre alimentation le permet, ce principe de connexions en cascade (série) et/ou en parallèle vous garanti de faire fonctionner un très grand nombre d'afficheurs sur un même automate programmable.</quote> <title>Exemple d'affichage aléatoire :</title> <underline></underline> <text>Avec MODULE il vous est possible de combiner les fonctionnalités de plusieurs classes comme vous le souhaitez, il devient alors facile de réaliser des effets en utilisant plusieurs classes dédiées à la réalisation de certaines tâches plus ou moins complexes.</text> <a href="photo/dsc08365.jpg"><img src="thumbnail/dsc08365.jpg"></img></a> <text>C'est ce que montre l'exemple suivant par l'utilisation de 3 classes, <bold>SpiMax7219</bold> pour piloter en SPI un affichage à matrice, <bold>Random</bold> pour générer des positions aléatoires ce qui permet d'allumer les dels au hasard sur la matrice, et <bold>Timer</bold> afin d'effectuer ces tâches périodiquement.</text> <text><bold>Ci-dessous le détail du programme :</bold></text> <code><purple>#include</purple> <pink><SpiMax7219.h></pink> <purple>#include</purple> <pink><Random.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { <green>unsigned char</green> line = <pink>1</pink>; SpiMax7219 myMatrix = SpiMax7219 (<pink>5</pink>); Random::seed (<pink>32</pink>); <red>while</red> (<red>true</red>) { for (line = <pink>1</pink>; line <= <pink>8</pink>; line++) { myMatrix.draw (Random::integer (<pink>0</pink>, <pink>255</pink>), line); } Timer::pause (<pink>100</pink>); } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus c'est la fonction <bold>draw</bold> associée à l'objet <bold>myMatrix</bold> qui est utilisée afin de changer l'allumage des dels.</text> <text>Cette fonction prend en 1er paramètre un nombre de <bold>0</bold> à <bold>255</bold> qui correspond aux 8 bits, et donc aux 8 dels de la ligne dont le numéro de ligne est indiqué en 2ème paramètre par la variable <bold>line</bold>. Ce 2ème paramètre est incrémenté dans la boucle <bold>for</bold> afin d'effectuer un balayage des 8 lignes de la matrice de 64 dels.</text> <text>Après quoi une pause bloquante de <bold>100</bold> millisecondes cadence le groupe de tâches précédentes dans le but d'effectuer un rafraîchissement périodique de l'affichage.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code>SpiMax7219 (<green>const unsigned char</green> PIN_SS); void brightness (<green>const unsigned char</green> BRIGHTNESS); void digit (<green>const unsigned char</green> DIGIT, <green>const bool</green> COMMA, <green>const unsigned char</green> POSITION); void integer (<green>const signed long</green> INTEGER, <green>const unsigned char</green> POSITION_MIN, <green>const unsigned char</green> POSITION_MAX, <green>const bool</green> SIDE); void decimal (<green>const float</green> DECIMAL, <green>const unsigned char</green> POSITION_MIN, <green>const unsigned char</green> POSITION_MAX, <green>const unsigned char</green> DIGIT_AFTER_COMMA, <green>const bool</green> SIDE); void character (const char *CHARACTER, <green>const unsigned char</green> POSITION); void word (const char *WORD); void byte (<green>const unsigned char</green> BYTE); void draw (<green>const unsigned char</green> DRAW, <green>const unsigned char</green> POSITION); void drawDevice (<green>const unsigned char</green> DRAW1, <green>const unsigned char</green> DRAW2, <green>const unsigned char</green> DRAW3, <green>const unsigned char</green> DRAW4, <green>const unsigned char</green> DRAW5, <green>const unsigned char</green> DRAW6, <green>const unsigned char</green> DRAW7, <green>const unsigned char</green> DRAW8); void dot (<green>const unsigned char</green> X, <green>const unsigned char</green> Y); void clearLine (<green>const unsigned char</green> LINE); void clearDevice();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationSpiNrf24l01p.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationSpiNrf24l01p"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Une radiocommande avec la classe SpiNrf24l01p</title> <underline></underline> <text>La classe <bold>SpiNrf24l01p</bold> permet de transmettre de manière <bold>multidirectionnelle</bold> (applications multiceivers, soit plusieurs transceivers) des informations (sur 32 bits quelles qu'elles soient) sur la bande fréquence des <bold>2.4GHz</bold> entre plusieurs périphériques (deux ou plus).</text> <caution>Le composant utilisé est le <bold>nRF24L01+</bold>, ce matériel est un <bold>transceiver</bold> pour émetteur/récepteur, la classe que je propose ici pilote ce composant et permet des <bold>applications multiceivers</bold> (réseau d'émetteurs/récepteurs), autorisant les projets les plus ambitieux notamment en robotique.</caution> <a href="photo/dsc08423.jpg"><img src="thumbnail/dsc08423.jpg"></img></a> <a href="photo/dsc08316.jpg"><img src="thumbnail/dsc08316.jpg"></img></a> <text>Le composant <bold>nRF24L01+</bold> communique en <bold>SPI</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text>Dans les exemples qui suivent, il s'agit de montrer le plus simplement possible (pour la compréhension du lecteur) un émetteur et un récepteur distinct (sans créer de confusion et donc sans évoquer le coté multiceiver) :</text> <quote>Mais sachez que <bold>la programmation de multiples émetteurs/récepteurs s'effectue exactement de la même façon</bold>, avec les fonctions employées dans les exemples (transmit et receive), de manière <bold>complètement transparente pour le programmeur</bold> via l'utilisation de la classe <bold>SpiNrf24l01p</bold>.</quote> <text>Ci-dessous, un premier périphérique nommé "émetteur" envoi des données à un deuxième montage appelé "récepteur".</text> <text><bold>Exemple d'émetteur :</bold></text> <code><purple>#include</purple> <pink><SpiNrf24l01p.h></pink> <green>int</green> main() { SpiNrf24l01p myChannel = SpiNrf24l01p (<pink>1</pink>); <green>unsigned char</green> myIteration = <pink>0</pink>; SpiNrf24l01p::start (<pink>5</pink>, <pink>32</pink>, <pink>1524003746</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { myChannel.transmit (myIteration); <red>if</red> (myIteration < <pink>255</pink>) { myIteration++; } <red>else</red> { myIteration = <pink>0</pink>; } } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myChannel</bold> de type <bold>SpiNrf24l01p</bold> est déclaré, en paramètre est indiqué le canal <bold>1</bold> sur lequel communiquer les données (il y a 64 canaux en tout). À la ligne suivante une variable <bold>myIteration</bold> de type <bold>unsigned char</bold> (8 bits non signés) est déclarée avec une valeur de <bold>0</bold>, elle va servir à incrémenter un nombre entier.</text> <text>Puis, le composant nRF24L01+ est démarré en appelant la fonction statique <bold>start</bold> prenant plusieurs paramètres : <br/>- Le 1er paramètre <bold>5</bold> est le numéro du port GPIO de l'automate programmable sur lequel est connectée la broche SS (slave select) du composant nRF24L01+.</text> <quote>Ce paramètre est utile lorsque vous souhaitez connecter en SPI différents composants en série ou en parallèle avec le microcontrôleur.</quote> <text>- Le 2ème paramètre <bold>32</bold> est le numéro du port GPIO de l'automate programmable relié en interne au convertisseur analogique/numérique (l'ADC) du microcontrôleur. Ce port doit être physiquement laissé libre (en l'air) car il sert au système anti-collisions qui lorsqu'un port approprié est sélectionné, utilise du bruit analogique pour générer de l'aléatoire. Si vous ne souhaitez pas utiliser de bruit analogique pour le système anti-collisions, indiquez <bold>0</bold> en paramètre, dans ce cas seul le générateur de bruit artificiel (pseudo aléatoire) sera utilisé.</text> <caution>Le système anti-collisions de la classe <bold>SpiNrf24l01p</bold> permet d'éviter que plusieurs (deux ou plus) nRF24L01+ ne se transmettent des données exactement au même moment. Afin de conserver cette qualité opérationnelle, il est vivement conseillé dans le cadre d'une communication bidirectionnelle ou multidirectionnelle de sélectionner un port approprié (voir la liste ci-dessous).</caution> <text><bold>Ports des automates programmables concernés par l'ADC :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 15 (PC0) = ADC0 (analog to digital converter 0) <br/>- Port GPIO 16 (PC1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 17 (PC2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 18 (PC3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 19 (PC4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 20 (PC5) = ADC5 (analog to digital converter 5) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 25 (PA7) = ADC7 (analog to digital converter 7) <br/>- Port GPIO 26 (PA6) = ADC6 (analog to digital converter 6) <br/>- Port GPIO 27 (PA5) = ADC5 (analog to digital converter 5) <br/>- Port GPIO 28 (PA4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 29 (PA3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 30 (PA2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 31 (PA1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 32 (PA0) = ADC0 (analog to digital converter 0)</caution> <text>- Le 3ème paramètre <bold>1524003746</bold> correspond au code de radio-identification (ou RFID unique par définition) qui permet de sécuriser la communication entre plusieurs (deux ou plus) nRF24L01+.</text> <caution>C'est à vous de choisir ce code RFID, plus le nombre est complexe et plus la communication sera sécurisée et protégée contre les parasites, mais il faut reconnaître que n'importe quel nombre sur 32 bits différent de 0 avec seulement quelques chiffres, est largement suffisant.</caution> <text>- Le 4ème paramètre <bold>true</bold> indique d'émettre à la puissance maximale (0dBm). Une valeur sur <bold>false</bold> serait la puissance minimale (-18dBm), ce qui peut être suffisant en communication courte distance (par exemple en intérieur).</text> <text>Puis dans la boucle <bold>while</bold>, la fonction <bold>transmit</bold> de l'objet <bold>myChannel</bold> est utilisée pour transmettre une information 32 bits à un autre nRF24L01+. Dans ce cas c'est la valeur de la variable <bold>myIteration</bold> qui est transmise, variable dont la valeur est incrémentée aux lignes suivantes.</text> <quote>Ce petit bout de programme est simple, mais il permet déjà d'assurer une communication 2.4GHz efficace et sécurisée entre deux nRF24L01+.</quote> <text>Envoyer la valeur d'une variable qui s'incrémente au cours du temps peut servir à programmer simplement un système à tolérance de pannes (fail-safe) sur la partie récepteur du montage. En effet, si la valeur reçue ne s'incrémente plus pendant un certain temps (1 seconde par exemple), il peut être alors intéressant de déclencher une mise au neutre des servo-moteurs, une coupure de la motorisation d'un aéronef, une procédure de vol automatisée par gyroscope, etc...</text> <text><bold>Exemple de récepteur :</bold></text> <code><purple>#include</purple> <pink><SpiNrf24l01p.h></pink> <green>int</green> main() { SpiNrf24l01p myChannel = SpiNrf24l01p (<pink>1</pink>); <green>unsigned char</green> myIteration = <pink>0</pink>; SpiNrf24l01p::start (<pink>5</pink>, <pink>32</pink>, <pink>1524003746</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { myChannel.receive(); <blue>//myChannel.data sont les données reçues sur ce canal :</blue> myIteration = myChannel.data; } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le seul changement notable est l'appel de la fonction <bold>receive</bold> de l'objet <bold>myChannel</bold> afin de recevoir les données émises, en l'occurrence ici la valeur de la variable incrémentée dans le montage coté émetteur.</text> <quote>La classe <bold>SpiNrf24l01p</bold> dispose d'une fonction <bold>reset</bold> ce qui permet de remettre à l'état <bold>false</bold> la variable <bold>received</bold>. Cette variable est utile pour savoir si une ou plusieurs données ont été reçues avec succès. La variable <bold>data</bold> (qui correspond aux données reçues) est également réinitialisée à <bold>0</bold>. <br/> <br/>Une fonction statique <bold>stop</bold> existe également et permet d'éteindre le circuit d'émission/réception du composant nRF24L01+, un nouvel appel à la fonction <bold>start</bold> permet de redémarrer le circuit.</quote> <title>Exemple d'un système radiocommandé 5 voies :</title> <underline></underline> <text>Dans l'exemple suivant, 4 potentiomètres (2 par manche) sont connectés aux ports GPIO 25, 26, 27, et 28 de l'automate programmable. Ce sont des entrées/sorties connectées au convertisseur analogique/numérique (l'ADC) du microcontrôleur. Un interrupteur est également connecté au port GPIO 1 de l'automate programmable, ce qui va servir d'interrupteur de coupure moteur dans ce cas précis.</text> <quote>Les 4 potentiomètres et l'interrupteur servent <bold>d'interface utilisateur entre l'homme et la machine</bold>.</quote> <a href="photo/dsc08302.jpg"><img src="thumbnail/dsc08302.jpg"></img></a> <a href="photo/dsc08305.jpg"><img src="thumbnail/dsc08305.jpg"></img></a> <text>5 objets de type <bold>SpiNrf24l01p</bold> (correspondants aux 5 voies) servent à transmettre les valeurs brutes des 4 potentiomètres et de l'interrupteur (respectivement des valeurs allants de 0 à 1023 pour les potentiomètres et 0 ou 1 pour l'interrupteur).</text> <text><bold>L'émetteur :</bold></text> <code><purple>#include</purple> <pink><AnalogRead.h></pink> <purple>#include</purple> <pink><GpioRead.h></pink> <purple>#include</purple> <pink><SpiNrf24l01p.h></pink> <green>int</green> main() { AnalogRead myStickThrottle = AnalogRead (<pink>25</pink>); AnalogRead myStickPitch = AnalogRead (<pink>26</pink>); AnalogRead myStickRoll = AnalogRead (<pink>27</pink>); AnalogRead myStickYaw = AnalogRead (<pink>28</pink>); GpioRead myButtonCut = GpioRead (<pink>1</pink>, <red>true</red>, <pink>10</pink>); SpiNrf24l01p myChannelThrottle = SpiNrf24l01p (<pink>1</pink>); SpiNrf24l01p myChannelPitch = SpiNrf24l01p (<pink>2</pink>); SpiNrf24l01p myChannelRoll = SpiNrf24l01p (<pink>3</pink>); SpiNrf24l01p myChannelYaw = SpiNrf24l01p (<pink>4</pink>); SpiNrf24l01p myChannelCut = SpiNrf24l01p (<pink>5</pink>); SpiNrf24l01p::start (<pink>5</pink>, <pink>32</pink>, <pink>1524003746</pink>, <red>true</red>); <red>while</red> (<red>true</red>) { myStickThrottle.read(); myStickPitch.read(); myStickRoll.read(); myStickYaw.read(); myButtonCut.read(); myChannelThrottle.transmit (myStickThrottle.value); myChannelPitch.transmit (myStickPitch.value); myChannelRoll.transmit (myStickRoll.value); myChannelYaw.transmit (myStickYaw.value); myChannelCut.transmit (myButtonCut.bistable); } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple suivant est la partie récepteur du montage. 5 objets de type <bold>PwmWrite</bold> sont utilisés pour générer des signaux <bold>PWM</bold> ce qui permet de faire fonctionner 4 servo-moteurs : <br/>- Le 1er pour les gaz (throttle). <br/>- Le 2ème pour l'axe de tangage (pitch). <br/>- Le 3ème pour l'axe de roulis (roll). <br/>- Le 4ème pour l'axe de lacet (yaw).</text> <text>Une fois reçues avec les fonctions <bold>receive</bold>, les valeurs brutes sont transformées à l'aide de la classe <bold>Math</bold> (qui permet de créer entre autres des courbes) en valeurs adaptées PWM (modulation de la largeur d'impulsion en microsecondes) afin de les envoyer aux servo-moteurs par les ports GPIO 1, 2, 3, et 4 de l'automate programmable.</text> <text><bold>Le récepteur :</bold></text> <code><purple>#include</purple> <pink><SpiNrf24l01p.h></pink> <purple>#include</purple> <pink><PwmWrite.h></pink> <purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { SpiNrf24l01p myChannelThrottle = SpiNrf24l01p (<pink>1</pink>); SpiNrf24l01p myChannelPitch = SpiNrf24l01p (<pink>2</pink>); SpiNrf24l01p myChannelRoll = SpiNrf24l01p (<pink>3</pink>); SpiNrf24l01p myChannelYaw = SpiNrf24l01p (<pink>4</pink>); SpiNrf24l01p myChannelCut = SpiNrf24l01p (<pink>5</pink>); PwmWrite myServoThrottle = PwmWrite (<pink>1</pink>); PwmWrite myServoPitch = PwmWrite (<pink>2</pink>); PwmWrite myServoRoll = PwmWrite (<pink>3</pink>); PwmWrite myServoYaw = PwmWrite (<pink>4</pink>); SpiNrf24l01p::start (<pink>5</pink>, <pink>32</pink>, <pink>1524003746</pink>, <red>true</red>); PwmWrite::start (<pink>50</pink>); <red>while</red> (<red>true</red>) { myChannelThrottle.receive(); myChannelPitch.receive(); myChannelRoll.receive(); myChannelYaw.receive(); myChannelCut.receive(); <red>if</red> (myChannelCut.data == <red>true</red>) { myServoThrottle.us (<pink>1000</pink>); } <red>else</red> { myServoThrottle.us (Math::curve (<pink>0</pink>, myChannelThrottle.data, <pink>1023</pink>, <pink>1000</pink>, <pink>2000</pink>, <pink>0</pink>)); myServoPitch.us (Math::curve (<pink>0</pink>, myChannelPitch.data, <pink>1023</pink>, <pink>1000</pink>, <pink>2000</pink>, <pink>0</pink>)); myServoRoll.us (Math::curve (<pink>0</pink>, myChannelRoll.data, <pink>1023</pink>, <pink>1000</pink>, <pink>2000</pink>, <pink>0</pink>)); myServoYaw.us (Math::curve (<pink>0</pink>, myChannelYaw.data, <pink>1023</pink>, <pink>1000</pink>, <pink>2000</pink>, <pink>0</pink>)); } } <red>return</red> <pink>0</pink>; }</code> <text>La 5ème voie (cut) permet la <bold>coupure des gaz</bold> quel que soit la position du manche de gaz, c'est une des sécurités fondamentales notamment en aéromodélisme.</text> <quote>Libre à vous d'explorer les possibilités de <bold>MODULE</bold> afin d'utiliser et de modifier ces exemples pour vos applications !</quote> <text>En l'occurrence je pense au retour air/sol de la pression atmosphérique et de la température à l'aide du capteur environnemental <bold>BME280</bold> et de la classe <bold>TwiBme280</bold>, de l'utilisation des centrales inertielles <bold>MPU6050</bold> et <bold>BNO055</bold> à l'aide des classes <bold>TwiMpu6050</bold> et <bold>TwiBno055</bold>, de l'ajout de trims, d'un écran de contrôle, d'une alarme batterie faible, d'une temporisation, de réglages divers (courbes, double débattements), etc...</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>signed long</green> data = <pink>0</pink>; <green>bool</green> received = <red>false</red>; SpiNrf24l01p (<green>const unsigned char</green> ADDRESS); <green>static void</green> start (<green>const unsigned char</green> PIN_SS, <green>const unsigned char</green> PIN_ANALOG, <green>const unsigned long</green> RFID, <green>const bool</green> POWER); <green>void</green> receive(); <green>void</green> transmit (<green>const signed long</green> DATA); <green>void</green> reset(); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTimer.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTimer"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La gestion du temps avec la classe Timer</title> <underline></underline> <text>La plupart des projets requièrent la dimension temporelle pour pouvoir fonctionner, c'est pourquoi la classe <bold>Timer</bold> apporte la temporisation des événements et des actions à effectuer dans un programme.</text> <caution>Contrairement à d'autres plates-formes de développement pour microcontrôleurs à registres 8 bits, la classe <bold>Timer</bold> utilise un compteur qui <bold>fonctionne à une fréquence de 2MHz sur une largeur mémoire de 64 bits</bold>, de sorte que le temps peut être compté à partir de zéro <bold>toutes les microsecondes</bold> pendant bien plus longtemps que la durée de vie du microcontrôleur lui-même (plusieurs centaines de milliers d'années), en effet une largeur mémoire de seulement 32 bits imposerait un retour à zéro (overflow) au bout d'un peu plus d'une demi-heure tout au plus, ce qui serait très limitant pour bons nombres de projets !</caution> <text>Les compteurs (ou timers) que vous déclarez avec la classe <bold>Timer</bold> se présentent sous la forme d'objets (c'est le principe de beaucoup de mes classes), il est donc possible de créer <bold>plusieurs compteurs ayant tous des fonctions indépendantes</bold> dans votre programme.</text> <text><bold>Exemple d'utilisation de la classe Timer :</bold></text> <code><purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { Timer myTimer = Timer(); myTimer.start (<pink>0</pink>); <red>while</red> (<red>true</red>) { myTimer.state(); <blue>//myTimer.s est le temps écoulé en secondes</blue> <blue>//myTimer.ms est le temps écoulé en millisecondes</blue> <blue>//myTimer.us est le temps écoulé en microsecondes</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myTimer</bold> de type <bold>Timer</bold> est déclaré, puis via cet objet, la fonction <bold>start</bold> est appelée prenant en paramètre <bold>0</bold>, le temps de départ indiqué en millisecondes :</text> <quote>Dans la plupart des cas nous souhaitons qu'un compteur <bold>démarre à 0</bold> (comme l'exemple) lorsque la fonction <bold>start</bold> est appelée, mais si vous le souhaitez vous pouvez le faire partir à une autre valeur.</quote> <text>Plus loin cet objet <bold>myTimer</bold> appelle la fonction <bold>state</bold> (état) dans une boucle ce qui permet de mettre à jour les variables <bold>s</bold> (secondes), <bold>ms</bold> (millisecondes), et <bold>us</bold> (microsecondes) que vous pourrez utiliser dans vos conditions logiques et divers calculs.</text> <title>La fonction pause :</title> <underline></underline> <text>Malgré que l'utilisation première de la classe <bold>Timer</bold> permet la création d'objets instanciés indépendants, il est néanmoins parfois utile de pouvoir bénéficier de <bold>pauses bloquantes</bold> appelées de façon statique sans objet, directement à partir de la classe concernée. La fonction <bold>pause</bold> remplie cette fonctionnalité.</text> <text><bold>Exemple de clignotement d'une del avec la classe Timer :</bold></text> <code><purple>#include</purple> <pink><GpioWrite.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { GpioWrite myLed = GpioWrite (<pink>1</pink>); <red>while</red> (<red>true</red>) { myLed.toggle(); Timer::pause (<pink>1000</pink>); } <red>return</red> <pink>0</pink>; }</code> <text>Contrairement au premier exemple et l'utilisation d'un objet, ici la fonction statique <bold>pause</bold> est directement appelée à partir de la classe <bold>Timer</bold>. Cette fonction prend en paramètre <bold>1000</bold>, la durée de la pause en millisecondes.</text> <quote>Dans l'exemple ci-dessus, si une del était branchée sur le port GPIO 1 de l'automate programmable, elle clignoterait toutes les secondes (1000 millisecondes), mais dans ces conditions <bold>le programme ne pourrait pas faire autre chose que gérer la commutation du port GPIO numéro 1</bold>, la pause est dite <bold>bloquante</bold> car rien d'autre ne peut être effectué en parallèle. L'exemple suivant résout ce problème.</quote> <text><bold>Exemple de clignotement d'une del sans pause bloquante avec la classe Timer :</bold></text> <code><purple>#include</purple> <pink><GpioWrite.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { GpioWrite myLed = GpioWrite (<pink>1</pink>); Timer myTimer = Timer(); myTimer.start (<pink>0</pink>); <red>while</red> (<red>true</red>) { myTimer.state(); <blue>//tâche à effectuer toutes les 1000ms :</blue> <red>if</red> (myTimer.ms >= <pink>1000</pink>) { myLed.toggle(); myTimer.start (<pink>0</pink>); } <blue>//autres tâches à effectuer en parallèle...</blue> } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple ci-dessus montre bien que lors d'un tour de boucle, si à partir du démarrage du compteur <bold>le temps écoulé est supérieur ou égal à 1000 millisecondes</bold>, l'exécution rentre dans la condition logique, effectue la commutation de la del, redémarre le compteur à zéro, et à la suite exécute toutes les autres tâches du programme <bold>sans passer par un état bloquant</bold> comme c'était le cas précédemment.</text> <quote>Dans une problématique comme celle-ci, plusieurs solutions sont souvent possibles, c'est ce que montre l'exemple suivant avec l'utilisation d'une <bold>variable qui est incrémentée pour suivre l'avancée du temps imposé par le compteur</bold> (ce qui évite un cumul d'erreurs dans le temps), ainsi ce dernier n'a pas besoin d'être redémarré à zéro à chaque fois.</quote> <text><bold>Autre exemple de clignotement d'une del sans pause bloquante avec la classe Timer :</bold></text> <code><purple>#include</purple> <pink><GpioWrite.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>int</green> main() { GpioWrite myLed = GpioWrite (<pink>1</pink>); Timer myTimer = Timer(); <green>unsigned long long</green> timePrevious = <pink>0</pink>; myTimer.start (<pink>0</pink>); <red>while</red> (<red>true</red>) { myTimer.state(); <blue>//tâche à effectuer toutes les 1000ms :</blue> <red>if</red> (myTimer.ms - timePrevious >= <pink>1000</pink>) { myLed.toggle(); timePrevious += <pink>1000</pink>; } <blue>//autres tâches à effectuer en parallèle...</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Cet exemple-ci est plus précis que les trois précédents car il met en jeu la variable <bold>timePrevious</bold> qui au passage dans la condition logique n'est pas initialisée sur le temps écoulé du compteur comme on pourrait être tenté de le programmer, mais plutôt bêtement incrémentée de <bold>1000</bold>, ce qui compense et ne tient pas compte du temps d'exécution de la condition logique elle-même, de la commutation de la del, et du reste du programme.</text> <quote>Pour parfaire l'utilisation de la classe <bold>Timer</bold>, une fonction <bold>stop</bold> existe et permet d'arrêter l'écoulement du temps, dans cette situation les variables <bold>s</bold> (secondes), <bold>ms</bold> (millisecondes), et <bold>us</bold> (microsecondes) resteront à leurs dernières valeurs mises à jour lors de l'appel de la fonction <bold>state</bold>, ceci avant l'appel à la fonction <bold>stop</bold>.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>unsigned long long</green> s = <pink>0</pink>; <green>unsigned long long</green> ms = <pink>0</pink>; <green>unsigned long long</green> us = <pink>0</pink>; Timer(); <green>void</green> start (<green>const unsigned long long</green> TIME_START); <green>void</green> state(); <green>void</green> stop(); <green>static void</green> pause (<green>const unsigned long long</green> DURATION);</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTool.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTool"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Quelques outils avec la classe Tool</title> <underline></underline> <text>La classe <bold>Tool</bold> propose quelques outils et fonctions génériques qui m'ont été utiles dans certains projets :</text> <quote>- <bold>digitToByte</bold> : cette fonction permet de convertir un chiffre (de 0 à 9) en octet compatible avec la classe SpiMax7219, c'est-à-dire dans un format qui permet l'allumage des bonnes diodes électroluminescentes pour représenter le chiffre sur les affichages numériques associés à cette classe.</quote> <text><bold>Exemple d'utilisation de la fonction digitToByte :</bold></text> <code><purple>#include</purple> <pink><Tool.h></pink> <purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.draw (Tool::digitToByte (<pink>4</pink>, <red>true</red>), <pink>1</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Ci-dessus la fonction statique <bold>digitToByte</bold> prend en 1er paramètre le chiffre à convertir en son équivalent compatible avec la classe <bold>SpiMax7219</bold>, le 2ème paramètre étant la possibilité d'inclure le point <bold>"."</bold> dans le formatage. <bold>"4."</bold> est le formatage obtenu dans l'exemple, ce chiffre et le point sont affichés sur un afficheur à digits à l'aide de la fonction <bold>draw</bold> de la classe <bold>SpiMax7219</bold>.</text> <text>Cette fonction trouve son intérêt dans des programmes fortement dynamiques, c'est-à-dire dans l'application de logiques variables dans la constitution des nombres et des textes afin de les combiner et les animer pour ensuite les afficher.</text> <quote>- <bold>characterToByte</bold> : cette fonction est similaire à la fonction digitToByte, elle permet de convertir un caractère alphanumérique (de a à z et de 0 à 9, ainsi que le point) en octet compatible avec la classe SpiMax7219 et les afficheurs associés.</quote> <text><bold>Exemple d'utilisation de la fonction characterToByte :</bold></text> <code><purple>#include</purple> <pink><Tool.h></pink> <purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.draw (Tool::characterToByte (<pink>"a."</pink>), <pink>1</pink>); <red>return</red> <pink>0</pink>; }</code> <text>La fonction statique <bold>characterToByte</bold> prend en seul paramètre le caractère alphanumérique à convertir. Dans l'exemple, le caractère <bold>"a"</bold> est demandé avec le point <bold>"."</bold> dans le formatage, ce qui donne <bold>"a."</bold>, ensemble qui est affiché sur un afficheur à digits à l'aide de la fonction <bold>draw</bold> de la classe <bold>SpiMax7219</bold>.</text> <quote>- <bold>scanTwi</bold> : cette fonction sert à connaître la première adresse occupée par un périphérique connecté au bus TWI.</quote> <text><bold>Ports des automates programmables concernés par le TWI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text><bold>Exemple d'utilisation de la fonction scanTwi :</bold></text> <code><purple>#include</purple> <pink><Tool.h></pink> <purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.integer (Tool::scanTwi(), <pink>1</pink>, <pink>3</pink>, <red>false</red>); <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple la fonction statique <bold>scanTwi</bold> ne prend aucun paramètre, elle retourne l'adresse du premier périphérique trouvé sur le bus TWI. Cette adresse est affichée sur un afficheur à digits à l'aide de la fonction <bold>integer</bold> de la classe <bold>SpiMax7219</bold>.</text> <quote>- <bold>mcuSram</bold> : cette fonction sert à connaître la quantité de SRAM (en octets) restante dans le microcontrôleur lors du fonctionnement de votre programme. Une valeur négative indique qu'il y a un dépassement de la mémoire (ce qui n'est pas souhaité car cela conduit au crash du programme en cours d'exécution).</quote> <text>La quantité de mémoire SRAM disponible dépend du microcontrôleur utilisé :</text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- SRAM du microcontrôleur ATmega48P = 512 octets (0.5Kio) <br/>- SRAM du microcontrôleur ATmega88P = 1024 octets (1Kio) <br/>- SRAM du microcontrôleur ATmega168P = 1024 octets (1Kio) <br/>- SRAM du microcontrôleur ATmega328P = 2048 octets (2Kio) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- SRAM du microcontrôleur ATmega164P = 1024 octets (1Kio) <br/>- SRAM du microcontrôleur ATmega324P = 2048 octets (2Kio) <br/>- SRAM du microcontrôleur ATmega644P = 4096 octets (4Kio) <br/>- SRAM du microcontrôleur ATmega1284P = 16384 octets (16Kio)</caution> <text><bold>Exemple d'utilisation de la fonction mcuSram :</bold></text> <code><purple>#include</purple> <pink><Tool.h></pink> <purple>#include</purple> <pink><SpiMax7219.h></pink> <green>int</green> main() { SpiMax7219 myDisplay = SpiMax7219 (<pink>5</pink>); myDisplay.integer (Tool::mcuSram(), <pink>1</pink>, <pink>8</pink>, <red>false</red>); <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple la fonction statique <bold>mcuSram</bold> ne prennant aucun paramètre renvoie simplement le nombre d'octets restants dans la mémoire SRAM du microcontrôleur. Cette quantité est affichée sur un afficheur à digits à l'aide de la fonction <bold>integer</bold> de la classe <bold>SpiMax7219</bold>.</text> <quote>- <bold>mcuSleep</bold> : cette fonction permet la mise en veille du microcontrôleur pour les applications à très faible consommation d'énergie. <br/>- <bold>mcuWakeUp</bold> : cette fonction qui doit être exécutée à l'aide d'une interruption permet la sortie de veille du microcontrôleur.</quote> <text><bold>Exemple d'utilisation des fonctions mcuSleep et mcuWakeUp :</bold> <code><purple>#include</purple> <pink><Tool.h></pink> <purple>#include</purple> <pink><InterruptRead.h></pink> <green>void</green> myFuction() { Tool::mcuWakeUp(); } <green>int</green> main() { InterruptRead myInterrupt = InterruptRead (<pink>3</pink>); myInterrupt.start (myFunction, <red>true</red>, <red>false</red>); Tool::mcuSleep(); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus le microcontrôleur est placé en veille lors de l'appel à la fonction statique <bold>mcuSleep</bold>, puis est sorti de veille à l'aide de la fonction statique <bold>mcuWakeUp</bold> lorsque se produit une interruption de programme, soit dans ce cas un front montant sur le port GPIO numéro <bold>3</bold> de l'automate programmable.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions de cette classe :</text> <code><green>static unsigned char</green> digitToByte (<green>const unsigned char</green> DIGIT, <green>const bool</green> COMMA); <green>static unsigned char</green> characterToByte (<green>const char</green> *CHARACTER); <green>static unsigned char</green> scanTwi(); <green>static signed int</green> mcuSram(); <green>static void</green> mcuSleep(); <green>static void</green> mcuWakeUp();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTwiAmg88.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTwiAmg88"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Une caméra thermique avec la classe TwiAmg88</title> <underline></underline> <text><bold>L'AMG88</bold> est une <bold>caméra thermique</bold> adaptée pour les projets miniaturisés et basse consommation électrique.</text> <quote>Une caméra thermique est sensible au <bold>rayonnement infrarouge</bold>, c'est une partie du spectre électromagnétique qui ce situe entre le rayonnement visible et radio. On l'appel thermique, car plus les objets sont chauds, plus ils émettent du rayonnement infrarouge.</quote> <text>L'AMG88 se présente comme une structure matricielle de forme carrée pourvue de <bold>64 capteurs thermiques</bold>, la définition est donc de <bold>8 x 8</bold> (pixels). L'angle de vision de la matrice est de <bold>60°</bold> angulaires en horizontale et en verticale.</text> <quote>L'avantage d'une définition de 8 x 8 est le traitement aisé via des microcontrôleurs à largeur de registres de 8 bits, et également l'affichage direct (sans traitement de redimensionnement) des valeurs de température via par exemple une matrice 8 x 8 pixels.</quote> <text>La photo suivante représente les températures (avec seuils) acquises par les 64 capteurs de la caméra puis affichés sur la matrice de 8 x 8 diodes électroluminescences :</text> <a href="photo/dsc08368.jpg"><img src="thumbnail/dsc08368.jpg"></img></a> <text>L'AMG88 communique en <bold>TWI</bold> (pour "Two Wire Interface" ou interface à deux fils) à la vitesse de <bold>400KHz</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le TWI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text>La classe <bold>TwiAmg88</bold> dédiée au fonctionnement du composant AMG88, permet très simplement de récupérer les valeurs des températures dans un tableau de 64 cases. Cette variable accessible en programmation se nomme <bold>temperature</bold>.</text> <text><bold>Représentation des données :</bold></text> <caution><bold>Noms des variables, intervalles, et unités de mesure :</bold> <br/>temperature = 0°C à +80°C (composant avec un gain élevé) <br/>temperature = -20°C à +100°C (composant avec un gain bas)</caution> <text><bold>Exemple d'utilisation de la classe TwiAmg88 :</bold></text> <code><purple>#include</purple> <pink><TwiAmg88.h></pink> <green>int</green> main() { TwiAmg88 myInfraredCamera = TwiAmg88 (<pink>0x69</pink>); <red>while</red> (<red>true</red>) { myInfraredCamera.read(); <blue>//myInfraredCamera.temperature [0] représente la température en degrés Celsius du pixel 1</blue> <blue>//myInfraredCamera.temperature [1] représente la température en degrés Celsius du pixel 2</blue> <blue>//myInfraredCamera.temperature [2] représente la température en degrés Celsius du pixel 3</blue> <blue>//etc...</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myInfraredCamera</bold> de type <bold>TwiAmg88</bold> est déclaré, en paramètre est indiqué l'adresse <bold>0x69</bold> du composant AMG88 sur le bus TWI :</text> <quote>Si vous ne connaissez pas l'adresse TWI du composant AMG88 et que ce dernier est le seul périphérique connecté au bus TWI, vous pouvez indiquer <bold>0</bold> en paramètre, car en interne une fonction se chargera d'effectuer une recherche et de trouver l'adresse du périphérique automatiquement.</quote> <text>Puis dans la boucle <bold>while</bold> la fonction <bold>read</bold> associée à l'objet <bold>myInfraredCamera</bold> est appelée, ce qui permet de lire en une fois les 64 capteurs thermiques du composant AMG88. Cette action met à jour la variable <bold>temperature</bold> (le tableau de 64 cases) relative à l'objet <bold>myInfraredCamera</bold>. Vous pouvez utiliser cette variable à la suite dans votre programme (via par exemple une boucle de lecture des 64 cases du tableau).</text> <text>De nombreuses applications sont possibles avec la caméra thermique AMG88. La classe dédiée <bold>TwiAmg88</bold> permet la mise en œuvre de ce composant en seulement quelques lignes de programmation de haut niveau. Libre à vous de l'utiliser dans vos projets notamment en robotique et dans l'industrie en général.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> temperature [<pink>64</pink>] = {<pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>, <pink>0</pink>}; TwiAmg88 (<green>const unsigned char</green> DEVICE); <green>void</green> read();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTwiBme280.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTwiBme280"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Une station météorologique avec la classe TwiBme280</title> <underline></underline> <text>Le composant électronique <bold>BME280</bold> est équipé d'un capteur <bold>hygrométrique</bold>, <bold>barométrique</bold>, et <bold>thermique</bold>, ce qui permet respectivement la mesure de l'humidité, de la pression, et de la température ambiante. Ces 3 données sont accessibles très simplement sous la forme de variables avec la classe dédiée <bold>TwiBme280</bold>.</text> <text><bold>Représentation des données :</bold></text> <caution><bold>Noms des variables, intervalles, et unités de mesure :</bold> <br/>humidity = 0% à 100% <br/>pressure = 300hPa à 1100hPa <br/>temperature = -40°C à +85°C</caution> <text>Ce composant communique en <bold>TWI</bold> (pour "Two Wire Interface" ou interface à deux fils) à la vitesse de <bold>400KHz</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le TWI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text><bold>Exemple d'utilisation de la classe TwiBme280 :</bold></text> <code><purple>#include</purple> <pink><TwiBme280.h></pink> <green>int</green> main() { TwiBme280 myEnvironmentSensor = TwiBme280 (<pink>0x77</pink>); <red>while</red> (<red>true</red>) { myEnvironmentSensor.read(); <blue>//myEnvironmentSensor.humidity représente l'humidité</blue> <blue>//myEnvironmentSensor.pressure représente la pression</blue> <blue>//myEnvironmentSensor.temperature représente la température</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myEnvironmentSensor</bold> de type <bold>TwiBme280</bold> est déclaré, en paramètre est indiqué l'adresse <bold>0x77</bold> du composant BME280 sur le bus TWI :</text> <quote>Si vous ne connaissez pas l'adresse TWI du composant BME280 et que ce dernier est le seul périphérique connecté au bus TWI, vous pouvez indiquer <bold>0</bold> en paramètre, car en interne une fonction se chargera d'effectuer une recherche et de trouver l'adresse du périphérique automatiquement.</quote> <text>Puis dans la boucle <bold>while</bold> la fonction <bold>read</bold> associée à l'objet <bold>myEnvironmentSensor</bold> est appelée, ce qui permet de lire la totalité des capteurs du composant BME280. Cette action met à jour les variables <bold>humidity</bold>, <bold>pressure</bold>, et <bold>temperature</bold> relatives à l'objet <bold>myEnvironmentSensor</bold>. Vous pouvez utiliser ces variables à la suite dans votre programme.</text> <text>Finalement le BME280 est simple d'utilisation via la classe <bold>TwiBme280</bold>. Ce composant est adapté notamment dans les applications de surveillance de l'atmosphère (projet de station ou de ballon météorologique), ou encore en robotique générale ou aérienne (altimètre barométrique via le capteur de pression).</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> humidity = <pink>0</pink>; <green>float</green> pressure = <pink>0</pink>; <green>float</green> temperature = <pink>0</pink>; TwiBme280 (<green>const unsigned char</green> DEVICE); <green>void</green> read();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTwiBno055.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTwiBno055"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Créer un horizon artificiel avec la classe TwiBno055</title> <underline></underline> <text>La centrale inertielle électronique <bold>BNO055</bold> de mise en œuvre grandement simplifiée via la classe <bold>TwiBno055</bold> dédiée, permet comme son équivalent mécanique, de détecter des mouvements sur les 3 axes de navigation. Équipé d'un puissant calculateur interne et d'un algorithme de fusion performant, ce composant propose des <bold>données résultantes absolues</bold>, au sens où elles ne sont pas influencées et perturbées par les mouvements du composant dans l'espace, et en abstraction par rapport à l'accélération de la pesanteur.</text> <quote>Le composant BNO055 dispose également de <bold>magnétomètres</bold> dont l'application principale est la détection du champ magnétique terrestre.</quote> <text>Ce composant communique en <bold>TWI</bold> (pour "Two Wire Interface" ou interface à deux fils) à la vitesse de <bold>400KHz</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le TWI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text>Les meilleures performances du composant <bold>BNO055</bold> sont exploitées avec simplicité via la classe <bold>TwiBno055</bold> afin de réaliser des applications notamment en robotique terrestre et aérienne les plus élaborées.</text> <a href="photo/dsc01885.jpg"><img src="thumbnail/dsc01885.jpg"></img></a> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <text>De nombreuses données sont disponibles avec la classe <bold>TwiBno055</bold> que vous pouvez utiliser dans le fonctionnement de vos projets les plus complexes et variés.</text> <text><bold>Représentation des données :</bold></text> <caution><bold>Noms des variables, intervalles, et unités de mesure :</bold> <br/>gx = ± 39.2266m/s² <br/>gy = ± 39.2266m/s² <br/>gz = ± 39.2266m/s² <br/>tx = ± 39.2266m/s² <br/>ty = ± 39.2266m/s² <br/>tz = ± 39.2266m/s² <br/>rx = ± 2000°/s <br/>ry = ± 2000°/s <br/>rz = ± 2000°/s <br/>mx = ± 1300µT <br/>my = ± 1300µT <br/>mz = ± 2500µT <br/>qw = ± 1 (sans unité) <br/>qx = ± 1 (sans unité) <br/>qy = ± 1 (sans unité) <br/>qz = ± 1 (sans unité) <br/>pitch = ± 180° angulaires <br/>pitchAero = ± 90° angulaires <br/>roll = ± 180° angulaires <br/>rollAero = ± 90° angulaires <br/>compass = ± 180° angulaires <br/>north = faux ou vrai (magnétomètre non calibré ou calibré) <br/>temperature = -40°C à +85°C</caution> <text><bold>Exemple d'utilisation de la classe TwiBno055 :</bold></text> <code><purple>#include</purple> <pink><TwiBno055.h></pink> <green>int</green> main() { TwiBno055 myInertialUnit = TwiBno055 (<pink>0x29</pink>); <red>while</red> (<red>true</red>) { myInertialUnit.read(); <blue>//myInertialUnit.gx représente l'accélération de la pesanteur sur l'axe x</blue> <blue>//myInertialUnit.gy représente l'accélération de la pesanteur sur l'axe y</blue> <blue>//myInertialUnit.gz représente l'accélération de la pesanteur sur l'axe z</blue> <blue>//myInertialUnit.tx représente l'accélération latérale sur l'axe x</blue> <blue>//myInertialUnit.ty représente l'accélération longitudinale sur l'axe y</blue> <blue>//myInertialUnit.tz représente l'accélération verticale sur l'axe z</blue> <blue>//myInertialUnit.rx représente la vitesse de rotation sur l'axe x</blue> <blue>//myInertialUnit.ry représente la vitesse de rotation sur l'axe y</blue> <blue>//myInertialUnit.rz représente la vitesse de rotation sur l'axe z</blue> <blue>//myInertialUnit.mx représente l'induction électromagnétique sur l'axe x</blue> <blue>//myInertialUnit.my représente l'induction électromagnétique sur l'axe y</blue> <blue>//myInertialUnit.mz représente l'induction électromagnétique sur l'axe z</blue> <blue>//myInertialUnit.qw représente le quaternion w</blue> <blue>//myInertialUnit.qx représente le quaternion x</blue> <blue>//myInertialUnit.qy représente le quaternion y</blue> <blue>//myInertialUnit.qz représente le quaternion z</blue> <blue>//myInertialUnit.pitch représente l'axe de tangage sur une rotation complète</blue> <blue>//myInertialUnit.pitchAero représente l'axe de tangage sur deux demi-rotations symétriques</blue> <blue>//myInertialUnit.roll représente l'axe de roulis sur une rotation complète</blue> <blue>//myInertialUnit.rollAero représente l'axe de roulis sur deux demi-rotations symétriques</blue> <blue>//myInertialUnit.compass représente la direction par rapport au Nord magnétique</blue> <blue>//myInertialUnit.north représente la calibration du magnétomètre</blue> <blue>//myInertialUnit.temperature représente la température dans le composant</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myInertialUnit</bold> de type <bold>TwiBno055</bold> est déclaré, en paramètre est indiqué l'adresse <bold>0x29</bold> du composant BNO055 sur le bus TWI :</text> <quote>Si vous ne connaissez pas l'adresse TWI du composant BNO055 et que ce dernier est le seul périphérique connecté au bus TWI, vous pouvez indiquer <bold>0</bold> en paramètre, car en interne une fonction se chargera d'effectuer une recherche et de trouver l'adresse du périphérique automatiquement.</quote> <text>Puis dans la boucle <bold>while</bold> la fonction <bold>read</bold> associée à l'objet <bold>myInertialUnit</bold> est appelée, ce qui permet de lire la totalité des capteurs du composant BNO055. Cette action met à jour les variables <bold>gx</bold>, <bold>gy</bold>, <bold>gz</bold>, <bold>tx</bold>, <bold>ty</bold>, <bold>tz</bold>, <bold>rx</bold>, <bold>ry</bold>, <bold>rz</bold>, <bold>mx</bold>, <bold>my</bold>, <bold>mz</bold>, <bold>qw</bold>, <bold>qx</bold>, <bold>qy</bold>, <bold>qz</bold>, <bold>pitch</bold>, <bold>pitchAero</bold>, <bold>roll</bold>, <bold>rollAero</bold>, <bold>compass</bold>, <bold>north</bold>, et <bold>temperature</bold> relatives à l'objet <bold>myInertialUnit</bold>. Vous pouvez utiliser ces variables à la suite dans votre programme.</text> <text>Autres fonctions utiles :</text> <quote>En supplément de la fonction <bold>read</bold> qui effectue la lecture de tous les capteurs du composant BNO055, vous pouvez utiliser les fonction <bold>readGravity</bold>, <bold>readTranslation</bold>, <bold>readRotation</bold>, <bold>readQuaternion</bold>, <bold>readMagnetism</bold>, <bold>readHorizon</bold>, <bold>readDirection</bold>, et <bold>readTemperature</bold> qui respectivement permettent d'effectuer uniquement la lecture des 3 axes de gravité, des 3 axes de translation, des 3 axes de rotation, des 3 axes de magnétisme, des 4 axes de quaternion, des 2 axes d'assiette (l'horizon artificiel), du cap (la boussole) et de la calibration du magnétomètre, ou seulement de la température. Ces fonctions offrent l'avantage comparativement à la fonction <bold>read</bold> d'être plus rapides d'exécution si vous avez besoin seulement de connaître la gravité, la translation, la rotation, les quaternions, le magnétisme, l'assiette, le cap, ou la température.</quote> <text>Le BNO055 est adapté pour les applications qui requièrent une centrale inertielle avec des données absolues, un horizon artificiel, et une boussole.</text> <title>Les données d'horizon artificiel :</title> <underline></underline> <text>Les variables <bold>pitch</bold>, <bold>pitchAero</bold>, <bold>roll</bold>, et <bold>rollAero</bold> représentent l'assiette, soit l'horizon artificiel. Les données des variables <bold>pitch</bold> et <bold>roll</bold> débattent sur <bold>± 180°</bold> angulaires, alors que les données des variables <bold>pitchAero</bold> et <bold>rollAero</bold> débattent sur <bold>± 90°</bold> angulaires, pour exemple ceci trouve son utilité en aéronautique :</text> <caution>Imaginons un avion en vol inversé et en piqué avec une inclinaison de 45° angulaires par rapport au sol. Le pilote automatique reprenant les commandes afin de remettre l'aéronef à plat, si l'axe de tangage est réglé sur <bold>± 180°</bold> angulaires, le plus court chemin avec le vol à plat, soit le 0° angulaire, est de rattraper l'assiette avec une action cabreur, ce qui fait parcourir seulement 135° angulaires au lieu de 225° angulaires si l'action était piqueur. Si l'avion est proche du sol, le crash est inévitable. En revanche, si l'axe de tangage est réglé sur <bold>± 90°</bold> angulaires, une remise à plat de l'avion ne demande de parcourir que 45° angulaires. Une fois cette action effectuée, l'avion est en vol horizontal mais toujours sur le dos (vol inversé), une action d'un demi-tour sur l'axe de roulis est moins périlleuse et permet de rétablir le vol à plat.</caution> <text>Pour le maintient de l'assiette d'un tel aéronef, il est donc recommandé d'utiliser <bold>± 90°</bold> angulaires pour l'axe de tangage, soit la variable <bold>pitchAero</bold>, et <bold>± 180°</bold> angulaires pour l'axe de roulis, soit la variable <bold>roll</bold>.</text> <caution>De même, un risque important existe si vous utilisez <bold>± 90°</bold> angulaires pour l'axe de tangage et également de roulis, l'avion risque fortement dans certaines situations de se retrouver en vol inversé, et le pilote automatique n'y pourra rien, il aura fait ses corrections pour revenir à plat !</caution> <text>Dans vos projets avec horizon artificiel, il est donc primordial d'utiliser les variables adaptées à l'application demandée, et de s'interroger sur les actions à effectuer pour une remise à plat dans certaines situations.</text> <title>Les données de direction par rapport au Nord magnétique :</title> <underline></underline> <text>La variable <bold>compass</bold> représente la boussole, soit la direction par rapport au Nord magnétique. Cette donnée débat de ± 180° angulaires, le 0° angulaire étant la direction du Nord magnétique. Cette donnée n'est valide que lorsque les magnétomètres du composant BNO055 sont calibrés, ce qui s'obtient en effectuant quelques mouvements circulaires avec celui-ci :</text> <quote>Au démarrage du BNO055, la direction du Nord magnétique est fausse, et est indiquée explicitement par la variable <bold>north</bold> avec la valeur <bold>false</bold> (faux). Pour effectuer la calibration des magnétomètres, effectuez quelques mouvements en huit avec le composant BNO055 afin qu'il enregistre une cartographie du magnétisme. Une fois la calibration réalisée, la variable <bold>north</bold> sera <bold>true</bold> (vrai), ce qui signifie que l'indication du Nord magnétique accessible avec la variable <bold>compass</bold> est valide.</quote> <caution>Attention, le Nord magnétique ne doit pas être confondu avec le Nord géographique, les deux non ni la même direction, ni le même sens.</caution> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> gx = <pink>0</pink>; <green>float</green> gy = <pink>0</pink>; <green>float</green> gz = <pink>0</pink>; <green>float</green> tx = <pink>0</pink>; <green>float</green> ty = <pink>0</pink>; <green>float</green> tz = <pink>0</pink>; <green>float</green> rx = <pink>0</pink>; <green>float</green> ry = <pink>0</pink>; <green>float</green> rz = <pink>0</pink>; <green>float</green> mx = <pink>0</pink>; <green>float</green> my = <pink>0</pink>; <green>float</green> mz = <pink>0</pink>; <green>float</green> qw = <pink>0</pink>; <green>float</green> qx = <pink>0</pink>; <green>float</green> qy = <pink>0</pink>; <green>float</green> qz = <pink>0</pink>; <green>float</green> pitch = <pink>0</pink>; <green>float</green> pitchAero = <pink>0</pink>; <green>float</green> roll = <pink>0</pink>; <green>float</green> rollAero = <pink>0</pink>; <green>float</green> compass = <pink>0</pink>; <green>bool</green> north = <red>false</red>; <green>signed int</green> temperature = <pink>0</pink>; TwiBno055 (<green>const unsigned char</green> DEVICE); <green>void</green> read(); <green>void</green> readGravity(); <green>void</green> readTranslation(); <green>void</green> readRotation(); <green>void</green> readQuaternion(); <green>void</green> readMagnetism(); <green>void</green> readHorizon(); <green>void</green> readDirection(); <green>void</green> readTemperature();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationTwiMpu6050.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationTwiMpu6050"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Mesurer des mouvements avec la classe TwiMpu6050</title> <underline></underline> <text>Le composant <bold>MPU6050</bold> est une <bold>centrale inertielle électronique</bold> qui, à l'instar de l'équivalent mécanique, permet de détecter des mouvements sous la forme de vitesses angulaires et d'accélérations latérales (x), longitudinales (y), et verticales (z).</text> <text>Ce composant communique en <bold>TWI</bold> (pour "Two Wire Interface" ou interface à deux fils) à la vitesse de <bold>400KHz</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le TWI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text>La classe <bold>TwiMpu6050</bold> simplifie grandement la mise en œuvre de ce composant complexe tout en y exploitant les meilleures performances afin de réaliser des applications notamment en robotique terrestre et aérienne les plus pointues.</text> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <a href="photo/dsc08424.jpg"><img src="thumbnail/dsc08424.jpg"></img></a> <text>Le composant <bold>MPU6050</bold> est équipé d'accéléromètres, de gyroscopes, et d'un calculateur intégré qui offre l'avantage de pouvoir dissocier les différents axes à l'aide d'algorithmes qui travaillent avec toutes les données des capteurs, de sorte qu'avec la classe <bold>TwiMpu6050</bold> vous disposez des variables représentant les axes de translation nommés <bold>tx</bold>, <bold>ty</bold>, et <bold>tz</bold>, ainsi que des axes de rotation nommés <bold>rx</bold>, <bold>ry</bold>, et <bold>rz</bold>.</text> <text>Le MPU6050 dispose également d'un capteur de température :</text> <quote>Pour compenser les dilatations thermiques des accéléromètres et des gyroscopes causées par les variations de température, le MPU6050 est équipé d'un capteur de température dont la valeur est accessible depuis la variable <bold>temperature</bold> de l'objet instancié correspondant.</quote> <text><bold>Représentation des données :</bold></text> <caution><bold>Noms des variables, intervalles, et unités de mesure :</bold> <br/>tx = ± 16g <br/>ty = ± 16g <br/>tz = ± 16g <br/>rx = ± 2000°/s <br/>ry = ± 2000°/s <br/>rz = ± 2000°/s <br/>temperature = -40°C à +85°C</caution> <text>Les accélérations en translation tx, ty, et tz sont exprimées en nombre de g (1g étant égal à l'accélération de la pesanteur à la surface de la Terre). Les vitesses angulaires rx, ry, et rz sont exprimées en degrés angulaires par seconde. La température est exprimée en degrés Celsius.</text> <text><bold>Exemple d'utilisation de la classe TwiMpu6050 :</bold></text> <code><purple>#include</purple> <pink><TwiMpu6050.h></pink> <green>int</green> main() { TwiMpu6050 myInertialUnit = TwiMpu6050 (<pink>0x69</pink>); <red>while</red> (<red>true</red>) { myInertialUnit.read(); <blue>//myInertialUnit.tx représente la translation sur l'axe x</blue> <blue>//myInertialUnit.ty représente la translation sur l'axe y</blue> <blue>//myInertialUnit.tz représente la translation sur l'axe z</blue> <blue>//myInertialUnit.rx représente la rotation sur l'axe x</blue> <blue>//myInertialUnit.ry représente la rotation sur l'axe y</blue> <blue>//myInertialUnit.rz représente la rotation sur l'axe z</blue> <blue>//myInertialUnit.temperature représente la température dans le composant</blue> } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myInertialUnit</bold> de type <bold>TwiMpu6050</bold> est déclaré, en paramètre est indiqué l'adresse <bold>0x69</bold> du composant MPU6050 sur le bus TWI :</text> <quote>Si vous ne connaissez pas l'adresse TWI du composant MPU6050 et que ce dernier est le seul périphérique connecté au bus TWI, vous pouvez indiquer <bold>0</bold> en paramètre, car en interne une fonction se chargera d'effectuer une recherche et de trouver l'adresse du périphérique automatiquement.</quote> <text>Puis dans la boucle <bold>while</bold> la fonction <bold>read</bold> associée à l'objet <bold>myInertialUnit</bold> est appelée, ce qui permet de lire la totalité des capteurs du composant MPU6050. Cette action met à jour les variables <bold>tx</bold>, <bold>ty</bold>, <bold>tz</bold>, <bold>rx</bold>, <bold>ry</bold>, <bold>rz</bold>, et <bold>temperature</bold> relatives à l'objet <bold>myInertialUnit</bold>. Vous pouvez utiliser ces variables à la suite dans votre programme.</text> <text>Autres fonctions utiles :</text> <quote>En supplément de la fonction <bold>read</bold> qui effectue la lecture de tous les capteurs du composant MPU6050, vous pouvez utiliser les fonction <bold>readTranslation</bold>, <bold>readRotation</bold>, et <bold>readTemperature</bold> qui respectivement permettent d'effectuer uniquement la lecture des 3 axes de translation, des 3 axes de rotation, ou seulement de la température. Ces fonctions offrent l'avantage comparativement à la fonction <bold>read</bold> d'être plus rapides d'exécution si vous avez besoin seulement de connaître la translation, la rotation, ou la température.</quote> <title>Stabilisation d'un aéronef :</title> <underline></underline> <text>Si vous souhaitez stabiliser les différents axes d'un aéronef, la centrale inertielle MPU6050 est toute indiquée.</text> <text><bold>Exemple d'asservissement d'un servo-moteur avec le composant MPU6050 afin de stabiliser un axe d'un aéronef :</bold></text> <code><purple>#include</purple> <pink><TwiMpu6050.h></pink> <purple>#include</purple> <pink><PwmWrite.h></pink> <purple>#include</purple> <pink><Math.h></pink> <green>int</green> main() { TwiMpu6050 myInertialUnit = TwiMpu6050 (<pink>0x68</pink>); PwmWrite myServo = PwmWrite (<pink>1</pink>); PwmWrite::start (<pink>50</pink>); <red>while</red> (<red>true</red>) { myInertialUnit.read(); <blue>//ci-dessous la largeur d'impulsion du signal PWM qui asservi le servo-moteur va varier en fonction de l'axe rx de la centrale inertielle</blue> myServo.us (Math::curve (<pink>-100</pink>, myInertialUnit.rx, <pink>100</pink>, <pink>1000</pink>, <pink>2000</pink>, <pink>0</pink>)); } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple le servo-moteur pourrait commander la gouverne aérodynamique d'un avion, le MPU6050 détecterait alors les mouvements du fuselage et pourrait les compenser en temps réel en envoyant les bons ordres aux bons moments avec la bonne amplitude (via quelques réglages de suivi de la consigne, de débattements, et de sens des commandes) pour conserver une trajectoire rectiligne de l'aéronef.</text> <text>Libre à vous d'utiliser toutes les capacités en précision et en rapidité de la centrale inertielle MPU6050 à l'aide de la classe dédiée <bold>TwiMpu6050</bold>.</text> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>float</green> tx = <pink>0</pink>; <green>float</green> ty = <pink>0</pink>; <green>float</green> tz = <pink>0</pink>; <green>float</green> rx = <pink>0</pink>; <green>float</green> ry = <pink>0</pink>; <green>float</green> rz = <pink>0</pink>; <green>float</green> temperature = <pink>0</pink>; TwiMpu6050 (<green>const unsigned char</green> DEVICE); <green>void</green> read(); <green>void</green> readTranslation(); <green>void</green> readRotation(); <green>void</green> readTemperature();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationUsartMidi.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationUsartMidi"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le pilotage des instruments de musique avec la classe UsartMidi</title> <underline></underline> <text>Séquenceurs MIDI, boucleurs, pédales d'effets, claviers maîtres, tout ceci est réalisable avec la classe <bold>UsartMidi</bold>.</text> <a href="photo/dsc08777.jpg"><img src="thumbnail/dsc08777.jpg"></img></a> <a href="photo/dsc08706.jpg"><img src="thumbnail/dsc08706.jpg"></img></a> <text>La classe <bold>UsartMidi</bold> automatise la réception et l'émission de commandes MIDI vers des instruments de musique standards. C'est le protocole <bold>USART</bold> (pour "Universal Synchronous Asynchronous Receiver Transmitter" ou émetteur récepteur synchrone asynchrone universel) qui est utilisé afin d'effectuer les communications bidirectionnelles à la vitesse de <bold>31250 bauds / seconde</bold> prenant la forme de messages MIDI d'une largeur de <bold>24 bits</bold> chacun (8 bits de statut, 8 bits de donnée, et 8 bits de description).</text> <text><bold>Ports des automates programmables concernés par l'USART :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) = RXD (receive data) <br/>- Port GPIO 2 (PD1) = TXD (transmit data) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 9 (PD0) = RXD (receive data) <br/>- Port GPIO 10 (PD1) = TXD (transmit data)</caution> <text><bold>Exemple d'envoi de commandes à un instrument de musique :</bold></text> <code><purple>#include</purple> <pink><UsartMidi.h></pink> <green>int</green> main() { UsartMidi::start (<green>void</green>); UsartMidi::transmit (<pink>144</pink>, <pink>69</pink>, <pink>127</pink>); <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, la fonction statique <bold>start</bold> est appelée prenant en seul paramètre une fonction à appeler lorsque des commandes sont reçues. Ici ce paramètre est indiqué <bold>void</bold> (vide) ce qui signifie qu'aucune fonction ne sera appelée lors de la réception de commandes (une interruption interviendra mais n'appellera pas de fonction).</text> <text>Puis la fonction statique <bold>transmit</bold> est utilisée afin d'envoyer des commandes à un instrument de musique : <br/>- Le 1er paramètre <bold>144</bold> est le statut. Ici il correspond à la commande "note ON" afin de jouer une note de musique. <br/>- Le 2ème paramètre <bold>69</bold> est la donnée. Dans ce cas elle correspond à une note de musique, soit un "la" conventionnel à 440Hz. <br/>- Le 3ème paramètre <bold>127</bold> est la description. Cette valeur indique une vélocité maximale (ce qui correspond à un appui fort sur la touche de l'instrument).</text> <quote>Cet exemple est simple mais permet de comprendre facilement l'utilisation de la classe <bold>UsartMidi</bold>. Un instrument de musique relié à l'automate programmable émetteur des commandes ci-dessus jouerait la note indiquée.</quote> <text><bold>Exemple de réception de commandes provenant d'un instrument de musique :</bold></text> <code><purple>#include</purple> <pink><UsartMidi.h></pink> <green>void</green> myReceiving() { <blue>//les commandes de statut, donnée, et description ont été reçues</blue> UsartMidi::receive(); <blue>//UsartMidi::status est le statut reçu</blue> <blue>//UsartMidi::data est la donnée reçue</blue> <blue>//UsartMidi::description est la description reçue</blue> } <green>int</green> main() { UsartMidi::start (myReceiving); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple ci-dessus montre que dans la fonction principale <bold>main</bold>, la communication MIDI est démarrée en appelant la fonction statique <bold>start</bold>, son seul paramètre est renseigné avec la fonction <bold>myReceiving</bold> qui sera appelée lorsque des commandes seront reçues (une série de 3 commandes exactement). Lors de la réception, la fonction statique <bold>receive</bold> est appelée permettant de stocker les commandes reçues respectivement dans les variables statiques <bold>status</bold>, <bold>data</bold>, et <bold>description</bold> que vous pouvez utiliser n'importe où dans votre programme.</text> <quote>Bien que cela soit moins pratique et moins optimisé d'un point de vue exécution du programme, il n'est pas forcément nécessaire d'utiliser une fonction dédiée à la réception des commandes.</quote> <text><bold>Exemple de réception de commandes sans utiliser de fonction dédiée :</bold></text> <code><purple>#include</purple> <pink><UsartMidi.h></pink> <green>int</green> main() { UsartMidi::start (<green>void</green>); <red>while</red> (<red>true</red>) { UsartMidi::receive(); <blue>//UsartMidi::status est le statut reçu</blue> <blue>//UsartMidi::data est la donnée reçue</blue> <blue>//UsartMidi::description est la description reçue</blue> } <red>return</red> <pink>0</pink>; }</code> <text>À l'instar du premier exemple énoncé, le seul paramètre de la fonction statique <bold>start</bold> est indiqué <bold>void</bold> (vide) ce qui signifie qu'aucune fonction ne sera appelée lors de la réception de commandes, ceci étant effectué directement dans la boucle <bold>while</bold> (ce qui à chaque tour de boucle consomme plus d'instructions que l'exemple précédent, de fait plus optimisé).</text> <caution>Dans ce dernier exemple la réception de commandes peut être plus difficilement anticipée et détectée.</caution> <text>Autre fonctionnalité disponible :</text> <quote>Si besoin la classe <bold>UsartMidi</bold> dispose d'une fonction statique <bold>stop</bold> ce qui permet d'arrêter les communications MIDI, un nouvel appel à la fonction statique <bold>start</bold> permet de redémarrer les communications MIDI.</quote> <title>Câblages et priorités :</title> <underline></underline> <text>Il convient dans l'utilisation de la classe <bold>UsartMidi</bold> de prendre note de quelques considérations techniques importantes pour le bon fonctionnement :</text> <caution>Si vous n'utilisez pas la partie réception du montage et que vous n'appelez pas la fonction statique <bold>receive</bold>, il est important de quand même connecter un câble sur le port <bold>RXD</bold> de l'automate programmable allant vers un port <bold>TXD</bold> du périphérique, car dans le cas contraire les fonctions matérielles USART capteraient tous les bruits électromagnétiques environnants sur la broche laissée en l'air du microcontrôleur, et générerait des interruptions intempestives, ce qui n'est pas souhaité.</caution> <quote>La classe <bold>UsartMidi</bold> utilise le protocole USART tout comme les classes <bold>UsartNetwork</bold> et <bold>UsartRs232</bold>, mais <bold>les vitesses de communication et les algorithmes mis en œuvre ne sont pas compatibles les uns avec les autres</bold>. Pour éviter tout problème de compatibilité, la classe utilisant l'USART déclarée en premier dans votre projet sera la seule activée et fonctionnelle.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>static unsigned char</green> status; <green>static unsigned char</green> data; <green>static unsigned char</green> description; <green>static void</green> start (<green>void</green> functionJump()); <green>static void</green> receive(); <green>static void</green> transmit (<green>const unsigned char</green> STATUS, <green>const unsigned char</green> DATA, <green>const unsigned char</green> DESCRIPTION); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationUsartNetwork.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationUsartNetwork"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Un réseau d'automates programmables avec la classe UsartNetwork</title> <underline></underline> <text>Avec la classe <bold>UsartNetwork</bold> vous pouvez relier plusieurs automates programmes en un réseau filaire pour permettre l'échange de données numériques. C'est le protocole <bold>USART</bold> (pour "Universal Synchronous Asynchronous Receiver Transmitter" ou émetteur récepteur synchrone asynchrone universel) qui est utilisé afin d'effectuer les communications bidirectionnelles à la vitesse de <bold>2M bauds / seconde</bold> sur une largeur de <bold>32 bits utiles</bold> (c'est-à-dire en faisant abstraction du marqueur de début de trame, de l'identifiant réseau, de l'adresse de destination, et du code de correction d'erreurs).</text> <text><bold>Ports des automates programmables concernés par l'USART :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) = RXD (receive data) <br/>- Port GPIO 2 (PD1) = TXD (transmit data) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 9 (PD0) = RXD (receive data) <br/>- Port GPIO 10 (PD1) = TXD (transmit data)</caution> <text>L'exemple ci-dessous est minimaliste afin de bien comprendre comment envoyer une donnée sur le réseau (constitué d'un ou de plusieurs automates programmables).</text> <text><bold>Exemple pour émettre des données avec la classe UsartNetwork :</bold></text> <code><purple>#include</purple> <pink><UsartNetwork.h></pink> <green>int</green> main() { UsartNetwork myVariable = UsartNetwork (<pink>1</pink>); UsartNetwork::start (<green>void</green>, <pink>1524003746</pink>); <red>while</red> (<red>true</red>) { myVariable.transmit (<pink>123</pink>); } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, un objet <bold>myVariable</bold> de type <bold>UsartNetwork</bold> est déclaré, en paramètre est indiqué l'adresse <bold>1</bold> sur lequel communiquer les données (il y a 64 adresses en tout). Puis, l'USART est démarré en appelant la fonction statique <bold>start</bold> prenant plusieurs paramètres : <br/>- Le 1er paramètre sert à indiquer une fonction à appeler lorsque des données sont reçues. Ici ce paramètre est indiqué <bold>void</bold> (vide) ce qui signifie qu'aucune fonction ne sera appelée lors de la réception de données (une interruption interviendra mais n'appellera pas de fonction). <br/>- Le 2ème paramètre <bold>1524003746</bold> correspond au code d'identification (ou ID unique par définition) qui permet de sécuriser la communication entre plusieurs (deux ou plus) automates programmables sur le réseau.</text> <caution>C'est à vous de choisir ce code ID, plus le nombre est complexe et plus la communication sera protégée.</caution> <text>Puis dans la boucle <bold>while</bold>, la fonction <bold>transmit</bold> de l'objet <bold>myVariable</bold> est utilisée pour transmettre le nombre <bold>123</bold> sur le réseau. Du fait de la boucle, le nombre <bold>123</bold> sera transmit continuellement à la vitesse du réseau.</text> <text><bold>Exemple pour recevoir des données avec la classe UsartNetwork :</bold></text> <code><purple>#include</purple> <pink><UsartNetwork.h></pink> <green>int</green> main() { UsartNetwork myVariable = UsartNetwork (<pink>1</pink>); UsartNetwork::start (<green>void</green>, <pink>1524003746</pink>); <red>while</red> (<red>true</red>) { myVariable.receive(); <blue>//myVariable.data est la donnée reçue</blue> } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple ci-dessus reprend le principe avec comme seul changement l'utilisation de la fonction <bold>receive</bold> en lieu et place de la fonction <bold>transmit</bold> de l'exemple précédent, afin cette fois de recevoir des données au lieu d'en émettre. Dans ce cas les données à leur arrivée sont stockées dans la variable <bold>data</bold> associée à l'objet <bold>myVariable</bold>.</text> <quote>Note : si les deux exemples fonctionneraient sur deux automates programmables distincts reliés ensembles, la communication aboutirait, et la variable <bold>data</bold> de l'objet <bold>myVariable</bold> du deuxième montage prendrait alors la valeur <bold>123</bold> envoyée par le premier montage.</quote> <text>Ce deuxième exemple est améliorable via l'utilisation d'une fonction qui est appelée uniquement lorsqu'une donnée valide est reçue du réseau.</text> <text><bold>Exemple d'utilisation d'une fonction qui est appelée lors de la réception de données :</bold></text> <code><purple>#include</purple> <pink><UsartNetwork.h></pink> UsartNetwork _myVariable = UsartNetwork (<pink>1</pink>); <green>void</green> myReceiving() { _myVariable.receive(); <blue>//_myVariable.data est la donnée reçue</blue> } <green>int</green> main() { UsartNetwork::start (myReceiving, <pink>1524003746</pink>); <red>while</red> (<red>true</red>) { } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, l'objet <bold>_myVariable</bold> de type <bold>UsartNetwork</bold> est déclaré cette fois à l'extérieur de la fonction principale <bold>main</bold> afin d'y avoir accès dans une fonction <bold>myReceiving</bold> qui sera exécutée uniquement lors de la réception de données.</text> <text>Dans la fonction principale <bold>main</bold>, la communication est démarrée en appelant la fonction statique <bold>start</bold>. Le 1er paramètre est renseigné avec la fonction <bold>myReceiving</bold> qui sera appelée lorsque des données seront reçues. Le 2ème paramètre <bold>1524003746</bold> reste inchangé par rapport aux exemples précédents (c'est le code d'identification unique).</text> <text>Autre fonctionnalité disponible :</text> <quote>Si besoin la classe <bold>UsartNetwork</bold> dispose d'une fonction statique <bold>stop</bold> ce qui permet d'arrêter les communications, un nouvel appel à la fonction statique <bold>start</bold> permet de redémarrer les communications.</quote> <title>Communication ping pong :</title> <underline></underline> <text>Les deux exemples suivants montrent comment envoyer la donnée <bold>1</bold> depuis un montage vers un autre, ce dernier se contentant simplement de retourner cette donnée (aussitôt reçue) vers le premier montage.</text> <text><bold>Montage ping :</bold></text> <code><purple>#include</purple> <pink><UsartNetwork.h></pink> <green>int</green> main() { UsartNetwork myVariablePing = UsartNetwork (<pink>1</pink>); UsartNetwork myVariablePong = UsartNetwork (<pink>2</pink>); UsartNetwork::start (<green>void</green>, <pink>1524003746</pink>); <red>while</red> (<red>true</red>) { myVariablePing.transmit (<pink>1</pink>); myVariablePong.receive(); } <red>return</red> <pink>0</pink>; }</code> <text>Dans l'exemple ci-dessus, tant que le montage "pong" n'existe pas, la variable <bold>data</bold> de l'objet <bold>myVariablePong</bold> sera toujours égale à <bold>0</bold>. Quand le montage "pong" existera et aura reçu la donnée du montage "ping", soit <bold>1</bold>, alors la donnée reçue stockée dans la variable <bold>data</bold> de l'objet <bold>myVariablePong</bold> sera égale à <bold>1</bold>, preuve qu'un aller/retour aura été effectué.</text> <text><bold>Montage pong :</bold></text> <code><purple>#include</purple> <pink><UsartNetwork.h></pink> <green>int</green> main() { UsartNetwork myVariablePing = UsartNetwork (<pink>1</pink>); UsartNetwork myVariablePong = UsartNetwork (<pink>2</pink>); UsartNetwork::start (<green>void</green>, <pink>1524003746</pink>); <red>while</red> (<red>true</red>) { myVariablePing.receive(); myVariablePong.transmit (myVariablePing.data); } <red>return</red> <pink>0</pink>; }</code> <text>Ce deuxième montage retourne simplement la donnée reçue à son propriétaire. La réception s'effectue sur l'adresse <bold>1</bold> via l'objet <bold>myVariablePing</bold>, et l'émission s'effectue sur l'adresse <bold>2</bold> via l'objet <bold>myVariablePong</bold>.</text> <title>Câblages et priorités :</title> <underline></underline> <text>Il convient dans l'utilisation de la classe <bold>UsartNetwork</bold> de prendre note de quelques considérations techniques importantes pour le bon fonctionnement :</text> <caution>Si vous n'utilisez pas la partie réception du montage et que vous n'appelez pas la fonction <bold>receive</bold>, il est important de quand même connecter un câble sur le port <bold>RXD</bold> de l'automate programmable allant vers un port <bold>TXD</bold> du périphérique, car dans le cas contraire les fonctions matérielles USART capteraient tous les bruits électromagnétiques environnants sur la broche laissée en l'air du microcontrôleur, et générerait des interruptions intempestives, ce qui n'est pas souhaité.</caution> <quote>La classe <bold>UsartNetwork</bold> utilise le protocole USART tout comme les classes <bold>UsartRs232</bold> et <bold>UsartMidi</bold>, mais <bold>les vitesses de communication et les algorithmes mis en œuvre ne sont pas compatibles les uns avec les autres</bold>. Pour éviter tout problème de compatibilité, la classe utilisant l'USART déclarée en premier dans votre projet sera la seule activée et fonctionnelle.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>signed long</green> data = <pink>0</pink>; UsartNetwork (<green>const unsigned char</green> ADDRESS); <green>static void</green> start (<green>void</green> functionJump(), <green>const unsigned long</green> ID); <green>void</green> receive(); <green>void</green> transmit (<green>const signed long</green> DATA); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier documentationUsartRs232.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#documentationUsartRs232"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Une communication vers les ordinateurs personnels avec la classe UsartRs232</title> <underline></underline> <text>Avec la classe <bold>UsartRs232</bold> il est simple de relier votre ordinateur personnel via son <bold>interface RS232</bold> (port DE-9) à votre automate programmable. En exemple d'application possible, ceci peut servir dans le pilotage de fonctions qui animent des moteurs pas à pas utilisés dans l'asservissement d'une machine à commande numérique (CNC).</text> <text>La couche d'abstraction que je propose avec la classe dédiée <bold>UsartRs232</bold> simplifie la mise en œuvre de cette liaison numérique. Le matériel utilisé dans le microcontrôleur et la partie logicielle utilisent le protocole <bold>USART</bold> (pour "Universal Synchronous Asynchronous Receiver Transmitter" ou émetteur récepteur synchrone asynchrone universel) pour communiquer. Les communications sont bidirectionnelles et s'effectuent à la vitesse de <bold>9600 bauds / seconde</bold> sur une largeur de <bold>8 bits utiles</bold>.</text> <text><bold>Ports des automates programmables concernés par l'USART :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) = RXD (receive data) <br/>- Port GPIO 2 (PD1) = TXD (transmit data) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 9 (PD0) = RXD (receive data) <br/>- Port GPIO 10 (PD1) = TXD (transmit data)</caution> <text><bold>Exemple de communication bidirectionnelle avec la classe UsartRs232 :</bold></text> <code><purple>#include</purple> <pink><UsartRs232.h></pink> <green>int</green> main() { UsartRs232::start (<green>void</green>); <red>while</red> (<red>true</red>) { UsartRs232::receive(); <blue>//UsartRs232::data est la donnée reçue</blue> UsartRs232::transmit (<pink>123</pink>); } <red>return</red> <pink>0</pink>; }</code> <text>Dans cet exemple, la fonction statique <bold>start</bold> est appelée prenant en seul paramètre une fonction à appeler lorsque des données sont reçues. Ici ce paramètre est indiqué <bold>void</bold> (vide) ce qui signifie qu'aucune fonction ne sera appelée lors de la réception de données (une interruption interviendra mais n'appellera pas de fonction).</text> <text>Puis dans la boucle <bold>while</bold> la fonction statique <bold>receive</bold> est appelée. Elle s'occupe de la réception des données en provenance de l'ordinateur personnel, et permet la mise à jour de la variable statique <bold>data</bold> qui représente la donnée 8 bits reçue.</text> <text>Ensuite la fonction statique <bold>transmit</bold> est utilisée pour transmettre le nombre <bold>123</bold> vers l'ordinateur personnel. Du fait de la boucle, le nombre <bold>123</bold> sera transmit continuellement à la vitesse de la liaison RS232.</text> <text><bold>Exemple via l'utilisation de fonctions dédiées :</bold></text> <code><purple>#include</purple> <pink><UsartRs232.h></pink> <purple>#include</purple> <pink><Timer.h></pink> <green>void</green> myReceiving() { <blue>//une donnée a été reçue en provenance de l'ordinateur personnel</blue> UsartRs232::receive(); <blue>//UsartRs232::data est la donnée reçue</blue> } <green>void</green> myTransmiting() { <blue>//une donnée va être envoyée vers l'ordinateur personnel</blue> UsartRs232::transmit (<pink>123</pink>); } <green>int</green> main() { UsartRs232::start (myReceiving); <red>while</red> (<red>true</red>) { myTransmiting(); Timer::pause (<pink>1000</pink>); <blue>//pause de 1 seconde</blue> } <red>return</red> <pink>0</pink>; }</code> <text>L'exemple ci-dessus montre que dans la fonction principale <bold>main</bold>, la communication RS232 est démarrée en appelant la fonction statique <bold>start</bold> avec en seul paramètre la fonction <bold>myReceiving</bold> qui sera appelée lorsqu'une donnée sera reçue. Lors de la réception, la fonction statique <bold>receive</bold> est appelée permettant de stocker la donnée reçue dans la variable statique <bold>data</bold>.</text> <text>Les fonctions <bold>myReceiving</bold> et <bold>myTransmiting</bold> sont dédiées respectivement à la réception et à l'émission de données via la liaison RS232. En effet dès la réception d'une donnée 8 bits, la fonction <bold>myReceiving</bold> est immédiatement appelée. Dans cette fonction il est commun d'utiliser la fonction statique <bold>receive</bold> afin de mettre à jour la variable statique <bold>data</bold> qui contient alors la donnée 8 bits reçue, que vous pouvez utiliser n'importe où dans votre programme.</text> <text>À la suite dans la boucle <bold>while</bold>, la fonction <bold>myTransmiting</bold> est utilisée permettant l'émission du nombre <bold>123</bold> vers l'ordinateur personnel, ceci 1 fois par seconde à l'aide de la fonction statique <bold>pause</bold> prenant <bold>1000</bold> en paramètre (la durée de la pause indiquée en millisecondes).</text> <caution>Les deux exemples expliqués ci-dessus permettent en toute simplicité de comprendre le principe d'application de la classe <bold>UsartRs232</bold> pour établir des liaisons RS232 fiables d'un point de vue logiciel.</caution> <text>Autre fonctionnalité disponible :</text> <quote>Si besoin la classe <bold>UsartRs232</bold> dispose d'une fonction statique <bold>stop</bold> ce qui permet d'arrêter les communications RS232, un nouvel appel à la fonction statique <bold>start</bold> permet de redémarrer les communications RS232.</quote> <title>Câblages et priorités :</title> <underline></underline> <text>Il convient dans l'utilisation de la classe <bold>UsartRs232</bold> de prendre note de quelques considérations techniques importantes pour le bon fonctionnement :</text> <caution>Si vous n'utilisez pas la partie réception du montage et que vous n'appelez pas la fonction statique <bold>receive</bold>, il est important de quand même connecter un câble sur le port <bold>RXD</bold> de l'automate programmable allant vers un port <bold>TXD</bold> du périphérique, car dans le cas contraire les fonctions matérielles USART capteraient tous les bruits électromagnétiques environnants sur la broche laissée en l'air du microcontrôleur, et générerait des interruptions intempestives, ce qui n'est pas souhaité.</caution> <quote>La classe <bold>UsartRs232</bold> utilise le protocole USART tout comme les classes <bold>UsartNetwork</bold> et <bold>UsartMidi</bold>, mais <bold>les vitesses de communication et les algorithmes mis en œuvre ne sont pas compatibles les uns avec les autres</bold>. Pour éviter tout problème de compatibilité, la classe utilisant l'USART déclarée en premier dans votre projet sera la seule activée et fonctionnelle.</quote> <title>Références :</title> <underline></underline> <text>Récapitulatif des fonctions et variables de cette classe :</text> <code><green>static unsigned char</green> data; <green>static void</green> start (<green>void</green> functionJump()); <green>static void</green> receive(); <green>static void</green> transmit (<green>const unsigned char</green> DATA); <green>static void</green> stop();</code> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier download.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#download"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Mes projets à télécharger</title> <underline></underline> <text>Dans cette section, vous pouvez télécharger les programmes en langage C++ (c'est la partie logicielle), ainsi que les plans de fabrication de mes circuits imprimés au format de fichiers Gerber (c'est la partie matérielle) du projet MODULE.</text> <title>Partie logicielle :</title> <underline></underline> <text>Le programme <bold>MODULE</bold> en langage C++ :</text> <a href="download/cpp/module.zip"><download>Télécharger le programme <bold>MODULE</bold> (.zip, ≈ 42.1Kio)</download></a> <text>Les <bold>programmes</bold> en langage C++ associés à MODULE :</text> <a href="download/cpp/radio_control.zip"><download>Télécharger le programme de la <bold>radiocommande</bold> (.zip, ≈ 17Kio)</download></a> <a href="download/cpp/quadcopter.zip"><download>Télécharger le programme du <bold>quadri-hélicoptère</bold> (.zip, ≈ 6.7Kio)</download></a> <a href="download/cpp/geiger_muller_counter.zip"><download>Télécharger le programme du <bold>compteur Geiger-Müller</bold> (.zip, ≈ 2.6Kio)</download></a> <a href="download/cpp/intervalometer.zip"><download>Télécharger le programme de <bold>l'intervallomètre</bold> pour la photographie (.zip, ≈ 1.4Kio)</download></a> <a href="download/cpp/bug.zip"><download>Télécharger le programme du <bold>bogue</bold> (.zip, ≈ 1Kio)</download></a> <title>Partie matérielle :</title> <underline></underline> <caution><bold>Attention, des projets sont en cours de réalisation, c'est pourquoi certains fichiers téléchargeables (.zip) sont incomplets !</bold></caution> <text>Les <bold>plans de fabrication</bold> de mes circuits imprimés au format de fichiers Gerber associés au programme MODULE :</text> <a href="download/pcb/modulable_32.zip"><download>Télécharger le plan de fabrication de l'automate programmable <bold>MODULABLE 32</bold> (.zip, 401 octets)</download></a> <a href="download/pcb/modulable_20.zip"><download>Télécharger le plan de fabrication de l'automate programmable <bold>MODULABLE 20</bold> (.zip, 401 octets)</download></a> <a href="download/pcb/digit_display.zip"><download>Télécharger le plan de fabrication de <bold>l'afficheur à digits</bold> (.zip, 403 octets)</download></a> <a href="download/pcb/digit_display_mini.zip"><download>Télécharger le plan de fabrication du <bold>mini afficheur à digits</bold> (.zip, 413 octets)</download></a> <a href="download/pcb/matrix_display.zip"><download>Télécharger le plan de fabrication de <bold>l'afficheur à matrice</bold> (.zip, 405 octets)</download></a> <a href="download/pcb/buzzer.zip"><download>Télécharger le plan de fabrication du <bold>buzzer</bold> piloté (.zip, 389 octets)</download></a> <a href="download/pcb/network_interface.zip"><download>Télécharger le plan de fabrication de l'interface de <bold>communication réseau filaire</bold> (.zip, 411 octets)</download></a> <a href="download/pcb/wireless_interface.zip"><download>Télécharger le plan de fabrication de l'interface de <bold>communication sans fil 2.4GHz</bold> (.zip, 413 octets)</download></a> <a href="download/pcb/musical_instrument_digital_interface.zip"><download>Télécharger le plan de fabrication de l'interface de <bold>communication MIDI</bold> (.zip, 449 octets)</download></a> <a href="download/pcb/computer_interface.zip"><download>Télécharger le plan de fabrication de l'interface de <bold>communication RS232</bold> (.zip, 413 octets)</download></a> <a href="download/pcb/gyroscope_sensor.zip"><download>Télécharger le plan de fabrication du <bold>capteur gyroscopique</bold> (.zip, 409 octets)</download></a> <a href="download/pcb/absolute_gyroscope_sensor.zip"><download>Télécharger le plan de fabrication du <bold>capteur gyroscopique absolu</bold> (.zip, 427 octets)</download></a> <a href="download/pcb/environment_sensor.zip"><download>Télécharger le plan de fabrication du <bold>capteur environnemental</bold> (.zip, 413 octets)</download></a> <a href="download/pcb/infrared_camera_sensor.zip"><download>Télécharger le plan de fabrication de la <bold>caméra thermique</bold> (.zip, 421 octets)</download></a> <a href="download/pcb/hold_switch.zip"><download>Télécharger le plan de fabrication de l'interrupteur <bold>d'alimentation maintenue</bold> (.zip, 399 octets)</download></a> <a href="download/pcb/geiger_muller_boost_converter.zip"><download>Télécharger le plan de fabrication de l'élévateur de <bold>tension +400V pour tube Geiger-Müller</bold> (.zip, 435 octets)</download></a> <a href="download/pcb/external_memory.zip"><download>Télécharger le plan de fabrication de la <bold>mémoire externe de 1Mio</bold> (.zip, 407 octets)</download></a> <a href="download/pcb/card.zip"><download>Télécharger le plan de fabrication de la <bold>carte de visite</bold> (.zip, 385 octets)</download></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier howToInstallModule.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#howToInstallModule"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Comment installer le programme MODULE</title> <underline></underline> <text>Installer le programme MODULE est un grand mot, en réalité MODULE ne demande qu'à être téléchargé et décompressé dans le répertoire de votre choix :</text> <a href="download/cpp/module.zip"><download>Télécharger le programme <bold>MODULE</bold> (.zip, ≈ 42.1Kio)</download></a> <text><bold>Dans l'archive module.zip vous trouverez 2 répertoires :</bold> <br/>- module, contenant la programmation C++ de MODULE. <br/>- example, contenant un exemple de fichier de programme C++ (main.cpp) et les routines de compilation et de téléversement pour Linux, macOS, et Windows.</text> <text>Dans le répertoire <bold>module</bold> se trouvent toutes les classes du programme MODULE optimisées via des directives de préprocesseur respectivement pour l'ATmega48P, l'ATmega88P, l'ATmega168P, l'ATmega328P, l'ATmega164P, l'ATmega324P, l'ATmega644P, ou l'ATmega1284P, ce qui comprend les <bold>fichiers d'en-tête</bold> (.h) que vous aurez à inclure dans vos projets si besoin, et les <bold>fichiers C++</bold> (.cpp) dans lesquels on trouve les fonctions.</text> <caution>Vous pouvez modifier le contenu de ces fichiers si vous souhaitez modifier et améliorer le programme MODULE !</caution> <text>Le répertoire <bold>example</bold> contient la <bold>routine pour Linux et macOS</bold> (Compiler uploader.sh), ainsi que la <bold>routine pour Windows</bold> (Compiler uploader.bat) permettant de compiler et téléverser votre programme dans l'automate programmable (le microcontrôleur plus exactement) via un programmateur. Le répertoire contient également un exemple de <bold>fichier de programme C++</bold> (main.cpp), c'est dans ce fichier que vous pouvez écrire votre programme en langage C++ (ou tout autre fichier ayant l'extension .cpp).</text> <quote>Le répertoire <bold>example</bold> est un exemple pour comprendre comment démarrer simplement la programmation de vos projets avec MODULE.</quote> <text>Pour plus d'informations sur les procédures à suivre afin d'utiliser les routines de compilation et de téléversement Compiler uploader.sh et Compiler uploader.bat, voir dans la section "Les outils complémentaires du projet MODULE" en page d'accueil de mon site Web.</quote> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier howToProgramWidthModule.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#howToProgramWidthModule"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Comment programmer avec MODULE</title> <underline></underline> <text>Pour programmer avec MODULE, vous avez à disposition <bold>28 classes</bold> organisées par fonctionnalités (sous la forme de fichiers d'en-tête et de fichiers C++). Toutes ces classes sont à la fois complètement indépendantes les unes des autres (au niveau du code source C++) et peuvent aussi fonctionner toutes ensembles sans problèmes d'interactions :</text> <caution>En effet dans MODULE il n'y a pas de communication entre les différentes classes, ni d'appels entre les différentes fonctions d'une même classe (d'un même fichier), de sorte que toutes les fonctions travaillent en autonomie, ce qui permet une modularité la plus importante possible et une totale indépendance des fonctionnalités.</caution> <text><bold>Les classes du programme MODULE :</bold></text> <quote>GpioRead <br/>GpioWrite <br/>AnalogRead <br/>InterruptRead <br/>PwmRead <br/>PwmWrite <br/>SoundWrite <br/>Timer <br/>Delay <br/>Period <br/>Math <br/>Iteration <br/>Average <br/>Filter <br/>Hysteresis <br/>Random <br/>Tool <br/>Eeprom <br/>UsartNetwork <br/>UsartRs232 <br/>UsartMidi <br/>SpiMax7219 <br/>SpiNrf24l01p <br/>Spi25aa1024 <br/>TwiMpu6050 <br/>TwiBno055 <br/>TwiBme280 <br/>TwiAmg88</quote> <text>Ce sont les fichiers d'en-tête (.h) des classes qu'il faut inclure dans vos projets si nécessaire à l'aide de la directive de préprocesseur <bold>#include</bold>, les fichiers C++ (.cpp) seront ajoutés automatiquement.</text> <text><bold>Exemple pour inclure une classe du programme MODULE dans votre projet :</bold></text> <code><purple>#include</purple> <pink><GpioRead.h></pink> <green>int</green> main() { <red>return</red> <pink>0</pink>; }</code> <text>Comme le montre l'exemple ci-dessus, il est commun d'inclure les classes au tout début de votre programme.</text> <text><bold>Pour comprendre comment utiliser les classes du programme MODULE :</bold> <br/>- Vous pouvez lire les exemples proposés dans la documentation (disponibles dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web). <br/>- Vous pouvez copier le code source des mes projets.</text> <text>Ou bien il est possible de regarder dans le répertoire <bold>module</bold> (dans l'archive de MODULE téléchargeable en page d'accueil de mon site Web dans la section "Téléchargements") le contenu des fichiers d'en-tête <bold>.h</bold> ce qui vous donnera une bonne idée de comment utiliser les fonctions et variables des classes si vous êtes déjà bien familiarisé à la programmation C++.</text> <title>La documentation du programme MODULE :</title> <underline></underline> <text>Tous les exemples qui utilisent des ports GPIO (entrées/sorties pour un usage général) proposés dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web, sont <bold>écrits pour correspondre aux numéros des ports GPIO de l'automate programmable MODULABLE 32</bold>, mais bien évidement cela reste de votre choix de programmer également pour l'automate programmable MODULABLE 20.</text> <quote>Si par exemple vous souhaitez programmer pour l'automate programmable MODULABLE 20 plutôt que l'automate programmable MODULABLE 32, il vous suffit uniquement, et seulement si besoin, d'adapter le numéro de certains ports GPIO dans votre programme par rapport à l'automate programmable choisi.</quote> <caution>Dans tous les cas, <bold>vous disposez exactement des mêmes fonctionnalités avec MODULE</bold> qu'il s'agisse de programmer l'automate programmable <bold>MODULABLE 20</bold> qui peut être équipé des microcontrôleurs ATmega48P, ATmega88P, ATmega168P, ou ATmega328P, ou l'automate programmable <bold>MODULABLE 32</bold> qui peut être équipé des microcontrôleurs ATmega164P, ATmega324P, ATmega644P, ou ATmega1284P.</caution> <text>Seul <bold>le nombre de ports GPIO disponibles</bold> par fonctionnalité et <bold>leurs distribution sur les automates programmables</bold> peut varier.</text> <text>Pour connaître précisément les caractéristiques de ces deux automates programmables je vous conseille d'aller voir dans la section "Fabrications et diverses réalisations" en page d'accueil de mon site Web.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier index.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html"><navigation>Accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Accueil</title> <underline></underline> <text>Toutes les photos de mes projets :</text> <a href="photo.html"><img src="thumbnail/dsc06923.jpg"></img></a> <a href="photo.html"><img src="thumbnail/dsc06711.jpg"></img></a> <title>Le projet MODULE :</title> <underline></underline> <text>Toutes les informations pour comprendre le projet MODULE :</text> <a id="understandWhatIsModule" href="understandWhatIsModule.html"><download><bold>Comprendre</bold> ce qu'est MODULE</download></a> <a id="howToInstallModule" href="howToInstallModule.html"><download><bold>Comment installer</bold> le programme MODULE</download></a> <a id="howToProgramWidthModule" href="howToProgramWidthModule.html"><download><bold>Comment programmer</bold> avec MODULE</download></a> <a id="complementaryToolOfModule" href="complementaryToolOfModule.html"><download><bold>Les outils complémentaires</bold> du projet MODULE</download></a> <title>La documentation du programme MODULE :</title> <underline></underline> <text>Exemples simples pour comprendre et débuter rapidement la programmation avec MODULE :</text> <a id="documentationGpioRead" href="documentationGpioRead.html"><download>Lire l'état d'un bouton avec la classe <bold>GpioRead</bold></download></a> <a id="documentationGpioWrite" href="documentationGpioWrite.html"><download>Allumer une del avec la classe <bold>GpioWrite</bold></download></a> <a id="documentationAnalogRead" href="documentationAnalogRead.html"><download>Lire un potentiomètre avec la classe <bold>AnalogRead</bold></download></a> <a id="documentationInterruptRead" href="documentationInterruptRead.html"><download>Les interruptions avec la classe <bold>InterruptRead</bold></download></a> <a id="documentationPwmRead" href="documentationPwmRead.html"><download>Lire les voies PWM d'un récepteur de modélisme avec la classe <bold>PwmRead</bold></download></a> <a id="documentationPwmWrite" href="documentationPwmWrite.html"><download>Les servo-moteurs avec la classe <bold>PwmWrite</bold></download></a> <a id="documentationSoundWrite" href="documentationSoundWrite.html"><download>Jouer des sons avec la classe <bold>SoundWrite</bold></download></a> <a id="documentationTimer" href="documentationTimer.html"><download>La gestion du temps avec la classe <bold>Timer</bold></download></a> <a id="documentationDelay" href="documentationDelay.html"><download>Les délais simplifiés avec la classe <bold>Delay</bold></download></a> <a id="documentationPeriod" href="documentationPeriod.html"><download>Mesurer une période avec la classe <bold>Period</bold></download></a> <a id="documentationMath" href="documentationMath.html"><download>Les fonctions mathématiques avec la classe <bold>Math</bold></download></a> <a id="documentationIteration" href="documentationIteration.html"><download>Incrémenter des nombres avec la classe <bold>Iteration</bold></download></a> <a id="documentationAverage" href="documentationAverage.html"><download>Les moyennes avec la classe <bold>Average</bold></download></a> <a id="documentationFilter" href="documentationFilter.html"><download>Filtrer des valeurs avec la classe <bold>Filter</bold></download></a> <a id="documentationHysteresis" href="documentationHysteresis.html"><download>Créer des seuils avec la classe <bold>Hysteresis</bold></download></a> <a id="documentationRandom" href="documentationRandom.html"><download>Générer des nombres aléatoires avec la classe <bold>Random</bold></download></a> <a id="documentationTool" href="documentationTool.html"><download>Quelques outils avec la classe <bold>Tool</bold></download></a> <a id="documentationEeprom" href="documentationEeprom.html"><download>Lire et écrire dans la mémoire du microcontrôleur avec la classe <bold>Eeprom</bold></download></a> <a id="documentationUsartNetwork" href="documentationUsartNetwork.html"><download>Un réseau d'automates programmables avec la classe <bold>UsartNetwork</bold></download></a> <a id="documentationUsartRs232" href="documentationUsartRs232.html"><download>Une comunication vers les ordinateurs personnels avec la classe <bold>UsartRs232</bold></download></a> <a id="documentationUsartMidi" href="documentationUsartMidi.html"><download>Le pilotage des instruments de musique avec la classe <bold>UsartMidi</bold></download></a> <a id="documentationSpiMax7219" href="documentationSpiMax7219.html"><download>Afficher des caractères avec la classe <bold>SpiMax7219</bold></download></a> <a id="documentationSpiNrf24l01p" href="documentationSpiNrf24l01p.html"><download>Une radiocommande avec la classe <bold>SpiNrf24l01p</bold></download></a> <a id="documentationSpi25aa1024" href="documentationSpi25aa1024.html"><download>Lire et écrire dans une mémoire externe de 1Mio avec la classe <bold>Spi25aa1024</bold></download></a> <a id="documentationTwiMpu6050" href="documentationTwiMpu6050.html"><download>Mesurer des mouvements avec la classe <bold>TwiMpu6050</bold></download></a> <a id="documentationTwiBno055" href="documentationTwiBno055.html"><download>Créer un horizon artificiel avec la classe <bold>TwiBno055</bold></download></a> <a id="documentationTwiBme280" href="documentationTwiBme280.html"><download>Une station météorologique avec la classe <bold>TwiBme280</bold></download></a> <a id="documentationTwiAmg88" href="documentationTwiAmg88.html"><download>Une caméra thermique avec la classe <bold>TwiAmg88</bold></download></a> <title>Fabrications et diverses réalisations :</title> <underline></underline> <caution><bold>Attention, des projets sont en cours de réalisation, c'est pourquoi certains articles ou fichiers téléchargeables (.zip) sont incomplets !</bold></caution> <text>Toutes mes fabrications et réalisations présentées et expliquées ici.</text> <text><bold>Cartes électroniques</bold> (détails de mes circuits imprimés) :</text> <a id="projectModulable32" href="projectModulable32.html"><download>L'automate programmable <bold>MODULABLE 32</bold></download></a> <a id="projectModulable20" href="projectModulable20.html"><download>L'automate programmable <bold>MODULABLE 20</bold></download></a> <a id="projectDigitDisplay" href="projectDigitDisplay.html"><download><bold>L'afficheur à digits</bold></download></a> <a id="projectDigitDisplayMini" href="projectDigitDisplayMini.html"><download>Le <bold>mini afficheur à digits </bold></download></a> <a id="projectMatrixDisplay" href="projectMatrixDisplay.html"><download><bold>L'afficheur à matrice</bold></download></a> <a id="projectBuzzer" href="projectBuzzer.html"><download>Le <bold>buzzer</bold> piloté</download></a> <a id="projectNetworkInterface" href="projectNetworkInterface.html"><download>L'interface de <bold>communication réseau filaire</bold></download></a> <a id="projectWirelessInterface" href="projectWirelessInterface.html"><download>L'interface de <bold>communication sans fil 2.4GHz</bold></download></a> <a id="projectMusicalInstrumentDigitalInterface" href="projectMusicalInstrumentDigitalInterface.html"><download>L'interface de <bold>communication MIDI</bold></download></a> <a id="projectComputerInterface" href="projectComputerInterface.html"><download>L'interface de <bold>communication RS232</bold></download></a> <a id="projectGyroscopeSensor" href="projectGyroscopeSensor.html"><download>Le <bold>capteur gyroscopique</bold></download></a> <a id="projectAbsoluteGyroscopeSensor" href="projectAbsoluteGyroscopeSensor.html"><download>Le <bold>capteur gyroscopique absolu</bold></download></a> <a id="projectEnvironmentSensor" href="projectEnvironmentSensor.html"><download>Le <bold>capteur environnemental</bold></download></a> <a id="projectInfraredCameraSensor" href="projectInfraredCameraSensor.html"><download>La <bold>caméra thermique</bold></download></a> <a id="projectHoldSwitch" href="projectHoldSwitch.html"><download>L'interrupteur <bold>d'alimentation maintenue</bold></download></a> <a id="projectGeigerMullerBoostConverter" href="projectGeigerMullerBoostConverter.html"><download>L'élévateur de <bold>tension +400V pour tube Geiger-Müller</bold></download></a> <a id="projectExternalMemory" href="projectExternalMemory.html"><download>La <bold>mémoire externe de 1Mio</bold></download></a> <a id="projectCard" href="projectCard.html"><download>La <bold>carte de visite</bold></download></a> <text><bold>Projets plus complexes</bold> (réalisés avec les cartes électroniques présentées ci-dessus) :</text> <a id="projectRadioControl" href="projectRadioControl.html"><download>La <bold>radiocommande</bold></download></a> <a id="projectQuadcopter" href="projectQuadcopter.html"><download>Le <bold>quadri-hélicoptère</bold></download></a> <a id="projectGeigerMullerCounter" href="projectGeigerMullerCounter.html"><download>Le <bold>compteur Geiger-Müller</bold></download></a> <a id="projectIntervalometer" href="projectIntervalometer.html"><download><bold>L'intervallomètre</bold> pour la photographie</download></a> <text><bold>Projets divers</bold> :</text> <a id="projectBook" href="projectBook.html"><download>Les <bold>livres</bold> de sauvegarde</download></a> <a id="projectUselessMachine" href="projectUselessMachine.html"><download>Les machines <bold>inutiles</bold></download></a> <a id="projectBug" href="projectBug.html"><download>Le <bold>bogue</bold></download></a> <a id="projectSite" href="projectSite.html"><download>Le <bold>site Web</bold></download></a> <title>Outils divers :</title> <underline></underline> <text>Routines d'automatisation de tâches :</text> <a id="toolBmpToMod" href="toolBmpToMod.html"><download>Conversion <bold>d'images bitmap vers une sérigraphie KiCad</bold></download></a> <a id="toolFileToBookContent" href="toolFileToBookContent.html"><download><bold>Création automatique du contenu d'un livre</bold> à partir d'une arborescence de fichiers</download></a> <title>Poésilosophie :</title> <underline></underline> <text>Quelques formes expressives poétiques et philosophiques :</text> <a id="poems" href="poems.html"><download>Le monde est <bold>poèmes</bold> (essai n°1)</download></a> <title>Téléchargements :</title> <underline></underline> <text>Le programme <bold>MODULE</bold> en langage C++ :</text> <a href="download/cpp/module.zip"><download>Télécharger le programme <bold>MODULE</bold> (.zip, ≈ 42.1Kio)</download></a> <text>Les programmes et les plans de fabrication de mes projets :</text> <a id="download" href="download.html"><download>Mes projets à <bold>télécharger</bold></download></a> <title>Services :</title> <underline></underline> <text>Il m'est possible si vous le souhaitez de fabriquer pour vous un circuit (à l'unité, ou très petites séries), dans la liste présentée ci-dessus dont vous auriez besoin pour vos projets, et de vous l'envoyer par la poste.</text> <caution>Seul le coût de la plaque PCB, des composants électroniques, et de l'expédition seront demandés.</caution> <text>Dans tous les cas, n'hésitez pas à me contacter par courrier électronique (voir "Formulaire de contact" ci-dessous) pour me faire part de votre demande.</text> <title>Formulaire de contact :</title> <underline></underline> <text>Pour me contacter et me faire part de votre demande (questions précises ou diverses, remarques et suggestions, idées à proposer, colaboration et fabrication en petites séries, etc...) :</text> <a id="contact" href="contact.php"><download>Contacter <bold>Sylvain Mahé</bold></download></a> <title>Licence officielle :</title> <underline></underline> <text>La licence officielle de mes différents projets (logiciel, matériel, documentation, livres, routines, site Web, etc...) :</text> <a id="license" href="license.html"><download>La <bold>licence officielle</bold></download></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier license.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#license"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La licence officielle</title> <underline></underline> <text>Tout ce qui est proposé en téléchargement et visualisation sur mon site Web (hors liens hypertexte vers des sources externes) est une création personnelle de Sylvain Mahé, <bold>libre de droit d'auteur et à sources ouvertes et modifiables</bold> (open source), ce qui comprend les fichiers de programmes (codes sources), les plans de fabrication de mes cartes électroniques (circuits imprimés), les différents exemples de programmation (documentation), les livres (sauvegardes de fichiers), les routines d'automatisation de tâches (outils) mises à disposition, ainsi que le site Web lui-même.</text> <quote>Il existe bon nombre de licences officielles disponibles et valides d'un point de vue juridique en ce qui concerne le logiciel libre, mais ne me reconnaissant dans aucunes de ces licences, j'ai préféré écrire quelques phrases simples qui me semblent de bon sens (voir ci-dessous).</quote> <text>Bien évidemment, sans être naïf et tout en prenant conscience du caractère non-officiel de ma propre licence au regard de la loi et de la société en général telle qu'elle a été établie à notre insu sans être consulté (finalement qu'est ce qui est officiel et qui ne l'est pas ?).</text> <text>Voici <bold>quelques pratiques de bon sens</bold> et une <bold>éthique à vous engager de respecter</bold> si vous faites usage de mes produits :</text> <caution>Tout ce qui est proposé en téléchargement et visualisation sur mon site Web peut être récupéré, utilisé, et modifié sur un système informatique autre que mon ordinateur personnel ainsi que le serveur qui héberge mon site Web (de sorte de maintenir les versions officielles de tous les fichiers).</caution> <caution>Tout ce qui est proposé en téléchargement et visualisation sur mon site Web ne peut être utilisé à des fins de pouvoir sur autrui, de destruction de la nature, pour contraindre ou discriminer une personne ou un peuple, ou encore asservir (esclavage) ou détruire des animaux (humains ou non-humains).</caution> <caution>Je ne fabrique pas de composants électroniques, ils sont donc soumis aux lois et règles établies par les constructeurs eux-mêmes (il vous appartient donc de vous renseigner en lisant les documentations techniques officielles des composants que vous mettez en œuvre dans vos projets).</caution> <caution>Les déchets résultants de la fabrication et de l'utilisation de mes circuits électroniques et des différents composants qui les animent doivent être traités dans un cycle adapté (démantèlement, tri sélectif, recyclage, réparation, réutilisation, etc...).</caution> <caution>Je ne pourrais être tenu pour responsable si vous faites une mauvaise utilisation des mes produits (c'est-à-dire de tout ce qui est proposé sur mon site Web).</caution> <caution>Seule la présente licence est valide et ne peut être modifiée.</caution> <text>Il vous appartient donc de faire une bonne utilisation des produits proposés sur mon site Web.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier photo.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Toutes les photos de mes projets</title> <underline></underline> <text>Tous mes projets récents et plus anciens en photos (triées par ordre anti-chronologique).</text> <caution>À noter que les médias (photos ou vidéos) ne sont pas forcément tous contractuels du fait du prototypage, et plus généralement de l'évolution constante du matériel mis en œuvre dans mes projets (ce qui est normal en conception).</caution> <a href="photo/dsc09034.jpg"><img src="thumbnail/dsc09034.jpg"></img></a> <a href="photo/dsc09033.jpg"><img src="thumbnail/dsc09033.jpg"></img></a> <a href="photo/dsc09031.jpg"><img src="thumbnail/dsc09031.jpg"></img></a> <a href="photo/dsc09030.jpg"><img src="thumbnail/dsc09030.jpg"></img></a> <a href="photo/dsc09029.jpg"><img src="thumbnail/dsc09029.jpg"></img></a> <a href="photo/dsc09028.jpg"><img src="thumbnail/dsc09028.jpg"></img></a> <a href="photo/dsc09027.jpg"><img src="thumbnail/dsc09027.jpg"></img></a> <a href="photo/dsc09026.jpg"><img src="thumbnail/dsc09026.jpg"></img></a> <a href="photo/dsc09025.jpg"><img src="thumbnail/dsc09025.jpg"></img></a> <a href="photo/dsc09024.jpg"><img src="thumbnail/dsc09024.jpg"></img></a> <a href="photo/dsc09023.jpg"><img src="thumbnail/dsc09023.jpg"></img></a> <a href="photo/dsc09021.jpg"><img src="thumbnail/dsc09021.jpg"></img></a> <a href="photo/dsc09020.jpg"><img src="thumbnail/dsc09020.jpg"></img></a> <a href="photo/dsc09019.jpg"><img src="thumbnail/dsc09019.jpg"></img></a> <a href="photo/dsc09018.jpg"><img src="thumbnail/dsc09018.jpg"></img></a> <a href="photo/dsc09017.jpg"><img src="thumbnail/dsc09017.jpg"></img></a> <a href="photo/dsc09016.jpg"><img src="thumbnail/dsc09016.jpg"></img></a> <a href="photo/dsc09014.jpg"><img src="thumbnail/dsc09014.jpg"></img></a> <a href="photo/dsc09013.jpg"><img src="thumbnail/dsc09013.jpg"></img></a> <a href="photo/dsc09012.jpg"><img src="thumbnail/dsc09012.jpg"></img></a> <a href="photo/dsc09009.jpg"><img src="thumbnail/dsc09009.jpg"></img></a> <a href="photo/dsc09008.jpg"><img src="thumbnail/dsc09008.jpg"></img></a> <a href="photo/dsc09007.jpg"><img src="thumbnail/dsc09007.jpg"></img></a> <a href="photo/dsc09006.jpg"><img src="thumbnail/dsc09006.jpg"></img></a> <a href="photo/dsc09005.jpg"><img src="thumbnail/dsc09005.jpg"></img></a> <a href="photo/dsc09004.jpg"><img src="thumbnail/dsc09004.jpg"></img></a> <a href="photo/dsc09003.jpg"><img src="thumbnail/dsc09003.jpg"></img></a> <a href="photo/dsc09002.jpg"><img src="thumbnail/dsc09002.jpg"></img></a> <a href="photo/dsc08787.jpg"><img src="thumbnail/dsc08787.jpg"></img></a> <a href="photo/dsc08786.jpg"><img src="thumbnail/dsc08786.jpg"></img></a> <a href="photo/dsc08785.jpg"><img src="thumbnail/dsc08785.jpg"></img></a> <a href="photo/dsc08784.jpg"><img src="thumbnail/dsc08784.jpg"></img></a> <a href="photo/dsc08783.jpg"><img src="thumbnail/dsc08783.jpg"></img></a> <a href="photo/dsc08780.jpg"><img src="thumbnail/dsc08780.jpg"></img></a> <a href="photo/dsc08779.jpg"><img src="thumbnail/dsc08779.jpg"></img></a> <a href="photo/dsc08778.jpg"><img src="thumbnail/dsc08778.jpg"></img></a> <a href="photo/dsc08777.jpg"><img src="thumbnail/dsc08777.jpg"></img></a> <a href="photo/dsc08775.jpg"><img src="thumbnail/dsc08775.jpg"></img></a> <a href="photo/dsc08773.jpg"><img src="thumbnail/dsc08773.jpg"></img></a> <a href="photo/dsc08772.jpg"><img src="thumbnail/dsc08772.jpg"></img></a> <a href="photo/dsc08771.jpg"><img src="thumbnail/dsc08771.jpg"></img></a> <a href="photo/dsc08770.jpg"><img src="thumbnail/dsc08770.jpg"></img></a> <a href="photo/dsc08769.jpg"><img src="thumbnail/dsc08769.jpg"></img></a> <a href="photo/dsc08768.jpg"><img src="thumbnail/dsc08768.jpg"></img></a> <a href="photo/dsc08767.jpg"><img src="thumbnail/dsc08767.jpg"></img></a> <a href="photo/dsc08766.jpg"><img src="thumbnail/dsc08766.jpg"></img></a> <a href="photo/dsc08765.jpg"><img src="thumbnail/dsc08765.jpg"></img></a> <a href="photo/dsc08763.jpg"><img src="thumbnail/dsc08763.jpg"></img></a> <a href="photo/dsc08761.jpg"><img src="thumbnail/dsc08761.jpg"></img></a> <a href="photo/dsc08757.jpg"><img src="thumbnail/dsc08757.jpg"></img></a> <a href="photo/dsc08755.jpg"><img src="thumbnail/dsc08755.jpg"></img></a> <a href="photo/dsc08754.jpg"><img src="thumbnail/dsc08754.jpg"></img></a> <a href="photo/dsc08706.jpg"><img src="thumbnail/dsc08706.jpg"></img></a> <a href="photo/dsc08704.jpg"><img src="thumbnail/dsc08704.jpg"></img></a> <a href="photo/dsc08703.jpg"><img src="thumbnail/dsc08703.jpg"></img></a> <a href="photo/dsc08646.jpg"><img src="thumbnail/dsc08646.jpg"></img></a> <a href="photo/dsc08632.jpg"><img src="thumbnail/dsc08632.jpg"></img></a> <a href="photo/dsc08571.jpg"><img src="thumbnail/dsc08571.jpg"></img></a> <a href="photo/dsc08570.jpg"><img src="thumbnail/dsc08570.jpg"></img></a> <a href="photo/dsc08568.jpg"><img src="thumbnail/dsc08568.jpg"></img></a> <a href="photo/dsc08567.jpg"><img src="thumbnail/dsc08567.jpg"></img></a> <a href="photo/dsc08566.jpg"><img src="thumbnail/dsc08566.jpg"></img></a> <a href="photo/dsc08565.jpg"><img src="thumbnail/dsc08565.jpg"></img></a> <a href="photo/dsc08560.jpg"><img src="thumbnail/dsc08560.jpg"></img></a> <a href="photo/dsc08552.jpg"><img src="thumbnail/dsc08552.jpg"></img></a> <a href="photo/dsc08436.jpg"><img src="thumbnail/dsc08436.jpg"></img></a> <a href="photo/dsc08431.jpg"><img src="thumbnail/dsc08431.jpg"></img></a> <a href="photo/dsc08429.jpg"><img src="thumbnail/dsc08429.jpg"></img></a> <a href="photo/dsc08428.jpg"><img src="thumbnail/dsc08428.jpg"></img></a> <a href="photo/dsc08427.jpg"><img src="thumbnail/dsc08427.jpg"></img></a> <a href="photo/dsc08425.jpg"><img src="thumbnail/dsc08425.jpg"></img></a> <a href="photo/dsc08424.jpg"><img src="thumbnail/dsc08424.jpg"></img></a> <a href="photo/dsc08423.jpg"><img src="thumbnail/dsc08423.jpg"></img></a> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <a href="photo/dsc08417.jpg"><img src="thumbnail/dsc08417.jpg"></img></a> <a href="photo/dsc08413.jpg"><img src="thumbnail/dsc08413.jpg"></img></a> <a href="photo/dsc08411.jpg"><img src="thumbnail/dsc08411.jpg"></img></a> <a href="photo/dsc08409.jpg"><img src="thumbnail/dsc08409.jpg"></img></a> <a href="photo/dsc08405.jpg"><img src="thumbnail/dsc08405.jpg"></img></a> <a href="photo/dsc08403.jpg"><img src="thumbnail/dsc08403.jpg"></img></a> <a href="photo/dsc08387.jpg"><img src="thumbnail/dsc08387.jpg"></img></a> <a href="photo/dsc08386.jpg"><img src="thumbnail/dsc08386.jpg"></img></a> <a href="photo/dsc08384.jpg"><img src="thumbnail/dsc08384.jpg"></img></a> <a href="photo/dsc08382.jpg"><img src="thumbnail/dsc08382.jpg"></img></a> <a href="photo/dsc08381.jpg"><img src="thumbnail/dsc08381.jpg"></img></a> <a href="photo/dsc08380.jpg"><img src="thumbnail/dsc08380.jpg"></img></a> <a href="photo/dsc08379.jpg"><img src="thumbnail/dsc08379.jpg"></img></a> <a href="photo/dsc08378.jpg"><img src="thumbnail/dsc08378.jpg"></img></a> <a href="photo/dsc08376.jpg"><img src="thumbnail/dsc08376.jpg"></img></a> <a href="photo/dsc08372.jpg"><img src="thumbnail/dsc08372.jpg"></img></a> <a href="photo/dsc08369.jpg"><img src="thumbnail/dsc08369.jpg"></img></a> <a href="photo/dsc08368.jpg"><img src="thumbnail/dsc08368.jpg"></img></a> <a href="photo/dsc08365.jpg"><img src="thumbnail/dsc08365.jpg"></img></a> <a href="photo/dsc08361.jpg"><img src="thumbnail/dsc08361.jpg"></img></a> <a href="photo/dsc08360.jpg"><img src="thumbnail/dsc08360.jpg"></img></a> <a href="photo/dsc08359.jpg"><img src="thumbnail/dsc08359.jpg"></img></a> <a href="photo/dsc08358.jpg"><img src="thumbnail/dsc08358.jpg"></img></a> <a href="photo/dsc08357.jpg"><img src="thumbnail/dsc08357.jpg"></img></a> <a href="photo/dsc08355.jpg"><img src="thumbnail/dsc08355.jpg"></img></a> <a href="photo/dsc08353.jpg"><img src="thumbnail/dsc08353.jpg"></img></a> <a href="photo/dsc08349.jpg"><img src="thumbnail/dsc08349.jpg"></img></a> <a href="photo/dsc08348.jpg"><img src="thumbnail/dsc08348.jpg"></img></a> <a href="photo/dsc08346.jpg"><img src="thumbnail/dsc08346.jpg"></img></a> <a href="photo/dsc08344.jpg"><img src="thumbnail/dsc08344.jpg"></img></a> <a href="photo/dsc08343.jpg"><img src="thumbnail/dsc08343.jpg"></img></a> <a href="photo/dsc08342.jpg"><img src="thumbnail/dsc08342.jpg"></img></a> <a href="photo/dsc08341.jpg"><img src="thumbnail/dsc08341.jpg"></img></a> <a href="photo/dsc08340.jpg"><img src="thumbnail/dsc08340.jpg"></img></a> <a href="photo/dsc08339.jpg"><img src="thumbnail/dsc08339.jpg"></img></a> <a href="photo/dsc08337.jpg"><img src="thumbnail/dsc08337.jpg"></img></a> <a href="photo/dsc08335.jpg"><img src="thumbnail/dsc08335.jpg"></img></a> <a href="photo/dsc08334.jpg"><img src="thumbnail/dsc08334.jpg"></img></a> <a href="photo/dsc08333.jpg"><img src="thumbnail/dsc08333.jpg"></img></a> <a href="photo/dsc08332.jpg"><img src="thumbnail/dsc08332.jpg"></img></a> <a href="photo/dsc08330.jpg"><img src="thumbnail/dsc08330.jpg"></img></a> <a href="photo/dsc08328.jpg"><img src="thumbnail/dsc08328.jpg"></img></a> <a href="photo/dsc08327.jpg"><img src="thumbnail/dsc08327.jpg"></img></a> <a href="photo/dsc08326.jpg"><img src="thumbnail/dsc08326.jpg"></img></a> <a href="photo/dsc08324.jpg"><img src="thumbnail/dsc08324.jpg"></img></a> <a href="photo/dsc08323.jpg"><img src="thumbnail/dsc08323.jpg"></img></a> <a href="photo/dsc08321.jpg"><img src="thumbnail/dsc08321.jpg"></img></a> <a href="photo/dsc08318.jpg"><img src="thumbnail/dsc08318.jpg"></img></a> <a href="photo/dsc08316.jpg"><img src="thumbnail/dsc08316.jpg"></img></a> <a href="photo/dsc08315.jpg"><img src="thumbnail/dsc08315.jpg"></img></a> <a href="photo/dsc08314.jpg"><img src="thumbnail/dsc08314.jpg"></img></a> <a href="photo/dsc08313.jpg"><img src="thumbnail/dsc08313.jpg"></img></a> <a href="photo/dsc08312.jpg"><img src="thumbnail/dsc08312.jpg"></img></a> <a href="photo/dsc08308.jpg"><img src="thumbnail/dsc08308.jpg"></img></a> <a href="photo/dsc08305.jpg"><img src="thumbnail/dsc08305.jpg"></img></a> <a href="photo/dsc08304.jpg"><img src="thumbnail/dsc08304.jpg"></img></a> <a href="photo/dsc08303.jpg"><img src="thumbnail/dsc08303.jpg"></img></a> <a href="photo/dsc08302.jpg"><img src="thumbnail/dsc08302.jpg"></img></a> <a href="photo/dsc08301.jpg"><img src="thumbnail/dsc08301.jpg"></img></a> <a href="photo/dsc08300.jpg"><img src="thumbnail/dsc08300.jpg"></img></a> <a href="photo/dsc08299.jpg"><img src="thumbnail/dsc08299.jpg"></img></a> <a href="photo/dsc08298.jpg"><img src="thumbnail/dsc08298.jpg"></img></a> <a href="photo/dsc08297.jpg"><img src="thumbnail/dsc08297.jpg"></img></a> <a href="photo/dsc08296.jpg"><img src="thumbnail/dsc08296.jpg"></img></a> <a href="photo/dsc08295.jpg"><img src="thumbnail/dsc08295.jpg"></img></a> <a href="photo/dsc08294.jpg"><img src="thumbnail/dsc08294.jpg"></img></a> <a href="photo/dsc08293.jpg"><img src="thumbnail/dsc08293.jpg"></img></a> <a href="photo/dsc08290.jpg"><img src="thumbnail/dsc08290.jpg"></img></a> <a href="photo/dsc08287.jpg"><img src="thumbnail/dsc08287.jpg"></img></a> <a href="photo/dsc08285.jpg"><img src="thumbnail/dsc08285.jpg"></img></a> <a href="photo/dsc08284.jpg"><img src="thumbnail/dsc08284.jpg"></img></a> <a href="photo/dsc08283.jpg"><img src="thumbnail/dsc08283.jpg"></img></a> <a href="photo/dsc08282.jpg"><img src="thumbnail/dsc08282.jpg"></img></a> <a href="photo/dsc08280.jpg"><img src="thumbnail/dsc08280.jpg"></img></a> <a href="photo/dsc08279.jpg"><img src="thumbnail/dsc08279.jpg"></img></a> <a href="photo/dsc08278.jpg"><img src="thumbnail/dsc08278.jpg"></img></a> <a href="photo/dsc08277.jpg"><img src="thumbnail/dsc08277.jpg"></img></a> <a href="photo/dsc08276.jpg"><img src="thumbnail/dsc08276.jpg"></img></a> <a href="photo/dsc08275.jpg"><img src="thumbnail/dsc08275.jpg"></img></a> <a href="photo/dsc08273.jpg"><img src="thumbnail/dsc08273.jpg"></img></a> <a href="photo/dsc08270.jpg"><img src="thumbnail/dsc08270.jpg"></img></a> <a href="photo/dsc08269.jpg"><img src="thumbnail/dsc08269.jpg"></img></a> <a href="photo/dsc08268.jpg"><img src="thumbnail/dsc08268.jpg"></img></a> <a href="photo/dsc08267.jpg"><img src="thumbnail/dsc08267.jpg"></img></a> <a href="photo/dsc08230.jpg"><img src="thumbnail/dsc08230.jpg"></img></a> <a href="photo/dsc08229.jpg"><img src="thumbnail/dsc08229.jpg"></img></a> <a href="photo/dsc08228.jpg"><img src="thumbnail/dsc08228.jpg"></img></a> <a href="photo/dsc08227.jpg"><img src="thumbnail/dsc08227.jpg"></img></a> <a href="photo/dsc08226.jpg"><img src="thumbnail/dsc08226.jpg"></img></a> <a href="photo/dsc08225.jpg"><img src="thumbnail/dsc08225.jpg"></img></a> <a href="photo/dsc08224.jpg"><img src="thumbnail/dsc08224.jpg"></img></a> <a href="photo/dsc08221.jpg"><img src="thumbnail/dsc08221.jpg"></img></a> <a href="photo/dsc08217.jpg"><img src="thumbnail/dsc08217.jpg"></img></a> <a href="photo/dsc08216.jpg"><img src="thumbnail/dsc08216.jpg"></img></a> <a href="photo/dsc08211.jpg"><img src="thumbnail/dsc08211.jpg"></img></a> <a href="photo/dsc08204.jpg"><img src="thumbnail/dsc08204.jpg"></img></a> <a href="photo/dsc08202.jpg"><img src="thumbnail/dsc08202.jpg"></img></a> <a href="photo/dsc08200.jpg"><img src="thumbnail/dsc08200.jpg"></img></a> <a href="photo/dsc08199.jpg"><img src="thumbnail/dsc08199.jpg"></img></a> <a href="photo/dsc08197.jpg"><img src="thumbnail/dsc08197.jpg"></img></a> <a href="photo/dsc08196.jpg"><img src="thumbnail/dsc08196.jpg"></img></a> <a href="photo/dsc08195.jpg"><img src="thumbnail/dsc08195.jpg"></img></a> <a href="photo/dsc08194.jpg"><img src="thumbnail/dsc08194.jpg"></img></a> <a href="photo/dsc08193.jpg"><img src="thumbnail/dsc08193.jpg"></img></a> <a href="photo/dsc08192.jpg"><img src="thumbnail/dsc08192.jpg"></img></a> <a href="photo/dsc08187.jpg"><img src="thumbnail/dsc08187.jpg"></img></a> <a href="photo/dsc08185.jpg"><img src="thumbnail/dsc08185.jpg"></img></a> <a href="photo/dsc08184.jpg"><img src="thumbnail/dsc08184.jpg"></img></a> <a href="photo/dsc08183.jpg"><img src="thumbnail/dsc08183.jpg"></img></a> <a href="photo/dsc08182.jpg"><img src="thumbnail/dsc08182.jpg"></img></a> <a href="photo/dsc08181.jpg"><img src="thumbnail/dsc08181.jpg"></img></a> <a href="photo/dsc08177.jpg"><img src="thumbnail/dsc08177.jpg"></img></a> <a href="photo/dsc08176.jpg"><img src="thumbnail/dsc08176.jpg"></img></a> <a href="photo/dsc08174.jpg"><img src="thumbnail/dsc08174.jpg"></img></a> <a href="photo/dsc08172.jpg"><img src="thumbnail/dsc08172.jpg"></img></a> <a href="photo/dsc08171.jpg"><img src="thumbnail/dsc08171.jpg"></img></a> <a href="photo/dsc08170.jpg"><img src="thumbnail/dsc08170.jpg"></img></a> <a href="photo/dsc08169.jpg"><img src="thumbnail/dsc08169.jpg"></img></a> <a href="photo/dsc08166.jpg"><img src="thumbnail/dsc08166.jpg"></img></a> <a href="photo/dsc08165.jpg"><img src="thumbnail/dsc08165.jpg"></img></a> <a href="photo/dsc08164.jpg"><img src="thumbnail/dsc08164.jpg"></img></a> <a href="photo/dsc08163.jpg"><img src="thumbnail/dsc08163.jpg"></img></a> <a href="photo/dsc08162.jpg"><img src="thumbnail/dsc08162.jpg"></img></a> <a href="photo/dsc08161.jpg"><img src="thumbnail/dsc08161.jpg"></img></a> <a href="photo/dsc08160.jpg"><img src="thumbnail/dsc08160.jpg"></img></a> <a href="photo/dsc08144.jpg"><img src="thumbnail/dsc08144.jpg"></img></a> <a href="photo/dsc08141.jpg"><img src="thumbnail/dsc08141.jpg"></img></a> <a href="photo/dsc08139.jpg"><img src="thumbnail/dsc08139.jpg"></img></a> <a href="photo/dsc08137.jpg"><img src="thumbnail/dsc08137.jpg"></img></a> <a href="photo/dsc08134.jpg"><img src="thumbnail/dsc08134.jpg"></img></a> <a href="photo/dsc08133.jpg"><img src="thumbnail/dsc08133.jpg"></img></a> <a href="photo/dsc08132.jpg"><img src="thumbnail/dsc08132.jpg"></img></a> <a href="photo/dsc08129.jpg"><img src="thumbnail/dsc08129.jpg"></img></a> <a href="photo/dsc08126.jpg"><img src="thumbnail/dsc08126.jpg"></img></a> <a href="photo/dsc08121.jpg"><img src="thumbnail/dsc08121.jpg"></img></a> <a href="photo/dsc08119.jpg"><img src="thumbnail/dsc08119.jpg"></img></a> <a href="photo/dsc08118.jpg"><img src="thumbnail/dsc08118.jpg"></img></a> <a href="photo/dsc08117.jpg"><img src="thumbnail/dsc08117.jpg"></img></a> <a href="photo/dsc08116.jpg"><img src="thumbnail/dsc08116.jpg"></img></a> <a href="photo/dsc08115.jpg"><img src="thumbnail/dsc08115.jpg"></img></a> <a href="photo/dsc08114.jpg"><img src="thumbnail/dsc08114.jpg"></img></a> <a href="photo/dsc08112.jpg"><img src="thumbnail/dsc08112.jpg"></img></a> <a href="photo/dsc08111.jpg"><img src="thumbnail/dsc08111.jpg"></img></a> <a href="photo/dsc08110.jpg"><img src="thumbnail/dsc08110.jpg"></img></a> <a href="photo/dsc08103.jpg"><img src="thumbnail/dsc08103.jpg"></img></a> <a href="photo/dsc08099.jpg"><img src="thumbnail/dsc08099.jpg"></img></a> <a href="photo/dsc08090.jpg"><img src="thumbnail/dsc08090.jpg"></img></a> <a href="photo/dsc08086.jpg"><img src="thumbnail/dsc08086.jpg"></img></a> <a href="photo/dsc08085.jpg"><img src="thumbnail/dsc08085.jpg"></img></a> <a href="photo/dsc08084.jpg"><img src="thumbnail/dsc08084.jpg"></img></a> <a href="photo/dsc08079.jpg"><img src="thumbnail/dsc08079.jpg"></img></a> <a href="photo/dsc08077.jpg"><img src="thumbnail/dsc08077.jpg"></img></a> <a href="photo/dsc08076.jpg"><img src="thumbnail/dsc08076.jpg"></img></a> <a href="photo/dsc08075.jpg"><img src="thumbnail/dsc08075.jpg"></img></a> <a href="photo/dsc08074.jpg"><img src="thumbnail/dsc08074.jpg"></img></a> <a href="photo/dsc08073.jpg"><img src="thumbnail/dsc08073.jpg"></img></a> <a href="photo/dsc08072.jpg"><img src="thumbnail/dsc08072.jpg"></img></a> <a href="photo/dsc08071.jpg"><img src="thumbnail/dsc08071.jpg"></img></a> <a href="photo/dsc08070.jpg"><img src="thumbnail/dsc08070.jpg"></img></a> <a href="photo/dsc08069.jpg"><img src="thumbnail/dsc08069.jpg"></img></a> <a href="photo/dsc08068.jpg"><img src="thumbnail/dsc08068.jpg"></img></a> <a href="photo/dsc08067.jpg"><img src="thumbnail/dsc08067.jpg"></img></a> <a href="photo/dsc08060.jpg"><img src="thumbnail/dsc08060.jpg"></img></a> <a href="photo/dsc08057.jpg"><img src="thumbnail/dsc08057.jpg"></img></a> <a href="photo/dsc08056.jpg"><img src="thumbnail/dsc08056.jpg"></img></a> <a href="photo/dsc08055.jpg"><img src="thumbnail/dsc08055.jpg"></img></a> <a href="photo/dsc08054.jpg"><img src="thumbnail/dsc08054.jpg"></img></a> <a href="photo/dsc08053.jpg"><img src="thumbnail/dsc08053.jpg"></img></a> <a href="photo/dsc08052.jpg"><img src="thumbnail/dsc08052.jpg"></img></a> <a href="photo/dsc08051.jpg"><img src="thumbnail/dsc08051.jpg"></img></a> <a href="photo/dsc08050.jpg"><img src="thumbnail/dsc08050.jpg"></img></a> <a href="photo/dsc08049.jpg"><img src="thumbnail/dsc08049.jpg"></img></a> <a href="photo/dsc08047.jpg"><img src="thumbnail/dsc08047.jpg"></img></a> <a href="photo/dsc08045.jpg"><img src="thumbnail/dsc08045.jpg"></img></a> <a href="photo/dsc08044.jpg"><img src="thumbnail/dsc08044.jpg"></img></a> <a href="photo/dsc08043.jpg"><img src="thumbnail/dsc08043.jpg"></img></a> <a href="photo/dsc08041.jpg"><img src="thumbnail/dsc08041.jpg"></img></a> <a href="photo/dsc08040.jpg"><img src="thumbnail/dsc08040.jpg"></img></a> <a href="photo/dsc08036.jpg"><img src="thumbnail/dsc08036.jpg"></img></a> <a href="photo/dsc08032.jpg"><img src="thumbnail/dsc08032.jpg"></img></a> <a href="photo/dsc08026.jpg"><img src="thumbnail/dsc08026.jpg"></img></a> <a href="photo/dsc08025.jpg"><img src="thumbnail/dsc08025.jpg"></img></a> <a href="photo/dsc08024.jpg"><img src="thumbnail/dsc08024.jpg"></img></a> <a href="photo/dsc08023.jpg"><img src="thumbnail/dsc08023.jpg"></img></a> <a href="photo/dsc08022.jpg"><img src="thumbnail/dsc08022.jpg"></img></a> <a href="photo/dsc08021.jpg"><img src="thumbnail/dsc08021.jpg"></img></a> <a href="photo/dsc08020.jpg"><img src="thumbnail/dsc08020.jpg"></img></a> <a href="photo/dsc08019.jpg"><img src="thumbnail/dsc08019.jpg"></img></a> <a href="photo/dsc08018.jpg"><img src="thumbnail/dsc08018.jpg"></img></a> <a href="photo/dsc08017.jpg"><img src="thumbnail/dsc08017.jpg"></img></a> <a href="photo/dsc08016.jpg"><img src="thumbnail/dsc08016.jpg"></img></a> <a href="photo/dsc08015.jpg"><img src="thumbnail/dsc08015.jpg"></img></a> <a href="photo/dsc08013.jpg"><img src="thumbnail/dsc08013.jpg"></img></a> <a href="photo/dsc08012.jpg"><img src="thumbnail/dsc08012.jpg"></img></a> <a href="photo/dsc08011.jpg"><img src="thumbnail/dsc08011.jpg"></img></a> <a href="photo/dsc08010.jpg"><img src="thumbnail/dsc08010.jpg"></img></a> <a href="photo/dsc08009.jpg"><img src="thumbnail/dsc08009.jpg"></img></a> <a href="photo/dsc08008.jpg"><img src="thumbnail/dsc08008.jpg"></img></a> <a href="photo/dsc08006.jpg"><img src="thumbnail/dsc08006.jpg"></img></a> <a href="photo/dsc08004.jpg"><img src="thumbnail/dsc08004.jpg"></img></a> <a href="photo/dsc08002.jpg"><img src="thumbnail/dsc08002.jpg"></img></a> <a href="photo/dsc08001.jpg"><img src="thumbnail/dsc08001.jpg"></img></a> <a href="photo/dsc08000.jpg"><img src="thumbnail/dsc08000.jpg"></img></a> <a href="photo/dsc07999.jpg"><img src="thumbnail/dsc07999.jpg"></img></a> <a href="photo/dsc07996.jpg"><img src="thumbnail/dsc07996.jpg"></img></a> <a href="photo/dsc07994.jpg"><img src="thumbnail/dsc07994.jpg"></img></a> <a href="photo/dsc07991.jpg"><img src="thumbnail/dsc07991.jpg"></img></a> <a href="photo/dsc07990.jpg"><img src="thumbnail/dsc07990.jpg"></img></a> <a href="photo/dsc07989.jpg"><img src="thumbnail/dsc07989.jpg"></img></a> <a href="photo/dsc07988.jpg"><img src="thumbnail/dsc07988.jpg"></img></a> <a href="photo/dsc07984.jpg"><img src="thumbnail/dsc07984.jpg"></img></a> <a href="photo/dsc07983.jpg"><img src="thumbnail/dsc07983.jpg"></img></a> <a href="photo/dsc07980.jpg"><img src="thumbnail/dsc07980.jpg"></img></a> <a href="photo/dsc07979.jpg"><img src="thumbnail/dsc07979.jpg"></img></a> <a href="photo/dsc07978.jpg"><img src="thumbnail/dsc07978.jpg"></img></a> <a href="photo/dsc07977.jpg"><img src="thumbnail/dsc07977.jpg"></img></a> <a href="photo/dsc07976.jpg"><img src="thumbnail/dsc07976.jpg"></img></a> <a href="photo/dsc07974.jpg"><img src="thumbnail/dsc07974.jpg"></img></a> <a href="photo/dsc07973.jpg"><img src="thumbnail/dsc07973.jpg"></img></a> <a href="photo/dsc07972.jpg"><img src="thumbnail/dsc07972.jpg"></img></a> <a href="photo/dsc07971.jpg"><img src="thumbnail/dsc07971.jpg"></img></a> <a href="photo/dsc07970.jpg"><img src="thumbnail/dsc07970.jpg"></img></a> <a href="photo/dsc07969.jpg"><img src="thumbnail/dsc07969.jpg"></img></a> <a href="photo/dsc07968.jpg"><img src="thumbnail/dsc07968.jpg"></img></a> <a href="photo/dsc07967.jpg"><img src="thumbnail/dsc07967.jpg"></img></a> <a href="photo/dsc07965.jpg"><img src="thumbnail/dsc07965.jpg"></img></a> <a href="photo/dsc07963.jpg"><img src="thumbnail/dsc07963.jpg"></img></a> <a href="photo/dsc07962.jpg"><img src="thumbnail/dsc07962.jpg"></img></a> <a href="photo/dsc07961.jpg"><img src="thumbnail/dsc07961.jpg"></img></a> <a href="photo/dsc07960.jpg"><img src="thumbnail/dsc07960.jpg"></img></a> <a href="photo/dsc07959.jpg"><img src="thumbnail/dsc07959.jpg"></img></a> <a href="photo/dsc07958.jpg"><img src="thumbnail/dsc07958.jpg"></img></a> <a href="photo/dsc07957.jpg"><img src="thumbnail/dsc07957.jpg"></img></a> <a href="photo/dsc07953.jpg"><img src="thumbnail/dsc07953.jpg"></img></a> <a href="photo/dsc07952.jpg"><img src="thumbnail/dsc07952.jpg"></img></a> <a href="photo/dsc07949.jpg"><img src="thumbnail/dsc07949.jpg"></img></a> <a href="photo/dsc07948.jpg"><img src="thumbnail/dsc07948.jpg"></img></a> <a href="photo/dsc07946.jpg"><img src="thumbnail/dsc07946.jpg"></img></a> <a href="photo/dsc07944.jpg"><img src="thumbnail/dsc07944.jpg"></img></a> <a href="photo/dsc07941.jpg"><img src="thumbnail/dsc07941.jpg"></img></a> <a href="photo/dsc07932.jpg"><img src="thumbnail/dsc07932.jpg"></img></a> <a href="photo/dsc07931.jpg"><img src="thumbnail/dsc07931.jpg"></img></a> <a href="photo/dsc07927.jpg"><img src="thumbnail/dsc07927.jpg"></img></a> <a href="photo/dsc07923.jpg"><img src="thumbnail/dsc07923.jpg"></img></a> <a href="photo/dsc07922.jpg"><img src="thumbnail/dsc07922.jpg"></img></a> <a href="photo/dsc07921.jpg"><img src="thumbnail/dsc07921.jpg"></img></a> <a href="photo/dsc07920.jpg"><img src="thumbnail/dsc07920.jpg"></img></a> <a href="photo/dsc07912.jpg"><img src="thumbnail/dsc07912.jpg"></img></a> <a href="photo/dsc07911.jpg"><img src="thumbnail/dsc07911.jpg"></img></a> <a href="photo/dsc07910.jpg"><img src="thumbnail/dsc07910.jpg"></img></a> <a href="photo/dsc07901.jpg"><img src="thumbnail/dsc07901.jpg"></img></a> <a href="photo/dsc07826.jpg"><img src="thumbnail/dsc07826.jpg"></img></a> <a href="photo/dsc07825.jpg"><img src="thumbnail/dsc07825.jpg"></img></a> <a href="photo/dsc07703.jpg"><img src="thumbnail/dsc07703.jpg"></img></a> <a href="photo/dsc07692.jpg"><img src="thumbnail/dsc07692.jpg"></img></a> <a href="photo/dsc07687.jpg"><img src="thumbnail/dsc07687.jpg"></img></a> <a href="photo/dsc07686.jpg"><img src="thumbnail/dsc07686.jpg"></img></a> <a href="photo/dsc07683.jpg"><img src="thumbnail/dsc07683.jpg"></img></a> <a href="photo/dsc07666.jpg"><img src="thumbnail/dsc07666.jpg"></img></a> <a href="photo/dsc07664.jpg"><img src="thumbnail/dsc07664.jpg"></img></a> <a href="photo/dsc07663.jpg"><img src="thumbnail/dsc07663.jpg"></img></a> <a href="photo/dsc07659.jpg"><img src="thumbnail/dsc07659.jpg"></img></a> <a href="photo/dsc07656.jpg"><img src="thumbnail/dsc07656.jpg"></img></a> <a href="photo/dsc07654.jpg"><img src="thumbnail/dsc07654.jpg"></img></a> <a href="photo/dsc07651.jpg"><img src="thumbnail/dsc07651.jpg"></img></a> <a href="photo/dsc07649.jpg"><img src="thumbnail/dsc07649.jpg"></img></a> <a href="photo/dsc07644.jpg"><img src="thumbnail/dsc07644.jpg"></img></a> <a href="photo/dsc07638.jpg"><img src="thumbnail/dsc07638.jpg"></img></a> <a href="photo/dsc07569.jpg"><img src="thumbnail/dsc07569.jpg"></img></a> <a href="photo/dsc07565.jpg"><img src="thumbnail/dsc07565.jpg"></img></a> <a href="photo/dsc07556.jpg"><img src="thumbnail/dsc07556.jpg"></img></a> <a href="photo/dsc07553.jpg"><img src="thumbnail/dsc07553.jpg"></img></a> <a href="photo/dsc07551.jpg"><img src="thumbnail/dsc07551.jpg"></img></a> <a href="photo/dsc07550.jpg"><img src="thumbnail/dsc07550.jpg"></img></a> <a href="photo/dsc07547.jpg"><img src="thumbnail/dsc07547.jpg"></img></a> <a href="photo/dsc07154.jpg"><img src="thumbnail/dsc07154.jpg"></img></a> <a href="photo/dsc06986.jpg"><img src="thumbnail/dsc06986.jpg"></img></a> <a href="photo/dsc06985.jpg"><img src="thumbnail/dsc06985.jpg"></img></a> <a href="photo/dsc06977.jpg"><img src="thumbnail/dsc06977.jpg"></img></a> <a href="photo/dsc06975.jpg"><img src="thumbnail/dsc06975.jpg"></img></a> <a href="photo/dsc06968.jpg"><img src="thumbnail/dsc06968.jpg"></img></a> <a href="photo/dsc06962.jpg"><img src="thumbnail/dsc06962.jpg"></img></a> <a href="photo/dsc06954.jpg"><img src="thumbnail/dsc06954.jpg"></img></a> <a href="photo/dsc06941.jpg"><img src="thumbnail/dsc06941.jpg"></img></a> <a href="photo/dsc06932.jpg"><img src="thumbnail/dsc06932.jpg"></img></a> <a href="photo/dsc06931.jpg"><img src="thumbnail/dsc06931.jpg"></img></a> <a href="photo/dsc06929.jpg"><img src="thumbnail/dsc06929.jpg"></img></a> <a href="photo/dsc06927.jpg"><img src="thumbnail/dsc06927.jpg"></img></a> <a href="photo/dsc06923.jpg"><img src="thumbnail/dsc06923.jpg"></img></a> <a href="photo/dsc06915.jpg"><img src="thumbnail/dsc06915.jpg"></img></a> <a href="photo/dsc06908.jpg"><img src="thumbnail/dsc06908.jpg"></img></a> <a href="photo/dsc06782.jpg"><img src="thumbnail/dsc06782.jpg"></img></a> <a href="photo/dsc06781.jpg"><img src="thumbnail/dsc06781.jpg"></img></a> <a href="photo/dsc06780.jpg"><img src="thumbnail/dsc06780.jpg"></img></a> <a href="photo/dsc06711.jpg"><img src="thumbnail/dsc06711.jpg"></img></a> <a href="photo/dsc06707.jpg"><img src="thumbnail/dsc06707.jpg"></img></a> <a href="photo/dsc06704.jpg"><img src="thumbnail/dsc06704.jpg"></img></a> <a href="photo/dsc06699.jpg"><img src="thumbnail/dsc06699.jpg"></img></a> <a href="photo/dsc06692.jpg"><img src="thumbnail/dsc06692.jpg"></img></a> <a href="photo/dsc06691.jpg"><img src="thumbnail/dsc06691.jpg"></img></a> <a href="photo/dsc06448.jpg"><img src="thumbnail/dsc06448.jpg"></img></a> <a href="photo/dsc06413.jpg"><img src="thumbnail/dsc06413.jpg"></img></a> <a href="photo/dsc06398.jpg"><img src="thumbnail/dsc06398.jpg"></img></a> <a href="photo/dsc06392.jpg"><img src="thumbnail/dsc06392.jpg"></img></a> <a href="photo/dsc06385.jpg"><img src="thumbnail/dsc06385.jpg"></img></a> <a href="photo/dsc06378.jpg"><img src="thumbnail/dsc06378.jpg"></img></a> <a href="photo/dsc06377.jpg"><img src="thumbnail/dsc06377.jpg"></img></a> <a href="photo/dsc06376.jpg"><img src="thumbnail/dsc06376.jpg"></img></a> <a href="photo/dsc06375.jpg"><img src="thumbnail/dsc06375.jpg"></img></a> <a href="photo/dsc06374.jpg"><img src="thumbnail/dsc06374.jpg"></img></a> <a href="photo/dsc06373.jpg"><img src="thumbnail/dsc06373.jpg"></img></a> <a href="photo/dsc06371.jpg"><img src="thumbnail/dsc06371.jpg"></img></a> <a href="photo/dsc06368.jpg"><img src="thumbnail/dsc06368.jpg"></img></a> <a href="photo/dsc06361.jpg"><img src="thumbnail/dsc06361.jpg"></img></a> <a href="photo/dsc06359.jpg"><img src="thumbnail/dsc06359.jpg"></img></a> <a href="photo/dsc06358.jpg"><img src="thumbnail/dsc06358.jpg"></img></a> <a href="photo/dsc06357.jpg"><img src="thumbnail/dsc06357.jpg"></img></a> <a href="photo/dsc03796.jpg"><img src="thumbnail/dsc03796.jpg"></img></a> <a href="photo/dsc03690.jpg"><img src="thumbnail/dsc03690.jpg"></img></a> <a href="photo/dsc03682.jpg"><img src="thumbnail/dsc03682.jpg"></img></a> <a href="photo/dsc03647.jpg"><img src="thumbnail/dsc03647.jpg"></img></a> <a href="photo/dsc03641.jpg"><img src="thumbnail/dsc03641.jpg"></img></a> <a href="photo/dsc03640.jpg"><img src="thumbnail/dsc03640.jpg"></img></a> <a href="photo/dsc03356.jpg"><img src="thumbnail/dsc03356.jpg"></img></a> <a href="photo/dsc02924.jpg"><img src="thumbnail/dsc02924.jpg"></img></a> <a href="photo/dsc02920.jpg"><img src="thumbnail/dsc02920.jpg"></img></a> <a href="photo/dsc02915.jpg"><img src="thumbnail/dsc02915.jpg"></img></a> <a href="photo/dsc02912.jpg"><img src="thumbnail/dsc02912.jpg"></img></a> <a href="photo/dsc02909.jpg"><img src="thumbnail/dsc02909.jpg"></img></a> <a href="photo/dsc02890.jpg"><img src="thumbnail/dsc02890.jpg"></img></a> <a href="photo/dsc02889.jpg"><img src="thumbnail/dsc02889.jpg"></img></a> <a href="photo/dsc02880.jpg"><img src="thumbnail/dsc02880.jpg"></img></a> <a href="photo/dsc02879.jpg"><img src="thumbnail/dsc02879.jpg"></img></a> <a href="photo/dsc02873.jpg"><img src="thumbnail/dsc02873.jpg"></img></a> <a href="photo/dsc02871.jpg"><img src="thumbnail/dsc02871.jpg"></img></a> <a href="photo/dsc02870.jpg"><img src="thumbnail/dsc02870.jpg"></img></a> <a href="photo/dsc02869.jpg"><img src="thumbnail/dsc02869.jpg"></img></a> <a href="photo/dsc02868.jpg"><img src="thumbnail/dsc02868.jpg"></img></a> <a href="photo/dsc02866.jpg"><img src="thumbnail/dsc02866.jpg"></img></a> <a href="photo/dsc02861.jpg"><img src="thumbnail/dsc02861.jpg"></img></a> <a href="photo/dsc02860.jpg"><img src="thumbnail/dsc02860.jpg"></img></a> <a href="photo/dsc02856.jpg"><img src="thumbnail/dsc02856.jpg"></img></a> <a href="photo/dsc02851.jpg"><img src="thumbnail/dsc02851.jpg"></img></a> <a href="photo/dsc02848.jpg"><img src="thumbnail/dsc02848.jpg"></img></a> <a href="photo/dsc02847.jpg"><img src="thumbnail/dsc02847.jpg"></img></a> <a href="photo/dsc02842.jpg"><img src="thumbnail/dsc02842.jpg"></img></a> <a href="photo/dsc02839.jpg"><img src="thumbnail/dsc02839.jpg"></img></a> <a href="photo/dsc02835.jpg"><img src="thumbnail/dsc02835.jpg"></img></a> <a href="photo/dsc02833.jpg"><img src="thumbnail/dsc02833.jpg"></img></a> <a href="photo/dsc02824.jpg"><img src="thumbnail/dsc02824.jpg"></img></a> <a href="photo/dsc02823.jpg"><img src="thumbnail/dsc02823.jpg"></img></a> <a href="photo/dsc02821.jpg"><img src="thumbnail/dsc02821.jpg"></img></a> <a href="photo/dsc02808.jpg"><img src="thumbnail/dsc02808.jpg"></img></a> <a href="photo/dsc02805.jpg"><img src="thumbnail/dsc02805.jpg"></img></a> <a href="photo/dsc02788.jpg"><img src="thumbnail/dsc02788.jpg"></img></a> <a href="photo/dsc02782.jpg"><img src="thumbnail/dsc02782.jpg"></img></a> <a href="photo/dsc02741.jpg"><img src="thumbnail/dsc02741.jpg"></img></a> <a href="photo/dsc02511.jpg"><img src="thumbnail/dsc02511.jpg"></img></a> <a href="photo/dsc02444.jpg"><img src="thumbnail/dsc02444.jpg"></img></a> <a href="photo/dsc02345.jpg"><img src="thumbnail/dsc02345.jpg"></img></a> <a href="photo/dsc02330.jpg"><img src="thumbnail/dsc02330.jpg"></img></a> <a href="photo/dsc02329.jpg"><img src="thumbnail/dsc02329.jpg"></img></a> <a href="photo/dsc02328.jpg"><img src="thumbnail/dsc02328.jpg"></img></a> <a href="photo/dsc02327.jpg"><img src="thumbnail/dsc02327.jpg"></img></a> <a href="photo/dsc02323.jpg"><img src="thumbnail/dsc02323.jpg"></img></a> <a href="photo/dsc02322.jpg"><img src="thumbnail/dsc02322.jpg"></img></a> <a href="photo/dsc02321.jpg"><img src="thumbnail/dsc02321.jpg"></img></a> <a href="photo/dsc02320.jpg"><img src="thumbnail/dsc02320.jpg"></img></a> <a href="photo/dsc02318.jpg"><img src="thumbnail/dsc02318.jpg"></img></a> <a href="photo/dsc01891.jpg"><img src="thumbnail/dsc01891.jpg"></img></a> <a href="photo/dsc01885.jpg"><img src="thumbnail/dsc01885.jpg"></img></a> <a href="photo/dsc01871.jpg"><img src="thumbnail/dsc01871.jpg"></img></a> <a href="photo/dsc01673.jpg"><img src="thumbnail/dsc01673.jpg"></img></a> <a href="photo/dsc01667.jpg"><img src="thumbnail/dsc01667.jpg"></img></a> <a href="photo/dsc01556.jpg"><img src="thumbnail/dsc01556.jpg"></img></a> <a href="photo/dsc01548.jpg"><img src="thumbnail/dsc01548.jpg"></img></a> <a href="photo/dsc01541.jpg"><img src="thumbnail/dsc01541.jpg"></img></a> <a href="photo/dsc01508.jpg"><img src="thumbnail/dsc01508.jpg"></img></a> <a href="photo/dsc01493.jpg"><img src="thumbnail/dsc01493.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier poems.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#poems"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le monde est poèmes (essai n°1)</title> <underline></underline> <text>Individualisme collectif :</text> <quote>...Avant d'être vécu fus-je cristalline, eau de mère sédiment Terre, l'ère des temps m'avait con-vécu d'exister là, pour ce beau paysage simple. Mais un jour sombre, remplie de charbon, totalement souillée, la nuit s'écroulera dans mes bras, puis je tomberai las avec elle, outre-tombe, lassé du monde, des sédiments convaincu d'avoir con-vécu sans tomber jusque-las, avant qu'elle ne m'y entraîne avec les restes. Passagère, éphémère, troublée et truffée de paradoxes sous cet arbre-vie sous-nommé Terre, bientôt sous tellure d'oranger, vécu ne songera plus à la manger, la vie. Du mouvement-resté las, s'abîmera le train du rien, la machine humaine stoppera net, jusqu'à ne plus penser quiet sans être, ni tête pour panser le monde...</quote> <text>Solitude temporelle :</text> <quote>...Plongé dans le réel thermocline comme dans la baignoire du monde, écoulement propre perçu propriété émergente associative de sagacité, sans âme ni fondement de plomb comme laissé tombé au fond contre la céramique, abandonne solipsiste notre réel conscient face aux visages passés de spectres mornes pourtant bien amicaux...</quote> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectAbsoluteGyroscopeSensor.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectAbsoluteGyroscopeSensor"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le capteur gyroscopique absolu</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectBook.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectBook"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les livres de sauvegarde</title> <underline></underline> <text>À l'instar des supports de sauvegarde analogiques ou numériques, le livre peut également remplir la fonction d'archivage de données :</text> <a href="photo/dsc09034.jpg"><img src="thumbnail/dsc09034.jpg"></img></a> <a href="photo/dsc09009.jpg"><img src="thumbnail/dsc09009.jpg"></img></a> <a href="photo/dsc09002.jpg"><img src="thumbnail/dsc09002.jpg"></img></a> <a href="photo/dsc09004.jpg"><img src="thumbnail/dsc09004.jpg"></img></a> <quote>Face à l'obsolescence progressive, mais bien réelle, des systèmes analogiques et numériques dans le paysage informatique complexe actuel (multitude de technologies matérielles et logicielles plus ou moins hétérogènes), nul ne sait si un matériel de sauvegarde standard considéré de nos jours pourra encore être lu (ouvert en lecture) dans les décennies à venir, et ce malgré le soin apporté à la propagation dans le temps des normes de standardisation de l'analogique et du numérique dans leur ensemble. <br/> <br/>Le support imprimé comme le papier relié sous la forme d'un livre peut, dans de bonnes conditions de conservation, rester lisible après plusieurs siècles, voir millénaires. Contrairement aux mémoires non volatiles analogiques ou numériques qui peuvent faire office de supports de sauvegarde (rubans perforés, bandes magnétiques, mémoires à base de semi-conducteurs, etc...), la lecture du papier imprimé s'affranchit d'utiliser un matériel spécifique pour être compréhensible ou décodable, ce qui en fait un candidat relativement pérenne afin d'archiver et de transmettre des informations aux générations futures, en considération de la dépréciation et de l'évolution continue et accélérée respectivement des anciennes et des nouvelles technologies. De surcroît, la grande accessibilité du livre en lecture/écriture est fonction des caractéristiques rudimentaires propres aux techniques de l'imprimerie. La rusticité du support d'impression et de fait, son fonctionnement et sa mise en œuvre minimaliste (sans source d'énergie et dépourvu de composants complexes), participent grandement à sa relative robustesse eu égard les aléas et la sensibilité électromagnétique à l'environnement extérieur des technologies de rétention informatiques analogiques et numériques conventionnelles. <br/> <br/>C'est pourquoi je pense être utile l'existence de ce présent dispositif particulièrement dans des contextes critiques, c'est-à-dire en cas d'obsolescence des techniques informatiques dites modernes à l'échéance de périodes dépréciatives et évolutives, de crash d'un ou de plusieurs systèmes redondants à différents lieux géographiques, de suppression intentionnelle de données à l'aide des techniques de piratage sur des machines particulières ou des serveurs connectés à internet, ceci conjointement à des situations éventuelles de crises systémiques, de conflits armés de types multiples, ou plus largement d'effondrement civilisationnel favorisant la dispersion et l'élimination d'informations importantes.</quote> <caution>Le contenu de chacun de mes livres a pour origine un seul fichier PDF généré automatiquement via une routine que j'ai développé. En effet cette routine explore l'arborescence de fichiers que vous souhaitez sauvegarder, en extrait le contenu UTF-8, et compile le tout en un fichier PDF que vous pouvez directement envoyer à un imprimeur (pour plus d'informations, j'explique le procédé section "Outils divers" en page d'accueil de mon site Web, page "Création automatique du contenu d'un livre à partir d'une arborescence de fichiers").</caution> <text><bold>Les caractéristiques du livre :</bold> <br/>- Dimensions : 148mm x 210mm.</text> <a href="photo/dsc09006.jpg"><img src="thumbnail/dsc09006.jpg"></img></a> <a href="photo/dsc09016.jpg"><img src="thumbnail/dsc09016.jpg"></img></a> <title>Quelques contraintes techniques :</title> <underline></underline> <text>Il existe à ce choix technique de l'imprimerie une contrainte assez importante d'encombrement. En effet pour comparaison des volumes informatiques, la page d'un livre au format A5 comme l'ouvrage présentement exposé, peut contenir en moyenne <bold>1Kio</bold> de données initialement numériques (soit 1024 octets). En considération de cette volumétrique, si nous souhaitons stocker dans un tel livre un fichier de <bold>1Mio</bold> (soit 1.048576 million d'octets), la somme considérable de <bold>1024 pages</bold> est tout de même nécessaire, ce qui pour exemple, équivaut seulement à l'espace mémoire occupé par une petite photographie numérique en faible résolution !</text> <text>Toute raison garder, l'impression directe des pixels de ladite image sur une unique page de ce livre est dans ce cas nettement plus approprié, même si fondamentalement ce procédé technique comporte lui aussi des défauts d'un autre ordre, notamment d'exactitude lors de la restitution des données initiales (la reproduction photographique étant vouée à perdre de l'information du fait de la relative imprécision des couleurs et du support utilisé).</text> <text>En revanche, pour les faibles volumes numériques comme le sont généralement les fichiers de programmes dans lesquels on trouve du texte brut, la rétention d'information par le procédé d'impression sur des supports composés de papier semble être une alternative raisonnable par rapport aux autres technologies.</text> <caution>Ceci, sans néanmoins être naïf sur la relative fragilité du support imprimé constitué de papier, ainsi que du possible travail laborieux que représente la réintégration du contenu d'un livre dans une machine analogique ou numérique (ce qui semble être une contrainte minimale en proportion de ce que représente la perte définitive d'informations importantes).</caution> <text>Éventuellement, et selon la durée de conservation par rapport à l'évolution des techniques dans le futur, une translation des langages d'écriture utilisés pourra être nécessaire afin de comprendre la logique et les algorithmes mis en œuvre dans les fichiers archivés (mais il faut observer que ceci est commun à n'importe quelle technique de conservation puisque dépendant des langages, de la logique, de l'interprétation qu'on en fait, soit indépendante du support).</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectBug.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectBug"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le bogue</title> <underline></underline> <text>Cet insecte ("bug" en anglais) sort tout droit de mon atelier déganté, créé à partir d'un <bold>microcontrôleur Atmega328P</bold> et d'un tas de composants divers recyclés de mes essais et autres prototypes obsolètes :</text> <quote>Résistance de tirage, quartz pour la cadence du microcontrôleur, condensateurs de découplage, dels pour les yeux, buzzer pour les bruits, grosses diodes pour les pattes avant, alimentation par une pile bouton Lithium-dioxyde de manganèse (LiMnO2) +3V 220mAh, inductances qui ne servent à rien mis à part récupérer des parasites venant du buzzer, etc...</quote> <a href="photo/dsc07941.jpg"><img src="thumbnail/dsc07941.jpg"></img></a> <a href="photo/dsc07952.jpg"><img src="thumbnail/dsc07952.jpg"></img></a> <text>Ce petit animal est programmé avec MODULE, il se contente aléatoirement d'émettre des sonorités ainsi que de faire clignoter ses yeux d'une façon proportionnelle via des signaux PWM.</text> <text><bold>Programmation du microcontrôleur Atmega328P avec MODULE :</bold> <br/>Le programme en langage C++ fonctionnant avec MODULE est téléchargeable ici :</text> <a href="download/cpp/bug.zip"><download>Télécharger le programme du <bold>bogue</bold> (.zip, ≈ 1Kio)</download></a> <a href="photo/dsc08221.jpg"><img src="thumbnail/dsc08221.jpg"></img></a> <a href="photo/dsc07932.jpg"><img src="thumbnail/dsc07932.jpg"></img></a> <text><bold>Connexions (microcontrôleur Atmega328P sur les différents systèmes embarqués) :</bold></text> <caution>- Broche PD0 sur anode del 5mm (œil principal gauche). <br/>- Broche PD1 sur anode del 3mm (œil secondaire gauche). <br/>- Broche PB1 sur cathode buzzer (émission de sonorités). <br/>- Broche PC3 sur anode del 3mm (œil secondaire droit). <br/>- Broche PC4 sur anode del 5mm (œil principal droit).</caution> <video src="video/00007.mov" controls></video> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectBuzzer.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectBuzzer"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le buzzer piloté</title> <underline></underline> <text>Cette carte permet via un signal périodique de piloter un <bold>buzzer piézoélectrique ou magnétique</bold> (sans oscillateur intégré au boîtier) :</text> <a href="photo/dsc08001.jpg"><img src="thumbnail/dsc08001.jpg"></img></a> <a href="photo/dsc08199.jpg"><img src="thumbnail/dsc08199.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/buzzer.zip"><download>Télécharger le plan de fabrication du <bold>buzzer</bold> piloté (.zip, 389 octets)</download></a> <text>Un simple buzzer demandant un courant de seulement <bold>35mA</bold> maximum (comme ceux que j'utilise dans mes montages), peut être alimenté sans risques directement sur les broches d'un microcontrôleur, ce qui conviendra à bon nombre d'applications. Mais il est plus propre de dédier une petite carte qui <bold>filtrera quelques parasites</bold>, via un <bold>transistor de puissance</bold> pilotera le buzzer et par la même occasion <bold>protégera</bold> ce dernier à l'aide d'une diode.</text> <text><bold>Connexions (buzzer piloté sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche WAVE (onde) sur port GPIO générant un signal périodique.</caution> <quote>À noter que la disposition des broches de cette carte correspond aux ports partie commande et partie puissance de mes automates programmables (GND, +5V, GPIO). Vous pouvez donc connecter cette carte à mes automates programmables directement avec une nappe de 3 fils adaptée.</quote> <a href="photo/dsc08129.jpg"><img src="thumbnail/dsc08129.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 1 broche GND (masse) pour l'alimentation. <br/>- 1 broche +5V (pôle positif) pour l'alimentation. <br/>- 1 broche WAVE (onde) pour l'entrée d'un signal périodique. <br/>- Dimensions : 26.67mm x 22.86mm. <br/>- Entre-axes de fixations : 19.05mm x 15.24mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Buzzer magnétique CEM-1203(42) (diamètre 12mm, hauteur 8.5mm, pas 6.5mm) <br/>1x Résistance 1kΩ ± 1% 250mW <br/>1x Résistance 10kΩ ± 1% 250mW <br/>1x Condensateur céramique 100nF >=10V (pas 5.08mm) <br/>1x Diode Schottky 1N5817 <br/>1x Transistor bipolaire 2N3904 (boîtier TO-92) <br/>3x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08000.jpg"><img src="thumbnail/dsc08000.jpg"></img></a> <a href="photo/dsc08194.jpg"><img src="thumbnail/dsc08194.jpg"></img></a> <text>Le buzzer indiqué dans la liste des composants dispose d'une <bold>fréquence de résonance de 2048Hz</bold>. Ceci est intéressant parce qu'il est alors possible de loger dans des boîtiers tout à fait hermétiques et exigus ce buzzer, mais de néanmoins l'entendre assez fort en lui appliquant un <bold>signal périodique carré d'une fréquence de 2048Hz</bold> ce qui le fait rentrer en résonance, et donc amplifie grandement la pression acoustique.</text> <caution>En résonance à 2048Hz, la pression acoustique de ce buzzer <bold>dépasse 85dB</bold>, il est important alors de se protéger avec un équipement de protection individuel adapté (bouchons d'oreilles, casque anti-bruit) afin de ne pas mettre en danger votre oreille interne. Je ne pourrais être tenu pour responsable si vous faites une mauvaise utilisation de cette carte électronique !</caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectCard.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectCard"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La carte de visite</title> <underline></underline> <text>Pour promouvoir un site Web, il est généralement approprié de communiquer des cartes de visite aux personnes susceptibles d'être intéressés par vos produits.</text> <a href="photo/dsc07965.jpg"><img src="thumbnail/dsc07965.jpg"></img></a> <a href="photo/dsc08202.jpg"><img src="thumbnail/dsc08202.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/card.zip"><download>Télécharger le plan de fabrication de la <bold>carte de visite</bold> (.zip, 385 octets)</download></a> <text>Pour être efficace, votre carte de visite doit au premier regard <bold>être représentatif de ce que vous proposez</bold> (produits, services, etc...), être <bold>simple</bold>, bien <bold>lisible</bold> et <bold>compréhensible</bold>, et avoir une certaine <bold>originalité</bold>, c'est-à-dire se distinguer d'autres cartes de visite pour ainsi éviter de finir à la poubelle dans les plus brefs délais !</text> <quote>La carte de visite de mon site Web que je propose ici est un réel circuit électronique fonctionnel, en effet il est équipé du mythique <bold>NE555</bold>, un oscillateur qui dans ce cas présent, alimenté en +5V, génère un signal périodique d'une fréquence très proche de 2048Hz (selon la précision des composants utilisés).</quote> <text>Cette fonction d'oscillation de ce circuit est un peu le reflet de ce qu'est le numérique en général dans mes montages, en l'occurrence la transformation d'une alimentation analogique en un signal à 2 états distincts (binaire) à une fréquence bien définie.</text> <a href="photo/dsc08204.jpg"><img src="thumbnail/dsc08204.jpg"></img></a> <text>Un code matriciel (QR Code) situé au dos de la carte permet via un scan avec un smartphone, de se rendre sur mon site Web :</text> <caution>Ce motif est généré sous la forme d'une image bitmap (.bmp) à l'aide d'un logiciel spécifique, puis est transformé en coordonnées de points sur le calque de sérigraphie de mon logiciel de dessin de circuits électroniques en vue PCB via une routine que j'ai développé (pour plus d'informations, j'explique le procédé section "Outils divers" en page d'accueil de mon site Web, page "Conversion d'images bitmap vers une sérigraphie KiCad").</caution> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 1 connecteur à braser GND (masse) pour l'alimentation. <br/>- 1 connecteur à braser +5V (pôle positif) pour l'alimentation. <br/>- 1 connecteur à braser OUTPUT (sortie) pour récupérer le signal périodique. <br/>- Dimensions : 85.725mm x 53.975mm. <br/>- Fixation par sangle standard (perçage oblong).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Oscillateur NE555 (boîtier DIP-8) <br/>1x Résistance 1kΩ ± 1% 250mW <br/>1x Résistance 10kΩ ± 1% 250mW <br/>1x Condensateur céramique 33nF >=10V (pas 5.08mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc07957.jpg"><img src="thumbnail/dsc07957.jpg"></img></a> <a href="photo/dsc07958.jpg"><img src="thumbnail/dsc07958.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>Les résistances <bold>1kΩ</bold> et <bold>10kΩ</bold> doivent être brasées avant de mettre en place l'oscillateur <bold>NE555</bold>, en effet ce dernier masquerait les broches des résistances rendant leur brasure impossible :</text> <a href="photo/dsc07960.jpg"><img src="thumbnail/dsc07960.jpg"></img></a> <a href="photo/dsc07961.jpg"><img src="thumbnail/dsc07961.jpg"></img></a> <text>Cet ordre de montage respecté, l'assemblage se finalise normalement.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectComputerInterface.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectComputerInterface"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'interface de communication RS232</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectDigitDisplay.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectDigitDisplay"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'afficheur à digits</title> <underline></underline> <text><bold>L'afficheur à diodes électroluminescences</bold> est le compagnon idéal de l'automate programmable parce qu'il permet de créer une interface visuelle entre l'utilisateur et la machine :</text> <a href="photo/dsc08174.jpg"><img src="thumbnail/dsc08174.jpg"></img></a> <a href="photo/dsc08171.jpg"><img src="thumbnail/dsc08171.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/digit_display.zip"><download>Télécharger le plan de fabrication de <bold>l'afficheur à digits</bold> (.zip, 403 octets)</download></a> <text>Cet afficheur est très utile pour réaliser des projets demandant un <bold>retour d'informations visuelles</bold> de la par de l'automate programmable. Il est équipé du très populaire <bold>MAX7219</bold>, un composant qui communique en <bold>SPI</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text><bold>Connexions (afficheur à digits sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur port SS ou tout autre port d'entrée/sortie disponible (sauf MISO qui doit rester libre sauf si il est déjà utilisé par un autre périphérique également SPI). <br/>- Broche MOSI (master output slave input) sur port MOSI. <br/>- Broche SCK (serial clock) sur port SCK.</caution> <text><bold>Connexions (afficheur en cascade sur autre afficheur) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur broche SS disponible. <br/>- Broche MISO (master input slave output) sur broche MOSI. <br/>- Broche SCK (serial clock) sur broche SCK disponible.</caution> <a href="photo/dsc08032.jpg"><img src="thumbnail/dsc08032.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 2 broches GND (masse) pour l'alimentation. <br/>- 2 broches +5V (pôle positif) pour l'alimentation. <br/>- 2 broches SS (slave select) pour la communication SPI. <br/>- 1 broche MOSI (master output slave input) pour la communication SPI. <br/>- 1 broche MISO (master input slave output) pour la communication SPI. <br/>- 2 broches SCK (serial clock) pour la communication SPI. <br/>- Branchements en cascade. <br/>- 8 digits pour l'affichage des caractères. <br/>- Dimensions : 116.84mm x 21.59mm. <br/>- Entre-axes de fixations : 109.22mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Contrôleur d'affichage MAX7219 (boîtier DIP-24) <br/>8x Afficheurs à digits SC56-11 (couleur de votre choix) <br/>1x Résistance 9.53kΩ ± 1% 250mW <br/>1x Condensateur céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=10V (pas 2mm) <br/>1x Support DIP-24 300mil <br/>10x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08162.jpg"><img src="thumbnail/dsc08162.jpg"></img></a> <a href="photo/dsc08160.jpg"><img src="thumbnail/dsc08160.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>Les afficheurs à digits <bold>SC56-11</bold> doivent être brasés en dernier, en effet ils masquent les broches des autres composants sur la face opposée du PCB, rendant dans le cas contraire leur brasure impossible :</text> <a href="photo/dsc08164.jpg"><img src="thumbnail/dsc08164.jpg"></img></a> <a href="photo/dsc08163.jpg"><img src="thumbnail/dsc08163.jpg"></img></a> <text>Cet ordre de montage respecté, il est ensuite conseillé d'écourter toutes les broches des composants avec une pince coupante adaptée, ceci permettant d'éviter un éventuel <bold>défaut de planéité des afficheurs sur le PCB</bold> (dans le cas ou un afficheur toucherait les broches traversantes d'un autre composant).</text> <a href="photo/dsc08165.jpg"><img src="thumbnail/dsc08165.jpg"></img></a> <a href="photo/dsc08166.jpg"><img src="thumbnail/dsc08166.jpg"></img></a> <a href="photo/dsc08170.jpg"><img src="thumbnail/dsc08170.jpg"></img></a> <a href="photo/dsc08184.jpg"><img src="thumbnail/dsc08184.jpg"></img></a> <text>Une fois ces opérations effectuées, le montage se finalise normalement.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectDigitDisplayMini.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectDigitDisplayMini"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le mini afficheur à digits</title> <underline></underline> <text>Cet afficheur à diodes électroluminescences est ici en <bold>version compacte</bold>, équipé d'un affichage composé d'éléments SC36-11 plus petits que les SC56-11 :</text> <a href="photo/dsc08134.jpg"><img src="thumbnail/dsc08134.jpg"></img></a> <a href="photo/dsc08021.jpg"><img src="thumbnail/dsc08021.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/digit_display_mini.zip"><download>Télécharger le plan de fabrication du <bold>mini afficheur à digits</bold> (.zip, 413 octets)</download></a> <text>Cet afficheur de part ses faibles dimensions, permet l'élaboration de systèmes embarqués compacts et maniables (appareils de mesures, instruments divers, etc...).</text> <a href="photo/dsc08276.jpg"><img src="thumbnail/dsc08276.jpg"></img></a> <a href="photo/dsc08303.jpg"><img src="thumbnail/dsc08303.jpg"></img></a> <text>Comme mes autres afficheurs, ce présent système d'affichage multiplexé fonctionne à l'aide du composant <bold>MAX7219</bold>, et communique en <bold>SPI</bold> avec le microcontrôleur.</text> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text><bold>Connexions (mini afficheur à digits sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur port SS ou tout autre port d'entrée/sortie disponible (sauf MISO qui doit rester libre sauf si il est déjà utilisé par un autre périphérique également SPI). <br/>- Broche MOSI (master output slave input) sur port MOSI. <br/>- Broche SCK (serial clock) sur port SCK.</caution> <text><bold>Connexions (afficheur en cascade sur autre afficheur) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur broche SS disponible. <br/>- Broche MISO (master input slave output) sur broche MOSI. <br/>- Broche SCK (serial clock) sur broche SCK disponible.</caution> <a href="photo/dsc08032.jpg"><img src="thumbnail/dsc08032.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 2 broches GND (masse) pour l'alimentation. <br/>- 2 broches +5V (pôle positif) pour l'alimentation. <br/>- 2 broches SS (slave select) pour la communication SPI. <br/>- 1 broche MOSI (master output slave input) pour la communication SPI. <br/>- 1 broche MISO (master input slave output) pour la communication SPI. <br/>- 2 broches SCK (serial clock) pour la communication SPI. <br/>- Branchements en cascade. <br/>- 8 digits pour l'affichage des caractères. <br/>- Dimensions (face avant) : 76.2mm x 21.59mm. <br/>- Dimensions (face arrière) : 55.88mm x 21.59mm. <br/>- Entre-axes de fixations : 68.58mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Contrôleur d'affichage MAX7219 (boîtier DIP-24) <br/>8x Afficheurs à digits SC36-11 (couleur de votre choix) <br/>1x Résistance 9.53kΩ ± 1% 250mW <br/>1x Condensateur céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=10V (pas 2mm) <br/>1x Support DIP-24 300mil <br/>26x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08004.jpg"><img src="thumbnail/dsc08004.jpg"></img></a> <a href="photo/dsc08006.jpg"><img src="thumbnail/dsc08006.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>Cette carte est <bold>composée de deux parties distinctes</bold> qu'il convient de finaliser indépendament avant de les assembler l'une avec l'autre. La première partie permet la fixation des blocs d'affichage à digits SC36-11, la deuxième partie loge les autres composants (le circuit intégré, son support, une résistance, deux condensateurs, les broches de fixation des deux PCB, ainsi que les broches de l'interface de communication et d'alimentation) :</text> <a href="photo/dsc08016.jpg"><img src="thumbnail/dsc08016.jpg"></img></a> <a href="photo/dsc08018.jpg"><img src="thumbnail/dsc08018.jpg"></img></a> <text>En premier lieu, il est conseillé de braser les broches de fixation sur le PCB équipé des blocs d'affichage à digits SC36-11, et à posteriori de positionner et braser ces derniers sur l'autre face du PCB. Ensuite, je recommande de <bold>couper au plus court les broches des blocs SC36-11</bold> qui dépassent afin d'éviter par la suite qu'elles ne viennent toucher (et court-circuiter par la même occasion) le circuit contenant tous les autres composants de cet assemblage.</text> <a href="photo/dsc08008.jpg"><img src="thumbnail/dsc08008.jpg"></img></a> <a href="photo/dsc08009.jpg"><img src="thumbnail/dsc08009.jpg"></img></a> <a href="photo/dsc08010.jpg"><img src="thumbnail/dsc08010.jpg"></img></a> <a href="photo/dsc08011.jpg"><img src="thumbnail/dsc08011.jpg"></img></a> <text>Après quoi il est nécessaire d'assembler entièrement et indépendamment la deuxième partie contenant tous les autres composants, <bold>avant de la positionner en sandwich sur la première partie</bold>. Dans le cas contraire d'un assemblage final avant d'avoir encore brasé tous les composants, il serait alors fort délicat de venir les braser correctement (les broches traversantes se trouvant plus ou moins masquées).</text> <a href="photo/dsc08019.jpg"><img src="thumbnail/dsc08019.jpg"></img></a> <a href="photo/dsc08020.jpg"><img src="thumbnail/dsc08020.jpg"></img></a> <text>Une fois dans la situation de la photo de droite ci-dessus, il ne reste plus qu'à superposer les deux parties, et les solidariser entres-elles. À noter que les broches de fixation servent à la fois pour le multiplexage, et pour la solidité de l'ensemble.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectEnvironmentSensor.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectEnvironmentSensor"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le capteur environnemental</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectExternalMemory.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectExternalMemory"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La mémoire externe de 1Mio</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectGeigerMullerBoostConverter.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectGeigerMullerBoostConverter"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'élévateur de tension +400V pour tube Geiger-Müller</title> <underline></underline> <text>Le tube d'un <bold>compteur Geiger-Müller</bold> est une chambre d'ionisation qui a besoin d'être alimentée avec une différence de potentielle entre son anode et sa cathode suffisamment élevée afin de détecter des particules issues de la désintégration d'isotopes radioactifs.</text> <a href="photo/dsc08055.jpg"><img src="thumbnail/dsc08055.jpg"></img></a> <a href="photo/dsc08056.jpg"><img src="thumbnail/dsc08056.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/geiger_muller_boost_converter.zip"><download>Télécharger le plan de fabrication de <bold>l'élévateur de tension +400V</bold> pour tube Geiger-Müller (.zip, 435 octets)</download></a> <text>Cette élévation de tension est obtenue à l'aide d'un montage qui dans son principe de fonctionnement est assez simple : <br/>- Charge d'une inductance. <br/>- Décharge de l'inductance dans un condensateur en passant par une diode de redressement. <br/>- Charge du condensateur. <br/>- Alimentation du tube Geiger-Müller via le condensateur.</text> <text>C'est au moment ou l'inductance n'est plus alimentée (via un découpage du courant à une fréquence fixe) que celle-ci produit une surtension, cet excédant de tension charge un condensateur adapté.</text> <a href="photo/dsc08060.jpg"><img src="thumbnail/dsc08060.jpg"></img></a> <text>Cette carte électronique permet donc d'élever la tension d'alimentation de <bold>+5V</bold> (délivrée par mes automates programmables) à <bold>+400V</bold>, elle détecte également la <bold>fermeture du tube Geiger-Müller</bold> (ci-dessous le prototype connecté sur le tube Geiger-Müller SBM20 de conception Russe) :</text> <a href="photo/dsc02511.jpg"><img src="thumbnail/dsc02511.jpg"></img></a> <text><bold>Connexions (élévateur de tension +400V sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SHOCK (coups) sur port GPIO relié à l'interruption externe (INT0, INT1, etc...) pour détecter la fermeture du tube Geiger-Müller.</caution> <text><bold>Connexions (tube Geiger-Müller sur élévateur de tension +400V) :</bold></text> <caution>- Anode du tube Geiger-Müller sur connecteur à braser GEIGER-MULLER TUBE +400V (pôle positif). <br/>- Cathode du tube Geiger-Müller sur connecteur à braser GEIGER-MULLER TUBE GND (masse).</caution> <a href="photo/dsc08216.jpg"><img src="thumbnail/dsc08216.jpg"></img></a> <a href="photo/dsc08217.jpg"><img src="thumbnail/dsc08217.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 1 broche GND (masse) pour l'alimentation. <br/>- 1 broche +5V (pôle positif) pour l'alimentation. <br/>- 1 broche SHOCK (coups) pour détecter la fermeture du tube Geiger-Müller (0V = fermé, +5V = ouvert). <br/>- 1 connecteur à braser GEIGER-MULLER TUBE GND (masse) pour alimenter un tube Geiger-Müller. <br/>- 1 connecteur à braser GEIGER-MULLER TUBE +400V (pôle positif) pour alimenter un tube Geiger-Müller. <br/>- Dimensions : 53.975mm x 25.4mm. <br/>- Entre-axes de fixations : 46.355mm x 17.78mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Oscillateur NE555 (boîtier DIP-8) <br/>3x Résistances 1kΩ ± 1% 250mW <br/>1x Résistance 2kΩ ± 1% 250mW <br/>4x Résistances 10kΩ ± 1% 250mW <br/>1x Résistance 10MΩ ± 1% 250mW <br/>1x Condensateur céramique 100pF >=800V (pas 5.08mm) <br/>1x Condensateur céramique 4.7nF >=800V (pas 5.08mm) <br/>1x Condensateur céramique 33nF >=10V (pas 5.08mm) <br/>3x Condensateurs céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=10V (pas 2mm) <br/>1x Inductance self 15mH 100mA (pas 5.08mm, boîtier radial) <br/>1x Diode 1N4007 <br/>1x Transistor bipolaire 2N3904 (boîtier TO-92) <br/>1x Transistor bipolaire MPSA44 (boîtier TO-92) <br/>1x Support DIP-8 300mil <br/>3x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08053.jpg"><img src="thumbnail/dsc08053.jpg"></img></a> <a href="photo/dsc08052.jpg"><img src="thumbnail/dsc08052.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectGeigerMullerCounter.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectGeigerMullerCounter"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le compteur Geiger-Müller</title> <underline></underline> <text>Le <bold>compteur Geiger-Müller</bold> est un projet élaboré en concordance avec ma curiosité pour la physique nucléaire et pour l'instrumentation scientifique en général :</text> <a href="photo/dsc02873.jpg"><img src="thumbnail/dsc02873.jpg"></img></a> <a href="photo/dsc02833.jpg"><img src="thumbnail/dsc02833.jpg"></img></a> <text>Si nous voulons en apprendre davantage sur les atomes, nous devons nous intéresser à la physique nucléaire. Comprendre en ce terme "nucléaire", les <bold>nucléons</bold> (protons et neutrons), c'est-à-dire les constituants du noyau des atomes.</text> <text><bold>Antériorité du projet de compteur Geiger-Müller :</bold> <br/>À l'époque ou j'ai commencé à m'intéresser à la radioactivité (années 1990 suite à l'accident de Tchernobyl), ce type d'appareil de détection me semblait infaisable par un amateur, et en l'occurrence se trouvait être (et est toujours aujourd'hui) très onéreux dans le commerce.</text> <text>Bien plus tard je débute l'électronique, précisément dans l'objectif de comprendre comment réaliser cet instrument, ainsi au fil de mon apprentissage et de persévérance, cela m'est apparut comme tout à fait réalisable, d'où cette présentation du projet finalisé.</text> <a href="photo/dsc06707.jpg"><img src="thumbnail/dsc06707.jpg"></img></a> <text><bold>Les caractéristiques du compteur Geiger-Müller :</bold> <br/>- Automate programmable MODULABLE 20 équipé du microcontrôleur ATmega328P. <br/>- Élévateur de tension à découpage (+5V vers +400V). <br/>- Tube de détection LND712 (détection des Alphas, Betas, Gammas, et rayonnement X). <br/>- Affichage digital avec mini afficheurs à digits. <br/>- Affichage analogique à l'aide d'un galvanomètre et d'une del. <br/>- Buzzer de signalement. <br/>- Bouton rotatif de sélection des modes. <br/>- Interrupteurs de visualisation des coups / seconde et doses maximales relevées. <br/>- Interrupteur d'allumage (on/off). <br/>- Accumulateur nickel-hydrure métallique (NiMH) 10S (+12V) 600mAh. <br/>- Alarme niveau de batterie faible (en dessous de +6V). <br/>- Boîtier ouvert en aluminium, acier inoxydable, cuivre, laiton, et ertalon.</text> <text><bold>L'affichage permet de visualiser plusieurs unités :</bold></text> <quote>- Le cumule des coups. <br/>- Les coups / seconde instantanés. <br/>- Les coups / seconde maximums relevés. <br/>- La dose cumulée au cours du temps. <br/>- La dose instantanée. <br/>- La dose maximale relevée.</quote> <a href="photo/dsc02880.jpg"><img src="thumbnail/dsc02880.jpg"></img></a> <a href="photo/dsc02890.jpg"><img src="thumbnail/dsc02890.jpg"></img></a> <video src="video/00005.mov" controls></video> <text>La dose affichée par mon appareil est le rapport (coefficient sans unité) à la radioactivité naturelle. À ne pas confondre avec le débit de dose (comme la plupart des radiamètres du commerce) qui serait exprimé en Sievert par unité de temps :</text> <caution>Il est important de préciser qu'un compteur Geiger-Müller est un ictomètre, autrement-dit seulement un <bold>compteur de coups</bold>. Un compteur Geiger-Müller ne peut pas estimer le débit de dose comme on le constate souvent sur les appareils du commerce grand public, ces appareils ne peuvent qu'effectuer une approximation qui de fait, est fausse, c'est-à-dire sous-évaluée ou surévaluée.</caution> <title>Qu'est-ce que la radioactivité ?</title> <underline></underline> <text>La radioactivité est la conséquence et la manifestation de <bold>l'instabilité du noyau des atomes</bold> qui composent la matière qui nous entoure et qui nous constitue.</text> <text>Cet état instable peut avoir plusieurs causes au niveau atomique : <br/>- Le noyau de l'atome a un excédant de neutrons (par rapport à la vallée de stabilité). <br/>- Le noyau de l'atome se réorganise (un neutron devient un proton). <br/>- Le noyau de l'atome est excité, il possède un excédant d'énergie (qu'il doit libérer).</text> <text>Dans tous les cas, l'atome souhaite retrouver un état plus stable.</text> <text><bold>Cette radioactivité se manifeste sous plusieurs formes :</bold></text> <caution>- <bold>Alpha</bold> (α) : 2 protons + 2 neutrons (4 nucléons) sont éjectés du noyau, c'est l'helium 4. <br/>- <bold>Beta-</bold> (β-) : 1 neutron (1 quark up + 2 quarks down) devient 1 proton (2 quarks up + 1 quark down), ceci est accompagné de l'émission d'1 électron + 1 anti-neutrino. <br/>- <bold>Beta+</bold> (β+) : 1 proton (2 quarks up + 1 quark down) devient 1 neutron (1 quark up + 2 quarks down), ceci est accompagné de l'émission d'1 positon + 1 neutrino. <br/>- <bold>Gamma</bold> (γ) : résultat de la collision d'1 particule avec son anti-particule, 1 ou plusieurs photons (rayonnement de nature électro-magnétique) peuvent êtres libérés de l'atome du fait de sa désexcitation. La fréquence vibratoire de cette onde est supérieure à 30 exahertz (30000000000000000000 hertz). <br/>- <bold>X</bold> : 1 électron passe d'un niveau d'énergie à un autre, ce qui s'accompagne d'une émission (photon) de même nature que le rayonnement Gamma mais de fréquence vibratoire inférieure (de 30 petahertz à 30 exahertz).</caution> <text>Ces émissions se comportent différemment selon le matériau traversé :</text> <quote>- <bold>l'Alpha</bold> est arrêté au contact d'une feuille de papier. <br/>- Le <bold>Beta</bold> est arrêté au contact d'une tôle d'aluminium. <br/>- Le <bold>Gamma</bold> est atténué en traversant plusieurs mètres de béton ou plusieurs centimètres de plomb, mais n'est pas arrêté.</quote> <text><bold>Quantifier la radioactivité :</bold> <br/>Plusieurs unités de mesure standards (ou dérivées du système standard) existent et permettent de quantifier le niveau de radioactivité et la dose reçue. Chaque unité est à placer dans un contexte précis de mesures par rapport aux conditions et à l'environnement associé, ceci afin d'éviter de fausses interprétations des résultats.</text> <text>Plusieurs paramètres interviennent pour quantifier la radioactivité : <br/>- <bold>La nature de l'émission</bold> (Alpha, Beta, Gamma, X). <br/>- <bold>La distance</bold> (à 1 cm, à 1 mètre, etc...). <br/>- <bold>La durée d'exposition</bold> (1 seconde, 1 heure, etc...). <br/>- <bold>Les parties du corps exposées au rayonnement</bold> (les effets seront bien différents selon la zone exposée). <br/>- <bold>La sensibilité du matériel utilisé</bold> pour effectuer les mesures.</text> <text>Voici une liste de quelques unités de mesure :</text> <quote>- Le <bold>Sievert</bold> (Sv) : établi une estimation de l'impact biologique de la radioactivité sur le corps humain (par unité de temps en heures ou en années). <br/>- Le <bold>Becquerel</bold> (Bq) : est l'activité d'un radio-nucléide. Souvent indiqué par kilogramme de matière, 1 Becquerel signifie 1 désintégration d'atome / seconde. <br/>- Le <bold>coup / seconde</bold> (Cps) : de même nature que le Becquerel mais sans quantification de la quantité de matière. <br/>- Le <bold>Gray</bold> (Gy) : représente l'énergie (en Joules) apportée à une masse homogène d'1kg.</quote> <text>La dose reçue liée à la radioactivité naturelle en France est en moyenne de <bold>1 millisievert / an par habitant</bold>. Pour les travailleurs du secteur du nucléaire en France, la dose maximale admissible est de <bold>20 millisievert sur 12 mois glissants par personne</bold>. Les risques de maladies et de cancers commencent à apparaître à partir de <bold>100 millisievert</bold> (pas forcément lié à une unité de temps cette fois-ci), mais d'une façon plus générale, toute dose ajoutée à la radioactivité naturelle est susceptible d'augmenter les risques de développer une pathologie (on parle alors des risques liés aux faibles doses d'exposition).</text> <text>Quelques notions sur les grandeurs physiques :</text> <caution>- 0.1 microsievert / heure par habitant est environ égal à 1 millisievert / an par habitant. <br/>- En règle générale (cela dépend de la zone du corps exposée), 1 Gray est égal à 1 Sievert (unités de même dimension). <br/>- 1 Joule est égal à 1 Watt / seconde.</caution> <text>Ces mesures sont déterminés par l'intermédiaire du <bold>tube Geiger-Müller</bold>, qui est <bold>l'élément sensitif</bold> d'un détecteur de radioactivité. Le tube Geiger-Müller est un dipôle (cathode + anode) qui, rempli d'un gaz inerte à basse pression (généralement le néon) et soumis à une différence de potentielle élevée (une tension électrique élevée), est ainsi placé dans un état de métastabilité.</text> <text>Le tube Geiger-Müller est une chambre d'ionisation. Il suffit donc d'une particule le traversant (électron, positon, proton, neutron, ou photon) pour <bold>ioniser le gaz</bold> qu'il contient (les atomes perdent ou gagnent des électrons), se qui a pour conséquence de créer une avalanche d'électrons se déplaçant de la cathode vers l'anode. Le tube est alors en saturation (le dipôle est fermé, comme un interrupteur), c'est le coup (quantifié ensuite en coups / seconde).</text> <text>Ci-dessous, un exemple de détection de la radioactivité naturelle avec le tube Geiger-Müller <bold>LND712</bold> (le relevé indique 0.45 coups / seconde) :</text> <a href="photo/dsc02912.jpg"><img src="thumbnail/dsc02912.jpg"></img></a> <a href="photo/dsc02915.jpg"><img src="thumbnail/dsc02915.jpg"></img></a> <text>La radioactivité naturelle (aussi appelée bruit de fond) a toujours été présente sur la planète Terre, elle fait partie intégrante de la croûte terrestre, de l'atmosphère, des océans, et du vivant.</text> <quote>Au cours de l'histoire et de l'évolution de la Terre, des réacteurs naturels ont existé bien avant l'apparition de l'homme. On en trouve des traces (vitrification des roches au voisinage de minerai d'uranium) au Gabon, à la mine d'uranium d'Oklo.</quote> <title>Une histoire d'isotopes et de descendants :</title> <underline></underline> <text><bold>Les isotopes radioactifs :</bold> <br/>Un isotope est un atome ayant un nombre différent de neutrons. De fait, <bold>l'uranium 236</bold> est un isotope plus lourd (il a 1 neutron de plus) que <bold>l'uranium 235</bold>.</text> <text>En revanche, un atome n'est pas un isotope d'un autre atome ayant un nombre différent de protons (comme le cesium 55 n'est pas un isotope du xénon 54), ce sont bien deux éléments chimiques différents.</text> <text>Cette opération de transformation d'un élément chimique en un autre élément chimique s'appelle la <bold>transmutation</bold>.</text> <quote>Le corps humain est constitué de potassium 40, un isotope radioactif !</quote> <text>Le potassium 40 (19 protons + 21 neutrons) est instable, il se désintègre par <bold>radioactivité Beta-</bold> dans 88.8% des cas en calcium 40 (20 protons + 20 neutrons), un élément chimique stable.</text> <text>Un isotope radioactif (instable donc) ne se désintègre pas forcément d'une seule manière, dans un certain nombre de cas (exemple ci-dessus : 88.8% des cas) cela peut être via <bold>radioactivité Alpha</bold>, dans d'autres cas par <bold>Beta-</bold> ou <bold>Beta+</bold>, ceci est variable selon l'isotope et la situation.</text> <text>Dans la plupart des cas <bold>l'uranium 236</bold> fissionne, mais dans un autre pourcentage de cas il se désintègre par radioactivité Alpha en <bold>thorium 232</bold>, et dans un certain nombre (faible) de cas à l'aide d'un bombardement intense de neutrons qu'il capture, il se transforme en uranium 237, puis par radioactivité Beta- devient du <bold>neptunium 237</bold>.</text> <text><bold>La désintégration d'un atome peut être spontanée :</bold> <br/>Un matériau constitué d'isotopes radioactifs perds la moitié de sa radioactivité durant une période radioactive, puis une autre moitié durant une autre période radioactive, et ainsi de suite, de sorte que la décroissance radioactive d'un matériau suit une courbe exponentielle. Ce temps est dépendant de l'isotope considéré, en effet plus il est instable, plus sa période radioactive est courte, et plus ses émissions radioactives sont fortes.</text> <text>Il n'est pas possible de prédire la désintégration d'un seul atome, ce phénomène peut intervenir à n'importe quel moment (aléatoire), par contre il est possible de prédire la désintégration de la moitié d'un groupe d'atomes :</text> <quote>1kg d'uranium 235 perds la moitié de sa radioactivité (ou de sa masse) en <bold>703.8 millions d'années</bold>. Il reste alors 0.5kg d'uranium 235 encore non désintégré, qui perds à son tour la moitié de sa radioactivité en 703.8 millions d'années supplémentaires, etc...</quote> <text>Les premiers 500g d'uranium 235 désintégrés ne sont pas volatilisés, il se sont transformés en <bold>thorium 231</bold> par désintégration <bold>Alpha</bold>, puis ce thorium par désintégration <bold>Beta-</bold> se transformera en <bold>protactinium 231</bold>, de sorte qu'un seul isotope radioactif au départ produit une grande quantité de descendants radioactifs dont il faut tenir compte pour les mesures effectuées dans le cadre de la radio-protection.</text> <text><bold>La désintégration d'un atome peut être induite :</bold> <br/>Par capture d'un neutron lent, l'uranium 235 devient de l'uranium 236, beaucoup plus instable dans la plupart des cas, qui en conséquence se désintègre (fission) en ce scindant en deux atomes, ce sont les produits de fission. L'un des possibles est la désintégration en <bold>krypton 92</bold> et en <bold>baryum 141</bold>, deux isotopes radioactifs aux périodes radioactives très courtes.</text> <quote>Remarquons que 236 - (92 + 141) = 3, ce qui signifie que 3 neutrons rapides sont éjectés lors de cette réaction de fission.</quote> <text>Les 3 neutrons rapides ainsi libérés, si ils sont ralentis (par exemple en traversant un volume d'eau), peuvent être à nouveau capturés par de l'uranium 235, qui à son tour deviendra un uranium 236 par nature instable qui se désintégrera et éjectera à nouveau 2 ou 3 neutrons : <br/>C'est la <bold>réaction en chaîne !</bold></text> <text>La réaction en chaîne est obtenue sous plusieurs conditions :</text> <caution>- <bold>La masse critique doit être atteinte</bold> (c'est-à-dire un certain volume de radio-isotopes dans le but de favoriser la capture de neutrons). <br/>- <bold>La géométrie du réacteur</bold> (endroit ou se produit la réaction) doit être considérée avec importance. <br/>- <bold>Des réflecteurs à neutrons</bold> (en carbure de tungstène) doivent êtres disposés autour des assemblages de radio-isotopes (crayons de combustible). <br/>- <bold>Les neutrons rapides doivent êtres ralentis par des modérateurs</bold> (eau, béryllium, ou graphite) afin qu'ils soient capturés par les noyaux d'atomes. Ceci n'est pas valable pour les réacteurs à neutrons rapides, dont le fonctionnement est différent.</caution> <text>Cette réaction en chaîne est accompagnée d'une <bold>forte émission Gamma</bold>, résultat de la perte de masse entre le début et la fin de la réaction, et du trop plein d'énergie à évacuer.</text> <text>Toutes ses émissions (Alpha, Beta, et Gamma) échauffent les différents matériaux utilisés au sein d'un réacteur d'une centrale nucléaire, ce qui permet de chauffer l'eau lourde, produire de la vapeur d'eau sous pression via un échangeur (interface entre le circuit primaire et secondaire), faire tourner des turbines, alternateurs, et produire de l'électricité sur le réseau.</text> <title>Différents combustibles nucléaires :</title> <underline></underline> <text><bold>Le minerai d'uranium 235 et ses dérivés :</bold> <br/>Le minerai d'uranium se trouve à l'état naturel la plupart du temps dans des roches Pechblende (littéralement : minerai de malheur) sous la forme <bold>UO2</bold> (dioxyde d'uranium). L'uranium se présente généralement dans des proportions de 0.7% <bold>d'uranium 235</bold> (fissile), et 99.3% <bold>d'uranium 238</bold> (fertile), c'est pourquoi l'isotope 235 doit être enrichit (augmenter le ratio de 0.7%) pour que le réacteur ait un meilleur rendement. Néanmoins, il a existé par le passé des réacteurs à uranium pauvre (non enrichit) nommés <bold>pile atomique</bold> :</text> <quote>La première <bold>pile atomique</bold> (premier réacteur nucléaire) à avoir existé fut celle d'Enrico Fermi en 1942 aux États-Unis (dans une ancienne salle de squash sous les gradins du Stagg Field à Chicago).</quote> <text>Ci-dessous un échantillon de minerai naturel d'uranium que j'ai isolé dans une résine polymères époxyde pour plus de sécurité :</text> <a href="photo/dsc02924.jpg"><img src="thumbnail/dsc02924.jpg"></img></a> <a href="photo/dsc03356.jpg"><img src="thumbnail/dsc03356.jpg"></img></a> <text><bold>L'uranium 238 pour fabriquer le plutonium 239 :</bold> <br/>Dans un réacteur nucléaire, comme évoqué <bold>l'uranium 238</bold> n'est pas fissile, il est fertile, ce qui signifie que par capture de neutrons il peut servir à la fabrication d'un isotope fissile. Ainsi bombardé de neutrons lents (neutrons thermiques), l'uranium 238 se transforme alors en son isotope 239, très instable, qui par désintégration Beta- se transforme à son tour en neptunium 239, ce dernier étant lui aussi radioactif Beta-, se transforme alors en <bold>plutonium 239</bold>, un élément chimique fissile cette fois-ci.</text> <quote>Le <bold>plutonium 239</bold> a servit à créer le cœur de la <bold>première bombe atomique de l'histoire</bold> (cœur qui mesurait seulement 93mm de diamètre), elle fut testée grandeur nature lors de l'essai Trinity réalisé par l'armée Américaine le 16 Juillet 1945 dans le cadre du projet Manhattan.</quote> <text>Le <bold>plutonium 241</bold> quant à lui se forme à partir du plutonium 239 puis 240 par capture de neutrons. Également, le plutonium 238 peut être formé par captures de neutrons successives par de l'uranium 236 n'ayant pas fissionné (U236 +1n > U237 Beta- > Np237 +1n > Np238 Beta- > Pu238).</text> <text>Il existe 15 isotopes connus du plutonium (tous radioactifs), les plus produits en réacteur sont :</text> <quote>- Le Pu238 <br/>- Le Pu239 <br/>- Le Pu240 <br/>- Le <bold>Pu241</bold> (voir plus bas : "La radio-toxicité du plutonium 241") <br/>- Le Pu242</quote> <text>Le plutonium 238 est souvent utilisé dans des missions spatiales de part le fait qu'il a une période radioactive courte (87.75 années) et donc une énergie issue de sa désintégration très élevée (environ 567 Watts / kg). Ce radio-isotope dégage une grande quantité de chaleur qui peut être utilisée pour produire de l'électricité à bord des astronefs dans des <bold>générateurs thermo-électriques à radio-isotopes</bold>. Sa désintégration spontanée Alpha n'étant pas accompagnée de rayonnements Gamma pénétrants, il est donc un bon candidat pour les longues expéditions habitées.</text> <text>Le plutonium est utilisé plus généralement dans les centrales électrogènes (nucléaires) sous la forme de <bold>crayons de combustibles</bold> en zirconium, dans lequels se trouvent enfermé un composé de dioxyde de plutonium (PuO2) et de dioxyde d'uranium (UO2). Ce combustible est appelé MOX par la filière nucléaire.</text> <quote>Certains isotopes du plutonium plus lourds que le Pu242, comme par exemple le <bold>Pu246</bold>, n'ont étés produits que lors des explosions atomiques car étant très lourds et instables, leurs fabrication requiert un bombardement de neutrons très intense.</quote> <title>L'exposition et la contamination :</title> <underline></underline> <text><bold>L'exposition externe :</bold> <br/>L'exposition à la radioactivité est dite externe lorsque la source d'émission est situé à l'extérieur du corps. Cela peut être provoqué par la radioactivité naturelle (minerai) ou artificielle (stockage de déchets ou pollution).</text> <quote>La durée d'exposition est très importante dans un calcul, associée à la dose reçue et à la zone du corps touchée, elle conditionne les facteurs de risques encourus.</quote> <text>Dans les usines de retraitement du combustible usé, les techniciens accumulent une certaine dose de rayonnement ionisant. Pour éviter d'être contaminé, les éléments chimiques les plus dangereux sont manipulés à l'aide de boites à gants étanches ou télémanipulateurs mécaniques et robotisés à assistance électrique, ceci derrière des vitres blindées composées de plomb (ce qui atténue les rayonnements).</text> <text><bold>L'exposition interne :</bold> <br/>L'exposition interne qu'en à elle intervient lorsque la source d'émission ce situe à l'intérieur du corps, c'est alors la <bold>contamination</bold>. Ceci est très dangereux parce que l'énergie émise par un radio-isotope décroit au carré de la distance. Ce qui signifie qu'un atome d'uranium 235 à quelques mètres de distance (sans danger immédiat), ne comporte pas les mêmes risques sur la santé que directement au contact des cellules du corps humain (dans le cas d'une ingestion ou inhalation).</text> <text>Émise depuis une source externe au corps humain, la <bold>particule Alpha</bold> (helium 4) est généralement inoffensive du fait qu'elle est peu pénétrante (elle s'arrête à la surface de la peau sans occasionner de lésions). En revanche, lors d'une contamination, l'émission Alpha (la plus ionisante comparé aux autres types de radiations) déposera toute son énergie dans le corps, ce qui pourra provoquer de façon irréversible beaucoup plus de dommages que les Beta, Gamma, ou encore rayonnements X (notamment la mutations des chromosomes).</text> <text>On différencie la <bold>contamination interne et externe</bold>, car si vous portez sur vous la source de radiation (exemple : une poussière radioactive sur votre équipement de protection individuel), vous êtes dans ce cas également contaminé. Il est alors possible de se décontaminer en effectuant différents lavages des équipements de protection et/ou douches successives du corps en totalité (tout dépend du degré de contamination).</text> <text><bold>La radio-toxicité du plutonium 241 :</bold> <br/>Le radio-isotope <bold>Pu241</bold> est l'élément le plus dangereux connu (plus de 1000 fois plus que les autres isotopes). Il a une période radioactive de <bold>14.4 années</bold>, et une activité massique de 3848000000000 Becquerels / gramme.</text> <text>Il est estimé que l'ingestion de seulement <bold>9 milligrammes</bold> de Pu241 provoquerait chez l'homme une mortalité probable de 50% au bout de 30 jours (au bout d'un an avec 0.9mg, et au bout de 1000 jours avec 0.4mg).</text> <text>Les descendants du Pu241 sont à considérer avec importance :</text> <caution>Le <bold>plutonium 241</bold> se désintègre par <bold>radioactivité Beta-</bold> en <bold>americium 241</bold>, un émetteur de rayonnement Gamma également particulièrement dangereux.</caution> <text>A l'instar du Pu241, d'autres isotopes comme le <bold>Pu239</bold> ont également une radio-toxicité particulièrement élevée. Par expérimentations, il est estimé que l'apparition de tumeurs pulmonaires chez l'homme après inhalation seraient provoquées par un dépôt de 200000 Bequerels soit environ <bold>87 microgrammes</bold> d'oxyde de plutonium 239.</text> <caution>La production mondiale de plutonium depuis sa découverte dans les années 1940 s'élève aujourd'hui à plus de <bold>500 Tonnes</bold> réparties en différents pays.</caution> <text><bold>Le cas de l'iode 131 :</bold> <br/><bold>L'iode 131</bold> est très radioactif parce qu'il a une période radioactive de seulement <bold>8.02 jours</bold>. À relativement faible dose, l'iode 131 provoque des mutations génétiques dans les cellules ou il pénètre et les cellules voisines, ce qui est le germe du cancer.</text> <text>Paradoxalement, c'est la raison pour laquelle ce radio-isotope est plus dangereux à faibles doses qu'à fortes doses. En effet, les cellules irradiées fortement étant détruites, elles ont moins de risque de propager un cancer. Notez que l'apoptose (mort cellulaire programmée) est essentiel dans l'équilibre et la survie des organismes multi-cellulaires en réponse à la <bold>prolifération cellulaire</bold>.</text> <quote>L'iode 131 prend place dans la <bold>thyroïde</bold> chez l'homme.</quote> <text>L'iode 131 est un isotope volatile, il est produit en grandes quantités dans les réacteurs nucléaires, et se désintègre par <bold>radioactivité Beta-</bold> (95% des cas) en <bold>xénon 131</bold>, c'est pourquoi les populations en zones classées à risque radiologique (accidents nucléaires) sont tenues informées et doivent le cas échéant prendre des pastilles d'iode <bold>stable</bold> (non radioactif) afin de saturer la thyroïde, ce qui a pour effet d'empêcher l'isotope 131 d'y prendre place.</text> <text>Notez que cette prise d'iode stable devrait s'effectuer 1 heure au moins avant la contamination, et que même l'iode stable en grande quantité dans la thyroïde n'est pas sans effets sur la santé.</text> <text><bold>La contamination au cesium 137 :</bold> <br/>L'isotope <bold>cesium 137</bold> est lui aussi produit en abondance dans les réacteurs nucléaires, et est l'un des nombreux produits de fission de L'uranium. Le cesium 137 se désintègre par <bold>radioactivité Beta-</bold> en <bold>baryum 137m</bold> instable (m pour isomère), puis en baryum 137 cette fois-ci stable.</text> <text>Le cesium 137 a une période radioactive de 30.15 années. Avec le strontium 90, il fait partie des déchets radioactifs à vie moyenne.</text> <caution>Le cesium 137 est la principale source de contamination de la chaîne alimentaire due aux essais nucléaires, et aux accidents de Tchernobyl et Fukushima.</caution> <text>Le cesium 137 est assez mobile, il se répand sur les sols, les minéraux, se fixe dans les végétaux et les êtres vivants (notamment au niveau des muscles).</text> <text>La communauté scientifique internationale émet l'hypothèse que le cesium 137 se réparti de façon homogène dans la masse musculaire de l'homme, tandis-que certains scientifiques Russes prétendent qu'il pourrait se concentrer au niveau du cœur de l'individu, provoquant diverses pathologies cardiaques (notamment des arythmies).</text> <text>Si il ne se stocke pas définitivement dans le corps, le cesium 137 à une période biologique d'environ 100 jours (temps après lequel il est évacué par l'organisme), ce qui dans ce cas précis signifie qu'1 noyau de cesium 137 seulement sur 160 a le temps de se désintégrer à l'intérieur du corps.</text> <text><bold>La chaîne de désintégration du radium 226 :</bold> <br/>Le <bold>radium 226</bold> par <bold>radioactivité Alpha</bold> et période radioactive de 1602 ans, se désintègre en <bold>radon 222</bold>, un gaz radioactif à la période radioactive très courte (3.824 jours) et donc très radioactif. Plus largement, le radon fait partie de la chaîne de désintégration de l'uranium et du thorium, on en trouve donc dans les mines d'uranium, et les constructions en granite.</text> <quote>Le radium fut découvert par Pierre et Marie Curie en 1898 et a trouvé de multiples applications. Il est aujourd'hui interdit à cause de sa radio-toxicité.</quote> <text>À l'époque (années 1920/1930) ou on ne connaissait pas bien encore les dangers de la radioactivité, le radium (sous différents isotopes) a été largement utilisé (car brillant dans le noir et aux soit-disant effets thérapeutiques) dans <bold>des produits du quotidien</bold> (chiffres et aiguilles des réveils, pendules, boussoles, différentes crèmes pour le visage, laine pour bébés au radium, etc...) et à usage professionnel (instruments pour le médical, cadrans des instruments de navigation en avionique, etc...). On ventait également ses bienfaits dans des stations thermales (aux eaux radioactives).</text> <text>Les femmes qui peignaient au radium (mélange de poudre de radium, d'eau, et de colle) dans les manufactures étaient des ouvrières non informées sur les risques, elles affinaient la pointe de leurs pinceaux enduits de radium (dont les poils finissaient par s'abîmer) avec leurs lèvres et leurs langues afin de continuer à peindre avec précision. Les conséquences sanitaires ne se sont pas fait attendre : cancers de la mâchoire et du cou.</text> <caution>Le <bold>plomb 214 et 210</bold> (deux descendants du radium 226) ne sont pas stables, ils peuvent rester dans les poumons lorsque le radon 222 est inhalé avant de se stabiliser en <bold>plomb 206</bold> (isotope stable) en passant par différentes étapes de désintégration (isotopes radioactifs de polonium et de bismuth).</caution> <text>Pour se faire une idée de la complexité des descendants d'un isotope radioactif, ci-dessous la chaîne de désintégration de <bold>l'uranium 238</bold> (appelée chaîne du radium) qui passe par le <bold>radium 226</bold> (la période radioactive est notée entre parenthèses) :</text> <quote><bold>Uranium 238</bold> ➙ Radioactivité Alpha (4.4688 milliards d'années) <br/>Thorium 234 ➙ Radioactivité Beta- et Gamma (24.1 jours) <br/>Protactinium 234 ➙ Radioactivité Beta- et Gamma (1.17 minutes) <br/>Uranium 234 ➙ Radioactivité Alpha (245500 années) <br/>Thorium 230 ➙ Radioactivité Alpha et Gamma (75380 années) <br/><bold>Radium 226</bold> ➙ Radioactivité Alpha et Gamma (1602 années) <br/><bold>Radon 222</bold> ➙ Radioactivité Alpha (3.8235 jours) <br/>Polonium 218 ➙ Radioactivité Alpha (3.1 minutes) <br/><bold>Plomb 214</bold> ➙ Radioactivité Beta- et Gamma (26.8 minutes) <br/>Bismuth 214 ➙ Radioactivité Beta- et Gamma (19.9 minutes) <br/>Polonium 214 ➙ Radioactivité Alpha (164.3 microsecondes) <br/><bold>Plomb 210</bold> ➙ Radioactivité Beta- et Gamma (22.2 années) <br/>Bismuth 210 ➙ Radioactivité Beta- (5.012 jours) <br/>Polonium 210 ➙ Radioactivité Alpha (138.376 jours) <br/><bold>Plomb 206</bold> ➙ Stable</quote> <text>Il est important de notifier que certaines des désintégrations <bold>Alpha</bold> ou <bold>Beta-</bold> à différentes étapes de la chaîne sont accompagnées d'émissions <bold>Gamma</bold> plus ou moins importantes.</text> <text>Ceci n'est pas le seul parcourt possible, par exemple dans un certain nombre de cas le polonium 218 peut se désintégrer par radioactivité Beta- et devenir de l'astate 218, le bismuth 214 peut se désintégrer par radioactivité Alpha et se transformer en thallium 210, etc...</text> <quote>Cet interlude était un aperçu pour les non-initiés de ce qu'est la radioactivité, j'espère vous avoir donné envie d'en savoir plus !</quote> <title>Quelques informations sur le compteur Geiger-Müller :</title> <underline></underline> <text><bold>Programmation de l'automate programmable MODULABLE 20 avec MODULE :</bold> <br/>Le programme en langage C++ fonctionnant avec MODULE est téléchargeable ici :</text> <a href="download/cpp/geiger_muller_counter.zip"><download>Télécharger le programme du <bold>compteur Geiger-Müller</bold> (.zip, ≈ 2.6Kio)</download></a> <a href="photo/dsc02833.jpg"><img src="thumbnail/dsc02833.jpg"></img></a> <text><bold>Connexions (automate programmable MODULABLE 20 sur les différents systèmes embarqués) :</bold></text> <caution>- Port GPIO 1 (PD0) sur anode del (témoin lumineux des coups du tube Geiger-Müller). <br/>- Port GPIO 2 (PD1) sur cathode galvanomètre (lecture analogique des coups du tube Geiger-Müller). <br/>- Port GPIO 3 (PD2) sur cathode buzzer de signalement (témoin sonore des coups du tube Geiger-Müller). <br/>- Port GPIO 4 (PD3) sur broche SHOCK (coups) élévateur de tension +400V (détection de la fermeture du tube Geiger-Müller). <br/>- Port GPIO 11 (PB2) sur broche SS (slave select) mini afficheur à digits 1. <br/>- Port GPIO 12 (PB3) sur broche MOSI (master output slave input) mini afficheur à digits 1. <br/>- Port GPIO 14 (PB5) sur broche SCK (serial clock) mini afficheur à digits 1. <br/>- Port GPIO 16 (PC1) sur curseur bouton rotatif (sélection des modes). <br/>- Port GPIO 17 (PC2) sur interrupteur de visualisation des coups / seconde maximums relevés. <br/>- Port GPIO 18 (PC3) sur interrupteur de visualisation des doses maximales relevées. <br/>- Port GPIO 20 (PC5) sur sortie pont diviseur de tension 10kΩ / 2kΩ (alarme niveau de batterie faible).</caution> <text><bold>Quelques étapes de l'assemblage des autres parties du projet :</bold> <br/>Fabrication des cartes électroniques pour l'affichage :</text> <a href="photo/dsc02741.jpg"><img src="thumbnail/dsc02741.jpg"></img></a> <a href="photo/dsc02782.jpg"><img src="thumbnail/dsc02782.jpg"></img></a> <a href="photo/dsc02788.jpg"><img src="thumbnail/dsc02788.jpg"></img></a> <a href="photo/dsc02808.jpg"><img src="thumbnail/dsc02808.jpg"></img></a> <text><bold>Élévateur de tension +400V pour l'alimentation du tube Geiger-Müller :</bold> <br/>Prototypage et conception finale :</text> <a href="photo/dsc02511.jpg"><img src="thumbnail/dsc02511.jpg"></img></a> <a href="photo/dsc08055.jpg"><img src="thumbnail/dsc08055.jpg"></img></a> <text><bold>Usinage des différentes pièces :</bold> <br/>Aluminium, ertalon, et découpe des tôles de cuivre :</text> <a href="photo/dsc02318.jpg"><img src="thumbnail/dsc02318.jpg"></img></a> <a href="photo/dsc02320.jpg"><img src="thumbnail/dsc02320.jpg"></img></a> <a href="photo/dsc02847.jpg"><img src="thumbnail/dsc02847.jpg"></img></a> <a href="photo/dsc02321.jpg"><img src="thumbnail/dsc02321.jpg"></img></a> <text><bold>Matériel utilisé pour l'usinage des pièces :</bold> <br/>Fraiseuse, perceuse à colonne, tour à métal :</text> <a href="photo/dsc02323.jpg"><img src="thumbnail/dsc02323.jpg"></img></a> <a href="photo/dsc02327.jpg"><img src="thumbnail/dsc02327.jpg"></img></a> <text><bold>Modification d'un petit Galvanomètre :</bold> <br/>Et assemblage sur les pièces usinées :</text> <a href="photo/dsc02805.jpg"><img src="thumbnail/dsc02805.jpg"></img></a> <a href="photo/dsc02835.jpg"><img src="thumbnail/dsc02835.jpg"></img></a> <a href="photo/dsc02842.jpg"><img src="thumbnail/dsc02842.jpg"></img></a> <a href="photo/dsc02851.jpg"><img src="thumbnail/dsc02851.jpg"></img></a> <text><bold>Câblage et montage final de l'ensemble :</bold> <br/>Puis validation du fonctionnement :</text> <a href="photo/dsc02823.jpg"><img src="thumbnail/dsc02823.jpg"></img></a> <a href="photo/dsc02866.jpg"><img src="thumbnail/dsc02866.jpg"></img></a> <a href="photo/dsc02856.jpg"><img src="thumbnail/dsc02856.jpg"></img></a> <a href="photo/dsc02861.jpg"><img src="thumbnail/dsc02861.jpg"></img></a> <a href="photo/dsc06711.jpg"><img src="thumbnail/dsc06711.jpg"></img></a> <a href="photo/dsc02868.jpg"><img src="thumbnail/dsc02868.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectGyroscopeSensor.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectGyroscopeSensor"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le capteur gyroscopique</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectHoldSwitch.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectHoldSwitch"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'interrupteur d'alimentation maintenue</title> <underline></underline> <text>Ce petit circuit électronique permet de <bold>maintenir l'alimentation d'un montage</bold> lorsque l'interrupteur de coupure d'alimentation passe à l'état ouvert. Seul l'automate programmable <bold>décidera lui-même de couper l'alimentation générale</bold> en temps voulu.</text> <a href="photo/dsc08041.jpg"><img src="thumbnail/dsc08041.jpg"></img></a> <a href="photo/dsc08043.jpg"><img src="thumbnail/dsc08043.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/hold_switch.zip"><download>Télécharger le plan de fabrication de l'interrupteur <bold>d'alimentation maintenue</bold> (.zip, 399 octets)</download></a> <text>Cette carte dispose de <bold>2 entrées pour l'alimentation</bold> (une qui par exemple peut servir à connecter une batterie, l'autre pouvant servir à connecter un cordon de charge de la batterie), <bold>1 sortie d'alimentation maintenue</bold> par l'automate programmable, et <bold>1 pont diviseur de tension</bold> (10kΩ / 2kΩ) afin de récupérer la valeur de la tension d'alimentation sur un microcontrôleur sans risques.</text> <quote>L'utilité du maintien d'une alimentation lorsque l'utilisateur décide l'arrêt d'un système peut avoir de nombreuses applications possibles : <br/>- Sécurité qui laisse un système critique actif avant l'extinction totale. <br/>- Sauvegarde de données dans une mémoire EEPROM avant la coupure de l'alimentation.</quote> <text>Ou plus simplement, jouer une musique à l'allumage et à l'extinction de votre montage électronique...</text> <caution>Par sécurité, l'alimentation maintenue ne peut être coupée par l'automate programmable que <bold>lorsque l'interrupteur de coupure générale est ouvert !</bold> Dans ce cas il est donc impossible de couper l'alimentation inopinément (via une erreur dans le programme par exemple).</caution> <text>Lorsque l'interrupteur d'alimentation est fermé, la sortie d'alimentation maintenue (OUTPUT) peut délivrer un courant jusqu'à <bold>8A</bold>. En revanche, interrupteur ouvert mais alimentation maintenue pilotée, le courant est limité à <bold>1A</bold> du fait qu'il passe seulement par le transistor bipolaire BC638, cependant ceci ne doit pas être un frein à vos projets puisque cette situation est spécifique et requiert d'être dans tous les cas maîtrisée en termes logiciel et matériel.</text> <a href="photo/dsc08050.jpg"><img src="thumbnail/dsc08050.jpg"></img></a> <text><bold>Connexions (source d'alimentation sur interrupteur d'alimentation maintenue) :</bold></text> <caution>- Anode ou masse de la source d'alimentation sur connecteur à braser INPUT GND (masse). <br/>- Cathode de la source d'alimentation sur connecteur à braser INPUT +6V/+26V (pôle positif).</caution> <text><bold>Connexions (interrupteur d'alimentation maintenue sur automate programmable) :</bold></text> <caution>- Connecteur à braser OUTPUT GND (masse) sur broche ou connecteur à braser POWER GND. <br/>- Connecteur à braser OUTPUT +6V/+26V (pôle positif) sur broche ou connecteur à braser POWER +6V/+26V. <br/>- Broche STATE (état de l'interrupteur) sur port GPIO (ou interruption) pour détecter lorsque l'interrupteur est ouvert ou fermé. <br/>- Broche HOLD (auto-maintien) sur port GPIO afin de maintenir l'alimentation. <br/>- Broche VOLT (tension de l'alimentation via le pont diviseur de tension 10kΩ / 2kΩ) sur port GPIO connecté au convertisseur analogique/numérique (l'ADC) afin de récupérer la tension d'alimentation sans risques (facultatif).</caution> <a href="photo/dsc08047.jpg"><img src="thumbnail/dsc08047.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- Courant de sortie jusqu'à 8A (8A interrupteur fermé, 1A interrupteur ouvert). <br/>- 2 connecteurs à braser INPUT GND (masses) pour l'alimentation. <br/>- 2 connecteurs à braser INPUT +6V/+26V (pôles positifs) pour l'alimentation. <br/>- 1 connecteur à braser OUTPUT GND (masse) pour l'alimentation maintenue. <br/>- 1 connecteur à braser OUTPUT +6V/+26V (pôle positif) pour l'alimentation maintenue. <br/>- 1 broche STATE (état) pour détecter la position de l'interrupteur (0V = ouvert, +5V = fermé). <br/>- 1 broche HOLD (auto-maintien) pour piloter le maintien de l'alimentation. <br/>- 1 broche VOLT (tension) reliée à la sortie du pont diviseur de tension 10kΩ / 2kΩ intégré (pour récupérer la tension de l'alimentation sur l'automate programmable sans risques). <br/>- Dimensions : 36.83mm x 35.56mm. <br/>- Fixation de l'ensemble par le pas de vis de l'interrupteur.</text> <text><bold>Liste des composants :</bold></text> <quote>1x Interrupteur inverseur (on/on) unipolaire à levier (3 broches, pas 4.7mm) <br/>1x Régulateur de tension LM2931 (version fixée +5V, boîtier TO-92) <br/>5x Résistances 1kΩ ± 1% 250mW <br/>1x Résistance 2kΩ ± 1% 250mW <br/>5x Résistances 10kΩ ± 1% 250mW <br/>1x Résistance 20kΩ ± 1% 250mW <br/>2x Résistances 100kΩ ± 1% 250mW <br/>1x Condensateur céramique 100pF tension >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=52V (pas 2mm) <br/>1x Condensateur électrolytique tantale 22μF >=10V (pas 2.54mm) <br/>2x Diodes Schottky 1N5819 <br/>3x Transistors bipolaires 2N3904 (boîtier TO-92) <br/>1x Transistor bipolaire 2N3906 (boîtier TO-92) <br/>1x Transistor bipolaire BC638 (boîtier TO-92) <br/>3x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08560.jpg"><img src="thumbnail/dsc08560.jpg"></img></a> <a href="photo/dsc08552.jpg"><img src="thumbnail/dsc08552.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>Il est plus aisé de braser les petits composants (résistances, condensateurs, etc...) en premier, et de <bold>mettre en place l'interrupteur d'alimentation en dernier</bold> du fait de sa taille imposante (en comparaison des autres composants) :</text> <a href="photo/dsc08036.jpg"><img src="thumbnail/dsc08036.jpg"></img></a> <a href="photo/dsc08040.jpg"><img src="thumbnail/dsc08040.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectInfraredCameraSensor.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectInfraredCameraSensor"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La caméra thermique</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectIntervalometer.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectIntervalometer"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'intervallomètre pour la photographie</title> <underline></underline> <text><bold>L'intervallomètre</bold> est un projet dont j'avais de plus en plus la nécessité en photo, en effet il permet de piloter le déclencheur d'un appareil photo numérique :</text> <a href="photo/dsc06392.jpg"><img src="thumbnail/dsc06392.jpg"></img></a> <a href="photo/dsc03690.jpg"><img src="thumbnail/dsc03690.jpg"></img></a> <caution>Le déclenchement est réglable et s'effectue à intervalles réguliers (d'où l'appellation). Il permet de prendre des photos par exemple toutes les secondes.</caution> <text>Pour effectuer une prise de vue en mouvement, j'ai équipé mon boîtier d'un bouton rotatif et d'une <bold>sortie PWM</bold> ce qui permet de faire fonctionner un servo-moteur, et donc de mettre en mouvement à vitesse fixe ou variable, dans un sens ou dans l'autre un chariot (slider) sur lequel est fixé l'appareil photo.</text> <text>Un buzzer de signalement indique le nombre de secondes de vidéo prises (à 24 images / seconde), cela signifie que toutes les 24 photos le buzzer émet un signal. Ceci permet de connaître l'état en cours de la prise de vue pour un montage futur en post-production. Ce buzzer sert également d'alarme <bold>niveau faible de la batterie</bold> (en dessous de +6V) et est accompagné du clignotement d'un témoin lumineux (la del d'alimentation).</text> <a href="photo/dsc06385.jpg"><img src="thumbnail/dsc06385.jpg"></img></a> <a href="photo/dsc06413.jpg"><img src="thumbnail/dsc06413.jpg"></img></a> <text>Une <bold>prise de charge</bold> externe (standard XT30) permet de recharger la batterie via un cordon et un chargeur adapté.</text> <quote>L'intervallomètre peut être utilisé comme appareil pour effectuer des photographies longues poses, utiles notamment en astro-photographie.</quote> <text>Il peut être utilisé dans une prise de vue fixe, en mouvement sur un chariot, ou éventuellement à main-levée comme c'est le cas ici dans cet essai :</text> <video src="video/00006.mov" controls></video> <text>Ci-dessous, photo de gauche, le boîtier fixé sur un stabilisateur de caméra (Glidecam HD-2000) que j'utilise habituellement dans d'autres circonstances, en l'occurrence pour réaliser des séquences filmées. Photo de droite, la batterie d'alimentation fabriquée sur-mesure pour que l'ensemble soit compact :</text> <a href="photo/dsc03796.jpg"><img src="thumbnail/dsc03796.jpg"></img></a> <a href="photo/dsc06373.jpg"><img src="thumbnail/dsc06373.jpg"></img></a> <text><bold>Programmation de l'automate programmable MODULABLE 20 avec MODULE :</bold> <br/>Le programme en langage C++ fonctionnant avec MODULE est téléchargeable ici :</text> <a href="download/cpp/intervalometer.zip"><download>Télécharger le programme de <bold>l'intervallomètre</bold> pour la photographie (.zip, ≈ 1.4Kio)</download></a> <text><bold>Connexions (automate programmable MODULABLE 20 sur les différents systèmes embarqués) :</bold></text> <caution>- Port GPIO 1 (PD0) sur signal PWM servo-moteur (chariot). <br/>- Port GPIO 2 (PD1) sur cathode buzzer de signalement. <br/>- Port GPIO 12 (PB3) sur anode del (témoin d'alimentation). <br/>- Port GPIO 15 (PC0) sur curseur bouton rotatif (vitesse et sens du chariot). <br/>- Port GPIO 16 (PC1) sur sortie pont diviseur de tension 10kΩ / 2kΩ (alarme niveau de batterie faible). <br/>- Port GPIO 18 (PC3) sur entrée déclencheur (vers l'appareil photo). <br/>- Port GPIO 19 (PC4) sur interrupteur chariot (démarrage du servo-moteur). <br/>- Port GPIO 20 (PC5) sur interrupteur photo (démarrage d'une séquence photo).</caution> <text><bold>Les caractéristiques de l'intervallomètre :</bold> <br/>- Automate programmable MODULABLE 20 équipé du microcontrôleur ATmega328P. <br/>- Interrupteur d'allumage (on/off). <br/>- Interrupteur 3 positions de démarrage de la prise de vue (off/chariot/chariot + photo). <br/>- Bouton rotatif de réglage de la vitesse du chariot. <br/>- Témoin d'alimentation (del) et buzzer de signalement. <br/>- Sortie déclencheur pour l'appareil photo. <br/>- Sortie PWM pour le servo-moteur du chariot. <br/>- Accumulateur nickel-hydrure métallique (NiMH) 8S (+9.6V) 300mAh. <br/>- Prise de charge de la batterie (XT30). <br/>- Alarme niveau de batterie faible (en dessous de +6V). <br/>- Boitier en aluminium très robuste. <br/>- Fixations par vis M6 (perçage taraudé).</text> <quote>L'interrupteur 3 positions permet d'amener le chariot en position souhaitée sans prendre de photos.</quote> <text>Photo ci-dessous, la fermeture de la boîte, il n'y a pas beaucoup de place !</text> <a href="photo/dsc06448.jpg"><img src="thumbnail/dsc06448.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectMatrixDisplay.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectMatrixDisplay"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'afficheur à matrice</title> <underline></underline> <text>À l'instar de l'afficheur à digits, <bold>l'afficheur à matrice 8 x 8</bold> permet un visuel graphique (pixels) et offre l'avantage de pouvoir dessiner des formes ou des symbols :</text> <a href="photo/dsc08365.jpg"><img src="thumbnail/dsc08365.jpg"></img></a> <a href="photo/dsc08361.jpg"><img src="thumbnail/dsc08361.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/matrix_display.zip"><download>Télécharger le plan de fabrication de <bold>l'afficheur à matrice</bold> (.zip, 405 octets)</download></a> <text>Cet afficheur est équipé du <bold>MAX7219</bold>, un composant qui gère le <bold>multiplexage des dels</bold>, il communique en <bold>SPI</bold> avec le microcontrôleur.</text> <text>La vitesse de communication SPI et le nombre de ports disponibles sur mes automates programmables (MODULABLE 20 ou MODULABLE 32) sont suffisants pour pouvoir réaliser un montage avec de nombreux afficheurs (projet de borne de jeu d'arcade par exemple).</text> <text><bold>Ports des automates programmables concernés par le SPI :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text><bold>Connexions (afficheur à matrice sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur port SS ou tout autre port d'entrée/sortie disponible (sauf MISO qui doit rester libre sauf si il est déjà utilisé par un autre périphérique également SPI). <br/>- Broche MOSI (master output slave input) sur port MOSI. <br/>- Broche SCK (serial clock) sur port SCK.</caution> <text><bold>Connexions (afficheur en cascade sur autre afficheur) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche SS (slave select) sur broche SS disponible. <br/>- Broche MISO (master input slave output) sur broche MOSI. <br/>- Broche SCK (serial clock) sur broche SCK disponible.</caution> <a href="photo/dsc08032.jpg"><img src="thumbnail/dsc08032.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 2 broches GND (masse) pour l'alimentation. <br/>- 2 broches +5V (pôle positif) pour l'alimentation. <br/>- 2 broches SS (slave select) pour la communication SPI. <br/>- 1 broche MOSI (master output slave input) pour la communication SPI. <br/>- 1 broche MISO (master input slave output) pour la communication SPI. <br/>- 2 broches SCK (serial clock) pour la communication SPI. <br/>- Branchements en cascade. <br/>- 8 x 8 pixels pour l'affichage. <br/>- Dimensions : 53.34mm x 40.64mm. <br/>- Entre-axes de fixations : 45.72mm x 33.02mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Contrôleur d'affichage MAX7219 (boîtier DIP-24) <br/>1x Afficheur à matrice TC15-11 (couleur de votre choix) <br/>1x Résistance 9.53kΩ ± 1% 250mW <br/>1x Condensateur céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=10V (pas 2mm) <br/>1x Support DIP-24 300mil <br/>10x Broches mâles (pas 2.54mm)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08144.jpg"><img src="thumbnail/dsc08144.jpg"></img></a> <a href="photo/dsc08334.jpg"><img src="thumbnail/dsc08334.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>L'afficheur à matrice <bold>TC15-11</bold> doit être brasé en dernier, en effet il masque les broches des autres composants (exepté les broches mâles d'alimentation et de communication SPI) sur la face opposée du PCB, rendant dans le cas contraire leur brasure impossible :</text> <a href="photo/dsc08353.jpg"><img src="thumbnail/dsc08353.jpg"></img></a> <a href="photo/dsc08355.jpg"><img src="thumbnail/dsc08355.jpg"></img></a> <text>Cet ordre de montage respecté, l'assemblage se finalise normalement.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectModulable20.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectModulable20"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'automate programmable MODULABLE 20</title> <underline></underline> <text>Cet <bold>automate programmable</bold> associé au programme MODULE (c'est-à-dire compatible dans les fonctionnalités et les entrées/sorties) est un calculateur embarqué qui est chargé d'exécuter les instructions machine de votre programme, il peut être équipé des microcontrôleurs <bold>ATmega48P</bold>, <bold>ATmega88P</bold>, <bold>ATmega168P</bold>, ou <bold>ATmega328P</bold>.</text> <a href="photo/dsc08337.jpg"><img src="thumbnail/dsc08337.jpg"></img></a> <a href="photo/dsc08341.jpg"><img src="thumbnail/dsc08341.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/modulable_20.zip"><download>Télécharger le plan de fabrication de l'automate programmable <bold>MODULABLE 20</bold> (.zip, 401 octets)</download></a> <text>Selon si votre projet requiert plus ou moins de mémoire <bold>Flash</bold>, <bold>EEPROM</bold>, ou <bold>SRAM</bold>, 4 microcontrôleurs différents peuvent être implantés sur la carte MODULABLE 20 :</text> <caution><bold>Microcontrôleur ATmega48P :</bold> <br/>- Mémoire Flash = 4096 octets (4Kio) <br/>- Mémoire EEPROM = 256 octets (0.25Kio) <br/>- Mémoire SRAM = 512 octets (0.5Kio) <br/> <br/><bold>Microcontrôleur ATmega88P :</bold> <br/>- Mémoire Flash = 8192 octets (8Kio) <br/>- Mémoire EEPROM = 512 octets (0.5Kio) <br/>- Mémoire SRAM = 1024 octets (1Kio) <br/> <br/><bold>Microcontrôleur ATmega168P :</bold> <br/>- Mémoire Flash = 16384 octets (16Kio) <br/>- Mémoire EEPROM = 512 octets (0.5Kio) <br/>- Mémoire SRAM = 1024 octets (1Kio) <br/> <br/><bold>Microcontrôleur ATmega328P :</bold> <br/>- Mémoire Flash = 32768 octets (32Kio) <br/>- Mémoire EEPROM = 1024 octets (1Kio) <br/>- Mémoire SRAM = 2048 octets (2Kio)</caution> <text>L'antériorité de ce projet veut que j'ai débuté la programmation de MODULE avec le microcontrôleur <bold>ATmega328P</bold> et un prototype qui ressemble beaucoup au MODULABLE 20. Mais depuis j'ai conçu un automate programmable, le MODULABLE 32, plus intéressant sur bons nombres de points.</text> <quote>Cet automate programmable en comparaison au MODULABLE 32 garde néanmoins l'avantage d'être moins onéreux en ce qui concerne le <bold>coût des composants</bold>, de dimension (longueur seulement) légèrement plus petite, ainsi que <bold>plus rapide à assembler</bold>.</quote> <a href="photo/dsc08343.jpg"><img src="thumbnail/dsc08343.jpg"></img></a> <a href="photo/dsc08340.jpg"><img src="thumbnail/dsc08340.jpg"></img></a> <caution>Cet automate programmable peut être alimenté de <bold>+6V</bold> jusqu'à <bold>+26V</bold>, ce qui est favorable à une batterie Lithium-ion polymère (LiPo) de <bold>2S</bold> à <bold>6S</bold> standard (+8.4V à +25.2V), ou encore à des sources d'alimentation assez communes de <bold>+12V</bold> ou <bold>+24V</bold> en courant continu.</caution> <text>Néanmoins selon le courant demandé, le circuit de régulation de tension embarqué dans cet automate programmable pourra délivrer une <bold>tension stable de +5V</bold> via une tension d'alimentation supérieure à +5V mais <bold>inférieure à +6V</bold>, ceci grâce aux faibles pertes (dropout) du régulateur de tension LM2940.</text> <quote>À noter que le microcontrôleur fonctionnera normalement (dans ses spécifications techniques) avec des <bold>tensions d'alimentation bien inférieures à +5V</bold> en entrée, ce qui est sécuritaire notamment pour certains systèmes embarqués dont la tension d'alimentation est critique.</quote> <text>L'utilisation d'un régulateur de tension linéaire a plusieurs avantages par rapport au régulateur de tension à découpage :</text> <quote>- Bruit électrique très faible. <br/>- Aucun bruit acoustique audible. <br/>- Grande stabilité en tension de sortie. <br/>- Bonne régulation lorsque la tension d'entrée est proche de la tension de sortie. <br/>- Grande plage de tensions d'entrée.</quote> <text><bold>Les caractéristiques de la carte :</bold> <br/>- Microcontrôleur ATmega48P, ATmega88P, ATmega168P ou ATmega328P. <br/>- Régulateur de tension LM2940 +5V 1A. <br/>- 1 port POWER (alimentation) de +6V à +26V. <br/>- 1 port ISP (programmation in-situ) pour la programmation du microcontrôleur. <br/>- 20 ports GPIO (entrées/sorties pour un usage général), avec 20 broches +5V (pôles positifs) et 20 broches GND (masses) pour l'alimentation des périphériques. <br/>- Fréquence de fonctionnement : 16MHz. <br/>- Dimensions : 66.04mm x 40.64mm. <br/>- Entre-axes de fixations : 58.42mm x 33.02mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Microcontrôleur ATMEGA48P (boîtier DIP-28) <br/>ou 1x Microcontrôleur ATMEGA88P (boîtier DIP-28) <br/>ou 1x Microcontrôleur ATMEGA168P (boîtier DIP-28) <br/>ou 1x Microcontrôleur ATMEGA328P (boîtier DIP-28) <br/>1x Régulateur de tension LM2940 (version fixée +5V, boîtier TO-220) <br/>1x Résistance 200Ω ± 1% 250mW <br/>1x Résistance 10kΩ ± 1% 250mW <br/>2x Condensateurs céramique 18pF >=10V (pas 5.08mm) <br/>4x Condensateurs céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique aluminium 10μF >=52V (pas 2mm) <br/>1x Condensateur électrolytique tantale 22μF >=10V (pas 2.54mm) <br/>1x Condensateur électrolytique aluminium 100μF >=10V (pas 2mm) <br/>1x Inductance self 10μH 100mA (boîtier axial) <br/>1x Diode Schottky 1N5819 <br/>1x Quartz 16MHz (pas 5.08mm) <br/>1x Del 3mm (pas 2.54mm, couleur de votre choix) <br/>1x Support DIP-28 300mil <br/>68x Broches mâles (pas 2.54mm) <br/>1x Dissipateur thermique (pour boîtier TO-220)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08090.jpg"><img src="thumbnail/dsc08090.jpg"></img></a> <a href="photo/dsc08333.jpg"><img src="thumbnail/dsc08333.jpg"></img></a> <title>Les ports d'entrée/sortie de l'automate programmable :</title> <underline></underline> <text>La fonction principale des ports d'entrée/sortie de l'automate programmable est la <bold>GPIO</bold> (pour "General Purpose Input/Output"), c'est-à-dire des <bold>entrées/sorties pour un usage général</bold>. Mais certains ports d'entrée/sortie sont reliés en interne aux microcontrôleurs à des fonctions matérielles spécifiques, comme par exemple <bold>USART</bold>, <bold>SPI</bold>, <bold>TWI</bold>, <bold>PWM</bold>, <bold>ADC</bold>, etc... Dans tous les cas l'usage de ces ports est détaillé ci-dessous et pour les classes les utilisant dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web.</text> <text><bold>Correspondance des ports GPIO (automate programmable par rapport aux microcontrôleurs) :</bold></text> <caution>- Port GPIO 1 = PD0 <br/>- Port GPIO 2 = PD1 <br/>- Port GPIO 3 = PD2 <br/>- Port GPIO 4 = PD3 <br/>- Port GPIO 5 = PD4 <br/>- Port GPIO 6 = PD5 <br/>- Port GPIO 7 = PD6 <br/>- Port GPIO 8 = PD7 <br/>- Port GPIO 9 = PB0 <br/>- Port GPIO 10 = PB1 <br/>- Port GPIO 11 = PB2 <br/>- Port GPIO 12 = PB3 <br/>- Port GPIO 13 = PB4 <br/>- Port GPIO 14 = PB5 <br/>- Port GPIO 15 = PC0 <br/>- Port GPIO 16 = PC1 <br/>- Port GPIO 17 = PC2 <br/>- Port GPIO 18 = PC3 <br/>- Port GPIO 19 = PC4 <br/>- Port GPIO 20 = PC5</caution> <text><bold>Ports de l'automate programmable concernés par les interruptions :</bold></text> <caution>- Port GPIO 3 (PD2) = INT0 (interrupt 0) <br/>- Port GPIO 4 (PD3) = INT1 (interrupt 1)</caution> <text><bold>Ports de l'automate programmable concernés par l'USART :</bold></text> <caution>- Port GPIO 1 (PD0) = RXD (receive data) <br/>- Port GPIO 2 (PD1) = TXD (transmit data)</caution> <text><bold>Ports de l'automate programmable concernés par le SPI :</bold></text> <caution>- Port GPIO 11 (PB2) = SS (slave select) <br/>- Port GPIO 12 (PB3) = MOSI (master output slave input) <br/>- Port GPIO 13 (PB4) = MISO (master input slave output) <br/>- Port GPIO 14 (PB5) = SCK (serial clock)</caution> <text><bold>Ports de l'automate programmable concernés par le TWI :</bold></text> <caution>- Port GPIO 19 (PC4) = SDA (serial data line) <br/>- Port GPIO 20 (PC5) = SCL (serial clock line)</caution> <text><bold>Ports de l'automate programmable concernés par la lecture du PWM :</bold></text> <caution>- Port GPIO 1 (PD0) = PCINT16 (pin change interrupt 16) <br/>- Port GPIO 2 (PD1) = PCINT17 (pin change interrupt 17) <br/>- Port GPIO 3 (PD2) = PCINT18 (pin change interrupt 18) <br/>- Port GPIO 4 (PD3) = PCINT19 (pin change interrupt 19) <br/>- Port GPIO 5 (PD4) = PCINT20 (pin change interrupt 20) <br/>- Port GPIO 6 (PD5) = PCINT21 (pin change interrupt 21) <br/>- Port GPIO 7 (PD6) = PCINT22 (pin change interrupt 22) <br/>- Port GPIO 8 (PD7) = PCINT23 (pin change interrupt 23) <br/>- Port GPIO 9 (PB0) = PCINT0 (pin change interrupt 0) <br/>- Port GPIO 10 (PB1) = PCINT1 (pin change interrupt 1) <br/>- Port GPIO 11 (PB2) = PCINT2 (pin change interrupt 2) <br/>- Port GPIO 12 (PB3) = PCINT3 (pin change interrupt 3) <br/>- Port GPIO 13 (PB4) = PCINT4 (pin change interrupt 4) <br/>- Port GPIO 14 (PB5) = PCINT5 (pin change interrupt 5) <br/>- Port GPIO 15 (PC0) = PCINT8 (pin change interrupt 8) <br/>- Port GPIO 16 (PC1) = PCINT9 (pin change interrupt 9) <br/>- Port GPIO 17 (PC2) = PCINT10 (pin change interrupt 10) <br/>- Port GPIO 18 (PC3) = PCINT11 (pin change interrupt 11) <br/>- Port GPIO 19 (PC4) = PCINT12 (pin change interrupt 12) <br/>- Port GPIO 20 (PC5) = PCINT13 (pin change interrupt 13)</caution> <text><bold>Ports de l'automate programmable concernés par la génération du PWM :</bold></text> <caution>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <text><bold>Ports de l'automate programmable concernés par la génération purement matérielle du PWM :</bold></text> <caution>- Port GPIO 10 (PB1) = OC1A (output compare 1A) <br/>- Port GPIO 11 (PB2) = OC1B (output compare 1B)</caution> <text><bold>Ports de l'automate programmable concernés par l'ADC :</bold></text> <caution>- Port GPIO 15 (PC0) = ADC0 (analog to digital converter 0) <br/>- Port GPIO 16 (PC1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 17 (PC2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 18 (PC3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 19 (PC4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 20 (PC5) = ADC5 (analog to digital converter 5)</caution> <text><bold>Ports de l'automate programmable concernés par la génération de sons :</bold></text> <caution>- Port GPIO 1 (PD0) <br/>- Port GPIO 2 (PD1) <br/>- Port GPIO 3 (PD2) <br/>- Port GPIO 4 (PD3) <br/>- Port GPIO 5 (PD4) <br/>- Port GPIO 6 (PD5) <br/>- Port GPIO 7 (PD6) <br/>- Port GPIO 8 (PD7) <br/>- Port GPIO 9 (PB0) <br/>- Port GPIO 10 (PB1) <br/>- Port GPIO 11 (PB2) <br/>- Port GPIO 12 (PB3) <br/>- Port GPIO 13 (PB4) <br/>- Port GPIO 14 (PB5) <br/>- Port GPIO 15 (PC0) <br/>- Port GPIO 16 (PC1) <br/>- Port GPIO 17 (PC2) <br/>- Port GPIO 18 (PC3) <br/>- Port GPIO 19 (PC4) <br/>- Port GPIO 20 (PC5)</caution> <title>Archives :</title> <underline></underline> <text>Quelques photos du prototype à l'époque où je débutais la programmation de MODULE :</text> <a href="photo/dsc01673.jpg"><img src="thumbnail/dsc01673.jpg"></img></a> <a href="photo/dsc01667.jpg"><img src="thumbnail/dsc01667.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectModulable32.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectModulable32"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'automate programmable MODULABLE 32</title> <underline></underline> <text>Ce nouvel <bold>automate programmable</bold> associé au programme MODULE (c'est-à-dire compatible dans les fonctionnalités et les entrées/sorties) est un calculateur embarqué qui est chargé d'exécuter les instructions machine de votre programme, il peut être équipé des microcontrôleurs <bold>ATmega164P</bold>, <bold>ATmega324P</bold>, <bold>ATmega644P</bold>, ou <bold>ATmega1284P</bold>.</text> <a href="photo/dsc08196.jpg"><img src="thumbnail/dsc08196.jpg"></img></a> <a href="photo/dsc08187.jpg"><img src="thumbnail/dsc08187.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/modulable_32.zip"><download>Télécharger le plan de fabrication de l'automate programmable <bold>MODULABLE 32</bold> (.zip, 401 octets)</download></a> <text>Selon si votre projet requiert plus ou moins de mémoire <bold>Flash</bold>, <bold>EEPROM</bold>, ou <bold>SRAM</bold>, 4 microcontrôleurs différents peuvent être implantés sur la carte MODULABLE 32 :</text> <caution><bold>Microcontrôleur ATmega164P :</bold> <br/>- Mémoire Flash = 16384 octets (16Kio) <br/>- Mémoire EEPROM = 512 octets (0.5Kio) <br/>- Mémoire SRAM = 1024 octets (1Kio) <br/> <br/><bold>Microcontrôleur ATmega324P :</bold> <br/>- Mémoire Flash = 32768 octets (32Kio) <br/>- Mémoire EEPROM = 1024 octets (1Kio) <br/>- Mémoire SRAM = 2048 octets (2Kio) <br/> <br/><bold>Microcontrôleur ATmega644P :</bold> <br/>- Mémoire Flash = 65536 octets (64Kio) <br/>- Mémoire EEPROM = 2048 octets (2Kio) <br/>- Mémoire SRAM = 4096 octets (4Kio) <br/> <br/><bold>Microcontrôleur ATmega1284P :</bold> <br/>- Mémoire Flash = 131072 octets (128Kio) <br/>- Mémoire EEPROM = 4096 octets (4Kio) <br/>- Mémoire SRAM = 16384 octets (16Kio)</caution> <text>L'automate programmable MODULABLE 32 est le cœur de mes montages électroniques, il contient dans le microcontrôleur <bold>le programme binaire</bold> écrit à l'origine en langage C++ à l'aide de MODULE permettant de gérer toute la logique combinatoire et mathématique du montage.</text> <text>En comparaison à l'automate programmable MODULABLE 20, le MODULABLE 32 est bien plus intéressant sur bien des aspects. En effet, il dispose de <bold>32 entrées/sorties</bold> groupées en 4 blocs de 8 broches chacun (logique des ports respectivement B, D, C et A) qui sont des <bold>GPIO</bold>, et peut développer un courant jusqu'à <bold>8A</bold> en pointe à l'aide d'un régulateur de tension <bold>LM2940</bold> assisté par un transistor bipolaire <bold>MJE15033</bold>.</text> <caution>L'automate programmable MODULABLE 32 (tout comme le MODULABLE 20) peut être alimenté de <bold>+6V</bold> jusqu'à <bold>+26V</bold>, ce qui est favorable à une batterie Lithium-ion polymère (LiPo) de <bold>2S</bold> à <bold>6S</bold> standard (+8.4V à +25.2V), ou encore à des sources d'alimentation assez communes de <bold>+12V</bold> ou <bold>+24V</bold> en courant continu.</caution> <text>Néanmoins selon le courant demandé, le circuit de régulation de tension embarqué dans cet automate programmable pourra délivrer une <bold>tension stable de +5V</bold> via une tension d'alimentation supérieure à +5V mais <bold>inférieure à +6V</bold>, ceci grâce aux faibles pertes (dropout) du régulateur de tension LM2940 couplé au transistor bipolaire MJE15033.</text> <quote>À noter que le microcontrôleur fonctionnera normalement (dans ses spécifications techniques) avec des <bold>tensions d'alimentation bien inférieures à +5V</bold> en entrée, ce qui est sécuritaire notamment pour certains systèmes embarqués dont la tension d'alimentation est critique.</quote> <text>L'utilisation d'un régulateur de tension linéaire a plusieurs avantages par rapport au régulateur de tension à découpage :</text> <quote>- Bruit électrique très faible. <br/>- Aucun bruit acoustique audible. <br/>- Grande stabilité en tension de sortie. <br/>- Bonne régulation lorsque la tension d'entrée est proche de la tension de sortie. <br/>- Grande plage de tensions d'entrée.</quote> <text>Cette alimentation robuste ainsi que les caractéristiques inhérentes aux microcontrôleurs qui peuvent être embarqués sur cette carte, élargissent le domaine d'application de l'automate programmable MODULABLE 32, ce qui permet entre autres de réaliser des projets de grande complexité mathématique et logique, et de haute fiabilité.</text> <a href="photo/dsc07988.jpg"><img src="thumbnail/dsc07988.jpg"></img></a> <a href="photo/dsc08099.jpg"><img src="thumbnail/dsc08099.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- Microcontrôleur ATmega164P, Atmega324P, Atmega644P ou ATmega1284P. <br/>- Régulateur de tension LM2940 +5V 1A assisté par un transistor bipolaire MJE15033 8A. <br/>- 2 ports POWER (alimentation) de +6V à +26V (broches ou connecteurs à braser). <br/>- 1 port ISP (programmation in-situ) pour la programmation du microcontrôleur. <br/>- 32 ports GPIO (entrées/sorties pour un usage général), avec 32 broches +5V (pôles positifs) et 32 broches GND (masses) pour l'alimentation des périphériques. <br/>- Fréquence de fonctionnement : 16MHz. <br/>- Dimensions : 88.9mm x 40.64mm. <br/>- Entre-axes de fixations : 81.28mm x 33.02mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Microcontrôleur ATMEGA164P (boîtier DIP-40) <br/>ou 1x Microcontrôleur ATMEGA324P (boîtier DIP-40) <br/>ou 1x Microcontrôleur ATMEGA644P (boîtier DIP-40) <br/>ou 1x Microcontrôleur ATMEGA1284P (boîtier DIP-40) <br/>1x Régulateur de tension LM2940 (version fixée +5V, boîtier TO-220) <br/>1x Résistance 10Ω ± 1% 250mW <br/>1x Résistance 200Ω ± 1% 250mW <br/>1x Résistance 10kΩ ± 1% 250mW <br/>2x Condensateurs céramique 18pF >=10V (pas 5.08mm) <br/>4x Condensateurs céramique 100nF >=10V (pas 5.08mm) <br/>1x Condensateur électrolytique tantale 22μF >=10V (pas 2.54mm) <br/>3x Condensateurs électrolytiques aluminium 100μF >=10V (pas 2mm) <br/>1x Condensateur électrolytique aluminium 100μF >=52V (pas 2.5mm) <br/>1x Inductance self 10μH 100mA (boîtier axial) <br/>1x Diode Schottky 1N5819 <br/>1x Transistor bipolaire MJE15033 (boîtier TO-220) <br/>1x Quartz 16MHz (pas 5.08mm, profil bas) <br/>1x Del 3mm (pas 2.54mm, couleur de votre choix) <br/>1x Support DIP-40 600mil <br/>98x Broches mâles (pas 2.54mm) <br/>1x Dissipateur thermique (pour boîtier TO-220)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc07970.jpg"><img src="thumbnail/dsc07970.jpg"></img></a> <a href="photo/dsc08192.jpg"><img src="thumbnail/dsc08192.jpg"></img></a> <title>Les ports d'entrée/sortie de l'automate programmable :</title> <underline></underline> <text>La fonction principale des ports d'entrée/sortie de l'automate programmable est la <bold>GPIO</bold> (pour "General Purpose Input/Output"), c'est-à-dire des <bold>entrées/sorties pour un usage général</bold>. Mais certains ports d'entrée/sortie sont reliés en interne aux microcontrôleurs à des fonctions matérielles spécifiques, comme par exemple <bold>USART</bold>, <bold>SPI</bold>, <bold>TWI</bold>, <bold>PWM</bold>, <bold>ADC</bold>, etc... Dans tous les cas l'usage de ces ports est détaillé ci-dessous et pour les classes les utilisant dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web.</text> <text><bold>Correspondance des ports GPIO (automate programmable par rapport aux microcontrôleurs) :</bold></text> <caution>- Port GPIO 1 = PB0 <br/>- Port GPIO 2 = PB1 <br/>- Port GPIO 3 = PB2 <br/>- Port GPIO 4 = PB3 <br/>- Port GPIO 5 = PB4 <br/>- Port GPIO 6 = PB5 <br/>- Port GPIO 7 = PB6 <br/>- Port GPIO 8 = PB7 <br/>- Port GPIO 9 = PD0 <br/>- Port GPIO 10 = PD1 <br/>- Port GPIO 11 = PD2 <br/>- Port GPIO 12 = PD3 <br/>- Port GPIO 13 = PD4 <br/>- Port GPIO 14 = PD5 <br/>- Port GPIO 15 = PD6 <br/>- Port GPIO 16 = PD7 <br/>- Port GPIO 17 = PC0 <br/>- Port GPIO 18 = PC1 <br/>- Port GPIO 19 = PC2 <br/>- Port GPIO 20 = PC3 <br/>- Port GPIO 21 = PC4 <br/>- Port GPIO 22 = PC5 <br/>- Port GPIO 23 = PC6 <br/>- Port GPIO 24 = PC7 <br/>- Port GPIO 25 = PA7 <br/>- Port GPIO 26 = PA6 <br/>- Port GPIO 27 = PA5 <br/>- Port GPIO 28 = PA4 <br/>- Port GPIO 29 = PA3 <br/>- Port GPIO 30 = PA2 <br/>- Port GPIO 31 = PA1 <br/>- Port GPIO 32 = PA0</caution> <text><bold>Ports de l'automate programmable concernés par les interruptions :</bold></text> <caution>- Port GPIO 3 (PB2) = INT2 (interrupt 2) <br/>- Port GPIO 11 (PD2) = INT0 (interrupt 0) <br/>- Port GPIO 12 (PD3) = INT1 (interrupt 1)</caution> <text><bold>Ports de l'automate programmable concernés par l'USART :</bold></text> <caution>- Port GPIO 9 (PD0) = RXD (receive data) <br/>- Port GPIO 10 (PD1) = TXD (transmit data)</caution> <text><bold>Ports de l'automate programmable concernés par le SPI :</bold></text> <caution>- Port GPIO 5 (PB4) = SS (slave select) <br/>- Port GPIO 6 (PB5) = MOSI (master output slave input) <br/>- Port GPIO 7 (PB6) = MISO (master input slave output) <br/>- Port GPIO 8 (PB7) = SCK (serial clock)</caution> <text><bold>Ports de l'automate programmable concernés par le TWI :</bold></text> <caution>- Port GPIO 17 (PC0) = SCL (serial clock line) <br/>- Port GPIO 18 (PC1) = SDA (serial data line)</caution> <text><bold>Ports de l'automate programmable concernés par la lecture du PWM :</bold></text> <caution>- Port GPIO 1 (PB0) = PCINT8 (pin change interrupt 8) <br/>- Port GPIO 2 (PB1) = PCINT9 (pin change interrupt 9) <br/>- Port GPIO 3 (PB2) = PCINT10 (pin change interrupt 10) <br/>- Port GPIO 4 (PB3) = PCINT11 (pin change interrupt 11) <br/>- Port GPIO 5 (PB4) = PCINT12 (pin change interrupt 12) <br/>- Port GPIO 6 (PB5) = PCINT13 (pin change interrupt 13) <br/>- Port GPIO 7 (PB6) = PCINT14 (pin change interrupt 14) <br/>- Port GPIO 8 (PB7) = PCINT15 (pin change interrupt 15) <br/>- Port GPIO 9 (PD0) = PCINT24 (pin change interrupt 24) <br/>- Port GPIO 10 (PD1) = PCINT25 (pin change interrupt 25) <br/>- Port GPIO 11 (PD2) = PCINT26 (pin change interrupt 26) <br/>- Port GPIO 12 (PD3) = PCINT27 (pin change interrupt 27) <br/>- Port GPIO 13 (PD4) = PCINT28 (pin change interrupt 28) <br/>- Port GPIO 14 (PD5) = PCINT29 (pin change interrupt 29) <br/>- Port GPIO 15 (PD6) = PCINT30 (pin change interrupt 30) <br/>- Port GPIO 16 (PD7) = PCINT31 (pin change interrupt 31) <br/>- Port GPIO 17 (PC0) = PCINT16 (pin change interrupt 16) <br/>- Port GPIO 18 (PC1) = PCINT17 (pin change interrupt 17) <br/>- Port GPIO 19 (PC2) = PCINT18 (pin change interrupt 18) <br/>- Port GPIO 20 (PC3) = PCINT19 (pin change interrupt 19) <br/>- Port GPIO 21 (PC4) = PCINT20 (pin change interrupt 20) <br/>- Port GPIO 22 (PC5) = PCINT21 (pin change interrupt 21) <br/>- Port GPIO 23 (PC6) = PCINT22 (pin change interrupt 22) <br/>- Port GPIO 24 (PC7) = PCINT23 (pin change interrupt 23) <br/>- Port GPIO 25 (PA7) = PCINT7 (pin change interrupt 7) <br/>- Port GPIO 26 (PA6) = PCINT6 (pin change interrupt 6) <br/>- Port GPIO 27 (PA5) = PCINT5 (pin change interrupt 5) <br/>- Port GPIO 28 (PA4) = PCINT4 (pin change interrupt 4) <br/>- Port GPIO 29 (PA3) = PCINT3 (pin change interrupt 3) <br/>- Port GPIO 30 (PA2) = PCINT2 (pin change interrupt 2) <br/>- Port GPIO 31 (PA1) = PCINT1 (pin change interrupt 1) <br/>- Port GPIO 32 (PA0) = PCINT0 (pin change interrupt 0)</caution> <text><bold>Ports de l'automate programmable concernés par la génération du PWM :</bold></text> <caution>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <text><bold>Ports de l'automate programmable concernés par la génération purement matérielle du PWM :</bold></text> <caution>- Port GPIO 13 (PD4) = OC1B (output compare 1B) <br/>- Port GPIO 14 (PD5) = OC1A (output compare 1A) <br/> <br/><bold>Spécificité pour le microcontrôleur ATmega1284P :</bold> <br/>- Port GPIO 7 (PB6) = OC3A (output compare 3A) <br/>- Port GPIO 8 (PB7) = OC3B (output compare 3B) <br/>- Port GPIO 13 (PD4) = OC1B (output compare 1B) <br/>- Port GPIO 14 (PD5) = OC1A (output compare 1A)</caution> <text><bold>Ports de l'automate programmable concernés par l'ADC :</bold></text> <caution>- Port GPIO 25 (PA7) = ADC7 (analog to digital converter 7) <br/>- Port GPIO 26 (PA6) = ADC6 (analog to digital converter 6) <br/>- Port GPIO 27 (PA5) = ADC5 (analog to digital converter 5) <br/>- Port GPIO 28 (PA4) = ADC4 (analog to digital converter 4) <br/>- Port GPIO 29 (PA3) = ADC3 (analog to digital converter 3) <br/>- Port GPIO 30 (PA2) = ADC2 (analog to digital converter 2) <br/>- Port GPIO 31 (PA1) = ADC1 (analog to digital converter 1) <br/>- Port GPIO 32 (PA0) = ADC0 (analog to digital converter 0)</caution> <text><bold>Ports de l'automate programmable concernés par la génération de sons :</bold></text> <caution>- Port GPIO 1 (PB0) <br/>- Port GPIO 2 (PB1) <br/>- Port GPIO 3 (PB2) <br/>- Port GPIO 4 (PB3) <br/>- Port GPIO 5 (PB4) <br/>- Port GPIO 6 (PB5) <br/>- Port GPIO 7 (PB6) <br/>- Port GPIO 8 (PB7) <br/>- Port GPIO 9 (PD0) <br/>- Port GPIO 10 (PD1) <br/>- Port GPIO 11 (PD2) <br/>- Port GPIO 12 (PD3) <br/>- Port GPIO 13 (PD4) <br/>- Port GPIO 14 (PD5) <br/>- Port GPIO 15 (PD6) <br/>- Port GPIO 16 (PD7) <br/>- Port GPIO 17 (PC0) <br/>- Port GPIO 18 (PC1) <br/>- Port GPIO 19 (PC2) <br/>- Port GPIO 20 (PC3) <br/>- Port GPIO 21 (PC4) <br/>- Port GPIO 22 (PC5) <br/>- Port GPIO 23 (PC6) <br/>- Port GPIO 24 (PC7) <br/>- Port GPIO 25 (PA7) <br/>- Port GPIO 26 (PA6) <br/>- Port GPIO 27 (PA5) <br/>- Port GPIO 28 (PA4) <br/>- Port GPIO 29 (PA3) <br/>- Port GPIO 30 (PA2) <br/>- Port GPIO 31 (PA1) <br/>- Port GPIO 32 (PA0)</caution> <title>Précautions pour l'assemblage :</title> <underline></underline> <text>Il convient pour assembler cette carte électronique de respecter un ordre lors de la brasure de certains composants, notamment ceux <bold>implantés en dessous du microcontrôleur</bold> :</text> <a href="photo/dsc07972.jpg"><img src="thumbnail/dsc07972.jpg"></img></a> <a href="photo/dsc07973.jpg"><img src="thumbnail/dsc07973.jpg"></img></a> <text>Un pliage spécifique doit être effectué avec une pince adéquate afin que les condensateurs viennent se loger sans toucher le microcontrôleur et son support :</text> <a href="photo/dsc07974.jpg"><img src="thumbnail/dsc07974.jpg"></img></a> <a href="photo/dsc07980.jpg"><img src="thumbnail/dsc07980.jpg"></img></a> <text>Une fois cette opération réalisée l'assemblage se fait normalement.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectMusicalInstrumentDigitalInterface.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectMusicalInstrumentDigitalInterface"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'interface de communication MIDI</title> <underline></underline> <text>Cette interface assure la connexion et la communication entre des instruments de musique standards et mes automates programmables en utilisant le <bold>protocole MIDI</bold> (pour "Musical Instrument Digital Interface" ou interface numérique pour instrument de musique). Ceci est réalisé en traduisant <bold>le protocole MIDI vers USART</bold> (et inversement).</text> <a href="photo/dsc08775.jpg"><img src="thumbnail/dsc08775.jpg"></img></a> <a href="photo/dsc08767.jpg"><img src="thumbnail/dsc08767.jpg"></img></a> <text>Le plan de fabrication de ce circuit imprimé est disponible au <bold>format de fichiers Gerber</bold> ici :</text> <a href="download/pcb/musical_instrument_digital_interface.zip"><download>Télécharger le plan de fabrication de l'interface de <bold>communication MIDI</bold> (.zip, 449 octets)</download></a> <text>Cette interface est équipée d'une <bold>protection contre les surtensions</bold> à l'aide d'un <bold>optocoupleur 6N139</bold>, et d'une <bold>protection contre les inversions</bold> sur les ports d'entrée/sortie DIN-5 femelles.</text> <text><bold>Ports des automates programmables concernés par l'USART :</bold></text> <caution><bold>Automate programmable MODULABLE 20 :</bold> <br/>- Port GPIO 1 (PD0) = RXD (receive data) <br/>- Port GPIO 2 (PD1) = TXD (transmit data) <br/> <br/><bold>Automate programmable MODULABLE 32 :</bold> <br/>- Port GPIO 9 (PD0) = RXD (receive data) <br/>- Port GPIO 10 (PD1) = TXD (transmit data)</caution> <text><bold>Connexions (interface de communication MIDI sur automate programmable) :</bold></text> <caution>- Broche GND (masse) sur broche GND disponible. <br/>- Broche +5V (pôle positif) sur broche +5V disponible. <br/>- Broche RXD (receive data) sur port RXD. <br/>- Broche TXD (transmit data) sur port TXD.</caution> <text><bold>Connexions (périphérique MIDI sur interface de communication MIDI) :</bold></text> <caution>- Port de sortie MIDI du périphérique sur port MIDI INPUT (entrée MIDI de l'interface de communication). <br/>- Port d'entrée MIDI du périphérique sur port MIDI OUTPUT (sortie MIDI de l'interface de communication).</caution> <a href="photo/dsc08632.jpg"><img src="thumbnail/dsc08632.jpg"></img></a> <a href="photo/dsc08777.jpg"><img src="thumbnail/dsc08777.jpg"></img></a> <a href="photo/dsc08784.jpg"><img src="thumbnail/dsc08784.jpg"></img></a> <a href="photo/dsc08706.jpg"><img src="thumbnail/dsc08706.jpg"></img></a> <text><bold>Les caractéristiques de la carte :</bold> <br/>- 1 broche GND (masse) pour l'alimentation. <br/>- 1 broche +5V (pôle positif) pour l'alimentation. <br/>- 1 broche RXD (receive data) pour la communication USART. <br/>- 1 broche TXD (transmit data) pour la communication USART. <br/>- 2 ports DIN-5 femelles (1 port d'entrée et 1 port de sortie) pour la communication MIDI. <br/>- Dimensions : 57.15mm x 38.735mm. <br/>- Entre-axes de fixations : 49.53mm x 31.115mm. <br/>- Fixations par vis M3 (perçages diamètre 3.2mm).</text> <text><bold>Liste des composants :</bold></text> <quote>1x Optocoupleur 6N139 (boîtier DIP-8) <br/>3x Résistances 200Ω ± 1% 250mW <br/>3x Résistances 1kΩ ± 1% 250mW <br/>3x Résistances 10kΩ ± 1% 250mW <br/>1x Condensateur céramique 100nF >=10V (pas 5.08mm) <br/>2x Diodes 1N4148 <br/>2x Transistors bipolaires 2N3904 (boîtier TO-92) <br/>1x Support DIP-8 300mil <br/>4x Broches mâles (pas 2.54mm) <br/>2x Ports DIN-5 femelles (montage CI)</quote> <text>À gauche les composants nécessaires, à droite le PCB nu :</text> <a href="photo/dsc08646.jpg"><img src="thumbnail/dsc08646.jpg"></img></a> <a href="photo/dsc08754.jpg"><img src="thumbnail/dsc08754.jpg"></img></a> <title>Conseils pour l'assemblage :</title> <underline></underline> <text>Différentes références de connecteurs DIN-5 femelles sont adaptés au montage sur ce PCB car <bold>certains perçages sont oblongs</bold>, et <bold>la disposition est prévue pour les connecteurs les plus volumineux</bold> :</text> <a href="photo/dsc08755.jpg"><img src="thumbnail/dsc08755.jpg"></img></a> <a href="photo/dsc08761.jpg"><img src="thumbnail/dsc08761.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectNetworkInterface.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectNetworkInterface"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'interface de communication réseau filaire</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectQuadcopter.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectQuadcopter"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le quadri-hélicoptère</title> <underline></underline> <text>Le <bold>quadri-hélicoptère</bold> (et non pas drone, voir plus bas "L'amalgame du drone en aéromodélisme") est un type d'hélicoptère propulsé par quatre moteurs. Ce projet est un hélicoptère acrobatique conçu spécialement pour effectuer de la <bold>voltige 3D</bold> (acrobaties en vol dos avec inversion du sens de rotation des moteurs), le tout piloté avec ma radiocommande de conception personnelle (pour plus d'informations, voir dans la section "Fabrications et diverses réalisations" en page d'accueil de mon site Web, page "La radiocommande").</text> <a href="photo/dsc08428.jpg"><img src="thumbnail/dsc08428.jpg"></img></a> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <text>Vidéo ci-dessous, un vol en cours de conception (filmé au début du projet) :</text> <video src="video/00003.mov" controls></video> <text>Photos ci-dessous, montage de l'électronique et assemblage du châssis :</text> <a href="photo/dsc08409.jpg"><img src="thumbnail/dsc08409.jpg"></img></a> <a href="photo/dsc08387.jpg"><img src="thumbnail/dsc08387.jpg"></img></a> <a href="photo/dsc08376.jpg"><img src="thumbnail/dsc08376.jpg"></img></a> <a href="photo/dsc08417.jpg"><img src="thumbnail/dsc08417.jpg"></img></a> <text><bold>Programmation de l'automate programmable MODULABLE 32 avec MODULE :</bold> <br/>Le programme en langage C++ fonctionnant avec MODULE est téléchargeable ici :</text> <a href="download/cpp/quadcopter.zip"><download>Télécharger le programme du <bold>quadri-hélicoptère</bold> (.zip, ≈ 6.7Kio)</download></a> <text>Les paramètres (settings) sont à régler via la radiocommande, voici les valeurs que j'ai indiqué qui sont optimisées pour un hélicoptère comportant des caractéristiques précises (voir les caractéristiques de mon hélicoptère plus bas) :</text> <caution>- "FRES" = <bold>800Hz</bold> (fréquence PWM des ESC). <br/>- "CUES" = <bold>187μs</bold> (coupure des ESC, moteur arrêté). <br/>- "MIEN" = <bold>198μs</bold> (gaz minimum des ESC en vol normal). <br/>- "MAEN" = <bold>250μs</bold> (gaz maximum des ESC en vol normal). <br/>- "MIEI" = <bold>176μs</bold> (gaz minimum des ESC en vol inversé). <br/>- "MAEI" = <bold>125μs</bold> (gaz maximum des ESC en vol inversé). <br/>- "SPPI" = <bold>360°/s</bold> (vitesse angulaire maximale sur l'axe de tangage). <br/>- "SPRO" = <bold>360°/s</bold> (vitesse angulaire maximale sur l'axe de roulis). <br/>- "SPYA" = <bold>360°/s</bold> (vitesse angulaire maximale sur l'axe de lacet). <br/>- "GAPI" = <bold>97%</bold> (gain du gyroscope sur l'axe de tangage). <br/>- "GARO" = <bold>95%</bold> (gain du gyroscope sur l'axe de roulis). <br/>- "GAYA" = <bold>99%</bold> (gain du gyroscope sur l'axe de lacet). <br/>- "TRAV" = <bold>40%</bold> (proportion des débattements de l'axe de tangage et de roulis par rapport au lacet). <br/>- "PROP" = <bold>100%</bold> (diminution des gains en fonction des gaz). <br/>- "LOCK" = <bold>30%</bold> (augmentation des gains lors des acrobaties). <br/>- "LIMI" = <bold>100%</bold> (limitation des gaz maximums).</caution> <text><bold>Connexions (automate programmable MODULABLE 32 sur les différents systèmes embarqués) :</bold></text> <caution>- Port GPIO 5 (PB4) sur broche CSN (slave select) composant nRF24L01+. <br/>- Port GPIO 6 (PB5) sur broche MOSI (master output slave input) composant nRF24L01+. <br/>- Port GPIO 7 (PB6) sur broche MISO (master input slave output) composant nRF24L01+. <br/>- Port GPIO 8 (PB7) sur broche SCK (serial clock) composant nRF24L01+. <br/>- Port GPIO 9 (PD0) sur broche PWM ESC moteur 1 (avant gauche). <br/>- Port GPIO 10 (PD1) sur broche PWM ESC moteur 2 (avant droit). <br/>- Port GPIO 11 (PD2) sur broche PWM ESC moteur 3 (arrière gauche). <br/>- Port GPIO 12 (PD3) sur broche PWM ESC moteur 4 (arrière droit). <br/>- Port GPIO 17 (PC0) sur broche SCL (serial clock line) composant MPU6050. <br/>- Port GPIO 18 (PC1) sur broche SDA (serial data line) composant MPU6050. <br/>- Port GPIO 25 (PA7) sur broche WAVE (onde) buzzer de signalement. <br/>- Port GPIO 31 (PA1) sur sortie pont diviseur de tension 10kΩ / 2kΩ (tension de la batterie).</caution> <title>Historique, faisabilité, et caractéristiques :</title> <underline></underline> <text>Étant fortement intéressé par les aéronefs en général, j'ai toujours souhaité faire se sustenter un objet semi-autonome en stationnaire au dessus du sol par un moyen technique de propulsion quel qu'il soit. Cette idée est devenue davantage une possibilité de réalisation sous la forme d'un réel projet technique, lorsque j'ai commencé le pilotage des aéro-modèles dans une association.</text> <text>À cette période, la propulsion électrique des modèles réduits d'aéronefs était à ses débuts, mais on voyait déjà apparaître sur les terrains d'aéromodélisme des mini-hélicoptères radio-commandés qui peinaient tout juste à se soulever de quelques centimètres, puis quelques mètres au dessus du sol.</text> <text>Depuis ce temps, la technologie a fait un bond, notamment au niveau des accumulateurs au <bold>lithium-ion polymère</bold> (LiPo) et des <bold>moteurs sans charbons</bold> (brushless), ce qui a permis des avancées jusqu'alors insoupçonnées en matière de durée de vol et de performances.</text> <quote>La miniaturisation de l'électronique, notamment des <bold>gyroscopes</bold> et des <bold>émetteurs/récepteurs radios</bold>, a progressé à tel point qu'aujourd'hui en comparaison des volumes occupés, toute l'électronique tient dans une petite boîte !</quote> <text><bold>L'algorithme de vol :</bold> <br/>Le vol basique d'un aéronef à 4 hélices a été avec le programme MODULE solutionné sans difficulté. En effet le programme MODULE simplifie grandement la mise en œuvre du calculateur et des périphériques requis pour ce type de projet, tels qu'un gyroscope et 4 contrôleurs de moteurs sans charbons, ceci sans passer des heures en programmation.</text> <text>En revanche, là où la première version de l'algorithme de vol a montré quelques limites au début du projet, fut lors des premiers tests acrobatiques (boucles, tonneaux). Ainsi, après de nombreux essais en vol (mises gaz au ralenti/pleins gaz et angles vifs à plat et sur le dos volontairement), je me suis aperçu qu'il fallait programmer dans le calculateur embarqué bien plus qu'une simple stabilisation (plus évoluée qu'un pendule stabilisé par exemple).</text> <text>Pour se faire, j'ai dû suivre une logique différente de ma première approche prototype, en voici quelques notions importantes :</text> <quote>- La consigne sur les 3 axes est un offset des vitesses angulaires données par le gyroscope. <br/>- À l'image de vases communicants proportionnels, un échange linéaire des débattements alloué pour les corrections à effectuer sur un même axe de vol (tangage, roulis, ou lacet) est effectué proportionnellement entre les différents moteurs suivant la position du manche de gaz, de sorte d'avoir toute la plage de corrections disponibles que ce soit manche de gaz positionné sur ralenti moteur, ou positionné sur plein gaz. <br/>- En résulte que les débattements maximums sur les 3 axes sont alloués à l'algorithme de stabilisation afin d'effectuer les corrections les plus importantes possibles dans toutes les conditions. <br/>- En résulte également un ralenti moteur à 0% et un plein gaz à 100%. <br/>- Le gain sur les 3 axes de l'algorithme de stabilisation est une modification proportionnelle de l'intervalle des vitesses angulaires minimales et maximales allouées par le gyroscope (cet intervalle se réduit de façon linéaire suivant l'augmentation du gain). <br/>- Le rendement des hélices est variable avec la vitesse de rotation, en résulte la variabilité de la sensibilité des corrections que l'algorithme doit effectuer (gains variables) selon les ordres du pilote aux gaz. <br/>- Le gain sur les axes de tangage et de roulis augmente proportionnellement suivant les ordres du pilote au cyclique afin de garantir un meilleur verrouillage de l'assiette lors des acrobaties.</quote> <text>Tous ces calculs assez subtils participent au bon comportement en vol de l'ensemble, et permettent des vols acrobatiques assez poussés (notamment pour la voltige 3D, comprendre ici le vol dos ou inversé).</text> <a href="photo/dsc08427.jpg"><img src="thumbnail/dsc08427.jpg"></img></a> <a href="photo/dsc08424.jpg"><img src="thumbnail/dsc08424.jpg"></img></a> <text><bold>Projet validé :</bold> <br/>L'expérience acquise lors de la conception de cet hélicoptère, de la logique de l'algorithme de vol, ainsi que le nombre de vols effectués, m'ont permis de valider le fonctionnement de l'ensemble des cartes électroniques à bord du modèle en matière de robustesse, de fiabilité, et de performances.</text> <text><bold>Les caractéristiques du quadri-hélicoptère :</bold> <br/>- Automate programmable MODULABLE 32 équipé du microcontrôleur ATmega644P. <br/>- Émetteur/récepteur radio 2.4GHz (composant nRF24L01+). <br/>- Communication bidirectionnelle. <br/>- Antenne Trèfle omnidirectionnelle 4 branches (7dBm). <br/>- Communication par trames de 32 bits. <br/>- Centrale inertielle MPU6050. <br/>- Buzzer de signalement. <br/>- Système à tolérance de pannes (fail-safe) sur 5 bits (0 à 31). <br/>- Surveillance de l'activité du modèle (watchdog) sur 5 bits (0 à 31). <br/>- 3 modes de vol ("Full 2D", "Half 2D", et "Full 3D"). <br/>- Contrôleurs de moteurs sans charbons KISS ESC 2-5S 24A Race Edition. <br/>- Moteurs sans charbons TIGER MOTORS MN2206 2000kV. <br/>- Hélices 3D Graupner 6" x 3". <br/>- Accumulateur lithium-ion polymère (LiPo) TURNIGY 4S (+14.8V) 2200mAh 40/50C. <br/>- Tension de la batterie envoyée à la radiocommande sur 10 bits (0 à 1023). <br/>- Allumage ou extinction du modèle ou de la radiocommande dans n'importe quel ordre. <br/>- Châssis en tubes d'aluminium 10mm x 12mm. <br/>- Entre-axes moteurs : 372mm x 372mm.</text> <text>Boîte de transport sur-mesure en contre-plaqué 10mm :</text> <a href="photo/dsc08431.jpg"><img src="thumbnail/dsc08431.jpg"></img></a> <a href="photo/dsc08436.jpg"><img src="thumbnail/dsc08436.jpg"></img></a> <title>Les modes de vol :</title> <underline></underline> <text>À l'instar des machines de voltige équipées de pas variable collectif, cet hélicoptère est conçu pour effectuer des acrobaties 3D (vol inversé) grâce à <bold>l'inversion du sens de rotation des moteurs en plein vol</bold> (sens normal, l'air est aspiré au dessus et est refoulé en dessous de l'hélicoptère, sens inversé, l'air est aspiré en dessous et est refoulé au dessus de l'hélicoptère). Ceci permet à l'aide d'hélices adaptées, soit symétriques et à double sens de rotation, de voler sur le dos (c'est le vol inversé).</text> <text>Pour un pilote habitué au vol 3D, cette caractéristique d'inversion du sens de rotation des moteurs en vol est intuitive, ce premier étant familiarisé à l'inversion du pas collectif (de positif à négatif et inversement) sur des hélicoptères à rotors classiques (rotor principal et rotor anti-couple), avec un neutre c'est-à-dire un pas collectif à 0 degrés, situé <bold>manche de gaz au milieu</bold>.</text> <caution>En revanche pour un pilote non-initié à la voltige 3D, cette convention d'un ralenti moteur manche de gaz au milieu, avec leur rotations inversées suivant la position de ce manche de gaz sur la moitié inférieure ou supérieure de sa course totale serait non seulement contraignante, contre-intuitive, mais pourrait être également très dangereuse !</caution> <text>C'est pourquoi j'ai décidé de programmer <bold>3 modes de vol</bold> adaptés aux différentes situations, que vous pouvez sélectionner à tout moment via l'interrupteur <bold>auxiliaire A</bold> (3 positions) :</text> <quote>- <bold>Interrupteur auxiliaire A sur position 1 = Mode "Full 2D"</bold> : toute la course du manche de gaz (de 0% à 100%) est utilisée sans inversion du sens de rotation des moteurs. <br/>- <bold>Interrupteur auxiliaire A sur position 2 = Mode "Half 2D"</bold> : la moitié supérieure de la course du manche de gaz (de 52.5% à 100%) est utilisée sans inversion du sens de rotation des moteurs. <br/>- <bold>Interrupteur auxiliaire A sur position 3 = Mode "Full 3D"</bold> : toute la course du manche de gaz (de 0% à 100%) est utilisée avec inversion du sens de rotation des moteurs (inversé si manche de gaz inférieur ou égal à 47.5%, normal si manche de gaz supérieur ou égal à 52.5%).</quote> <text>Plus exactement, en mode de vol "Full 3D", lorsque le manche de gaz descend au moins à <bold>47.5%</bold> de sa course totale (soit égal ou inférieur à 47.5%), le sens de rotation des moteurs s'inverse, au contraire lorsque le manche de gaz monte au moins à <bold>52.5%</bold> de sa course totale (soit égal ou supérieur à 52.5%), le sens de rotation des moteurs s'inverse à nouveau (sens normal). C'est donc un hystérésis de <bold>5%</bold> qui a pour avantage de ne pas faire inverser le sens de rotation des moteurs de façon intempestive lorsque le manche de gaz se situe dans la zone du milieu (vers la moitié de sa course totale).</text> <caution>Pour éviter un démarrage involontaire des moteurs à l'allumage du modèle <bold>quel que soit le mode de vol</bold>, il est indispensable d'avoir en premier lieu prévu les sécurités nécessaires pour prévenir tout accident (voir ci-dessous : "Les sécurités d'avant vol").</caution> <title>Les sécurités d'avant vol :</title> <underline></underline> <text>Afin de garantir le non-démarrage des moteurs à l'allumage du modèle, j'ai mis en place quelques sécurités (ou conditions à remplir) : <br/>- Vérification de <bold>l'arrivée de toutes les voies</bold> de la radiocommande. <br/>- Vérification que l'interrupteur de coupure moteur soit <bold>activé</bold>. <br/>- Vérification que le manche de gaz soit inférieur à <bold>5%</bold> de sa course totale (ralenti moteur en mode "Full 2D"), ou inférieur à <bold>52.5%</bold> de sa course totale (ralenti moteur en mode "Half 2D"), ou <bold>centré entre 47.5% à 52.5%</bold> de sa course totale (ralenti moteur en mode "Full 3D"), sans trim ni courbe de gaz. <br/>- Buzzer de signalement (code sonore).</text> <quote>Le buzzer de signalement produit 3 types de signaux différents : <br/>- <bold>2 bips consécutifs</bold> : le modèle ne reçoit pas la radiocommande, il est en "fail-safe", et/ou est en attente que l'utilisateur active l'interrupteur de coupure moteur, et positionne le manche de gaz en cohérence avec le mode de vol sélectionné avec l'interrupteur auxiliaire A. <br/>- <bold>Mélodie courte</bold> : le modèle confirme qu'il a mis à jour ses paramètres (section "UPDATE" de la radiocommande) et qu'il les a sauvegardé dans sa mémoire interne. <br/>- <bold>Mélodie longue</bold> : le modèle est prêt à voler.</quote> <text>Une fois les conditions remplies, l'hélicoptère est prêt à être mis en vol, il est alors en attente du basculement de l'interrupteur de coupure moteur pour une mise au ralenti de ces derniers (sous réserve d'une position du manche de gaz cohérente au mode de vol sélectionné).</text> <a href="photo/dsc08429.jpg"><img src="thumbnail/dsc08429.jpg"></img></a> <a href="photo/dsc08381.jpg"><img src="thumbnail/dsc08381.jpg"></img></a> <quote>Par sécurité, cet hélicoptère est équipé d'un <bold>système à tolérance de pannes</bold> (fail-safe), ce qui permet d'arrêter les moteurs lorsque la radiocommande ne répond plus.</quote> <title>Précautions :</title> <underline></underline> <text>On ne rappellera jamais assez que <bold>les hélicoptères en aéromodélisme ne sont pas des jouets</bold>, surtout quand il s'agit d'hélices entraînées à plusieurs milliers de tours par minute comme c'est le cas sur cet hélicoptère !</text> <caution>Vous devez prendre une extrême précaution lors des réglages d'un tel hélicoptère, il est vivement conseillé de démonter les hélices lors des réglages et de les remonter uniquement lorsque vous êtes certain de vos paramètres.</caution> <title>Possibilités d'évolution :</title> <underline></underline> <text>Il est possible d'utiliser le capteur <bold>BNO055</bold> si vous souhaitez voler avec un horizon artificiel (vol assisté conseillé pour les débutants), ainsi que le capteur <bold>BME280</bold> si vous souhaitez mesurer la pression atmosphérique et donc connaître l'altitude de votre hélicoptère.</text> <text>Exemple de l'utilisation de <bold>l'horizon artificiel</bold> (vol du prototype) :</text> <video src="video/00004.mov" controls></video> <title>L'amalgame du drone en aéromodélisme :</title> <underline></underline> <text>Qu'est-ce qu'un <bold>drone</bold> ? Si ce n'est un mot anglais dont la simple traduction est "bourdonnement", "vrombissement", ou encore "ronronnement". Dans ce cas, un bourdon, une voiture de course, et un chat seraient-ils des drones ? La question est posée !</text> <quote>Plus sérieusement, je vais essayer d'expliquer simplement ce que je pense être l'origine de l'amalgame qui est fait aujourd'hui, largement propagé par les médias (de tous types, amateurs et professionnels), et venu s'incruster dans les mœurs de nos fameux terrains d'aéromodélisme !</quote> <text>Quel est le premier drone ayant marqué l'histoire récente ? Cela semble être le tristement mythique <bold>V1</bold>, un avion militaire allemand sans pilote équipé d'une lourde bombe destinée à faire des ravages outre Manche contre le Royaume-Uni (plus précisément Londres), et plus tard sur la Belgique. Cela a fait partie des armes secrètes de l'Allemagne Nazie...</text> <text>Cet avion avait à son bord trois gyroscopes permettant de le guider d'une façon autonome, et était propulsé par un moteur (appelé parfois moteur-fusée) de type <bold>pulso-réacteur</bold> :</text> <quote>Ce type de moteur fait <bold>énormément de bruit !</bold> Bien plus encore qu'un turbo-réacteur conventionnel (équipé d'un rotor), surtout à notre époque où beaucoup de progrès sont réalisés pour diminuer les émissions sonores notamment pour les vols commerciaux.</quote> <text>Ce bruit s'apparente à un bourdonnement sourd (avec beaucoup de sons dans les bases fréquences), audible à de grandes distances. Propulsé par le pulso-réacteur, cette machine infernale sans pilote était destinée à tomber à court de carburant, précisément au dessus des grandes villes (comme Londres), et venait s'écraser dans une violente explosion, faisant de nombreuses victimes la plupart du temps civils.</text> <text>Bien plus tard, des drones ont été élaboré dans l'armée américaine sous diverses formes, dans un premier temps dans un but de prospection (simplement équipés de caméras, de radars, etc...), et dans un deuxième temps équipés de missiles et autres engins de destruction de cibles considérées ennemies.</text> <caution>Vous l'aurez compris, dans ma compréhension de cette problématique plus d'ordre littéraire qu'autre chose, les <bold>drones civils</bold> n'existent pas, l'historique veut <bold>qu'un drone est un engin sans pilote à but militaire</bold>, et cela doit le rester !</caution> <text>Autrement dit, un tri-hélicoptère (trois rotors), un quadri-hélicoptère (quatre rotors), un hexa-hélicoptère (six rotors), ou encore un octo-hélicoptère (huit rotors), <bold>sont des types d'hélicoptères radiocommandés</bold> (ou radio-pilotés), soit entièrement pilotés, semi-pilotés ou semi-autonomes, ou bien complètement autonomes, appelés également multi-coptères, ou multi-hélicoptères (pour plus de 2 rotors, en opposition au rotor principal et anti-couple d'un hélicoptère plus conventionnel), mais ces machines volantes <bold>ne sont en aucun cas des drones !</bold> Sauf si effectivement pour vous, les bourdons dans mon jardin, ma voiture de course, ou mon chat sont des drones, auquel cas je ne peux plus rien faire pour vous !</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectRadioControl.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectRadioControl"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>La radiocommande</title> <underline></underline> <text>Ce projet de <bold>radiocommande</bold> est la suite logique de mon intérêt et de mes convictions pour un modélisme aérien tel qu'il devrait être pratiqué, c'est-à-dire la conception et la fabrication de systèmes radio-pilotés en commençant le plus possible de zéro.</text> <a href="photo/dsc08332.jpg"><img src="thumbnail/dsc08332.jpg"></img></a> <a href="photo/dsc08314.jpg"><img src="thumbnail/dsc08314.jpg"></img></a> <a href="photo/dsc08425.jpg"><img src="thumbnail/dsc08425.jpg"></img></a> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <a href="photo/dsc08323.jpg"><img src="thumbnail/dsc08323.jpg"></img></a> <a href="photo/dsc08326.jpg"><img src="thumbnail/dsc08326.jpg"></img></a> <a href="photo/dsc08330.jpg"><img src="thumbnail/dsc08330.jpg"></img></a> <a href="photo/dsc08297.jpg"><img src="thumbnail/dsc08297.jpg"></img></a> <a href="photo/dsc06915.jpg"><img src="thumbnail/dsc06915.jpg"></img></a> <a href="photo/dsc06927.jpg"><img src="thumbnail/dsc06927.jpg"></img></a> <text>À partir des premières ébauches sur papier, études des possibilités et contraintes techniques, schémas des circuits électroniques, conception des programmes dans la radiocommande et les modèles associés, dessins du boîtier et définition des différentes pièces d'usinage (etc...), jusqu'à la finalisation du projet, il aura fallu plus d'une année de conception, fabrication, et tests de validation.</text> <text><bold>Les caractéristiques de la radiocommande :</bold> <br/>- Automate programmable MODULABLE 32 équipé du microcontrôleur ATmega1284P. <br/>- Émetteur/récepteur (transceiver) radio 2.4GHz (composant nRF24L01+). <br/>- Antenne Trèfle omnidirectionnelle 3 branches (7dBm). <br/>- Communication multidirectionnelle vers (sol/air air/sol) et entre (air/air) plusieurs modèles. <br/>- Communication vers périphériques relais pour applications longues distances basse puissance. <br/>- Communication par trames de 32 bits. <br/>- Affichage digital avec mini afficheur à digits. <br/>- Buzzer de signalement. <br/>- Système à tolérance de pannes (fail-safe) sur 5 bits (0 à 31). <br/>- Surveillance de l'activité du modèle (watchdog) sur 5 bits (0 à 31). <br/>- 1 menu principal + 1 menu des paramètres/réglages. <br/>- Aucune mémoire de modèles (la mémoire est située dans les modèles physiques). <br/>- Possibilité de copier les réglages d'un modèle vers un autre très facilement. <br/>- 15 paramètres/réglages par défaut envoyés par le modèle. <br/>- Réglage des trims (autour des neutres) des manches de gaz/roulis et profondeur/lacet. <br/>- Réglage d'une alarme (visuelle et sonore) tension de batterie faible du modèle (de 0V à 100V). <br/>- Réglage d'une alarme (visuelle et sonore) temporisation/chronomètre (de 0s à 3600s). <br/>- Réglage de l'inversion des manches de gaz/roulis et profondeur/lacet. <br/>- Réglage de courbes des manches de gaz/roulis et profondeur/lacet. <br/>- Jusqu'à 16 paramètres/réglages personnalisés supplémentaires envoyés par le modèle. <br/>- 5 paramètres/réglages par défaut propres à la radiocommande. <br/>- Calibration des potentiomètres des manches et auxiliaire (si remplacement/autre). <br/>- Verrouillage des menus (plus de réglages possibles, ni d'extinction de la radiocommande). <br/>- Affichage de la tension de la batterie de la radiocommande. <br/>- Affichage de la tension de la batterie du modèle. <br/>- Affichage d'une temporisation/chronomètre (temps d'utilisation du modèle/autre). <br/>- Affichage des trims (verrouillage et remise à 0 possible par le bouton de sélection). <br/>- Affichage d'une télémétrie personnalisée. <br/>- Affichage des paramètres/réglages par défaut et personnalisés. <br/>- Menu de mise à jour des paramètres/réglages du modèle. <br/>- Menu de sauvegarde des réglages propres à la radiocommande. <br/>- Allumage ou extinction de la radiocommande ou du modèle dans n'importe quel ordre. <br/>- Accumulateur nickel-hydrure métallique (NiMH) 8S (+9.6V) 600mAh. <br/>- Alarme niveau de batterie faible (en dessous de +6V). <br/>- Prise de charge de la batterie (XT30). <br/>- Prise de programmation du microcontrôleur (mini XLR). <br/>- Boîtier fermé en aluminium, acier inoxydable, peuplier, okoumé, et ertalon. <br/>- Dimensions : 214mm x 205mm x 118mm.</text> <a href="photo/dsc08284.jpg"><img src="thumbnail/dsc08284.jpg"></img></a> <a href="photo/dsc08290.jpg"><img src="thumbnail/dsc08290.jpg"></img></a> <text><bold>L'interface électromécanique entre l'homme et la machine :</bold> <br/>- 2 manches analogiques (1 gaz/roulis + 1 tangage/lacet) sur 10 bits chacun (0 à 1023). <br/>- 4 interrupteurs de trims (3 positions) sur 2 bits chacun (0 à 2). <br/>- 1 interrupteur de coupure moteur/autre (2 positions) sur 1 bit (0 à 1). <br/>- 3 interrupteurs auxiliaires (3 positions) sur 2 bits chacun (0 à 2). <br/>- 1 bouton rotatif auxiliaire sur 10 bits (0 à 1023). <br/>- 1 bouton rotatif de sélection/menus sur 10 bits (0 à 1023). <br/>- 1 bouton poussoir de sélection/menus (2 positions, dont 1 momentanée) sur 1 bit (0 à 1). <br/>- 1 interrupteur d'alimentation maintenue on/off (2 positions).</text> <text><bold>Programmation de l'automate programmable MODULABLE 32 avec MODULE :</bold> <br/>Le programme en langage C++ fonctionnant avec MODULE est téléchargeable ici :</text> <a href="download/cpp/radio_control.zip"><download>Télécharger le programme de la <bold>radiocommande</bold> (.zip, ≈ 17Kio)</download></a> <a href="photo/dsc08312.jpg"><img src="thumbnail/dsc08312.jpg"></img></a> <a href="photo/dsc08313.jpg"><img src="thumbnail/dsc08313.jpg"></img></a> <text><bold>Connexions (automate programmable MODULABLE 32 sur les différents systèmes embarqués) :</bold></text> <caution>- Port GPIO 1 (PB0) sur broche STATE (état) interrupteur d'alimentation maintenue. <br/>- Port GPIO 2 (PB1) sur broche HOLD (auto-maintien) interrupteur d'alimentation maintenue. <br/>- Port GPIO 3 (PB2) sur broche SS (slave select) mini afficheur à digits. <br/>- Port GPIO 4 (PB3) sur broche WAVE (onde) buzzer de signalement. <br/>- Port GPIO 5 (PB4) sur broche CSN (slave select) composant nRF24L01+. <br/>- Port GPIO 6 (PB5) sur broche MOSI (master output slave input) mini afficheur à digits et composant nRF24L01+. <br/>- Port GPIO 7 (PB6) sur broche MISO (master input slave output) composant nRF24L01+. <br/>- Port GPIO 8 (PB7) sur broche SCK (serial clock) mini afficheur à digits et composant nRF24L01+. <br/>- Port GPIO 9 (PD0) sur bouton poussoir de sélection/menus. <br/>- Port GPIO 10 (PD1) sur interrupteur de coupure moteur/autre. <br/>- Port GPIO 11 (PD2) sur interrupteur auxiliaire A (position 1). <br/>- Port GPIO 12 (PD3) sur interrupteur auxiliaire A (position 3). <br/>- Port GPIO 13 (PD4) sur interrupteur auxiliaire B (position 1). <br/>- Port GPIO 14 (PD5) sur interrupteur auxiliaire B (position 3). <br/>- Port GPIO 15 (PD6) sur interrupteur auxiliaire C (position 1). <br/>- Port GPIO 16 (PD7) sur interrupteur auxiliaire C (position 3). <br/>- Port GPIO 17 (PC0) sur interrupteur trim de gaz (position 1). <br/>- Port GPIO 18 (PC1) sur interrupteur trim de gaz (position 3). <br/>- Port GPIO 19 (PC2) sur interrupteur trim de tangage (position 1). <br/>- Port GPIO 20 (PC3) sur interrupteur trim de tangage (position 3). <br/>- Port GPIO 21 (PC4) sur interrupteur trim de roulis (position 1). <br/>- Port GPIO 22 (PC5) sur interrupteur trim de roulis (position 3). <br/>- Port GPIO 23 (PC6) sur interrupteur trim de lacet (position 1). <br/>- Port GPIO 24 (PC7) sur interrupteur trim de lacet (position 3). <br/>- Port GPIO 25 (PA7) sur curseur bouton rotatif de sélection/menus. <br/>- Port GPIO 26 (PA6) sur curseur manche analogique des gaz. <br/>- Port GPIO 27 (PA5) sur curseur manche analogique de tangage. <br/>- Port GPIO 28 (PA4) sur curseur manche analogique de roulis. <br/>- Port GPIO 29 (PA3) sur curseur manche analogique de lacet. <br/>- Port GPIO 30 (PA2) sur curseur bouton rotatif auxiliaire. <br/>- Port GPIO 31 (PA1) sur broche VOLT (tension) interrupteur d'alimentation maintenue.</caution> <title>Le concept de cette radiocommande :</title> <underline></underline> <text>Pour comprendre le concept de cette radiocommande et ce qu'il peut apporter aux modélistes notamment en matière de facilité de réglages sur le terrain et fondamentalement de sécurité, il convient de faire quelques rappels importants des avancées technologiques que j'ai vu apparaître sur les systèmes radiocommandés du commerce.</text> <text>En effet, dès l'arrivée sur le marché des systèmes de radiocommandes à communication bidirectionnelle (sol/air air/sol pour l'aéromodélisme), une interrogation est venue à moi, soit la question suivante :</text> <caution><bold>Mais pourquoi donc les radiocommandes du commerce ont-elles des "mémoires de modèles" ?</bold> Les "mémoires de modèles" permettent la rétention des réglages relatifs à un modèle physique, ceci dans la mémoire de la radiocommande.</caution> <text>Quiconque pratique le modélisme radiocommandé est habitué aux systèmes des "mémoires de modèles". C'est un principe utilisé par tous, et comme tout principe utilisé par tous, il n'est jamais remis en cause, chose que je me permets évidement ici.</text> <text>Pourtant, les "mémoires de modèles" n'ont plus aucun sens dès lors que la communication des systèmes radio est bidirectionnelle, ce qui est le cas de toutes les radiocommandes modernes aujourd'hui. D'un point de vue simplement technique, qu'est-ce qui empêche le système de faire remonter les paramètres et réglages du modèle physique dans la radiocommande lors de l'allumage des deux, et qui empêche de les faire redescendre lorsque l'utilisateur les a modifié et décide de les enregistrer ?</text> <text>De fait, le principe des "mémoires de modèles" dans les radiocommandes modernes est commun et admis par tous car c'était à l'origine la seule solution envisagée à la rétention des paramètres et réglages relatifs à un modèle physique, dans un système électronique à communication radio unidirectionnel. En effet, les premières radiocommandes étaient uniquement <bold>émetteurs</bold> d'informations, et les modèles physiques étaient simplement <bold>récepteurs</bold> d'informations. Dans cette situation unidirectionnelle, il est facile de comprendre que le modèle physique reste toujours muet, et donc ne permet pas la communication des paramètres et réglages qui l'anime vers une radiocommande.</text> <text>Ce n'est que plus tard que les concepteurs et divers fabricants (en rapport à l'augmentation de la demande des utilisateurs et du besoin d'innovation) ont ajouté une communication du modèle physique vers la radiocommande, ce faisant sur un circuit électronique bien distinct et avec une antenne radio supplémentaire sur le modèle physique et la radiocommande. C'est un retour air/sol qui a été appelé <bold>télémétrie</bold> (en rapport avec la télémétrie à l'époque des débuts de la conquête spatiale jusqu'à nos jours).</text> <quote>L'avancée en matière de miniaturisation des composants permet aujourd'hui d'avoir <bold>dans une même puce un émetteur et un récepteur</bold>, qui utilise la même antenne radio pour communiquer, ces systèmes sont appelés <bold>transceivers</bold> (émetteurs/récepteurs).</quote> <text>Cette notion technique bien intégrée concernant les communications radio des systèmes, cela me permets de vous expliquer le concept même de ma radiocommande, qui est le suivant :</text> <caution>Ma radiocommande ne possède aucune "mémoire de modèles", ayant souhaité aller au bout de la logique, <bold>c'est le modèle physique qui contient la mémoire.</bold></caution> <text>Comprendre que dans le principe que j'ai développé, c'est le modèle physique qui téléverse ses paramètres et réglages personnalisés dans la radiocommande, qui à l'origine dispose d'un menu des paramètres et réglages vide. Le menu de la radiocommande est alors rempli de paramètres personnalisés relatifs au modèle physique qui est actuellement en communication avec elle. Ces paramètres peuvent être de n'importe quels types et agir sur n'importe quelle fonction du modèle physique.</text> <text>Pour l'ergonomie d'utilisation, cette opération de téléversement des paramètres et réglages personnalisés vers la radiocommande s'effectue d'une manière complètement transparente pour l'utilisateur, dès lors qu'un modèle physique est présent à portée radio. Et contrairement à une radiocommande du commerce, dans ce que je propose l'utilisateur n'a pas à sélectionner de "mémoire de modèle" (il n'y en a pas) correspondant au modèle physique mis en œuvre.</text> <text>Ce principe des paramètres et réglages stockés dans le modèle physique plutôt que la radiocommande apporte une notion fondamentale en matière de sécurité : <caution>En effet et de fait, ce principe n'autorise plus à l'utilisateur de charger par erreur une "mémoire de modèle" qui ne correspond pas au modèle physique mis en œuvre.</caution> <quote>À ce propos, il me serait possible de relater de nombreuses expériences d'utilisateurs sur les terrains de modélisme qui par mégarde chargent une "mémoire de modèle" qui ne correspond absolument pas au modèle physique mis en œuvre. Selon le modèle physique considéré, cela peut poser un <bold>réel problème de sécurité</bold>. La conséquence peut être mineure, soit simplement un écrasement des paramètres et des réglages, mais aussi plus grave, soit des blessures corporelles (en cause un démarrage involontaire de moteurs électriques par exemple), cela peut également conduire au crash du modèle physique si les réglages sont propices au décollage mais pas au vol (axe inversé ou encore sensibilité au débattement rendant le modèle impilotable), etc...</quote> <text>Cet aspect pratique de la sécurité évoqué et traité, un autre avantage important du concept de radiocommande que je propose est la simplicité à effectuer les réglages du modèle physique que ce soit à l'atelier ou sur le terrain de modélisme.</text> <text>En effet, pour régler votre modèle, ma radiocommande dispose de <bold>15 paramètres par défaut</bold> qui en général sont assez communs aux modèles réduits (trims, alarmes, inversion des voies, courbes de gaz, etc...), et d'un maximum de <bold>16 paramètres personnalisés par le modèle</bold> (dont le type de paramètre n'est pas défini par défaut). Ceci est largement suffisant parce que par définition même, ces paramètres sont spécifiques au modèle physique considéré :</text> <quote>Dans le principe de radiocommande que je propose ici, vous disposez des <bold>paramètres et des réglages uniquement nécessaires au modèle mis en œuvre</bold>, ce qui facilite grandement son utilisation sur le terrain de modélisme !</quote> <text>De même que précédemment, je pourrais relater nombre d'utilisateurs de radiocommandes du commerce qui, cherchant et parcourant avec lassitude des quantités de menus et de sous-menus (la plupart du temps inutilisés), passent un temps très important à effectuer les réglages de leurs modèles réduits, ce qui certaines fois par voie de conséquence, conduit inévitablement à effectuer des erreurs de réglages.</text> <text>En outre d'une manière plus générale, le principe de communication bidirectionelle permet également à ma radiocommande de disposer de fonctionnalités assez courantes de nos jours :</text> <quote>La communication bidirectionelle permet nativement à ma radiocommande de disposer de <bold>l'affichage en temps réel de la tension de la batterie d'alimentation du modèle</bold>, et d'une télémétrie personnalisée (qu'il est possible d'assigner à n'importe quel capteur et/ou variable logicielle du modèle physique).</quote> <text>Modestement par cette contribution, j'espère apporter aux modélistes une réponse qu'en à la facilité à effectuer les réglages de leurs modèles, mais également et surtout pour la sécurité de mise en œuvre sur les terrains de modélisme.</text> <title>Le système multidirectionnel de la radiocommande :</title> <underline></underline> <text>Le système de radiocommande 2.4GHz que je propose ici permet la <bold>communication multidirectionnelle entre la radiocommande et un ou plusieurs modèles</bold>, autorise le <bold>dialogue entre les modèles</bold> eux-mêmes (réseau d'émetteurs/récepteurs, ou multiceivers), et rend possible l'ajout de plusieurs émetteurs/récepteurs (transceivers) embarqués dans un même véhicule (pour les gros modèles notamment).</text> <a href="photo/dsc08076.jpg"><img src="thumbnail/dsc08076.jpg"></img></a> <a href="photo/dsc08077.jpg"><img src="thumbnail/dsc08077.jpg"></img></a> <text>Tout projet est alors possible, sans même évoquer le modélisme piloté dont il est question ici :</text> <quote>Par exemple des applications robotiques mettant en œuvre des réseaux de robots qui communiquent entre-eux, et bien d'autres projets encore. Libre à vous d'imaginer vos propres applications en fonction de vos besoins !</quote> <text>Ce principe d'émetteur/récepteur intégré donne également la possibilité à l'utilisateur d'effectuer des communications longues distances en basse puissance d'émission (inférieure à 100mW), ceci par <bold>transmission de données de la radiocommande vers des périphériques relais</bold> qui se chargent non pas de traiter l'information et de l'utiliser, mais plutôt de la relayer vers d'autres périphériques afin d'atteindre la portée radio vers le modèle.</text> <caution>Cette propriété de pouvoir recevoir et émettre avec de multiples périphériques ainsi que de relayer l'information est effectuée de manière <bold>complètement transparente pour l'utilisateur ou le programmeur</bold> (voir dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web, page "Une radiocommande avec la classe SpiNrf24l01p").</caution> <text>Il est envisageable d'imaginer un robot d'exploration de décombres hors de portée radio directe avec le poste de pilotage (à cause des bardages métalliques des bâtiments par exemple), mais étant à portée radio de plusieurs relais qui se chargent seulement de transmettre (relayer) les informations aux téléopérateurs.</text> <quote>Toutes ces propriétés multidirectionnelles (multiceivers) sont à définir non pas dans la radiocommande, mais <bold>uniquement à la conception des programmes à bord de vos modèles, robots, et autres systèmes embarqués</bold> (libre à chacun de créer une logique en rapport avec le type de système piloté).</quote> <text>À noter que les paragraphes qui suivent font état d'une utilisation avec un seul modèle physique en simultané, car c'est mon application principale (l'aéromodélisme). Néanmoins tout ce qui est expliqué ci-dessous (utilisation des menus, fonctionnalités, etc...) fonctionne avec plusieurs modèles (suivant la logique que vous avez programmé dans leurs microcontrôleurs respectifs bien évidement).</text> <title>Démarrage de la radiocommande :</title> <underline></underline> <text>À l'allumage de la radiocommande, se propose à vous le choix de démarrer celle-ci en <bold>mode "ON AIR"</bold> (à l'antenne) ou en <bold>mode "OFF AIR"</bold> (hors antenne) en faisant pivoter le bouton rotatif de sélection. Si vous choisissez "ON AIR" (à l'antenne), le circuit radio d'émission/réception est démarré, la radiocommande se met alors à envoyer et recevoir des données, et cherche si un modèle est physiquement présent à portée radio.</text> <quote><bold>Si un modèle est présent et répond à la radiocommande</bold>, cette dernière récupère alors tous les paramètres nécessaires (trims, paramètres par défaut, paramètres personnalisés, etc...) <bold>lors de ce démarrage uniquement</bold>, et vous emmène directement au menu principal pour une utilisation normale.</quote> <a href="photo/dsc08299.jpg"><img src="thumbnail/dsc08299.jpg"></img></a> <a href="photo/dsc08300.jpg"><img src="thumbnail/dsc08300.jpg"></img></a> <text><bold>Si au contraire, aucun modèle ne se présente à la radiocommande</bold>, l'affichage indiquera "BINDING" (liaison), et vous aurez le choix d'attendre ou de quitter (en appuyant sur le bouton de sélection) <bold>sans récupérer les paramètres du modèle</bold>, ce qui en conséquence vous donnera l'impossibilité de régler ses paramètres, car <bold>le menu des paramètres sera vide</bold>.</text> <caution>Attention, la radiocommande émet et reçoit des données (le circuit radio d'émission/réception est démarré) <bold>même en ayant quitté la tentative de liaison</bold> ("BINDING") avec le modèle, vous pourrez alors tout de même le piloter (sans pouvoir en changer les paramètres).</caution> <text>En résulte que les trims, alarmes, inversions des voies, et courbes (qui doivent normalement êtres récupérés du modèle, et qui sont mixés non pas dans le modèle physique, mais dans la radiocommande) seront alors à leur <bold>valeur par défaut</bold> ("OFF" pour les trims/alarmes/courbes, et "NOR" pour l'inversion des voies), il convient alors d'être prudent suivant le modèle piloté, et une telle configuration n'est en soit pas idéale, mais est possible.</text> <quote>Si vous démarrez la radiocommande en <bold>mode "OFF AIR"</bold> (hors antenne), cette dernière reste <bold>muette</bold> (circuit d'émission/réception éteint).</quote> <text>Dans ce cas, le menu des paramètres ("SETTINGS") vous permettra non pas de régler les paramètres du modèle (voir plus bas : "Réglages et enregistrement des paramètres"), mais plutôt de modifier <bold>certains réglages propres à la radiocommande</bold>, et enregistrés dans celle-ci (comme la calibration des potentiomètres des manches et auxiliaire, voir plus bas : "Calibration des potentiomètres").</text> <text>Ne pas démarrer le circuit radio d'émission/réception permet également de se familiariser avec l'interface de cette radiocommande, ou bien encore de contrôler la tension de la batterie interne avant de se rendre sur votre terrain de modélisme favoris.</text> <title>Allumage de la radiocommande et du modèle :</title> <underline></underline> <text>Il n'existe aucune contrainte au niveau de l'ordre d'allumage ou de la mise hors tension de la radiocommande ou du modèle, tout deux attendent une réponse de l'autre :</text> <caution><bold>Vous pouvez allumer la radiocommande ou le modèle dans n'importe quel ordre</bold>, éteindre votre modèle ou la radiocommande quand vous le souhaitez, et rallumer l'une ou l'autre en cours d'utilisation !</caution> <a href="photo/dsc08302.jpg"><img src="thumbnail/dsc08302.jpg"></img></a> <a href="photo/dsc08428.jpg"><img src="thumbnail/dsc08428.jpg"></img></a> <text>Lorsque le modèle s'aperçoit que plus aucune radiocommande ne répond, il active alors son <bold>système à tolérance de pannes</bold> (fail-safe), et envoi en boucle les paramètres dont la radiocommande a besoin jusqu'à temps que celle-ci réponde.</text> <quote>Si la radiocommande a besoin de paramètres à son allumage, <bold>elle ira les chercher si un modèle est sous tension et répond</bold>, de même si le modèle a besoin de paramètres et qu'aucune radiocommande n'est allumée, <bold>il ira les chercher au moment où elle sera activée en communication</bold> (via le menu de démarrage "ON AIR").</quote> <title>Différents menus :</title> <underline></underline> <text>Ma radiocommande dispose d'un <bold>menu principal</bold> :</text> <quote>- Verrouillage de la radiocommande ("LOCK/-LOCKED-", voir plus bas : "Le verrouillage de la radiocommande"). <br/>- Visualisation de la tension de la batterie de la radiocommande et alarme ("CTRL", voir plus bas : "Alarmes"). <br/>- Visualisation de la tension de la batterie du modèle et alarme ("MODL", voir plus bas : "Alarmes"). <br/>- Visualisation d'une temporisation/chronomètre et alarme ("TIME", voir plus bas : "Alarmes"). <br/>- Visualisation et modification des trims ("THRO", "PITC", "ROLL", "YAW"). <br/>- Visualisation d'une télémétrie personnalisée ("TLMT"). <br/>- Accès au menu des paramètres ("SETTINGS").</quote> <a href="photo/dsc08301.jpg"><img src="thumbnail/dsc08301.jpg"></img></a> <a href="photo/dsc08423.jpg"><img src="thumbnail/dsc08423.jpg"></img></a> <text>À partir du menu principal et par la pression du bouton de sélection sur la section "SETTINGS" (paramètres) en <bold>mode "ON AIR"</bold> (à l'antenne), vous entrez dans le menu des paramètres/réglages dans lequel on trouve <bold>11 paramètres par défaut</bold>, ainsi qu'un maximum de <bold>16 paramètres personnalisés</bold> agrémentés par le modèle si besoin :</text> <quote><bold>Paramètres par défaut :</bold> <br/>- Réglage d'une alarme tension de batterie faible du modèle ("BMDL", voir plus bas : "Alarmes"). <br/>- Réglage de la limite d'une temporisation/chronomètre avec alarme ("TMED", voir plus bas : "Alarmes"). <br/>- Réglage de la manière dont la temporisation/chronomètre se déclenche ("TMTR", voir plus bas : "Alarmes"). <br/>- Réglage de l'inversion des manches de gaz/roulis et profondeur/lacet ("DRTH", "DRPI", "DRRO", "DRYA"). <br/>- Réglage de courbes des manches de gaz/roulis et profondeur/lacet ("CUTH", "CUPI", "CURO", "CUYA"). <br/> <br/><bold>Paramètres personnalisés :</bold> <br/>- Paramètres dont le type n'est pas défini par défaut (nom affiché dans le menu, valeur initiale, valeurs minimales et maximales possibles, etc...). <br/> <br/><bold>Autres sections :</bold> <br/>- Retour au menu principal sans enregistrer les paramètres dans le modèle ni conserver les dernières modifications effectuées ("EXIT"). <br/>- Retour au menu principal et mise à jour des paramètres dans le modèle ("UPDATE", si la radiocommande n'est pas verrouillée).</quote> <text>Lorsque la radiocommande est démarrée en <bold>mode "OFF AIR"</bold> (hors antenne, c'est-à-dire circuit d'émission/réception éteint), à partir du menu principal et par la pression du bouton de sélection sur la section "SETTINGS" (paramètres), vous entrez dans le menu dans lequel vous pouvez modifier <bold>certains réglages propres à la radiocommande</bold>, paramètres qui sont enregistrés dans sa mémoire :</text> <quote><bold>Réglages :</bold> <br/>- Calibration des potentiomètres des manches et auxiliaire ("CLTH", "CLPI", "CLRO", "CLYA", "CLAX", voir plus bas : "Calibration des potentiomètres"). <br/> <br/><bold>Autres sections :</bold> <br/>- Retour au menu principal sans enregistrer les paramètres dans la radiocommande ni conserver les dernières modifications effectuées ("EXIT"). <br/>- Retour au menu principal et enregistrement des paramètres dans la radiocommande ("SAVE", si la radiocommande n'est pas verrouillée).</quote> <title>Alarmes :</title> <underline></underline> <text>Ma radiocommande est équipée d'une alarme niveau de batterie faible de la radiocommande et du modèle, et d'une alarme qui s'active via une temporisation/chronomètre réglable (lorsque le temps paramétré est dépassé). Ces 3 alarmes sont visibles dans le menu principal, ce sont respectivement les sections <bold>"CTRL"</bold>, <bold>"MODL"</bold>, et <bold>"TIME"</bold>.</text> <quote>Ma radiocommande est équipée d'une temporisation (chronomètre) dont <bold>la durée limite</bold> est paramétrable, et <bold>la manière dont elle se déclenche</bold> : <br/>- Avec l'interrupteur de coupure moteur/autre. <br/>- En dépassant une certaine position (réglable) au manche de gaz.</quote> <text>Au pilotage, vous avez donc le choix de déceler la fin de votre session lors du dépassement d'une certaine tension de la batterie d'alimentation du modèle <bold>réglable de 0V à 100V</bold> (par pas de 0.1V), et/ou du dépassement d'une temporisation/chronomètre <bold>réglable de 0s à 3600s</bold> (par pas de 1s), soit 1h au total.</text> <text>Le dépassement du temps (réglé préalablement) de la temporisation/chronomètre est indiqué de façon <bold>visuelle et sonore</bold> (alarme sonore de quelques secondes mais affichage permanent), ce chronomètre est activable et désactivable via le menu des paramètres ("SETTINGS") et peut être redémarré ou stoppé à tout moment en pressant le bouton de sélection sur la section "TIME" dans le menu principal.</text> <text>Le dépassement de la tension limite de la batterie d'alimentation du modèle (réglée par l'utilisateur) provoque également un affichage visuel et sonore (alarme sonore de quelques secondes mais affichage permanent).</text> <caution>Cette alarme visuelle du <bold>niveau de batterie faible du modèle</bold>, n'est qu'en à elle désactivable uniquement lorsque le niveau de la batterie d'alimentation dépasse à nouveau (augmente positivement) le seuil minimum que vous avez réglé en paramètre (ceci peut se produire lors du changement de la batterie de votre modèle par exemple).</caution> <text>Une alarme de niveau de batterie faible de la radiocommande existe à l'instar de celle du modèle, mais la valeur limite n'est pas réglable et est <bold>fixée à +6V</bold>, ce qui correspond à la tension minimum d'alimentation de l'automate programmable MODULABLE 32.</text> <quote>Cette alarme de niveau de batterie faible de la radiocommande intervient de manière visuelle et sonore lorsque le <bold>seuil de +6V minimum</bold> est dépassé.</quote> <text>Dans cette situation, même si la tension de la batterie d'alimentation de la radiocommande (pour une raison x ou y) remonte au dessus de +6V, <bold>l'alarme perdurera</bold>, seul la partie sonore une fois active pourra être désactivée (par une pression sur le bouton de sélection dans la partie relative à ce paramètre dans le menu principal), l'alarme visuelle restera qu'en à elle présente dans tous les cas.</text> <caution>Si cette alarme de niveau de batterie faible vient à s'activer (que ce soit celle de la radiocommande ou du modèle), et que votre modèle est en vol, il est alors <bold>vivement conseillé de le poser dans les plus brefs délais !</bold></caution> <text>Si aucune intervention de l'utilisateur pour désactiver ou réinitialiser l'une (ou l'ensemble) des 3 alarmes n'est effectuée, <bold>un bip se fait entendre toutes les 30 secondes</bold>, ce qui signifie qu'une alarme visuelle <bold>est toujours active</bold>. Rendez-vous alors dans le menu principal pour les désactiver (si possible).</text> <title>Inversions des voies et courbes :</title> <underline></underline> <text>En paramètres par défaut, il vous est également possible de définir <bold>le sens des voies de gaz, de tangage, de roulis, et de lacet</bold> envoyés au modèle par la radiocommande (de 0 à 1023 en mode normal, ou de 1023 à 0 en mode inversé), et de définir des valeurs de courbes, soit "OFF" pour linéaire, jusqu'à 100 pour fortement non-linéaire.</text> <caution>Tout comme les trims, l'inversion des voies et les courbes sont <bold>mixés dans la radiocommande</bold>, et envoyés au modèle en l'état.</caution> <text>Si vous souhaitez inverser une ou plusieurs voies, rendez-vous dans le menu des paramètres via le menu principal en cliquant sur la section "SETTINGS" (paramètres) tout en étant en <bold>mode "ON AIR"</bold> (à l'antenne), cherchez les paramètres <bold>"DRTH"</bold>, <bold>"DRPI"</bold>, <bold>"DRRO"</bold>, ou <bold>"DRYA"</bold> (qui correspondent respectivement aux gaz, tangage, roulis, et lacet).</text> <text>Les paramètres ayant en suffixe <bold>"NOR"</bold> (normal) indiquent que la voie concernée n'est pas inversée, et ceux mentionnés <bold>"REV"</bold> (inversé) sont inversées. Pour les modifier, il vous suffit de cliquer dessus avec le bouton de sélection, ou d'utiliser les interrupteurs de trims pour en changer les valeurs. Ensuite, rendez-vous dans la section <bold>"UPDATE"</bold> (mettre à jour) pour mettre à jour les modifications dans le modèle et les prendre en compte dans la radiocommande (car ces paramètres sont mixés dans la radiocommande, et non pas le modèle).</text> <quote>En plus des trims et de l'inversion des voies, vous disposez de la possibilité de modifier les <bold>courbes de gaz, de tangage, de roulis, et de lacet</bold>. Celles-ci sont linéaires ("OFF") par défaut, et leurs actions s'appliquent de part et d'autre du neutre des manches (gaz y compris).</quote> <text>De même que pour le réglage des autres paramètres, dans le menu "SETTINGS" (paramètres), cherchez les mots <bold>"CUTH"</bold>, <bold>"CUPI"</bold>, <bold>"CURO"</bold>, ou <bold>"CUYA"</bold> (qui correspondent respectivement aux gaz, tangage, roulis, et lacet).</text> <text>Si il est indiqué <bold>"OFF"</bold>, les courbes sont <bold>linéaires</bold>, si il est indiqué un nombre, les courbes sont <bold>non-linéaires</bold>. Vous pouvez modifier cela via les interrupteurs de trims, ou plus rapidement à l'aide du bouton rotatif auxiliaire tout en restant appuyé sur le bouton de sélection (comme expliqué ci-dessous : "Réglages et enregistrement des paramètres").</text> <caution>Plus les valeurs des courbes seront hautes (proches de 100), plus <bold>le pilotage sera doux autour du neutre des manches</bold> et moins sensible. Le pilotage d'un modèle à forts débattements sera donc plus aisé en augmentant les valeurs des courbes.</caution> <text>À noter qu'une courbe sur l'axe des gaz peut être utile au pilotage des hélicoptères de voltige (dont le neutre, et donc le centre du manche correspond au pas 0 sur le modèle), même si pour ma part je préfère piloter de façon linéaire le gaz/pas.</text> <title>Réglages et enregistrement des paramètres :</title> <underline></underline> <text>Ma radiocommande dispose de l'affichage des trims dans le menu principal, parce que leurs réglage s'effectue à tout moment via les 4 interrupteurs 3 positions prévus à cet effet (c'est pourquoi dans le menu des paramètres/réglages vous ne trouvez que 11 paramètres par défaut sur les 15 au total, soit les 4 trims en moins). <bold>Les trims sont eux aussi enregistrés dans le modèle</bold> (et non la radiocommande). Ils peuvent être remis à 0 individuellement par la simple pression du bouton poussoir de sélection, et verrouillés ("OFF") si besoin.</text> <quote>Sur un modèle radiocommandé à propulsion électrique disposant de son propre algorithme de vol, il est souvent rare d'avoir besoin d'un trim sur le manche de gaz, ou même sur les autres axes de vol, d'ou cette possibilité de verrouillage d'un ou plusieurs trims avec la radiocommande que j'ai développé.</quote> <text>Le menu des paramètres et réglages en <bold>mode "ON AIR"</bold> (à l'antenne) est <bold>accessible en cliquant sur "SETTINGS"</bold> (paramètres) dans le menu principal, et dispose d'une section "EXIT" (sortie) et "UPDATE" (mettre à jour). Lorsque vous avez effectué vos réglages (trims, paramètres par défaut, paramètres personnalisés, etc...), <bold>vous devez mettre à jour la mémoire du modèle</bold> en cliquant sur "UPDATE" (mettre à jour) afin que le modèle enregistre tous les paramètres dans sa mémoire et mette à jour son algorithme de vol (si il en dispose, vous pouvez très bien piloter un bateau sans algorithme de contrôle de la navigation par exemple, mais disposant tout de même de réglages et de paramètres).</text> <a href="photo/dsc08299.jpg"><img src="thumbnail/dsc08299.jpg"></img></a> <a href="photo/dsc08303.jpg"><img src="thumbnail/dsc08303.jpg"></img></a> <quote>Si vous avez modifié des paramètres (trims, paramètres par défaut, paramètres personnalisés, etc...) et qu'une mise à jour du modèle est nécessaire, <bold>la section "UPDATE"</bold> (mettre à jour) <bold>se changera en "-UPDATE-"</bold> (-mettre à jour-), les tirets de part et d'autre du mot faisant office d'indication.</quote> <text>Si aucun modèle ne répond à la radiocommande lorsque vous souhaitez mettre à jour les paramètres dans celui-ci après avoir cliqué sur "UPDATE" (mettre à jour) dans le menu des paramètres, dans ce cas <bold>l'affichage indiquera "BINDING"</bold> (liaison), et vous aurez le choix d'attendre ou de quitter (en appuyant sur le bouton de sélection) <bold>sans mettre à jour les paramètres dans le modèle</bold>.</text> <text>Quitter la mise à jour n'aura pas le même effet que de sortir du menu avec "EXIT" (sortie), <bold>vos paramètres dernièrement modifiés le resteront tant que la radiocommande sera allumée</bold>, et vous devrez alors retourner ultérieurement dans le menu pour mettre à jour vos paramètres dans le modèle (si vous le souhaitez).</text> <caution>Si vous ne souhaitez pas enregistrer les paramètres dans le modèle <bold>ni conserver les dernières modifications effectuées</bold> dans le menu des paramètres ("SETTINGS"), <bold>vous pouvez sortir du menu en cliquant sur "EXIT"</bold> (sortie).</caution> <text>Les réglages des trims sont actifs en permanence, car ils sont <bold>mixés avec les manches directement dans la radiocommande</bold>, mais ils ne s'enregistrent pas dans celle-ci. Cette possibilité donne l'avantage bien entendu d'avoir des trims distincts par modèle, mais aussi de pouvoir trimer votre modèle sur le terrain sans avoir forcément envie de les enregistrer à l'extinction de la radiocommande comme c'est le cas avec les radiocommandes du commerce (si par exemple vous avez trimé votre modèle alors qu'il y avait du vent, ce qui fausse votre perception des bons réglages).</text> <quote>À noter que ce sont les interrupteurs de trims qui servent à régler les valeurs dans le menu des paramètres et réglages en mode "ON AIR" (à l'antenne), <bold>sauf lorsque la radiocommande est verrouillée</bold> (voir plus bas : "Le verrouillage de la radiocommande"), auquel cas les trims agissent toujours comme tel.</quote> <text>Il existe une méthode rapide pour régler des paramètres aux valeurs minimales et maximales trop larges (par exemple 0 à 3600 par pas de 1 comme c'est le cas pour le chronomètre intégré). Pour ce faire il suffit de <bold>rester appuyé sur un trim</bold> (ce qui fera défiler les valeurs plus rapidement).</text> <text>L'autre méthode de réglage rapide consiste à <bold>presser continuellement le bouton de sélection</bold>, ce qui vous permettra de régler la plupart des valeurs directement avec <bold>le bouton rotatif auxiliaire</bold> (pour la majorité des paramètres, et si le potentiomètre de ce bouton rotatif auxiliaire est calibré, voir plus bas : "Calibration des potentiomètres"), ou en ce qui concerne le paramètre de déclenchement de la temporisation/chronomètre, ce sera <bold>le manche de gaz</bold> (si le potentiomètre de ce manche est lui aussi calibré, voir plus bas : "Calibration des potentiomètres").</text> <a href="photo/dsc08318.jpg"><img src="thumbnail/dsc08318.jpg"></img></a> <caution>Si vous décidez de régler la valeur de déclenchement de la temporisation/chronomètre à l'aide du manche de gaz, il convient que <bold>l'interrupteur de coupure moteur doit être actif</bold>, ou que que le modèle soit mis <bold>hors tension !</bold></caution> <text>À noter qu'il est tout à fait possible de régler les paramètres de votre modèle (sans parler des trims bien entendu) alors que celui-ci est <bold>en cours de pilotage</bold>, et que la radiocommande <bold>n'est pas verrouillée</bold> (voir plus bas : "Le verrouillage de la radiocommande").</text> <text>Bien évidement, même qu'il s'agisse d'une voiture, ou d'un bateau (ou de tout autre modèle ne pouvant se crasher quand il n'y a plus d'intervention du pilote), je ne peux que vous conseiller de <bold>régler votre modèle que lorsque il est à l'arrêt et en sécurité</bold> (et je ne ferais à ce propos pas de commentaires en ce qui concerne un modèle aérien !).</text> <title>Calibration des potentiomètres :</title> <underline></underline> <text>De part la conception même des manches de la radiocommande, <bold>la plupart des potentiomètres de ceux-ci ne tournent pas mécaniquement sur leur plage de résistance complète minimale et maximale</bold>, ne produisant pas une plage de valeurs sur 10 bits (converties d'analogique à numérique) de 0 à 1023.</text> <quote>Cette contrainte technique conduit donc l'utilisateur de cette radiocommande à devoir calibrer les potentiomètres (au moins lors du premier allumage) pour que cette dernière sache les <bold>plages de valeurs minimales et maximales des gaz, de l'axe de tangage, de l'axe de roulis, de l'axe de lacet, et du bouton rotatif auxiliaire</bold>.</quote> <a href="photo/dsc07663.jpg"><img src="thumbnail/dsc07663.jpg"></img></a> <a href="photo/dsc07683.jpg"><img src="thumbnail/dsc07683.jpg"></img></a> <caution>Cette opération doit être effectuée <bold>à la première utilisation de la radiocommande</bold>, et lorsque que vous souhaitez <bold>remplacer les manches et/ou les potentiomètres</bold> de celle-ci (voie des gaz, tangage, roulis, lacet, ou auxiliaire).</caution> <text>Pour ce faire, vous devez démarrer la radiocommande en <bold>mode "OFF AIR"</bold> (hors antenne), puis vous rendre dans le menu des paramètres ("SETTINGS") dans lequel vous trouverez la calibration des potentiomètres des manches et auxiliaire de la radiocommande.</text> <a href="photo/dsc08300.jpg"><img src="thumbnail/dsc08300.jpg"></img></a> <a href="photo/dsc08303.jpg"><img src="thumbnail/dsc08303.jpg"></img></a> <text>5 sections respectivement utiles pour calibrer le potentiomètre de <bold>gaz</bold> ("CLTH"), de <bold>tangage</bold> ("CLPI"), de <bold>roulis</bold> ("CLRO"), de <bold>lacet</bold> ("CLYA"), ou <bold>auxiliaire</bold> ("CLAX"), permettent de calibrer les potentiomètres concernés par ces voies.</text> <quote>Pour effectuer le calibrage, positionnez vous dans la section voulue (l'une des 5 mentionnées), puis <bold>pressez de façon continue le bouton de sélection</bold>, et <bold>pivotez le manche concerné aux positions minimales et maximales</bold>. La valeur par défaut de 0 <bold>augmentera alors jusqu'à atteindre un maximum</bold>, ce qui signifiera que le potentiomètre est calibré (c'est-à-dire que la radiocommande a trouvée les valeurs minimales et maximales de celui-ci).</quote> <text>Si par exemple le potentiomètre de tangage à une plage de résistance telle qu'il retourne en numérique une valeur pouvant varier de <bold>104</bold> à <bold>985</bold>, une fois correctement calibré cela signifie que la valeur qui s'affichera à vous dans la section correspondante à cet axe sera de <bold>881</bold> (car 985 - 104 = 881).</text> <caution>La valeur de calibration qui s'affiche à vous est une <bold>soustraction entre la valeur maximale et la valeur minimale</bold> (convertie d'analogique à numérique sur 10 bits) que produit le potentiomètre.</caution> <text>Le menu dispose d'une section "EXIT" (sortie) et "SAVE" (enregistrer). Lorsque vous avez effectué vos réglages, <bold>vous devez les sauvegarder dans la radiocommande</bold> en cliquant sur "SAVE" (enregistrer) afin que celle-ci prenne en compte ces nouveaux réglages.</text> <quote>Si vous avez modifié des paramètres (calibration des potentiomètres) et qu'un enregistrement dans la radiocommande est nécessaire, <bold>la section "SAVE"</bold> (enregistrer) <bold>se changera en "-SAVE-"</bold> (-enregistrer-), les tirets de part et d'autre du mot faisant office d'indication.</quote> <title>Le verrouillage de la radiocommande :</title> <underline></underline> <text>Il est possible avec cette radiocommande <bold>d'empêcher l'extinction de celle-ci via l'interrupteur d'alimentation on/off</bold>, et d'éviter de pouvoir modifier les paramètres dans les menus (sauf les trims qui doivent servir même lorsque la radiocommande est verrouillée). Ceci s'effectue en <bold>restant appuyé 1 seconde sur le bouton de sélection</bold> sur la section "LOCK" (verrouillage) dans le menu principal. Le mot "LOCK" (verrouillage) se change alors en "-LOCKED-" (-verrouillé-).</text> <caution>À noter que vous ne pouvez pas éteindre la radiocommande tout en vous trouvant dans la section "LOCK/-LOCKED-" du menu principal (c'est une sécurité supplémentaire).</caution> <text>Pour déverrouiller à nouveau la radiocommande, répétez l'opération (pression de 1 seconde sur le bouton de sélection dans cette partie du menu).</text> <quote>Ce sont les interrupteurs de trims qui servent à régler les valeurs dans le menu des paramètres et réglages en mode "ON AIR" (à l'antenne), <bold>sauf lorsque la radiocommande est verrouillée</bold>, auquel cas les trims agissent toujours comme tel.</quote> <text>Les trims <bold>ne peuvent pas être réinitialisés</bold> à leur valeur par défaut ("OFF") en pressant le bouton de sélection dans le menu principal dans la section concernée lorsque la radiocommande est verrouillée.</text> <text>Lorsque la radiocommande est verrouillée, vous pouvez visualiser et modifier les réglages dans le menu des paramètres, mais vous ne pouvez pas les mettre à jour dans le modèle (en mode "ON AIR") ou les enregistrer dans la radiocommande (en mode "OFF AIR"), car respectivement les sections "UPDATE" (mettre à jour) et "SAVE" (enregistrer) sont absents du menu.</text> <title>La copie des paramètres d'un modèle :</title> <underline></underline> <text>Avec ma radiocommande il est très simple de copier les paramètres (trims, paramètres par défaut, paramètres personnalisés) d'un modèle vers un autre <bold>sans jamais pouvoir se tromper</bold>, voici la procédure :</text> <quote><bold>1</bold> - Allumez la radiocommande et le modèle à copier. <br/><bold>2</bold> - Activez la transmission radio dans le menu qui vous est proposé au démarrage de la radiocommande ("ON AIR"). <br/><bold>3</bold> - Au signal sonore, les paramètres du modèle viennent d'être copiés dans la radiocommande, vous pouvez éteindre le modèle à copier, et allumer l'autre modèle dans lesquels vous souhaitez écraser les paramètres. <br/><bold>4</bold> - Rendez-vous dans le menu des paramètres en cliquant sur la section "SETTINGS" (paramètres), puis cliquez sur "UPDATE" (mettre à jour). Vous entendez alors les signaux sonores de la radiocommande et du modèle vous indiquant que les paramètres ont bien été copiés dans ce dernier.</quote> <text>Si vous avez plusieurs modèles devant recevoir les mêmes paramètres, répétez la procédure de l'opération <bold>3</bold> à <bold>4</bold>.</text> <caution>Il est très important de comprendre que cette opération de copie n'a de sens que si les paramètres du modèle à copier vers ceux du modèle à écraser sont <bold>identiques</bold> non pas en termes de valeurs, mais bien <bold>en termes de nature et de caractéristiques</bold> (valeurs minimales et maximales, emplacements dans le menu des paramètres, etc...), et que les modèles à copier se situent tous dans la même logique (axes de manœuvrabilité, types de pilotage, etc...).</caution> <text>Dans le cas contraire, cela peut être un choix délibéré de votre part de copier les paramètres vers un système complètement différent du modèle à copier, je pense par exemple à la copie vers un automate programmable nu afin de <bold>sauvegarder vos paramètres préférés</bold> (sans qu'il soit question de modèle à proprement parlé).</text> <title>La sécurité de la communication :</title> <underline></underline> <text>La communication s'effectue de manière encodée avec une <bold>clé 32 bits unique</bold> paramétrable dans le programme de la radiocommande et des modèles (voir dans la section "La documentation du programme MODULE" en page d'accueil de mon site Web, page "Une radiocommande avec Nrf24l01p"), ce qui permet de rendre ce système de communication radio très fiable et sécurisé.</text> <text>Lors d'une communication, un encodage (CRC) valide est généré puis vérifié, c'est un <bold>code de correction d'erreurs</bold> (sur 16 bits) très performant qui permet de contrôler la validité des informations reçues.</text> <caution>Par sécurité, le modèle est pourvu d'un <bold>système à tolérance de pannes</bold> (fail-safe) qui permet d'effectuer certaines opérations spécifiques <bold>lorsque la radiocommande ne répond plus</bold> (mise au neutre des servo-moteurs, coupure de la motorisation, etc...).</caution> <text>Tout ceci est à définir à la conception du programme de vol à bord du modèle (libre à chacun de créer une logique en rapport avec le type de modèle piloté).</text> <quote>La radiocommande dispose également d'une <bold>surveillance de l'activité du modèle</bold> (watchdog) qui permet de connaître l'état actif ou inactif de celui-ci (par l'affichage de la tension de la batterie du modèle dans la section "MODL" si actif, ou si inactif par l'affichage "OFF" dans cette même section), dans les deux cas un <bold>signal sonore</bold> (pour actif et inactif) se fait entendre.</quote> <title>Les trames de communication :</title> <underline></underline> <text>La communication des informations entre la radiocommande et les modèles s'effectue sur une largeur de <bold>32 bits</bold> utiles (c'est-à-dire en faisant abstraction de l'encodage, des adresses ou canaux, des codes de correction d'erreurs, de la clé unique, etc...).</text> <a href="photo/dsc08295.jpg"><img src="thumbnail/dsc08295.jpg"></img></a> <a href="photo/dsc08296.jpg"><img src="thumbnail/dsc08296.jpg"></img></a> <text>En définitif, les données utiles à l'utilisateur qui proviennent de l'interface électromécanique entre l'homme et la machine sont englobées dans <bold>2 trames de 32 bits</bold>, ce qui comprends :</text> <quote><bold>1ère trame de 32 bits :</bold> <br/>- Gaz sur 10 bits (0 à 1023). <br/>- Axe de roulis sur 10 bits (0 à 1023). <br/>- Interrupteur auxiliaire C sur 2 bits (0 à 2). <br/>- Bouton rotatif auxiliaire D sur 10 bits (0 à 1023). <br/> <br/><bold>2ème trame de 32 bits :</bold> <br/>- Axe de tangage sur 10 bits (0 à 1023). <br/>- Axe de lacet sur 10 bits (0 à 1023). <br/>- Interrupteur de coupure moteur/autre sur 1 bit (0 à 1). <br/>- Interrupteur auxiliaire A sur 2 bits (0 à 2). <br/>- Interrupteur auxiliaire B sur 2 bits (0 à 2). <br/>- Système à tolérance de pannes (fail-safe) sur 5 bits (0 à 31). <br/>- Ordre de mise à jour sur 2 bits (0 à 2).</quote> <text>Soit un total de seulement <bold>64 bits</bold> pour transmettre tous les ordres de la radiocommande vers le modèle. Grâce à ce principe, la latence de la communication est très faible, car j'encode les données en binaire toutes ensembles sur 2 x 32 bits à l'émission et je les décode à la réception, ce qui prend le minimum de place possible (évite de perdre des bits dans des variables aux tailles fixes de 8, 16, ou 32 bits).</text> <text>Également, dans les essais pratiques effectués notamment avec un servo-moteur <bold>SH-262MG</bold> de marque Savox (presque le plus rapide de la marque), les mouvements du palonnier se trouvent être on ne peut plus fidèles aux manches de la radiocommande. En effet lorsque le manche concerné est positionné en butée puis relâché, ce dernier effectue naturellement des rebonds au niveau du neutre (à cause des rappels par ressorts), ainsi l'observation montre que le palonnier du servo-moteur semble imiter les rebonds avec une exactitude pratique (qu'il est difficile de remettre en cause à l'œil nu), ce qui démontre bien la quantité et la qualité des échanges entre la radiocommande et le modèle.</text> <quote>De même, les potentiomètres des manches sont <bold>filtrés en temps réel</bold> (sans latence), et encodés sur <bold>1024 valeurs</bold> (0 à 1023), ceci permet d'assurer une très grande précision des ordres analogiques de pilotage.</quote> <title>La charge de la batterie d'alimentation :</title> <underline></underline> <text>La batterie qui alimente cet ensemble radiocommandé comporte <bold>8 éléments</bold> nickel-hydrure métallique (NiMH) de <bold>+1.2V</bold> chacun (soit +9.6V au total) avec une <bold>autonomie de 600mAh</bold>. Il convient alors d'utiliser un chargeur adapté comme le montre les photos suivantes :</text> <a href="photo/dsc08369.jpg"><img src="thumbnail/dsc08369.jpg"></img></a> <a href="photo/dsc08372.jpg"><img src="thumbnail/dsc08372.jpg"></img></a> <text>La charge s'effectue avec un courant constant de 100mAh, ce qui correspond à une charge lente pour ce type de batterie.</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectSite.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectSite"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Le site Web</title> <underline></underline> <text>Je vous propose ici l'intégralité de la programmation (code source) de ce présent site Web (cette page y compris, sauf les fichiers présentés ci-dessous, auquel cas il y aurait redondance infinie), ce qui comprend les <bold>fichiers de feuille de style en cascade</bold> (.css), les <bold>fichiers de script</bold> (.js), les <bold>fichiers de langage de balisage d'hypertexte</bold>, autrement dit, les <bold>pages de contenu HTML</bold> (.html), et les <bold>fichiers de langage de préprocesseur d'hypertexte</bold> (.php).</text> <quote>En effet dans cette philosophie de partage de mon travail avec le plus grand nombre, <bold>tout est libre de droits d'auteur</bold> (voir dans la section "Licence officielle" en page d'accueil), ainsi les fichiers sources (programmation notamment) sont tous ouverts et modifiables (open source).</quote> <quote>Tout le site Web est écrit à l'aide d'un simple éditeur de texte (gedit) pourvu uniquement de la coloration syntaxique.</quote> <text>Libre à vous de récupérer par exemple des parties (ou la totalité) de mes fichiers de programmation .css, .js, .html, et .php afin de créer votre propre site Web.</text> <text>(fichiers .css, .js, .html, et .php du site Web)</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectUselessMachine.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectUselessMachine"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Les machines inutiles</title> <underline></underline> <text>Les machines <bold>inutiles</bold> sont les créations personnelles d'un inventeur raté (moi), mais elles ont tout de même un intérêt pédagogique certain !</text> <text><bold>La roue perpétuellement inutile :</bold> <br/>Cette roue est l'incarnation de la déchéance ultime en matière de physique et notamment de thermodynamique, généralement laissée au stade d'idée dans des boites crâniennes aux cerveaux ravagés (et encore il faut chercher tellement c'est vide la dedans), j'ai pour ma part souhaité en réaliser une pour en avoir le cœur net !</text> <a href="photo/dsc06361.jpg"><img src="thumbnail/dsc06361.jpg"></img></a> <a href="photo/dsc06357.jpg"><img src="thumbnail/dsc06357.jpg"></img></a> <text>Le principe est simple : <bold>PAS DE PRINCIPE !</bold> Bien entendu cette roue reste statique, comme les molécules à 0 degrés Kelvin qui composent les ramifications nerveuses de son créateur...</text> <a href="photo/dsc06359.jpg"><img src="thumbnail/dsc06359.jpg"></img></a> <a href="photo/dsc06358.jpg"><img src="thumbnail/dsc06358.jpg"></img></a> <text>Les masselottes (sur le cercle extérieur) circulants à droite de la roue sont plus excentrées (plus loins de l'axe de rotation) que les masselottes circulants à gauche, de sorte qu'un déséquilibre est créé. Mais les masses permettant cet excentrique (dissymétrie) abaissent le centre de gravité du système dans son ensemble, ce qui a pour conséquence de ramener <bold>la somme des moments</bold> (forces) à <bold>0</bold>.</text> <text>Au mieux cela peut servir de tourniquet ou de moulin à prière...</text> <title>L'additionneuse de poche 8 bits :</title> <underline></underline> <text>La machine à calculer 8 bits est comme son nom ne l'indique pas, <bold>compacte et légère</bold>, vous pouvez l'emmener partout dès que vous avez un problème pour additionner des nombres de <bold>0</bold> à <bold>255</bold> dont la somme (résultat) ne dépasse pas 255 !</text> <a href="photo/dsc01493.jpg"><img src="thumbnail/dsc01493.jpg"></img></a> <a href="photo/dsc01556.jpg"><img src="thumbnail/dsc01556.jpg"></img></a> <text>Pour s'en servir c'est assez simple, il suffit de comprendre et lire le <bold>binaire</bold> avec un petit peu de pratique de la logique combinatoire...</text> <text>Cette machine dispose de 8 bascules (registre), qui représentent à l'état repos 8 zéros, c'est-à-dire <bold>1 octet</bold> de poids faible (00000000). Quand vous souhaitez additionner 2 nombres, il vous faut insérer les <bold>bits</bold> (ou billes) par le dessus, de droite à gauche (logique de la programmation). Les bascules selon leurs états (0 ou 1) changent d'état quand un bit est inséré dans le mécanisme. Ceci est le premier nombre à additionner avec un second.</text> <text>Le second nombre s'insère dans la machine de la même manière. Le résultat du calcul étant la position finale des bascules.</text> <a href="photo/dsc01508.jpg"><img src="thumbnail/dsc01508.jpg"></img></a> <a href="photo/dsc01541.jpg"><img src="thumbnail/dsc01541.jpg"></img></a> <text><bold>Exemple :</bold> <br/>- J'insère l'octet 00001010 dans la machine (10 en décimal). <br/>- J'insère un nouvel octet 00000111 dans la machine (7 en décimal). <br/>- Le registre indique en binaire 00010001, soit 17 en décimal, c'est le résultat du calcul.</text> <quote>Quand le résultat du calcul est supérieur à 255, la machine se trouve dans une situation de dépassement de la taille du registre. Un bit (une bille) est alors éjecté à gauche dans la 9ème case disponible, si il existait plusieurs machines en cascade, ce bit viendrait alors changer l'état d'un 9ème transistor (bascule) d'un second registre de 8 bits.</quote> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier projectWirelessInterface.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#projectWirelessInterface"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>L'interface de communication sans fil 2.4GHz</title> <underline></underline> <caution><bold>Attention, ce projet est en cours de réalisation, c'est pourquoi cet article est vide !</bold></caution> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier toolBmpToMod.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#toolBmpToMod"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Conversion d'images bitmap vers une sérigraphie KiCad</title> <underline></underline> <text>Avec cette routine de conversion d'images (pour le système d'exploitation Linux que j'utilise), vous allez pouvoir <bold>importer des logos</bold> (et autres graphismes) dans vos dessins KiCad en vue PCB <bold>sur le calque de sérigraphie</bold> de la face avant (F.SilkS).</text> <quote>Il existe un outil par défaut dans cette suite KiCad nommé <bold>Bitmap2Component</bold> qui est censé remplir cette fonction, mais notamment dépendant de la résolution (hauteur/largeur) de l'image d'origine, il ne permet pas le redimensionnement, est basé sur un principe de conversion vectorielle qui détruit l'information, et au final fait apparaître pour certains dessins de petites tailles des lignes courbes là où il y a des droites parfaites, et plus une bouillie de pixels qu'une sérigraphie de qualité...</quote> <text>Ainsi cet outil proposé par défaut est pour moi inutilisable lorsque l'on souhaite un rendu exact par rapport à notre image noir et blanc initiale.</text> <text>À l'instar de Bitmap2Component, ma routine d'automatisation prend en entrée une image qui doit être initialement en noir et blanc (monochrome) afin que les pixels blancs soient utilisés dans le traitement :</text> <caution>Ce que je vous propose ici permettra <bold>qu'un pixel blanc dans votre image d'origine sera très exactement un carré de sérigraphie</bold> (de la taille souhaitée) dans votre dessin en vue PCB.</caution> <text>Ci-dessous, la routine (.sh) permettant la conversion d'images bitmap vers une sérigraphie KiCad :</text> <code>#!/bin/bash echo "Pixel size in mil ?" read sizeRaw clear rm tmp -r -f mkdir tmp size=$(echo $sizeRaw"*10" | bc -l) for file in *.bmp do if [ -f "$file" ] then echo $file" to "${file%%.*}.mod convert -quiet "$file" tmp/tmp.txt grep "white" tmp/tmp.txt > tmp/tmp grep -o ".*:" tmp/tmp > tmp/tmpxy grep -o ".*," tmp/tmpxy > tmp/x sed -i tmp/x -e "s/,//" grep -o ",.*:" tmp/tmpxy > tmp/y sed -i tmp/y -e "s/,//" -e "s/://" countList=0 while read x do xList[$countList]=$(echo $x"*"$size | bc -l) ((countList++)) done < tmp/x countList=0 while read y do yList[$countList]=$(echo $y"*"$size | bc -l) ((countList++)) done < tmp/y echo "PCBNEW-LibModule-V1" > tmp/tmp.mod echo "\$INDEX" >> tmp/tmp.mod echo ${file%%.*} >> tmp/tmp.mod echo "\$EndINDEX" >> tmp/tmp.mod echo "\$MODULE "${file%%.*} >> tmp/tmp.mod echo "Li "${file%%.*} >> tmp/tmp.mod for ((iterationList=0; $iterationList < $countList; iterationList++)) do echo "DP 0 0 0 0 4 0 200" >> tmp/tmp.mod echo "Dl "${xList[$iterationList]}" "${yList[$iterationList]} >> tmp/tmp.mod echo "Dl "$(echo ${xList[$iterationList]}"+"$size | bc -l)" "${yList[$iterationList]} >> tmp/tmp.mod echo "Dl "$(echo ${xList[$iterationList]}"+"$size | bc -l)" "$(echo ${yList[$iterationList]}"+"$size | bc -l) >> tmp/tmp.mod echo "Dl "${xList[$iterationList]}" "$(echo ${yList[$iterationList]}"+"$size | bc -l) >> tmp/tmp.mod done echo "\$EndMODULE "${file%%.*} >> tmp/tmp.mod echo "\$EndLIBRARY" >> tmp/tmp.mod mv tmp/tmp.mod "${file%%.*}".mod fi done rm tmp -r -f exit 0</code> <caution>La routine présentée ci-dessus utilise le programme (ou paquet) <bold>imagemagick</bold> pour extraire les valeurs matricielles des images traitées.</caution> <text>Il vous faut donc l'installer à l'aide de la ligne de commande suivante (à écrire dans le terminal de Linux) :</text> <code>sudo apt-get install imagemagick -y</code> <text>Une fois cette installation effectuée, lorsque vous exécutez la routine (.sh) se propose à vous une question <bold>"Pixel size in mil ?"</bold>, il vous faut alors renseigner la taille souhaitée en millième de pouce que fera un pixel dans votre dessin KiCad (cohérent lorsque les unités de mesures sont indiquées en pouces et non pas en millimètres) :</text> <quote>Par exemple si vous indiquez en taille de pixel le nombre <bold>25</bold>, avec une grille dans votre dessin KiCad réglée sur <bold>25</bold> (et des unités de mesures en pouces) vous verrez que <bold>le pas des pixels de votre graphisme en vue PCB fera très exactement le même pas que la grille</bold>.</quote> <text>Après avoir validé le choix de la taille des pixels, toutes les images ayant l'extension <bold>.bmp</bold> (bitmap) dans le répertoire courant sont converties successivement en fichiers <bold>.mod</bold> (footprint) que vous pouvez ajouter à vos projets KiCad par l'intermédiaire du menu d'ajout de bibliothèques (Preferences > Library) en vue PCB.</text> <caution>Si vous apercevez le crénelage des pixels de votre graphisme sérigraphié une fois votre circuit réalisé, je vous conseille d'utiliser une image bitmap (.bmp) initiale de <bold>plus grande résolution</bold>, et d'indiquer une taille de pixel (lors de la conversion avec la routine) d'autant <bold>plus faible</bold>, par exemple <bold>2.5</bold> (attention cependant, les temps de traitement peuvent s'avérer assez longs avec des résolutions d'images trop grandes).</caution> <text>Libre à vous de faire une utilisation de ce petit programme de conversion d'image, qui vous permettra aisément d'apposer vos logos et divers graphismes sur vos circuits imprimés avec une <bold>parfaite exactitude de conversion</bold> (1 pixel bitmap vers 1 pixel sérigraphié).</text> <text>Ci-dessous un exemple de code matriciel (QR Code) sérigraphié avec mon outil :</text> <a href="photo/dsc08204.jpg"><img src="thumbnail/dsc08204.jpg"></img></a> <a href="photo/dsc07963.jpg"><img src="thumbnail/dsc07963.jpg"></img></a> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier toolFileToBookContent.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#toolFileToBookContent"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Création automatique du contenu d'un livre à partir d'une arborescence de fichiers</title> <underline></underline> <text>Habituellement dans le monde informatique digital, il est commun d'archiver des fichiers sur des supports de sauvegarde analogiques ou numériques (rubans perforés, bandes magnétiques, mémoires à base de semi-conducteurs, etc...). C'est oublier que les supports imprimés (livres, documents divers) peuvent également remplir la fonction d'archivage de données :</text> <a href="photo/dsc09034.jpg"><img src="thumbnail/dsc09034.jpg"></img></a> <a href="photo/dsc09009.jpg"><img src="thumbnail/dsc09009.jpg"></img></a> <text>Mais pour effectuer cette translation, soit la copie des fichiers numériques à sauvegarder vers des supports imprimés, un outil intermédiaire automatique est nécessaire. C'est cet outil remplissant cette fonction qui est proposé ici.</text> <text>Cet outil se présente sous la forme d'une routine (pour le système d'exploitation Linux que j'utilise) qui permet de générer automatiquement le contenu d'un livre complet sous la forme d'un seul fichier PDF via une arborescence de fichiers (organisation hiérarchique des fichiers dans des répertoires) dont le contenu UTF-8 est extrait :</text> <caution>C'est le <bold>contenu UTF-8</bold> (pour "Unicode Transformation Format 8" ou format de transformation Unicode sur 8 bits) de vos fichiers à sauvegarder qui est utilisé afin de générer un fichier unique PDF imprimable (book content.pdf), contenu prenant ainsi la forme de caractères normalisés qui peut être issu de divers langages, soit par exemple du binaire, de l'hexadécimal, du C++, ou tout autre caractère UTF-8 imprimable. Attention cependant, si des caractères dans vos fichiers ne font pas partie de la norme UTF-8, ils ne pourront pas être traités correctement.</caution> <text>Le fichier PDF imprimable qui résulte de la translation peut être envoyé à un imprimeur, ce qui donne le résultat suivant :</text> <a href="photo/dsc09002.jpg"><img src="thumbnail/dsc09002.jpg"></img></a> <a href="photo/dsc09004.jpg"><img src="thumbnail/dsc09004.jpg"></img></a> <quote>À noter que le format de fichier <bold>PDF</bold> (pour "Portable Document Format" ou format de document portable) est le standard directement pris en charge par toutes les imprimeries modernes.</quote> <text>La routine d'automatisation proposée prend donc en entrée une arborescence de fichiers, et permet de choisir de multiples paramètres détaillés plus bas (comme par exemple les dimensions des pages du livre, les dimensions des marges, etc...). Une fois ces choix effectués, un fichier nommé <bold>book content.pdf</bold> est créé. Ce fichier répertorie tout le contenu des fichiers de l'arborescence, avec la <bold>pagination</bold>, la <bold>numérotation des lignes</bold> (si besoin), la <bold>numérotation des pages</bold>, et la <bold>table des fichiers</bold> en toute fin du livre.</text> <text>Ci dessous, la routine (.sh) permettant la création automatique du contenu d'un livre à partir d'une arborescence de fichiers :</text> <code>#!/bin/bash echo "Page width in mm ?" read menuWidthPage echo -e "\nPage height in mm ?" read menuHeightPage echo -e "\nPage margin in mm ?" read menuMarginPage echo -e "\nGutter margin in mm ?" read menuMarginGutter echo -e "\nFont size in mm ?" read menuFontSize echo -e "\nFont name ?" read menuFontName echo -e "\nCutter margin in mm ?" read menuMarginCutter echo -e "\nFile name prefix ?" read menuPrefixFileName echo "" next=false while [ $next == false ] do echo "File size suffix ?" echo "n = No" echo "e = English" echo "f = French" read menuFileSizeSuffix if [ $menuFileSizeSuffix == "n" ] || [ $menuFileSizeSuffix == "e" ] || [ $menuFileSizeSuffix == "f" ] then next=true else clear fi done echo "" next=false while [ $next == false ] do echo "Line numbering ?" echo "n = No" echo "y = Yes" read menuLineNumbering if [ $menuLineNumbering == "n" ] || [ $menuLineNumbering == "y" ] then next=true else clear fi done echo -e "\nFile table title ?" read menuTitleFileTable echo "" next=false while [ $next == false ] do echo "Color style ?" echo "n = Black and white" echo "y = Colored" read menuColorStyle if [ $menuColorStyle == "n" ] || [ $menuColorStyle == "y" ] then next=true else clear fi done echo "" next=false while [ $next == false ] do echo "Sort option ?" echo "a = Alphanumeric sort" echo "m = Manual sort" read menuSortOption if [ $menuSortOption == "a" ] || [ $menuSortOption == "m" ] then next=true fi clear done rm tmp -r -f rm "book content.pdf" -f nameBash=$(basename "$0") nameLink=$(basename "$1") countTable=0 shopt -s globstar for file in **/* do if [ -f "$file" ] && [ "$file" != "$nameBash" ] && [ "$file" != "$nameLink" ] then fileTable[$countTable]=$file ((countTable++)) fi done if [ $countTable == 0 ] then echo "No file detected" else iterationTable=0 if [ $menuSortOption == "m" ] then next=false while [ $next == false ] do echo "Manual sort :" echo "e = Exit" echo "s = Save file tree (file.tree)" echo "l = Load file tree (file.tree)" echo "d = Delete file tree (file.tree)" echo "" echo "File tree :" for ((iterationTableDisplay=0; $iterationTableDisplay < $countTable; iterationTableDisplay++)) do if [ $iterationTableDisplay == $iterationTable ] then echo $((iterationTableDisplay+1))" = "${fileTable[$iterationTableDisplay]}" <" else echo $((iterationTableDisplay+1))" = "${fileTable[$iterationTableDisplay]} fi done read menuManualSort if [ $menuManualSort == "e" ] then next=true elif [ $menuManualSort == "s" ] then rm file.tree -f for ((iterationTableForWriting=0; $iterationTableForWriting < $countTable; iterationTableForWriting++)) do echo ${fileTable[$iterationTableForWriting]} >> file.tree done elif [ $menuManualSort == "l" ] then countTable=0 while read line do if [ -f "$line" ] then fileTable[$countTable]=$line ((countTable++)) fi done < file.tree elif [ $menuManualSort == "d" ] then rm file.tree -f elif (($menuManualSort >= 1 && $menuManualSort <= $countTable)) then saveTable=${fileTable[$iterationTable]} fileTable[$iterationTable]=${fileTable[$((menuManualSort-1))]} fileTable[$((menuManualSort-1))]=$saveTable fi clear if (($iterationTable == $countTable - 1)) then iterationTable=0 else ((iterationTable++)) fi done fi echo "Progress = 0.0%" rm tmp -r -f mkdir tmp for ((iterationPatternBinary = 0; iterationPatternBinary <= 9; iterationPatternBinary++)) do patternBinaryTable[$iterationPatternBinary]="¡¿¡¿¡¿¡¿"$(echo "obase=2;"$((iterationPatternBinary+1)) | bc | awk '{ printf "%08d\n", $0 }' | sed -e "s/0/¿/g" -e "s/1/¡/g")"¡¿¡¿¡¿¡¿" done printf "\t\n" > tmp/tmpFoldAscii1Byte printf "\t\t\n" > tmp/tmpFoldAscii2Byte for ((iterationAscii = 32; iterationAscii < 127; iterationAscii++)) do printf "\\$(printf %03o "$iterationAscii")\n" >> tmp/tmpFoldAscii1Byte printf "\\$(printf %03o "$iterationAscii")\\$(printf %03o "$iterationAscii")\n" >> tmp/tmpFoldAscii2Byte done sed -i tmp/tmpFoldAscii1Byte -e "s/\t/"${patternBinaryTable[0]}"/g" -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" sed -i tmp/tmpFoldAscii2Byte -e "s/\t/"${patternBinaryTable[0]}"/g" -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" countLineTotal=0 characterMeasure="" for ((iterationCharacter=0; $iterationCharacter < 1000; iterationCharacter++)) do characterMeasure=$characterMeasure"_" done ratioFontSize=$(inkscape --without-gui -W <(echo "<svg><text font-family=\""$menuFontName"\" font-size=\""$menuFontSize"\">"$characterMeasure"</text></svg>") 2>/dev/null) countCharacterPerLine=$(echo "("$menuWidthPage"-(("$menuMarginPage"*2)+"$menuMarginGutter"))/("$ratioFontSize"/1000)" | bc -l) countCharacterPerLineStyle=$(echo "("$menuWidthPage"-(("$menuMarginPage"*2)+("$menuMarginGutter"+"$menuFontSize")))/("$ratioFontSize"/1000)" | bc -l) countCharacterPerLineDisplay=$(echo "scale=0;("$countCharacterPerLine"*10)/10" | bc -l) countCharacterPerLineStyleDisplay=$(echo "scale=0;("$countCharacterPerLineStyle"*10)/10" | bc -l) countLinePerPage=$(echo "("$menuHeightPage"-(("$menuMarginPage"*2)+("$menuFontSize"/3)))/"$menuFontSize | bc -l) countLinePerPageDisplay=$(echo "scale=0;("$countLinePerPage"*10)/10" | bc -l) countLineStylePrevious=0 countLineStyleTotal=0 for ((iterationTable=0; $iterationTable < $countTable; iterationTable++)) do clear progress=$(echo "25/("$countTable"/("$iterationTable"+1))" | bc -l) progressDisplay=$(echo "scale=1;(("$progress"+0.05)*10)/10" | bc -l) if ((${#progressDisplay} == 2)) then echo "Progress = 0"$progressDisplay"%" else echo "Progress = "$progressDisplay"%" fi sizeRaw=$(stat -c "%s" "${fileTable[$iterationTable]}") if [ $sizeRaw == 0 ] then if [ $menuFileSizeSuffix == "e" ] then size="(0 byte)" elif [ $menuFileSizeSuffix == "f" ] then size="(0 octet)" fi elif [ $sizeRaw == 1 ] then if [ $menuFileSizeSuffix == "e" ] then size="(1 byte)" elif [ $menuFileSizeSuffix == "f" ] then size="(1 octet)" fi elif (($sizeRaw < 1024)) then if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets)" fi elif (($sizeRaw < 1048576)) then sizeInteger=$((sizeRaw/1024)) sizeDecimal=$(echo "("$sizeRaw"/1024)-"$((sizeRaw/1024)) | bc -l) sizeDecimalDisplay=$(echo "scale=1;("$sizeDecimal"*10)/10" | bc -l) sizeNumber=$(echo $sizeRaw"/1024" | bc -l) sizeNumberDisplay=$(echo "scale=1;("$sizeNumber"*10)/10" | bc -l) if [ $sizeDecimalDisplay == 0 ] then if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes = "$sizeInteger"KiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets = "$sizeInteger"Kio)" fi else if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes ≈ "$sizeInteger"KiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets ≈ "$sizeInteger"Kio)" fi fi else if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes = "$sizeNumberDisplay"KiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets = "$sizeNumberDisplay"Kio)" fi else if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes ≈ "$sizeNumberDisplay"KiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets ≈ "$sizeNumberDisplay"Kio)" fi fi fi elif (($sizeRaw < 1073741824)) then sizeInteger=$((sizeRaw/1048576)) sizeDecimal=$(echo "("$sizeRaw"/1048576)-"$((sizeRaw/1048576)) | bc -l) sizeDecimalDisplay=$(echo "scale=1;("$sizeDecimal"*10)/10" | bc -l) sizeNumber=$(echo $sizeRaw"/1048576" | bc -l) sizeNumberDisplay=$(echo "scale=1;("$sizeNumber"*10)/10" | bc -l) if [ $sizeDecimalDisplay == 0 ] then if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes = "$sizeInteger"MiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets = "$sizeInteger"Mio)" fi else if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes ≈ "$sizeInteger"MiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets ≈ "$sizeInteger"Mio)" fi fi else if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes = "$sizeNumberDisplay"MiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets = "$sizeNumberDisplay"Mio)" fi else if [ $menuFileSizeSuffix == "e" ] then size="("$sizeRaw" bytes ≈ "$sizeNumberDisplay"MiB)" elif [ $menuFileSizeSuffix == "f" ] then size="("$sizeRaw" octets ≈ "$sizeNumberDisplay"Mio)" fi fi fi fi if [ $menuColorStyle == "y" ] && [ $iterationTable != 0 ] then countLineStylePrevious=$(($(wc -l < tmp/tmp2)+(($(wc -l < tmp/tmp2)/(countLinePerPageDisplay-2))*2))) fi if [[ ! -z $menuPrefixFileName ]] then if [ $menuFileSizeSuffix != "n" ] then echo -e $menuPrefixFileName" "${fileTable[$iterationTable]}" "$size"\u00a0:" > tmp/tmpFoldInput else echo -e $menuPrefixFileName" "${fileTable[$iterationTable]}"\u00a0:" > tmp/tmpFoldInput fi else if [ $menuFileSizeSuffix != "n" ] then echo -e ${fileTable[$iterationTable]}" "$size"\u00a0:" > tmp/tmpFoldInput else echo -e ${fileTable[$iterationTable]}"\u00a0:" > tmp/tmpFoldInput fi fi if [ $menuColorStyle == "y" ] then valueFold=$countCharacterPerLineStyleDisplay else valueFold=$countCharacterPerLineDisplay fi sed -i tmp/tmpFoldInput -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldInput -e "s/"$lineAscii1Byte"/"$lineAscii2Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte echo $(head -1 tmp/tmpFoldInput) | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" | fold -s -w $((valueFold*2)) | sed -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" > tmp/tmpFoldOutput while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldOutput -e "s/"$lineAscii2Byte"/"$lineAscii1Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte sed -i tmp/tmpFoldOutput -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" cat tmp/tmpFoldOutput >> tmp/tmp2 countLineStyleNext=$(($(wc -l < tmp/tmp2)+(($(wc -l < tmp/tmp2)/(countLinePerPageDisplay-2))*2))) if [ $menuColorStyle == "y" ] then for ((iterationLineStyle=countLineStylePrevious; $iterationLineStyle < $countLineStyleNext; iterationLineStyle++)) do if (($iterationLineStyle % $countLinePerPageDisplay < $countLinePerPageDisplay - 2)) then numberLineStyle[$countLineStyleTotal]=$((iterationLineStyle+1)) ((countLineStyleTotal++)) fi done fi quickSearchModulo=false resultSearchModulo=0 iterationSearchModulo=$countLineStylePrevious if [ $countLinePerPageDisplay == 3 ] then resultSearchModulo=0 elif (($countLineStyleNext - $countLineStylePrevious == 1)) then resultSearchModulo=1 else while [ $quickSearchModulo == false ] do if (($iterationSearchModulo <= $countLineStyleNext - 1)) then if (($resultSearchModulo == $countLinePerPageDisplay - 2)) then resultSearchModulo=0 else ((resultSearchModulo++)) fi ((iterationSearchModulo++)) else quickSearchModulo=true fi done fi if [ $resultSearchModulo != 0 ] then echo "" >> tmp/tmp2 fi cp "${fileTable[$iterationTable]}" tmp/tmp1 sed -i tmp/tmp1 -e "s/\t/"${patternBinaryTable[0]}"/g" -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" countTmpLine=$(wc -l < tmp/tmp1) iterationTmpLine=1 while read line do spacePrefixLine="" for ((iterationSpace=0; $iterationSpace < ${#countTmpLine} - ${#iterationTmpLine}; iterationSpace++)) do spacePrefixLine=$spacePrefixLine${patternBinaryTable[1]} done spacePrefixSubline="" for ((iterationSpace=0; $iterationSpace < ${#countTmpLine}; iterationSpace++)) do spacePrefixSubline=$spacePrefixSubline${patternBinaryTable[1]} done echo $line > tmp/tmpFoldInput if [ $menuLineNumbering == "y" ] then valueFold=$((countCharacterPerLineDisplay-(${#countTmpLine}+3))) else valueFold=$countCharacterPerLineDisplay fi while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldInput -e "s/"$lineAscii1Byte"/"$lineAscii2Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte echo $(head -1 tmp/tmpFoldInput) | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[0]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" | fold -s -w $((valueFold*2)) | sed -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/ /"${patternBinaryTable[0]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" > tmp/tmpFoldOutput while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldOutput -e "s/"$lineAscii2Byte"/"$lineAscii1Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte iterationTmpSubline=1 while read subline do if [ $menuLineNumbering == "y" ] then if [ $iterationTmpSubline == 1 ] then echo $spacePrefixLine$iterationTmpLine" : "$subline | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[0]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp2 else echo $spacePrefixSubline" : "$subline | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[0]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp2 fi else echo $subline | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[0]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp2 fi ((iterationTmpSubline++)) done < tmp/tmpFoldOutput ((iterationTmpLine++)) done < tmp/tmp1 countLine=$(wc -l < tmp/tmp2) iterationLinePerPage=0 fillPage=$((countLinePerPageDisplay-2)) for ((iterationLine=0; $iterationLine < $countLine - 1; iterationLine++)) do if (($iterationLinePerPage == $countLinePerPageDisplay - 3)) then fillPage=$((fillPage+(countLinePerPageDisplay-2))) iterationLinePerPage=0 else ((iterationLinePerPage++)) fi done for ((iterationLine=0; $iterationLine < $fillPage - $countLine; iterationLine++)) do echo "" >> tmp/tmp2 done titlePageTable[$iterationTable]=${fileTable[$iterationTable]} if [ $countLineTotal == 0 ] then numberPageTable[$iterationTable]=1 else numberPageTable[$iterationTable]=$(((countLineTotal/(countLinePerPageDisplay-2))+1)) fi countLineTotal=$(wc -l < tmp/tmp2) done iterationLinePerPage=0 numberPageContent=1 flipFlop=false for ((iterationLine=0; $iterationLine < $countLineTotal; iterationLine++)) do if (($iterationLinePerPage == $countLinePerPageDisplay - 1)) then sed -i tmp/tmp2 -e $iterationLine"i\\\\" if [ $flipFlop == false ] then lenghtNumberPageContent=${#numberPageContent} fillSpace="" for ((iterationCharacter=0; $iterationCharacter < $countCharacterPerLineDisplay - $lenghtNumberPageContent; iterationCharacter++)) do fillSpace=$fillSpace${patternBinaryTable[1]} done sed -i tmp/tmp2 -e $((iterationLine+1))"i"$fillSpace$numberPageContent | sed -e "s/"${patternBinaryTable[1]}"/ /g" flipFlop=true else sed -i tmp/tmp2 -e $((iterationLine+1))"i"$numberPageContent flipFlop=false fi iterationLinePerPage=0 ((numberPageContent++)) clear progress=$(echo "25+(50/("$countLineTotal"/("$iterationLine"+1)))" | bc -l) progressDisplay=$(echo "scale=1;(("$progress"+0.05)*10)/10" | bc -l) echo "Progress = "$progressDisplay"%" else ((iterationLinePerPage++)) fi countLineTotal=$(wc -l < tmp/tmp2) done if [ $flipFlop == false ] then lenghtNumberPageContent=${#numberPageContent} fillSpace="" for ((iterationCharacter=0; $iterationCharacter < $countCharacterPerLineDisplay - $lenghtNumberPageContent; iterationCharacter++)) do fillSpace=$fillSpace${patternBinaryTable[1]} done echo -e "\n"$fillSpace$numberPageContent | sed -e "s/"${patternBinaryTable[1]}"/ /g" >> tmp/tmp2 else echo -e "\n"$numberPageContent >> tmp/tmp2 fi if [ $menuColorStyle == "y" ] then countLineStylePrevious=$(wc -l < tmp/tmp2) fi if [[ ! -z $menuTitleFileTable ]] then if [ $menuColorStyle == "y" ] then echo -e $menuTitleFileTable"\u00a0:" > tmp/tmpFoldInput else echo -e $menuTitleFileTable"\u00a0:" > tmp/tmpFoldInput fi else if [ $menuColorStyle == "y" ] then echo -e "File table\u00a0:" > tmp/tmpFoldInput else echo -e "File table\u00a0:" > tmp/tmpFoldInput fi fi if [ $menuColorStyle == "y" ] then valueFold=$countCharacterPerLineStyleDisplay else valueFold=$countCharacterPerLineDisplay fi sed -i tmp/tmpFoldInput -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldInput -e "s/"$lineAscii1Byte"/"$lineAscii2Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte echo $(head -1 tmp/tmpFoldInput) | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" | fold -s -w $((valueFold*2)) | sed -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" > tmp/tmpFoldOutput while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldOutput -e "s/"$lineAscii2Byte"/"$lineAscii1Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte sed -i tmp/tmpFoldOutput -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" cat tmp/tmpFoldOutput >> tmp/tmp2 countLineStyleNext=$(wc -l < tmp/tmp2) if [ $menuColorStyle == "y" ] then for ((iterationLineStyle=countLineStylePrevious; $iterationLineStyle < $countLineStyleNext; iterationLineStyle++)) do numberLineStyle[$countLineStyleTotal]=$((iterationLineStyle+1)) ((countLineStyleTotal++)) done fi if (($countLineStyleNext % $countLinePerPageDisplay != 0)) then echo "" >> tmp/tmp2 fi lenghtMaxTitlePageTable=$(((countCharacterPerLineDisplay-3)-${#numberPageTable[$((countTable-1))]})) for ((iterationTable=0; $iterationTable < $countTable; iterationTable++)) do echo ${titlePageTable[$iterationTable]} > tmp/tmpFoldInput valueFold=$lenghtMaxTitlePageTable sed -i tmp/tmpFoldInput -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldInput -e "s/"$lineAscii1Byte"/"$lineAscii2Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte echo $(head -1 tmp/tmpFoldInput) | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" | fold -s -w $((valueFold*2)) | sed -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/\\&/"${patternBinaryTable[3]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" > tmp/tmpFoldOutput while read lineAscii1Byte <&3 && read lineAscii2Byte <&4 do sed -i tmp/tmpFoldOutput -e "s/"$lineAscii2Byte"/"$lineAscii1Byte"/g" done 3< tmp/tmpFoldAscii1Byte 4< tmp/tmpFoldAscii2Byte sed -i tmp/tmpFoldOutput -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[3]}"/\\&/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" cat tmp/tmpFoldOutput > tmp/tmp3 countTmpLine=$(wc -l < tmp/tmp3) iterationTmpLine=1 point="." while read line do if [ $iterationTmpLine != $countTmpLine ] then echo $line >> tmp/tmp2 else lenghtLastLine=$((${#line}+${#numberPageTable[$iterationTable]})) for ((iterationCharacter=0; $iterationCharacter < $countCharacterPerLineDisplay - ($lenghtLastLine + 3); iterationCharacter++)) do point=$point"." done echo $line" "$point" "${numberPageTable[$iterationTable]} >> tmp/tmp2 fi ((iterationTmpLine++)) done < tmp/tmp3 done countLineTotal=$(wc -l < tmp/tmp2) iterationLinePerPage=0 fillPage=$countLinePerPageDisplay for ((iterationLine=0; $iterationLine < $countLineTotal - 1; iterationLine++)) do if (($iterationLinePerPage == $countLinePerPageDisplay - 1)) then fillPage=$((fillPage+countLinePerPageDisplay)) iterationLinePerPage=0 else ((iterationLinePerPage++)) fi done for ((iterationLine=0; $iterationLine < $fillPage - $countLineTotal; iterationLine++)) do echo "" >> tmp/tmp2 done iterationLine=0 iterationPage=0 firstPage=false flipFlop=false countPageTotal=$(($(wc -l < tmp/tmp2)/countLinePerPageDisplay)) iterationLineStyle=0 iterationLineTotal=1 styleColor=false styleSize=false sed -i tmp/tmp2 -e "s/ /"${patternBinaryTable[1]}"/g" -e "s/\\$/"${patternBinaryTable[2]}"/g" -e "s/*/"${patternBinaryTable[4]}"/g" -e "s/\\./"${patternBinaryTable[5]}"/g" -e "s/\\//"${patternBinaryTable[6]}"/g" -e "s/\\[/"${patternBinaryTable[7]}"/g" -e "s/\\\/"${patternBinaryTable[8]}"/g" -e "s/\\^/"${patternBinaryTable[9]}"/g" while read line do if [ $iterationLine == 0 ] then echo "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" > tmp/tmp.svg echo "<svg width=\""$(echo "("$menuMarginCutter"*2)+"$menuWidthPage | bc -l)"mm\" height=\""$(echo "("$menuMarginCutter"*2)+"$menuHeightPage | bc -l)"mm\">" >> tmp/tmp.svg fi if (($iterationLineStyle < $countLineStyleTotal)) then if (($iterationLineStyle > 0)) then if (($iterationLine != 0 && ${numberLineStyle[$iterationLineStyle]} - 1 == ${numberLineStyle[$((iterationLineStyle-1))]})) then styleSize=true else styleSize=false fi fi if [ ${numberLineStyle[$iterationLineStyle]} == $iterationLineTotal ] then styleColor=true ((iterationLineStyle++)) else styleColor=false fi else styleColor=false fi if [ $flipFlop == false ] then if [ $styleColor == false ] then echo "<text x=\""$(echo $menuMarginCutter"+("$menuMarginGutter"+"$menuMarginPage")" | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*("$iterationLine"+1)))" | bc -l)"mm\" text-anchor=\"start\" font-family=\""$menuFontName"\" font-size=\""$menuFontSize"mm\" fill=\"#000000\" xml:space=\"preserve\">"$(echo $line | sed -e "s/&/&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" -e "s/\"/\&quot;/g" -e "s/'/\&apos;/g")"</text>" | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp.svg else if [ $styleSize == false ] then echo "<rect x=\""$(echo $menuMarginCutter"+("$menuMarginGutter"+"$menuMarginPage")" | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*"$iterationLine"))" | bc -l)"mm\" width=\""$(echo $menuWidthPage"-("$menuMarginGutter"+("$menuMarginPage"*2))" | bc -l)"mm\" height=\""$(echo $menuFontSize"+("$menuFontSize"/3)" | bc -l)"mm\" fill=\"#ff0000\"/>" >> tmp/tmp.svg else echo "<rect x=\""$(echo $menuMarginCutter"+("$menuMarginGutter"+"$menuMarginPage")" | bc -l)"mm\" y=\""$(echo "("$menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*"$iterationLine")))+("$menuFontSize"/3)" | bc -l)"mm\" width=\""$(echo $menuWidthPage"-("$menuMarginGutter"+("$menuMarginPage"*2))" | bc -l)"mm\" height=\""$menuFontSize"mm\" fill=\"#ff0000\"/>" >> tmp/tmp.svg fi echo "<text x=\""$(echo $menuMarginCutter"+(("$menuMarginGutter"+"$menuMarginPage")+("$menuFontSize"/2))" | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*("$iterationLine"+1)))" | bc -l)"mm\" text-anchor=\"start\" font-family=\""$menuFontName"\" font-size=\""$menuFontSize"mm\" fill=\"#ffffff\" xml:space=\"preserve\">"$(echo $line | sed -e "s/&/&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" -e "s/\"/\&quot;/g" -e "s/'/\&apos;/g")"</text>" | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp.svg fi else if [ $styleColor == false ] then echo "<text x=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*("$iterationLine"+1)))" | bc -l)"mm\" text-anchor=\"start\" font-family=\""$menuFontName"\" font-size=\""$menuFontSize"mm\" fill=\"#000000\" xml:space=\"preserve\">"$(echo $line | sed -e "s/&/&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" -e "s/\"/\&quot;/g" -e "s/'/\&apos;/g")"</text>" | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp.svg else if [ $styleSize == false ] then echo "<rect x=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*"$iterationLine"))" | bc -l)"mm\" width=\""$(echo $menuWidthPage"-("$menuMarginGutter"+("$menuMarginPage"*2))" | bc -l)"mm\" height=\""$(echo $menuFontSize"+("$menuFontSize"/3)" | bc -l)"mm\" fill=\"#ff0000\"/>" >> tmp/tmp.svg else echo "<rect x=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" y=\""$(echo "("$menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*"$iterationLine")))+("$menuFontSize"/3)" | bc -l)"mm\" width=\""$(echo $menuWidthPage"-("$menuMarginGutter"+("$menuMarginPage"*2))" | bc -l)"mm\" height=\""$menuFontSize"mm\" fill=\"#ff0000\"/>" >> tmp/tmp.svg fi echo "<text x=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"/2))" | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+("$menuMarginPage"+("$menuFontSize"*("$iterationLine"+1)))" | bc -l)"mm\" text-anchor=\"start\" font-family=\""$menuFontName"\" font-size=\""$menuFontSize"mm\" fill=\"#ffffff\" xml:space=\"preserve\">"$(echo $line | sed -e "s/&/&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" -e "s/\"/\&quot;/g" -e "s/'/\&apos;/g")"</text>" | sed -e "s/"${patternBinaryTable[1]}"/ /g" -e "s/"${patternBinaryTable[2]}"/\\$/g" -e "s/"${patternBinaryTable[4]}"/*/g" -e "s/"${patternBinaryTable[5]}"/\\./g" -e "s/"${patternBinaryTable[6]}"/\\//g" -e "s/"${patternBinaryTable[7]}"/\\[/g" -e "s/"${patternBinaryTable[8]}"/\\\/g" -e "s/"${patternBinaryTable[9]}"/\\^/g" >> tmp/tmp.svg fi fi if (($iterationLine == $countLinePerPageDisplay - 1)) then echo "<rect x=\"0mm\" y=\"0mm\" width=\""$(echo "("$menuMarginCutter"*2)+"$menuWidthPage | bc -l)"mm\" height=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" fill=\"#ffffff\"/>" >> tmp/tmp.svg echo "<rect x=\"0mm\" y=\""$(echo $menuMarginCutter"+("$menuHeightPage"-"$menuMarginPage")" | bc -l)"mm\" width=\""$(echo "("$menuMarginCutter"*2)+"$menuWidthPage | bc -l)"mm\" height=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" fill=\"#ffffff\"/>" >> tmp/tmp.svg echo "<rect x=\"0mm\" y=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" width=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" height=\""$(echo $menuHeightPage"-("$menuMarginPage"*2)" | bc -l)"mm\" fill=\"#ffffff\"/>" >> tmp/tmp.svg echo "<rect x=\""$(echo $menuMarginCutter"+("$menuWidthPage"-"$menuMarginPage")" | bc -l)"mm\" y=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" width=\""$(echo $menuMarginCutter"+"$menuMarginPage | bc -l)"mm\" height=\""$(echo $menuHeightPage"-("$menuMarginPage"*2)" | bc -l)"mm\" fill=\"#ffffff\"/>" >> tmp/tmp.svg echo "</svg>" >> tmp/tmp.svg if [ $firstPage == false ] then rsvg-convert -f pdf -d 72 -p 72 tmp/tmp.svg -o tmp/tmp1.pdf firstPage=true else rsvg-convert -f pdf -d 72 -p 72 tmp/tmp.svg -o tmp/tmp2.pdf pdftk tmp/tmp1.pdf tmp/tmp2.pdf cat output tmp/tmp3.pdf mv tmp/tmp3.pdf tmp/tmp1.pdf fi if [ $flipFlop == false ] then flipFlop=true else flipFlop=false fi iterationLine=0 ((iterationPage++)) clear progress=$(echo "75+(25/("$countPageTotal"/"$iterationPage"))" | bc -l) progressDisplay=$(echo "scale=1;(("$progress"+0.05)*10)/10" | bc -l) echo "Progress = "$progressDisplay"%" else ((iterationLine++)) fi ((iterationLineTotal++)) done < tmp/tmp2 exiftool -q -m -all= tmp/tmp1.pdf mv tmp/tmp1.pdf "book content.pdf" rm tmp -r -f lenghtTotalCover=$(echo "(("$menuMarginCutter"*2)+("$menuWidthPage"*2))+("$countPageTotal"*0.06)" | bc -l) widthFrontBackCover=$(echo $menuMarginCutter"+"$menuWidthPage | bc -l) heightFrontBackCover=$(echo "("$menuMarginCutter"*2)+"$menuHeightPage | bc -l) widthSideCover=$(echo "("$countPageTotal"*0.06)" | bc -l) lenghtTotalCoverDisplay=$(echo "scale=3;(("$lenghtTotalCover"+0.0005)*10)/10" | bc -l) widthFrontBackCoverDisplay=$(echo "scale=3;(("$widthFrontBackCover"+0.0005)*10)/10" | bc -l) heightFrontBackCoverDisplay=$(echo "scale=3;(("$heightFrontBackCover"+0.0005)*10)/10" | bc -l) widthSideCoverDisplay=$(echo "scale=3;(("$widthSideCover"+0.0005)*10)/10" | bc -l) sizeRaw=0 for ((iterationTable=0; $iterationTable < $countTable; iterationTable++)) do sizeRaw=$((sizeRaw+$(stat -c "%s" "${fileTable[$iterationTable]}"))) done if [ $sizeRaw == 0 ] then size="0 byte" elif [ $sizeRaw == 1 ] then size="1 byte" elif (($sizeRaw < 1024)) then size=$sizeRaw" bytes" elif (($sizeRaw < 1048576)) then sizeInteger=$((sizeRaw/1024)) sizeDecimal=$(echo "("$sizeRaw"/1024)-"$((sizeRaw/1024)) | bc -l) sizeDecimalDisplay=$(echo "scale=1;("$sizeDecimal"*10)/10" | bc -l) sizeNumber=$(echo $sizeRaw"/1024" | bc -l) sizeNumberDisplay=$(echo "scale=1;("$sizeNumber"*10)/10" | bc -l) if [ $sizeDecimalDisplay == 0 ] then if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then size=$sizeRaw" bytes ("$sizeInteger"KiB)" else size=$sizeRaw" bytes (≈ "$sizeInteger"KiB)" fi else if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then size=$sizeRaw" bytes ("$sizeNumberDisplay"KiB)" else size=$sizeRaw" bytes (≈ "$sizeNumberDisplay"KiB)" fi fi elif (($sizeRaw < 1073741824)) then sizeInteger=$((sizeRaw/1048576)) sizeDecimal=$(echo "("$sizeRaw"/1048576)-"$((sizeRaw/1048576)) | bc -l) sizeDecimalDisplay=$(echo "scale=1;("$sizeDecimal"*10)/10" | bc -l) sizeNumber=$(echo $sizeRaw"/1048576" | bc -l) sizeNumberDisplay=$(echo "scale=1;("$sizeNumber"*10)/10" | bc -l) if [ $sizeDecimalDisplay == 0 ] then if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then size=$sizeRaw" bytes ("$sizeInteger"MiB)" else size=$sizeRaw" bytes (≈ "$sizeInteger"MiB)" fi else if (($(echo $sizeNumberDisplay" == "$sizeNumber | bc -l))) then size=$sizeRaw" bytes ("$sizeNumberDisplay"MiB)" else size=$sizeRaw" bytes (≈ "$sizeNumberOne"MiB)" fi fi fi clear echo "Book cover specifications for printing :" if ((${#lenghtTotalCoverDisplay} == 4)) then echo "Total lenght (front + side + back) = 0"$lenghtTotalCoverDisplay"mm" else echo "Total lenght (front + side + back) = "$lenghtTotalCoverDisplay"mm" fi if ((${#widthFrontBackCoverDisplay} == 4)) then echo "Front width = 0"$widthFrontBackCoverDisplay"mm" else echo "Front width = "$widthFrontBackCoverDisplay"mm" fi if ((${#heightFrontBackCoverDisplay} == 4)) then echo "Front height = 0"$heightFrontBackCoverDisplay"mm" else echo "Front height = "$heightFrontBackCoverDisplay"mm" fi if ((${#widthSideCoverDisplay} == 4)) then echo "Side width = 0"$widthSideCoverDisplay"mm" else echo "Side width = "$widthSideCoverDisplay"mm" fi if ((${#heightFrontBackCoverDisplay} == 4)) then echo "Side height = 0"$heightFrontBackCoverDisplay"mm" else echo "Side height = "$heightFrontBackCoverDisplay"mm" fi if ((${#widthFrontBackCoverDisplay} == 4)) then echo "Back width = 0"$widthFrontBackCoverDisplay"mm" else echo "Back width = "$widthFrontBackCoverDisplay"mm" fi if ((${#heightFrontBackCoverDisplay} == 4)) then echo "Back height = 0"$heightFrontBackCoverDisplay"mm" else echo "Back height = "$heightFrontBackCoverDisplay"mm" fi echo -e "\nBook content specifications for printing :" echo "Number of pages = "$countPageTotal if [ $countTable == 1 ] then echo "Total file size = "$size else echo "Total files size = "$size fi fi read exit 0</code> <caution>La routine présentée ci-dessus utilise les programmes (ou paquets) <bold>inkscape</bold>, <bold>librsvg2-bin</bold>, <bold>pdftk</bold>, et <bold>exiftool</bold> afin d'effectuer tous les traitements nécessaires.</caution> <text>Il vous faut donc les installer à l'aide de la ligne de commande suivante (à écrire dans le terminal de Linux) :</text> <code>sudo apt-get install inkscape librsvg2-bin pdftk exiftool -y</code> <text>Une fois cette installation effectuée, lorsque vous exécutez la routine (.sh), se propose à vous dans l'ordre d'apparition les questions suivantes :</text> <quote>- <bold>Page width in mm ?</bold> : largeur des pages (en millimètres). <br/>- <bold>Page height in mm ?</bold> : hauteur des pages (en millimètres). <br/>- <bold>Page margin in mm ?</bold> : dimensions des marges générales (en millimètres). <br/>- <bold>Gutter margin in mm ?</bold> : dimension de la marge de reliure qui servira à positionner le texte en retrait par rapport à la reliure du livre afin de faciliter l'ergonomie de lecture (en millimètres). <br/>- <bold>Font size in mm ?</bold> : taille des caractères du texte qui sera imprimé (en millimètres). <br/>- <bold>Font name ?</bold> : police de caractère utilisée (elle doit être à espacement unique, par exemple "ubuntu mono"). <br/>- <bold>Cutter margin in mm ?</bold> : dimensions du fond perdu (en millimètres). <br/>- <bold>File name prefix ?</bold> : préfixe qui sera visible avant le nom des fichiers (par exemple "Fichier monFichier.txt :"). <br/>- <bold>File size suffix ?</bold> : suffixe qui sera visible après le nom des fichiers indiquant la taille de ceux-ci en anglais ou en français (par exemple "myFile.txt (128 bytes) :" ou "monFichier.txt (128 octets) :"). <br/>- <bold>Line numbering ?</bold> : numérotation des lignes. <br/>- <bold>File table title ?</bold> : titre de la table des fichiers (si omis, le titre "File table" sera affiché par défaut). <br/>- <bold>Color style ?</bold> : surlignage en rouge des titres pour plus de visibilité (utile pour une impression couleur). <br/>- <bold>Sort option ?</bold> : tri manuel de l'ordre d'apparition des fichiers dans le livre (intéressant si le tri alphanumérique par défaut n'est pas souhaité).</quote> <text>Si vous avez choisi l'option de tri <bold>"m"</bold> pour cette dernière question <bold>"Sort option ?"</bold>, le menu <bold>"Manual sort :"</bold> (tri manuel) s'affiche à l'écran suivi de quelques commandes (détaillées ci-dessous), ainsi que l'arborescence des fichiers qui vont être inclus dans le livre, avec successivement le numéro d'apparition des fichiers et le chemin d'accès, c'est à ce moment que vous pouvez modifier l'ordre du tri. Voici ci-dessous le détail des commandes possibles :</text> <caution>Détail des commandes du menu <bold>"Manual sort :"</bold> : <br/>- <bold>e</bold> (pour "Exit" ou sortie) permet de sortir du menu et commencer la génération du livre. <br/>- <bold>s</bold> (pour "Save" ou sauvegarde) permet de sauvegarder l'arborescence de fichiers dans un fichier nommé <bold>file.tree</bold>. <br/>- <bold>l</bold> (pour "Load" ou chargement) permet de charger le fichier nommé <bold>file.tree</bold> contenant l'arborescence de fichiers. <br/>- <bold>d</bold> (pour "Delete" ou suppression) permet de supprimer le fichier nommé <bold>file.tree</bold> contenant l'arborescence de fichiers. <br/> <br/>Utilisez ces options pour sauvegarder l'arborescence avec la commande <bold>"s"</bold>, la modifier en ouvrant manuellement le fichier <bold>file.tree</bold> avec un éditeur de texte (comme gedit par exemple). Puis rechargez cette arborescence modifiée avec la commande <bold>"l"</bold>, vous verrez les modifications s'afficher dans le menu <bold>"File tree :"</bold>.</caution> <text>Plus bas le menu <bold>"File tree :"</bold> est affiché, c'est l'arborescence de fichiers :</text> <quote>La <bold>flèche</bold> orientée vers la gauche en suffixe des chemins d'accès aux fichiers indique la position de la <bold>destination</bold> d'un autre fichier <bold>source</bold> que vous pouvez choisir de déplacer. Validez pour décaler ce curseur vers une autre destination (c'est-à-dire vers le bas), ou écrivez un nombre, puis validez afin de changer la position dans l'arborescence (l'ordre de tri) du fichier indiqué en source (soit le nombre indiqué) vers la destination (soit le curseur en forme de flèche).</quote> <text><bold>Exemple :</bold> <br/>- Le curseur est positionné sur le fichier numéro 3, c'est la destination. <br/>- J'indique le numéro 10, c'est la source, puis je valide. <br/>- Le fichier en position 10 (la source) prend la position 3 (la destination), et inversement, le 3 prend la position 10.</text> <caution>Lorsque l'ordre de tri des fichiers correspond à ce que vous souhaitez, indiquez la commande <bold>"e"</bold> puis validez pour sortir du menu et débuter la génération du livre.</caution> <text>La génération du livre commence alors. Elle prend logiquement un temps proportionnel à la complexité de l'arborescence de fichiers utilisée comme source, ainsi que le nombre de lignes et de caractères dans la programmation et l'encodage de chaque fichiers. Une fois la génération du livre terminée, un fichier PDF nommé <bold>book content.pdf</bold> est constitué, et les spécifications utiles pour l'impression du livre sont affichées :</text> <quote>- <bold>Book cover specifications for printing</bold> : caractéristiques de la couverture du livre pour l'impression. <br/>- <bold>Total lenght (front + side + back)</bold> : longueur totale de la couverture (soit la somme des largeurs de la face avant, du dos, et de la face arrière). <br/>- <bold>Front width</bold> : largeur de la face avant. <br/>- <bold>Front height</bold> : hauteur de la face avant. <br/>- <bold>Side width</bold> : largeur du dos. <br/>- <bold>Side height</bold> : hauteur du dos. <br/>- <bold>Back width</bold> : largeur de la face arrière. <br/>- <bold>Back height</bold> : hauteur de la face arrière. <br/> <br/>- <bold>Book content specifications for printing</bold> : caractéristiques du contenu du livre pour l'impression. <br/>- <bold>Number of pages</bold> : nombre total de pages du contenu du livre. <br/>- <bold>Total files size</bold> : taille totale des fichiers de votre arborescence faisant partie du contenu, ce qui correspond à la taille totale des fichiers inclus dans le livre, autrement dit, le contenu utile (cette taille exclue donc les titres et la numérotation des pages, de même que la table des fichiers à la toute fin du livre qui n'est là que pour faciliter la navigation dans l'ouvrage final imprimé).</quote> <caution>Note importante : la largeur du dos du livre est calculée par rapport à un papier de 100g/m².</caution> <text>Toutes ces caractéristiques vont vous permettre de créer la couverture du livre manuellement. Dans la continuité, la génération de la couverture aurait pu être également automatisée, mais je pense que c'est contre-artistique, ne laissant plus aucun libre cours à la création et l'imagination. C'est donc un choix mûrement réfléchit de ma part que de laisser la création de la couverture à la charge de l'auteur.</text> <caution>Après avoir créé la couverture de votre livre à votre guise, il suffit simplement d'envoyer cette dernière ainsi que le fichier <bold>book content.pdf</bold> à un imprimeur !</caution> <a href="photo/dsc09006.jpg"><img src="thumbnail/dsc09006.jpg"></img></a> <a href="photo/dsc09016.jpg"><img src="thumbnail/dsc09016.jpg"></img></a> <text>Libre à vous de faire une utilisation de ce petit programme de génération automatique de contenu de livre, lorsque vous aurez besoin de sauvegarder vos fichiers sur un autre support que ceux habituellement utilisés dans le monde du numérique !</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier understandWhatIsModule.html : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#understandWhatIsModule"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Comprendre ce qu'est MODULE</title> <underline></underline> <text>MODULE est un système embarqué d'automates programmables, c'est-à-dire une partie logicielle (programmation) et une partie matérielle (électronique) permettant de réaliser des tâches d'automatisation.</text> <text>Partie logicielle, le programme MODULE est un outil de développement qui se présente sous la forme d'une suite de classes autonomes écrites en langage C++ dédiées à la programmation des microcontrôleurs <bold>ATmega48P</bold>, <bold>ATmega88P</bold>, <bold>ATmega168P</bold>, <bold>ATmega328P</bold>, <bold>ATmega164P</bold>, <bold>ATmega324P</bold>, <bold>ATmega644P</bold>, et <bold>ATmega1284P</bold> qui équipent mes automates programmables.</text> <text>Partie matérielle, le projet MODULE est un ensemble de circuits imprimés constituants la base de cartes électroniques complètes partie commande équipées de microcontrôleurs (ce sont les automates programmables associés au programme MODULE), et également d'autres cartes électroniques périphériques que vous pouvez connecter aux automates programmables.</text> <text>Photos ci-dessous, l'automate programmable <bold>MODULABLE 20</bold> équipé de 20 entrées/sorties et <bold>MODULABLE 32</bold> équipé de 32 entrées/sorties :</text> <a href="photo/dsc08339.jpg"><img src="thumbnail/dsc08339.jpg"></img></a> <a href="photo/dsc08185.jpg"><img src="thumbnail/dsc08185.jpg"></img></a> <quote>Les plans de fabrication des PCB (pour "Printed Circuit Board", ou circuit imprimé) de mes cartes électroniques sont disponibles dans les sections "Fabrications et diverses réalisations" et "Téléchargements" en page d'accueil de mon site Web.</quote> <text><bold>Historique du projet MODULE :</bold> <br/>Le projet MODULE et les circuits électroniques qui y sont associé a débuté il y a quelques années, et aura demandé beaucoup de travail pour aboutir au produit actuel.</text> <text>Personnellement je me suis toujours intéressé à l'électricité d'un point de vue physique, mais l'électronique (qui est la mise en pratique de la physique de l'électron) m'apparaissait comme obscure et difficile à appréhender. J'ai donc décidé d'apprendre l'électronique en autodidacte avec la meilleure volonté, parce que c'était un domaine que je ne connaissais (sans même encore parler de maîtriser ou de pratiquer) absolument pas.</text> <text>Sans aucune formation dans le domaine, j'ai donc progressé en lisant pendant des années les fiches techniques des composants électroniques, des articles sur internet (dans lesquels il convient souvent de trier et de recouper l'information), mais aussi et surtout à force de pratique et d'expériences personnelles (ce qui finalement peut être appelé le bricolage).</text> <a href="photo/dsc02345.jpg"><img src="thumbnail/dsc02345.jpg"></img></a> <a href="photo/dsc02821.jpg"><img src="thumbnail/dsc02821.jpg"></img></a> <text><bold>La philosophie du programme MODULE :</bold> <br/>L'objectif de MODULE est de trouver le point de performance le plus élevé pour chaque composant électronique mis en œuvre. Ceci est réalisé en étudiant très finement les fiches techniques des composants (registres, paramètres, fréquences de fonctionnement, etc...), puis en effectuant des bancs d'essai successifs jusqu'à l'obtention des meilleurs résultats, tout en restant complètement valide eu égard les tolérances constructeur et la portabilité du code écrit en langage C++.</text> <text>De surcroît, MODULE n'est pas programmé en surcouche d'une autre bibliothèque comme l'est la plupart des autres plates-formes de développement pour microcontrôleurs. Le code source C++ de MODULE, minimaliste de fait, est dédié et optimisé pour chaque microcontrôleur programmé, soit l'ATmega48P, l'ATmega88P, l'ATmega168P, l'ATmega328P, l'ATmega164P, l'ATmega324P, l'ATmega644P, ou l'ATmega1284P afin d'obtenir le meilleur compromis en matière de rapidité et d'espace mémoire.</text> <quote>MODULE est une bonne alternative à d'autres plates-formes de développement pour programmer plus efficacement l'ATmega48P, l'ATmega88P, l'ATmega168P, l'ATmega328P, l'ATmega164P, l'ATmega324P, l'ATmega644P, ou l'ATmega1284P.</quote> <text>Le programme MODULE est une création singulière unique (car non plagiée), dans le seul but de la compréhension, de l'optimisation, et du partage d'une modeste expression créative personnelle libre de droit d'auteur et à sources ouvertes et modifiables.</text> <quote>Tous mes programmes sont écrits avec un simple éditeur de texte (gedit) pourvu uniquement de la coloration syntaxique (nul besoin d'autre chose).</quote> <text>Le programme MODULE fonctionne en totale autonomie et ne requiert pas de ressources annexes externes. En effet, même aucune bibliothèque couramment admise comme indispensable (par la communauté des programmeurs) faisant partie du standard du langage C++ n'a été utilisée pour programmer MODULE, comme par exemple stdlib, stdio, ou encore math, ceci dans un objectif pédagogique de compréhension du fonctionnement intime matériel des circuits intégrés.</text> <caution>Ne pas être lié à d'autres programmes permet à MODULE d'être autonome et indépendant, en outre de ne pas subir les aléas, évolutions, bogues, ou encore obsolescences de fichiers concurrents.</caution> <text>MODULE qui a débuté avec l'ATmega328P (ce fut le point de départ), c'est aussi redonner tout l'intérêt pour ce petit microcontrôleur 8 bits de plus en plus délaissé au profit de microcontrôleurs 32 bits aux fréquences de fonctionnement plus élevées du fait que les bibliothèques concurrentes demandent plus de cycles pour faire les mêmes opérations que le programme MODULE.</text> <text><bold>La normalisation de la structure logique et syntaxique du programme MODULE :</bold> <br/>MODULE a été programmé avec rigueur et normalisation du code source (comme tous les programmes proposés en exemple).</text> <text>Une ligne de conduite concernant la logique, la structure, la syntaxe, le nommage des variables, des fonctions et des classes, ou même simplement l'aspect visuel (indentation, espaces, etc...), a été respectée afin d'obtenir le code source le plus lisible, fonctionnel et propre possible.</text> <quote>Ceci n'est pas plus une réponse à tout ce que je peux constater dans la communauté des programmeurs actuellement, mais plus une volonté personnelle de bonnes pratiques en termes d'écriture des programmes.</quote> <text><bold>Simplicité de programmation avec MODULE :</bold> <br/>En interne, le programme MODULE s'occupe de réaliser les tâches les plus laborieuses, ardues et complexes que requiert la programmation brute d'un microcontrôleur et des circuits intégrés périphériques. Ceci permet au développeur de réaliser des projets élaborés en un minimum de lignes de programmation, sans pour autant pâtir sur les performances ou brider le nombre de possibilités.</text> <text>MODULE se veut accessible aux débutants, tout en permettant la réalisation d'applications professionnelles.</text> <text><bold>Que peut-on faire avec MODULE ?</bold> <br/>MODULE est modulaire (ce qui a donné le nom au projet), il n'a en soit pas de limite (logicielle ou matérielle), la seule est notre imagination. Sachez qu'à l'époque de la conquête spatiale, des ingénieurs et techniciens ont envoyés des fusées dans l'espace avec bien moins comme calculateur qu'un ATmega328P !</text> <text>Avec le programme MODULE vous pouvez faire fonctionner des accéléromètres, gyroscopes, magnétomètres, baromètres, thermomètres, hygromètres, et même des caméras thermiques. Pour des applications robotiques et modélisme vous pouvez générer des signaux PWM et donc entre autres faire fonctionner des servo-moteurs et des contrôleurs de moteurs sans charbons, lire des signaux PWM permettant par exemple de récupérer les différentes voies d'un récepteur de modélisme, créer une interface entre l'utilisateur et l'automate programmable via des boutons, des potentiomètres, des afficheurs, et des buzzers. Il est possible de temporiser les actions et les événements à effectuer, de réaliser des calculs et diverses courbes et fonctions mathématiques, de générer de l'aléatoire à partir de bruit analogique, de filtrer des valeurs en temps réel, de créer des états multiples avec hystérésis, de gérer la veille du microcontrôleur, de communiquer en MIDI avec des instruments de musique standards du commerce, d'effectuer des communications type réseaux filaires et sans fil 2.4GHz entre plusieurs automates programmables, de sauvegarder des données en mémoire EEPROM une fois le montage coupé de l'alimentation électrique, et bien d'autres choses encore...</text> <quote>Libre à vous de programmer d'autres fonctions dans MODULE si vous le souhaitez !</quote> <text>Photo ci-dessous, un exemple de projet réalisé avec le programme MODULE et l'automate programmable MODULABLE 32, équipé d'un ATmega1284P pour la partie radiocommande, et ATmega644P pour la partie quadri-hélicoptère (cependant ce prototype était initialement équipé d'un ATmega328P) :</text> <a href="photo/dsc08421.jpg"><img src="thumbnail/dsc08421.jpg"></img></a> <text><bold>La partie matérielle associée au programme MODULE :</bold> <br/>Les cartes électroniques, soit la partie matérielle proposée en téléchargement (dans les sections "Fabrications et diverses réalisations" et "Téléchargements" en page d'accueil de mon site Web), sont réalisées dans des contraintes et des critères normatifs stricts imposés notamment par les fiches techniques officielles des composants électroniques, et également de mon expérience personnelle concernant leurs implantations (ergonomie de positionnement et de brasure, etc...).</text> <quote>Les dessins de mes circuits imprimés sont réalisés sur papier, puis numériquement à l'aide du <bold>logiciel KiCad</bold> avec le système d'exploitation Linux, ceci via ma <bold>propre bibliothèque de composants</bold> dans des vues schématiques et PCB.</quote> <a href="photo/dsc07971.jpg"><img src="thumbnail/dsc07971.jpg"></img></a> <a href="photo/dsc07980.jpg"><img src="thumbnail/dsc07980.jpg"></img></a> <text>Les plans de fabrication de mes circuits imprimés sont au <bold>format de fichiers Gerber</bold> (.gbl, .gbs, .gbo, .gbr, .gtl, .gts, .gto, .drl), car ce sont des fichiers normalisés utilisés par toute l'industrie de l'électronique pour la transmission de plans de production entre les différentes manufactures.</text> <quote>Le format de fichiers Gerber est le standard directement pris en charge par toutes les usines de fabrication.</quote> <text><bold>Le choix des composants traversants ou montés en surface :</bold> <br/>Dans mes circuits électroniques j'ai souhaité l'implantation de composants traversants plutôt que montés en surface (cms) :</text> <quote>Ceci est un choix arbitraire dans le but de privilégier la facilité de montage des éléments par des débutants notamment dans les <bold>"Fab lab"</bold> (pour "Fabrication laboratory", ou laboratoire de fabrication). En effet les composants étant plus volumineux, leurs brasure sur les PCB est moins minutieuse et peut être effectuée avec du matériel peu onéreux. Aussi, les composants se trouvent plus facilement dans la petite boutique locale d'électronique, ou via un recyclage des composants provenant d'appareils du commerce destinés à la casse (entre autres victimes de l'obsolescence programmée). Le démontage pour réparation est également plus aisé, ainsi que d'éventuels tests in-situ avec un multimètre. Ensuite, certains composants traversants ne trouvent logiquement pas d'équivalents montés en surface (certains condensateurs par exemple de par leurs capacité), et finalement la place prise sur le PCB est toute relative.</quote> <text>En outre, ceci ne doit en aucun cas être un frein à votre créativité et à vos projets !</text> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html> Fichier contact.php : <html> <head> <meta charset="utf-8"/> <title>sylvainmahe.site</title> <link rel="stylesheet" type="text/css" href="style.css"> <script type="text/javascript" src="script.js"></script> </head> <body> <name id="name">Sylvain Mahé</name> <function id="function">Le site Web</function> <side> <img src="image/avatar.jpg"></img> <a href="index.html#contact"><navigation><bold>Retour</bold> à l'accueil</navigation></a> <title>Principes</title> <underline></underline> <text>Partager mes idées et mes projets librement et gratuitement.</text> <title>Thématiques</title> <underline></underline> <text>Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté.</text> <title>Contact</title> <underline></underline> <text><bold>✆ Téléphone :</bold> 06.45.49.96.98 <br/><bold>✉ E-mail :</bold> contact@sylvainmahe.site <br/><bold>✎ Site Web :</bold> sylvainmahe.site</text> </side> <page> <header>Écriture de la page : Sylvain Mahé</header> <separator></separator> <title>Contacter Sylvain Mahé</title> <underline></underline> <text>Pour me contacter et me faire part de votre demande (questions précises ou diverses, remarques et suggestions, idées à proposer, colaboration et fabrication en petites séries, etc...), il vous suffit de renseigner les champs de saisie suivants, puis de cliquer sur le bouton "Envoyer votre message".</text> <?php if (isset ($_POST ["submit"]) == true) { $to = "contact@sylvainmahe.site"; $from = htmlspecialchars ($_POST ["address"], ENT_QUOTES, UTF-8, true); $subject = htmlspecialchars ($_POST ["subject"], ENT_QUOTES, UTF-8, true); $message = htmlspecialchars ($_POST ["message"], ENT_QUOTES, UTF-8, true); $header = "From:" . $from; if (empty ($_POST ["address"]) == true) { echo "<caution>Veuillez indiquer une adresse de courrier électronique.</caution>\n"; } else if (empty ($_POST ["subject"]) == true) { echo "<caution>Veuillez indiquer le sujet de votre message.</caution>\n"; } else if (empty ($_POST ["message"]) == true) { echo "<caution>Veuillez écrire un message.</caution>\n"; } else { if (mail ($to, $subject, $message, $header) == true) { echo "<valid>Votre message a été envoyé, je vais essayer de vous répondre dans les plus brefs délais.</valid>\n"; $from = ""; $subject = ""; $message = ""; } else { echo "<caution>Votre message n'a pas été envoyé à cause d'un problème technique, veuillez réésayer.</caution>\n"; } } } ?> <form action="contact.php" method="post"> <text>Votre adresse de courrier électronique :</text> <input type="text" name="address" placeholder="exemple@gmail.com" value="<?php echo $from; ?>"></input> <text>Le sujet de votre message :</text> <input type="text" name="subject" placeholder="..." value="<?php echo $subject; ?>"></input> <text>Votre message :</text> <textarea name="message" placeholder="..."><?php echo $message; ?></textarea> <input type="submit" name="submit" value="Envoyer votre message"></input> </form> <line></line> <footer>Programmation et graphismes de la page : Sylvain Mahé</footer> </page> </body> </html>