Projet Station météo portable
Membres du groupe :
ianel AKOU, Paul BOUDET, Rose PEYBERNES, Mathéo TONNEYCK
Séance : Découverte du FabLab
Nous avons commencé la séance par une présentation du principe et du fonctionnement du Fablab , nous permettant d'en découvrir davantage notamment sur leur origine, leur localisation et l'importance de la documentation qui y est associée. Par la suite, nous avons détaillé les objectifs et le programme de l'UE . Une visite du Fablab nous permet ensuite de découvrir l'ensemble des machines et composants avec lesquels nous pourrons travailler afin de confectionner et concrétiser notre projet final : imprimantes 3D, découpeuses laser, fraiseuses numériques, cartes Arduino. Cette année, nos projets doivent être portés sur le thème des mesures environnementales à l'aide de capteurs . Après avoir formé des groupes de projet, nous avons exploré le wiki du fablab, trouvé la bibliothèque de documents à notre disposition et émis les premières idées pour notre projet final.
Séance 2 : Prise en main de l'Arduino UNO
Partie théorique :
- Pour débuter la séance, nous avons eu une discussion autour de l'évolution de l'électronique en dates ( de la diode de John Fleming en 1904 au M5Stack en 2017).
- Par la suite, nous avons été introduits aux cartes Arduino dans les détails nous permettant de comprendre leur fonctionnement et la façon de communiquer avec la suite Arduino IDE. Chaque carte supporte plusieurs composants ayant chacun une fonctionnalité précise.
- Grâce au logiciel Arduino, nous avons commencé à découvrir le langage des cartes et la bonne façon de transmettre une volonté à notre carte. Nous avons défini des termes et fonctions pouvant être présents dans les codes que nous pouvons avoir à utiliser pour notre projet :
Exemples :
SETUP : La fonction setup() est appelée au démarrage du programme. Cette fonction est utilisée pour initialiser les variables, les librairies utilisées.
LOOP : cette fonction appelle à répéter en boucle une certaine action.
- Pour finir sur la théorie, nous avons appris qu'avant de brancher n'importe quel module à une carte Arduino et de créer un code il y a une démarche à suivre pour avoir un résultat rapide et de qualité :
1) Identifier le module avec son nom ou une référence.
2) Trouver sa fiche technique (si elle existe) sur le site seeed studio
3) Correctement appréhender le module et comprendre son mécanisme et sa fonctionnalité
4) Télécharger la bibliothèque qui lui correspond et l'introduire dans le programme sur Arduino
5) Choisir un programme sur le site qui répond à la demande et le transférer dans Arduino
6) Brancher les composants
Partie pratique :
- Après avoir bien compris le fonctionnement d'Arduino, nous avons branché une carte Arduino à notre ordinateur. Sur le logiciel, à l'aide des exemples de codes à disposition nous sommes parvenus premièrement à faire de simples manipulations comme allumer la LED de la plaque et la faire clignoter à des intervalles de temps différents. Par la suite, nous avons superposé un shield sur notre carte Arduino et y avons branché sur l'un des ports I2C un capteur de température et d'humidité avec un connecteur grove . De nouveau à l'aide d'un exemple de code, nous sommes parvenus à afficher la température et l'humidité de la salle.Par la suite avec la fonctionnalité module en série, nous avons réussi à mesurer toutes les deux secondes la température et l'humidité. Pour être sur que notre dispositif fonctionnait nous l'avions placé à différents endroits et vérifié qu'il y avait bien une variation des valeurs (dans les mains, sur une table, dans un pull). Suite à cela, nous avons voulu améliorer notre dispositif en numérisant les valeurs sur un écran en temps réel. Pour cela, nous avons d'abord choisi le bon programme pour relier l'écran à notre carte. Nous avons ensuite combiné le programme du capteur et celui de l'écran pour afficher les valeurs. Nous avons ainsi obtenu le programme suivant :
#include <Arduino.h>
#include <Wire.h>
#include "SHT31.h"
#include <Wire.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
SHT31 sht31 = SHT31();
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("begin...");
sht31.begin();
}
void loop() {
float temp = sht31.getTemperature();
float hum = sht31.getHumidity();
Serial.print("Temp = ");
Serial.print(temp);
Serial.println(" C"); //The unit for Celsius because original arduino don't support speical symbols
Serial.print("Hum = ");
Serial.print(hum);
Serial.println("%");
Serial.println();
delay(1000);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Temp = ");
lcd.print(sht31.getTemperature());
lcd.setCursor(0, 1);
lcd.print("Humidity = ");
// print the number of seconds since reset:
lcd.print(sht31.getHumidity());
delay(2000);
}
- À la fin de la séance, nous avons pu avoir accès à d'autres types de capteurs que nous pouvons utiliser dans notre projet final : capteur de lumière, CO2, gaz, qualité de l'eau, débit de l'eau, pression.
Matériel utilisé en image et vidéos :
Carte Arduino Shield
Capteur de température et d'humidité Connecteur bosquet
Ecran pour Arduino
La prochaine séance nous travaillerons sur la représentation et le dessin en 2 et 3 dimensions . Nous verrons aussi l'utilité et le fonctionnement de M5Stack qui est un système de plusieurs modules que l'on peut approcher par programmation avec la suite Arduino IDE.
Séance 3 : Découverte du dessin 2D/3D, de la découpe laser et de l'impression 3D
Pour cette séance nous sommes concentrés sur la représentation en deux dimensions et en trois dimensions avec plusieurs logiciels :
- INKSCAPE : le logiciel Inskcape permet de réaliser des dessins vectoriels gratuitement et qui reste relativement abordable en utilisation. Nous nous servirons pour la modélisation destinée à la découpe laser. Nous avons commencé par faire nos premiers pas sur Inskape en reproduisant un dessin géométrique aléatoire proposé par notre professeur avec plusieurs paramètres de dimensions :
Il est aussi important de connaître l'existence de Makercase : qui est une proposition en ligne d'une banque de modèles de boîtes de toutes les sortes déjà réalisées. Ce sont des formes basiques que l'on peut ensuite modifier sur Inskcape en les importantes.
- OPENSCAD : est un logiciel libre de modélisation paramétrique gratuit. La modélisation sur ce logiciel se fait par programmation avec un langage C++. Une aide-mémoire existe sur le site officiel du logiciel où l'on retrouve les fonctions de base pour créer des designs relativement élaborés. Sur ce logiciel, nous avons modélisé un cube percé par 3 cylindres :
- FREECAD : FreeCAD est un modeleur 3D paramétrique open-source conçu principalement pour concevoir des objets réels de toute taille. La modélisation paramétrique nous permet de modifier facilement nos conceptions en revenant dans l'historique du modèle et en modifiant ses paramètres. Ce logiciel permet notamment de générer des fichiers 3d au format STL (qui est un format adapté aux impressions 3D mais qui ne peut plus être modifié). En effet, il faut créer au préalable un fichier de conception que l'on peut modifier à notre aise puis l'exporter en fichier STL pour l'impression ou la découpe laser. Nous avons de nouveau modélisé le même cube troué :
Nous avons ensuite transféré notre modélisation 3D de cube percé à une imprimante 3D et nous avons lancé l'impression. Nous avons fait de même pour la découpeuse laser. L'objectif était de comprendre le commentaire autorisé le modèle obtenu grâce aux logiciels de dessin sur les machines de conception.
NB : La durée d'une impression 3D peut dépendre de la taille, du choix de remplissage de l'objet à imprimer ou encore du filament utilisé. Il arrive parfois que le bus se bouche ou que l'impression rate à cause de mauvaises dimensions. Par conséquent, il faut prévoir une marge de temps pour que le projet soit prêt à la date butoir au cas où il serait nécessaire de recommencer une impression.
Séance 4.1 : Prise en main du M5Stack
Découverte du M5Stack
Au cours de cette séance, l'objectif était de comprendre le fonctionnement de M5Stack. Pour rappel, un M5Stack est un kit de développement intégré autour de l'ESP32. Il se compose d'une partie centrale appelée core , qui intègre notamment un écran et un lecteur de cartes SD. Il faut aussi savoir que le M5Stack répond au langage C / C++ via l' IDE Arduino. Cela signifie que les codes utilisés pour la programmation d'une carte Arduino peuvent aussi être utilisés pour la programmation de M5Stack. Attention ! --> il faut tout de même effectuer quelques modifications : changer toutes les adresses à la carte Arduino en adresses au M5Stack (ex : #include <Arduino.h> en #include <M5Stack.h>Il faut aussi bien penser à aller changer/vérifier le port et l'entrée sélectionnée pour transférer le programme !
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
Après avoir compris ce qu'était un M5Stack et comment nous pouvions nous en servir, nous sommes passés à la partie pratique. Celle-ci a été facilitée par l'existence du site internet github proposant de nombreux codes standards pour donner des missions basiques à M5Stack. Notre première mission étant d'afficher "Hello World" sur l'écran du M5Stack, nous nous sommes donc servis du programme HelloWorld.ino qui se trouve dans le dossier Basics des exemples :
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core sample source code
* 配套 M5Core 示例源代码
* Visit for more information: https://docs.m5stack.com/en/core/gray
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
*
* Describe: Hello World
* Date: 2021/7/15
*******************************************************************************
*/
#include <M5Stack.h>
/* After M5Core is started or reset
the program in the setUp () function will be run, and this part will only be run
once. 在 M5Core
启动或者复位后,即会开始执行setup()函数中的程序,该部分只会执行一次。 */
void setup() {
M5.begin(); // Init M5Core. 初始化 M5Core
M5.Power.begin(); // Init Power module. 初始化电源模块
/* Power chip connected to gpio21, gpio22, I2C device
Set battery charging voltage and current
If used battery, please call this function in your project */
M5.Lcd.print("Hello World"); // Print text on the screen (string)
// 在屏幕上打印文本(字符串)
}
/* After the program in setup() runs, it runs the program in loop()
The loop() function is an infinite loop in which the program runs repeatedly
在setup()函数中的程序执行完后,会接着执行loop()函数中的程序
loop()函数是一个死循环,其中的程序会不断的重复运行 */
void loop() {
}
Après avoir réussi cette étape, nous avons branché le même capteur d'humidité et de température qu'à la séance 2 et nous avons essayé d'afficher les valeurs sur l'écran du M5Stack. Pour cela, notre première idée était de réutiliser notre programme de la séance 2 en le modifiant pour qu'il soit compris par le M5Stack. Nous avons obtenu ceci :
Cependant, les données s'affichaient à la suite et en très petit. Après avoir passé un certain temps à chercher comment modifier la taille, la police et la couleur des écritures, nous ne sommes pas parvenus à un résultat concluant. Mais un groupe de camarades a écrit un code qui fonctionne parfaitement (il s'agit du groupe B1). Nous les remercions pour le travail efficace qu'ils ont fourni. Voici leur code :
#include <Arduino.h>
#include <M5Stack.h>
#include <Wire.h>
#include "SHT31.h"
#include "Free_Fonts.h"
SHT31 sht31 = SHT31();
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("begin...");
sht31.begin();
M5.begin(); // Init M5Core. 初始化 M5Core
M5.Power.begin(); // Init Power module. 初始化电源模块
}
void loop() {
float temp = sht31.getTemperature();
float hum = sht31.getHumidity();
M5.Lcd.setFreeFont(FSB18);
M5.Lcd.print("Temp = ");
M5.Lcd.print(temp);
M5.Lcd.println(" C");
M5.Lcd.print("Hum = ");
M5.Lcd.print(hum);
M5.Lcd.println(" %");
M5.Lcd.println();
delay(1000);
}
Séance 4.2 : Projet Personnel
Après avoir travaillé sur les M5Stacks, nous avons chacun avancé sur nos mini projets dont l'objectif est de modéliser un objet en 3D et de l'imprimer mais aussi de prototyper un objet/dessiner et de le découper/graver sur une planche de bois avec la découpeuse laser.
Chaque membre du groupe détaillera son projet ci-dessous :
Paul Boudet
Modélisation d'un marteau en 3D :
Pour modéliser mon objet en 3D, j'ai utilisé le logiciel FREECAD qui a été introduit lors de la séance 2. J'ai créé un nouveau document puis la fenêtre Part Design. Grâce à cette fenêtre, j'ai réalisé une esquisse d'un rectangle puis utilisé l'outil protrusion afin de créer un pavé en 3D à partir de cette esquisse de longueur l= 30 mm, de largeur L= 10 mm et de hauteur h = 15 millimètres. Une fois mon pavé réalisé, j'ai sélectionné une des faces du pavé et réalisé une nouvelle esquisse, d'un cercle cette fois ci, sur cette face. A partir de cette esquisse d'un cercle, en utilisant l'outil protrusion, j'ai créé un cylindre de 30 mm de hauteur dont la base est le cercle réalisé en esquisse.J'ai ensuite fait un trou dans ce cylindre à l'aide de l'outil préconisé. Ces étapes m'ont permis de modéliser un petit marteau en 3D de dimensions 50*50 mm :
A droite, sur le fond bleu ce situe la modélisation du marteau.
A gauche on retrouve la fenêtre "vue combinée", qui résume les actions réalisées afin de modéliser cette pièce. Cette vue nous permet, si l'on souhaite modifier notre objet, de réaliser ces modifications sur une partie spécifique de notre objet au lieu de tout recommencer.
Enfin, en haut, sur la ligne du bas, se trouvent les outils du mode part design qui m'ont permis de modéliser cette pièce.
Une fois, la modélisation terminée, il faut exporter le fichier en format STL afin de l'imprimer à l'aide des imprimantes 3D du Fablab qui sont des imprimantes FDM Raise 3D Pro 2. Une documentation sur le fonctionnement de ces imprimantes est disponible dans l'onglet Tutoriels puis Machines, du wiki.
Voici un lien vers mon fichier : pièce-3D-2.FCStd
Documentation dessin 2D Paul BOUDET :
Pour réaliser mon dessin en 2D, j'ai dessiné mon objet dans le logiciel de dessin vectoriel INKSCAPE . Grâce à ce logiciel, j'ai dessiné un motif connu par les amateurs du manga Naruto. Ce motif esthétique représente les yeux de certains personnages dans le manga et est nommé "sharingan" :
Pour dessiner ce motif, j'ai utilisé les outils mis à ma disposition à droite de l'interface. A droite se situe une fenêtre qui m'a permis de gérer les fonds et les contours comme je le souhaitais. Notons, que les motifs de couleur rouge seront découpés, tandis que ceux de couleur noire seront gravés.
Afin de dessiner le cercle plein au centre et les cercles noirs et rouges autour j'ai tout simplement utilisé l'outil "créer des cercles" situé à gauche. J'ai ensuite pu gérer la couleur et le fond comme je le voulais grâce à la fenêtre de droite. Pour dessiner les motifs un peu plus mis au point sur le cercle vide noir, j'ai utilisé l'outil "tracer des courbes de Bézier et des segments de droite" pour réaliser des courbes. Ce dessin a été fait en dimension 80 mm par 80 mm.
Une fois ce modèle enregistré, il sera gravé et découpé à l'aide des découpeuses laser présentes au Fablab qui inclura des formats SVG. Sont présents au fablab, une découpeuse laser Trotec Speedy 360 et une découpeuse laser Trotec Speedy 100. Une documentation sur le fonctionnement de ces découpeuses est présente dans l'onglet Tutoriels puis Machines, du wiki.
Voici un lien vers mon fichier : dessin-1.svg
Mathéo Tonneyck
Modélisation 2D et utilisation de la découpeuse laser :
Pour ce procédé, j'ai décidé d'utiliser Inkscape afin de reproduire le logo du CMI de Sorbone Université.
Pour cela, j'ai utilisé deux techniques.
La première technique consiste à le reproduire à la main avec les outils du logiciel :
- Formes : cercle, cube
- Texte
- Caractéristiques et couleurs des objets
La deuxième technique consiste à utiliser l'outils Trace Bitmap du logiciel qui va vectoriser automatiquement l'image
Résultat obtenu :
Modélisation 3D et utilisation de l'imprimante 3D :
Dans le cadre de notre projet, nous aurons certainement besoin d'un système d'accroche pour des accessoires supplémentaires tel qu'un trépied donc j'ai décidé de travailler sur un système qui permet de viser un objet à un autre.
Pour ce faire, j'ai utilisé le logiciel Freecad.
J'ai utilisé deux techniques différentes pour chaque partie.
Pour le cube avec un trou fileté, j'ai utilisé l'outil "Hole" dans Part design que j'ai appliqué sur un cube déjà tracer.
Avec cet outils j'ai pu appliquer des paramètres pour y insérer un vis de taille avec des dimensions standard M10.
Tandis que pour créer la vis, j'ai utilisé la librairie "Fasterners" qui intègre de nombreux modèles de vis et d'écrous de différentes tailles pré-conçu nous n'avons plus qu'à appliquer des paramètres tel que le diamètre de la vis ou encore sa longueur.
Résultat obtenu :
Rose Peybernes
Modélisation 3D :
Pour cette modélisation, je n'avais pas d'idée précise d'un objet à créer mais je voulais savoir s'il était possible d'imprimer un objet dans un autre objet et que celui-ci soit aussi mobile. Comme nous ne devions pas faire un objet trop volumineux je me suis inspiré du travail que nous avons fait à la troisième séance et j'ai modélisé un cube 5x5cm avec une sphère d=2.5cm à l'intérieur à l'aide du logiciel OPENSCAD . Voici le code à taper pour obtenir la modélisation 3D :
$fn=50;
//cube(5, center = true);
//cylinder(10, 4, 4, center = true);
//rotate([90, 0, 0])cylinder(10, 4, 4, center = true);
//rotate([90,90, 90])cylinder(10, 4, 4, center = true);
//rotate([90, 0, 0])cylinder(10, 2, 2, center = true);
// rotate([90,90, 90])cylinder(3, 2, 5, center = true);
sphere( r = 2, d = 5);
difference (){
cube(5, center = true);
cylinder(10, 2, 2, center = true);
rotate([90, 0, 0])cylinder(10, 2, 2, center = true);
rotate([90,90, 90])cylinder(10, 2, 2, center = true);
}
Afin d'imprimer mon objet je suis servi du tutoriel sur le wiki et j'ai aussi été aidée par le personnel du Fablab afin d'être sur que mon impression se fasse correctement. Je tiens à préciser que lorsque j'ai transféré mon fichier dans le logiciel d'impression, ce dernier m'a proposé des supports automatiquement et que ce n'est pas moi qui les ai modélisés. Pour cette impression j'ai donc utilisé une bobine de filament ABS et une imprimante FDM Raise 3D Pro 2 dont les caractéristiques sont les suivantes :
- Utilisation : Impression 3D à dépôt de filament
- Volume maximal d'impression : 305mm*305mm*300mm.
- Extrusion : directe, double-extrusion possible
- Matières compatibles : bobines de filament PLA / ABS / HIPS / PC / TPU / TPE / NYLON / PETG / ASA / PP
- Diamètre du filament : 1,75mm
- Buse : laiton, 0.4mm
- Logiciel : ideaMaker
- Formats de fichiers requis : stl, obj
Modélisation et réglages sur logiciel d'impression :
NB : Bien que mon objet soit plutôt petit, l'impression à tout de même pris 3h. Il faut donc prévoir une plage de temps suffisante au cas où l'impression raterait et serait à refaire.
Voici un lien vers mon fichier : modifiable --> cube avec sphere.scad
final --> cube avec sphère final.stl
Modélisation 2D :
Pour mon dessin en 2D, je voulais faire un objet qui pourrait m'être utile et qui en même temps me suffirait suffisamment travailler sur le logiciel pour le maîtriser. Je me suis donc servie de INKSCAPE pour dessiner un jeu morpion de poche 10x10 cm. Pour cela j'ai du imaginer une espèce de petite boîte qui pourrait accueillir les pièces de jeu (2cm) et un plateau de jeu. Une fois que j'avais une idée arrêtée de toutes mes pièces, je me suis imposé sur le dessin 2D :
à noter que les éléments noirs sont gravés et les rouges découpés.
Pour la découpe laser j'ai utilisé une découpeuse laser Trotec Speedy 360 et une planche de bois de 3mm d'épaisseur.
- Description : découpe et gravure de certains matériaux plans comme le contreplaqué et le PMMA
- Caractéristiques techniques : équipé d'une lentille CO2 2,5" ou d'une lentille CO2 1,5"
- Surface de travail : 813*508mm
- Épaisseur max de découpe : environ 12mm, selon matériaux
- Hauteur max de la pièce à usiner : ...
- Matériaux compatibles : voir la liste des matériaux utilisables
- Logiciel : Ruby
- Formats de fichiers requis : privilégier svg. En principe compatibilité ai, dxf, pdf, cdr + jpeg pour les gravures
Pour réaliser correctement la découpe je me suis de nouveau aidée du tutoriel.
Pour réaliser mon objet j'ai décidé de prendre du contre plaqué de 3mm d'épaisseur. Ainsi, les pièces du jeux et la boîte ne seront pas trop épaisses et donc trop gros pour un objet de poche.
NB : Avant de lancer la découpe laser, il ne faut pas oublier de faire la focale du laser de la découpeuse.
Une fois tous les morceaux découpés, je les assemble. Si certaines parties étaient trop épaisses, je les ai poncé pour être sûr que toutes les pièces s'emboitent correctement.
Voici un lien vers mon fichier : modifiable et final --> dessin modifiable.svg
Ianel Akou
Modélisation 3D :
De mon côté, j'ai utilisé le logiciel fusion 360 pour modéliser mon objet en 3 dimensions. Etant un joueur d'Ultimate Flying Disc, mon projet était de créer un ustensile, appelé "disc clip", permettant de pouvoir accrocher un disque (freesbie) à son sac. J'ai donc pu d'abord modéliser en 2D une esquisse de la forme de mon objet pour ensuite utiliser l'outil extrusion afin de lui donner de l'épaisseur et obtenir un premier objet en 3 dimensions. Par la suite, j'ai travaillé sur cet objet brut en lui arrondissant les angles pour lui donner un aspect plus ergonomique. Enfin, en utilisant toujours l'outil d'extrusion mais cette fois ci en mode différence j'ai pu faire des trous à certains endroits afin d'obtenir un gain de matière inutile.Pour finir, j'ai pu exporter mon fichier sous format STL,
Découpe laser :
Mon projet de découpe laser était une boite en bois avec des trous, qui accueillerait une bougie et illuminerait la pièce avec certains motifs. Afin de réaliser le patron de la boite je me suis rendu sur un site qui modélise ce genre de patron "box maker", comme montré en cours. De cette manière j'ai obtenu un patron de ma boite aux dimensions souhaitées. Par la suite, j'ai utilisé le logiciel Inkscape afin de rajouter sur ce patron les motifs en étoiles de tailles différentes qui seront découpées dans les paroisses de la boite afin de laisser passer la lumière. Pour finir j'ai pu exporter le fichier de mon projet sous format STD.
(image à insérer)
Séance 5 à 10 : Projet Final - Station météorologique portable
Nous avons décidé de partir sur une station météo portable capable de mesurer la température, l'humidité et dotée d'un GPS. Cette station sera de la taille d'un M5Stack et pourra être accrochée à un sac ou sur un trépied. Elle serait donc destinée aux randonneurs.
Pour fabriquer cette station météo portable, nous n'utiliserons que des capteurs ayant des ports I2C. Nous allons donc utiliser un hub contenant des ports I2C que nous attribuerons à tous nos capteurs. Ce hub sera lui même connecté à notre M5stack qui affichera sur un écran les données relevées et sur un autre les données recueillies à l'aide de l'antenne GPS.
Code d'affichage de la température et de l'humidité
#include <Arduino.h>
#include <M5Stack.h>
#include <Wire.h>
#include "SHT31.h"
#include "Free_Fonts.h"
SHT31 sht31 = SHT31();
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("begin...");
sht31.begin();
M5.begin(); // Init M5Core. 初始化 M5Core
M5.Power.begin(); // Init Power module. 初始化电源模块
}
void loop() {
float temp = sht31.getTemperature();
float hum = sht31.getHumidity();
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 120);
M5.Lcd.setFreeFont(FSB18);
M5.Lcd.print("Temp = ");
M5.Lcd.print(temp);
M5.Lcd.println(" C");
M5.Lcd.print("Hum = ");
M5.Lcd.print(hum);
M5.Lcd.println(" %");
M5.Lcd.println();
delay(2000);
}
Nous avons obtenu ce code sur le site seeed studio en utilisant la référence du capteur d'humidité et de température que nous allons utiliser dont voici une image ci-dessous :
Puis nous l'avons légèrement modifié, notamment la commode M5.Lcd.serCursor afin que les valeurs de température et d'humidité puissent s'afficher correctement sur notre M5STack.
Par la suite nous avons modifier ce code afin de créer un design pour notre affichage graphique :
#include <Arduino.h>
#include <M5Stack.h>
#include <Wire.h>
#include "SHT31.h"
#include "Free_Fonts.h"
SHT31 sht31 = SHT31();
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("begin...");
sht31.begin();
M5.begin(); // Init M5Core. 初始化 M5Core
M5.Power.begin(); // Init Power module. 初始化电源模块
}
void loop() {
float temp = sht31.getTemperature();
float hum = sht31.getHumidity();
M5.Lcd.fillRect(0, 0, 320, 30, 0x439); /* Upper dark blue area */
M5.Lcd.fillRect(0, 31, 320, 178, 0x1E9F); /* Main light blue area */
M5.Lcd.fillRect(0, 210, 320, 30, 0x439); /* Lower dark blue area */
M5.Lcd.fillRect(0, 30, 320, 4, 0xffff); /* Upper white line */
M5.Lcd.fillRect(0, 208, 320, 4, 0xffff); /* Lower white line */
M5.Lcd.fillRect(0, 125, 160, 4, 0xffff); /* vertical white line */
M5.Lcd.fillRect(160, 30, 4, 180, 0xffff); /* Horizontal white line */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
M5.Lcd.setTextColor(WHITE); /* Set text color to white */
M5.Lcd.setCursor(10, 7); /* Display header info */
M5.Lcd.print("Weather");
M5.Lcd.setCursor(200, 7);
M5.Lcd.print("Analyz'Air");
M5.Lcd.setTextSize(2.5); M5.lcd.setCursor(12.5,40);
M5.Lcd.print("Temperature: ");
M5.Lcd.setTextSize(4); M5.lcd.setCursor(15,70);
M5.Lcd.print(temp);
M5.Lcd.setTextSize(3); M5.lcd.setCursor(140,75); M5.Lcd.println("C");
M5.Lcd.setTextSize(2.5); M5.lcd.setCursor(30,135);
M5.Lcd.print("Humidity: ");
M5.Lcd.setTextSize(4); M5.lcd.setCursor(15,165);
M5.Lcd.print(hum);
M5.Lcd.setTextSize(3); M5.lcd.setCursor(140,170); M5.Lcd.println("%");
M5.Lcd.println();
delay(2000);
}
Par la suite, il faudra réussir à combiner ce code avec celui du baromètre
Codage GPS
Voici le programme pour faire fonctionner notre module GPS, trouver sur le site hackster.io
https://m5stack.hackster.io/ptschulik/simple-gps-tracker-d3500e
Après avoir compris ce programme, nous avons réalisé quelques modifications tel que changer la langue de base qui était l'allemand en français ainsi que réaliser des modifications au niveau du graphisme.
/****************************************************************************************/
/* GPS Logger with M5Stack and M5 GPS Module */
/* Version: 1.0 */
/* Date: 27.06.2019 */
/* */
/* Special features: */
/* Key A: Change language between German and Englis */
/* Key B: Changes format of location data */
/* Key C: Change brightness of display */
/* */
/* Used library: */
/* Tiny GPS Plus: https://github.com/mikalhart/TinyGPSPlus */
/* */
/****************************************************************************************/
#include <M5Stack.h> /* Include M5 Stack library */
#include <TinyGPS++.h> /* Include Tiny GPS++ library */
/* Definitions */
#define NOTE_DH2 661
/* Constants */
const byte DELAY_READ = 10; /* Delay between two reads: 10 = 100ms */
const byte DELAY_CHECK_CONST = 100; /* Delay to check if any data received 100 * 10 = 1 sec */
const byte MINUMUM_SAT = 4; /* Minumum number of satellites before fix is accepted */
const byte UTC_CET = 2; /* Time difference from UTC to CET */
/* Variables */
boolean UPDATE_FLAG; /* Display update flag: TRUE = Update, FALSE = No update */
boolean LOC_UPDATE_FLAG; /* Location update flag: TRUE = Update, FALSE = No update */
boolean ALT_UPDATE_FLAG; /* Altitude update flag: TRUE = Update, FALSE = No update */
boolean SPEED_UPDATE_FLAG; /* Speed update flag: TRUE = Update, FALSE = No update */
boolean SAT_UPDATE_FLAG; /* Nr. of sattelites update flag: TRUE = Update, FALSE = No update */
boolean HDOP_UPDATE_FLAG; /* HDOP update flag: TRUE = Update, FALSE = No update */
byte LOOP_COUNTER; /* Generic loop counter for delay */
byte DELAY_CHECK = 0; /* Delay to check if any data received */
byte LCD_BRIGHTNESS = 250; /* LCD brightness value (0-250) */
byte MENU_LANGUAGE = 0; /* Menu Language 0 = German, 1 = English */
byte GPS_FORMAT = 0; /* GPS format 0 = Decimal degree, 1= Degree, Minutes, Seconds */
byte GPS_STATUS; /* GPS status: 0 = No GPS receiver detected, 1 = No valid GPS fix, 2 = Valid GPS data */
unsigned int NO_OF_SAT; /* Number of satellites */
unsigned int CHARS_PROCESSED = 0; /* Number of procesed chars */
unsigned int OLD_CHARS_PROCESSED = 1; /* Number of procesed chars */
unsigned int OLD_NO_OF_SAT; /* Old number of satellites */
unsigned int OLD_HDOP; /* Old HDOP value */
int OLD_SEC = 0; /* Old second */
int OLD_ALTITUDE; /* Old altitude value */
int OLD_SPEED; /* Old speed value */
float OLD_LOC_LAT; /* Old lateral location */
float OLD_LOC_LNG; /* Old longitudinal location */
/* Table for day of month */
unsigned char DAY_OF_MONTH[] = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30,31};
char CONVERTED[32]; /* Conversion string for display */
TinyGPSPlus gps; /* Reference the TinyGPS++ object */
HardwareSerial GPSRaw(2); /* By default, GPS is connected with M5Core through UART2 */
/****************************************************************************************/
/* Init routine */
/****************************************************************************************/
void setup()
{
M5.begin(); /* Start M5 functions */
GPSRaw.begin(9600); /* Init GPS serial interface */
M5.Lcd.setBrightness(LCD_BRIGHTNESS); /* Set initial LCD brightness */
delay (2000); /* 2000ms init delay */
UPDATE_FLAG = true; /* Set update flag true */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
}
/****************************************************************************************/
/* Main routine */
/****************************************************************************************/
void loop()
{
while (GPSRaw.available() > 0) /* Check if new GP data is available */
{
gps.encode(GPSRaw.read()); /* Read until no more data is available */
}
CHARS_PROCESSED = gps.charsProcessed(); /* Read processed chars */
/* No chars processed or no more data received --> Checked every 10ms ? */
if ((CHARS_PROCESSED < 10)|| (CHARS_PROCESSED == OLD_CHARS_PROCESSED))
{
if (DELAY_CHECK < 230) /* Prevent variable from overflow */
{
DELAY_CHECK = DELAY_CHECK + 10; /* Increase delay check if any data received each 10ms by 10 */
}
}
else /* No chars received ? */
{
DELAY_CHECK = 0; /* Reset delay check if any data received */
}
/* Case 1: Timeout */
if (DELAY_CHECK > DELAY_CHECK_CONST)
{
if (GPS_STATUS > 0) /* Was already in an other GPS status ? */
{
UPDATE_FLAG = true; /* Set update flag true */
}
if (UPDATE_FLAG == true) /* Update flag true ? */
{
SUB_DISPLAY_NO_REC(); /* Call sub routine to display no receiver error message */
UPDATE_FLAG = false; /* Set update flag false */
}
GPS_STATUS = 0; /* Set GPS status 0 */
}
else /* New data received correctly ? */
{
if (GPS_STATUS == 0) /* GPS state 0 ? */
{
GPS_STATUS = 1; /* Set GPS status 1 */
UPDATE_FLAG = true; /* Set update flag true */
}
}
/* Case 2: Receiver found and data are received but no GPS signal --> Status 1 */
if (GPS_STATUS == 1) /* GPS status is 1 ? */
{
/* Check number of satellites */
if (gps.satellites.isValid() == true) /* Valid GPS number of satellites received ? */
{
NO_OF_SAT = gps.satellites.value(); /* Save number of satellites */
}
else /* Not valid GPS number of satellites received ? */
{
NO_OF_SAT = 0; /* Set number of satellites to 0 */
}
/* Decide on number of satellites received */
if (NO_OF_SAT < MINUMUM_SAT) /* Too less satelites received ? */
{
if (UPDATE_FLAG == true) /* Update flag true ? */
{
SUB_DISPLAY_NO_GPS(); /* Call sub routine to display no GPS message */
UPDATE_FLAG = false; /* Set update flag false */
}
}
else /* Correct number of satellites received? */
{
GPS_STATUS = 2; /* Set GPS status 2 --> Fix received */
UPDATE_FLAG = true; /* Set update flag true */
UPDATE_FLAG = true; /* Set display update flag true */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
ALT_UPDATE_FLAG = true; /* Set altitude update flag true */
SPEED_UPDATE_FLAG = true; /* Set speed update flag true */
SAT_UPDATE_FLAG = true; /* Set number of sattelites update flag true */
HDOP_UPDATE_FLAG = true; /* Set HDOP update flag true */
}
}
/* Case 2: Enough satellites received ? --> Valid fix*/
if (GPS_STATUS == 2) /* GPS status is 2 ? */
{
/* Check number of satellites */
if (gps.satellites.isValid() == true) /* Valid GPS number of sattllites received ? */
{
NO_OF_SAT = gps.satellites.value(); /* Save number of satellites */
}
else /* Not valid GPS number of sattelites received ? */
{
NO_OF_SAT = 0; /* Set number of satellites to 0 */
}
if (NO_OF_SAT < MINUMUM_SAT) /* Too less satelites received ? */
{
GPS_STATUS = 1; /* Set GPS status 1 */
UPDATE_FLAG = true; /* Set update flag true */
}
else /* Correct number of satellites received? */
{
if (UPDATE_FLAG == true) /* Update flag true ? */
{
SUB_DISPLAY_MAIN(); /* Call sub routine to display main menu */
UPDATE_FLAG = false; /* Set update flag false */
}
SUB_DISPLAY_DATE_TIME(); /* Call sub routine to display time and date info */
SUB_DISPLAY_LOCATION(); /* Call sub routine to display location */
SUB_DISPLAY_ALTITUDE(); /* Call sub routine to display altitude */
SUB_DISPLAY_SPEED(); /* Call sub routine to display speed */
SUB_DISPLAY_SAT(); /* Call sub routine to display number of sattelites */
SUB_DISPLAY_HDOP(); /* Call sub routine to display HDOP value */
}
}
OLD_CHARS_PROCESSED = CHARS_PROCESSED;
/* Delay as defined in delay read const and check on key pressed every 10ms */
for (LOOP_COUNTER = 0; LOOP_COUNTER < DELAY_READ; LOOP_COUNTER++)
{
delay (10); /* 10 ms delay */
M5.update(); /* Update on reading keys */
if (M5.BtnA.wasPressed() == true) /* Button A pressed ? --> Change language */
{
// M5.Speaker.tone(NOTE_DH2, 1);
if (MENU_LANGUAGE == 0) /* German selected ? */
{
MENU_LANGUAGE = 1; /* Set menu language to English */
UPDATE_FLAG = true; /* Set display update flag true */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
ALT_UPDATE_FLAG = true; /* Set altitude update flag true */
SPEED_UPDATE_FLAG = true; /* Set speed update flag true */
SAT_UPDATE_FLAG = true; /* Set number of sattelites update flag true */
HDOP_UPDATE_FLAG = true; /* Set HDOP update flag true */
}
else /* English selected ? */
{
MENU_LANGUAGE = 0; /* Set menu language to German */
UPDATE_FLAG = true; /* Set display update flag true */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
ALT_UPDATE_FLAG = true; /* Set altitude update flag true */
SPEED_UPDATE_FLAG = true; /* Set speed update flag true */
SAT_UPDATE_FLAG = true; /* Set number of sattelites update flag true */
HDOP_UPDATE_FLAG = true; /* Set HDOP update flag true */
}
}
if (M5.BtnB.wasPressed() == true) /* Button B pressed ? --> Change format */
{
// M5.Speaker.tone(NOTE_DH2, 1);
if (GPS_FORMAT == 0) /* Format 0 selected ? */
{
GPS_FORMAT = 1; /* Set Format to 1 */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
}
else /* Format 1 selected ? */
{
GPS_FORMAT = 0; /* Set Format to 0 */
LOC_UPDATE_FLAG = true; /* Set location update flag true */
}
}
if (M5.BtnC.wasPressed() == true) /* Button C pressed ? --> Change brightness */
{
// M5.Speaker.tone(NOTE_DH2, 1);
if (LCD_BRIGHTNESS < 250) /* Maximum brightness not reached ? */
{
LCD_BRIGHTNESS = LCD_BRIGHTNESS + 10; /* Increase brightness */
}
else /* Maximum brightness reached ? */
{
LCD_BRIGHTNESS = 10; /* Set brightness to lowest value */
}
M5.Lcd.setBrightness(LCD_BRIGHTNESS); /* Change brightness value */
}
}
}
/****************************************************************************************/
/* SUBROUTINE Display Date and Time Information */
/* This subroutine displays the time and date information and corrects the time zone */
/****************************************************************************************/
void SUB_DISPLAY_DATE_TIME ()
{
boolean TIME_VALID; /* True = Valid time, False = not valid */
boolean DATE_VALID; /* True = Valid date, False = not valid */
boolean TIME_DATE_UPDATE; /* True = Needs update, False = Needs no update */
byte NTP_TIME_ZONE; /* Variable for time zone: 0 = UTC time, 1 = CET winter time, 2 = CET summer time */
int BEGIN_DST_DATE; /* Begin date summer time */
int BEGIN_DST_MONTH; /* Begin month summer time */
int END_DST_DATE; /* End date summer time */
int END_DST_MONTH; /* End month summer time */
int ACT_YEAR; /* Actual year */
int ACT_MONTH; /* Actual month */
int ACT_DAY; /* Actual day */
int ACT_HOUR; /* Actual hour */
int ACT_MIN; /* Actual minute */
int ACT_SEC; /* Actual second */
TIME_DATE_UPDATE = false; /* No update needed */
if (gps.time.isValid()) /* Valid time available ? */
{
ACT_HOUR = gps.time.hour(); /* Get actual hour */
ACT_MIN = gps.time.minute(); /* Get actual minute */
ACT_SEC = gps.time.second(); /* Get actual second */
TIME_VALID = true; /* Set valid time flag true */
TIME_DATE_UPDATE = true; /* Update needed */
}
else /* Valid time not available ? */
{
TIME_VALID = false; /* Set valid time flag false */
}
if (gps.date.isValid()) /* Valid date available ? */
{
ACT_YEAR = gps.date.year(); /* Get actual year */
ACT_MONTH = gps.date.month(); /* Get actual month */
ACT_DAY = gps.date.day(); /* Get actual day */
DATE_VALID = true; /* Set valid time flag true */
TIME_DATE_UPDATE = true; /* Update needed */
}
else /* Valid time not available ? */
{
DATE_VALID = false; /* Set valid date flag false */
}
/* Changed second and valid date/time --> Update display */
if ((OLD_SEC != ACT_SEC) && (TIME_VALID == true) && (DATE_VALID == true))
{
OLD_SEC = ACT_SEC; /* Save old second */
/* Step 1: Leap year? --> Adjust February */
if (ACT_YEAR%400 == 0 || (ACT_YEAR%4 == 0 && ACT_YEAR%100 !=0))
{
DAY_OF_MONTH[1] = 29; /* Set day of month to 29 */
}
else
{
DAY_OF_MONTH[1] = 28; /* Set day of month to 28 */
}
/* Step 2: Determine start and end date of summer time */
BEGIN_DST_DATE= (31 - (5* ACT_YEAR /4 + 4) % 7); /* Determine last Sunday of March */
BEGIN_DST_MONTH = 3; /* Begin month is March */
END_DST_DATE= (31 - (5 * ACT_YEAR /4 + 1) % 7); /* Determine last Sunday of October */
END_DST_MONTH = 10; /* Begin month is October */
/* Step 3: Check for summer time */
if (((ACT_MONTH > BEGIN_DST_MONTH) && (ACT_MONTH < END_DST_MONTH))
|| ((ACT_MONTH == BEGIN_DST_MONTH) && (ACT_DAY >= BEGIN_DST_DATE))
|| ((ACT_MONTH == END_DST_MONTH) && (ACT_DAY <= END_DST_DATE)))
{
NTP_TIME_ZONE = UTC_CET; /* Set time zone for CET = UTC + 2 hour */
}
else /* Winter time ? */
{
NTP_TIME_ZONE = UTC_CET-1; /* Set time zone for CET = UTC +1 hour */
}
/* Step 4: Generate correct adjusted time */
ACT_HOUR = ACT_HOUR + NTP_TIME_ZONE;
if (ACT_HOUR > 23) /* Next day ? */
{
ACT_HOUR = ACT_HOUR - 23; /* Correct hour */
if (ACT_DAY = DAY_OF_MONTH [ACT_MONTH-1]) /* Last day of month ? */
{
ACT_DAY = 1; /* Set day to 1st of month */
ACT_MONTH = ACT_MONTH +1; /* Increase month */
if (ACT_MONTH > 12) /* Beyond December ? */
{
ACT_MONTH = 1; /* Set actual month to January */
ACT_YEAR = ACT_YEAR + 1; /* Increase year */
}
}
}
/* Step 4: Display actual time and date according chosen language */
M5.Lcd.fillRect(0, 215, 320, 25, 0x439); /* Clear old time and date */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
M5.Lcd.setCursor(10, 219); /* Position cursor to display time */
/* Convert into dispaly string */
sprintf(CONVERTED, "%02d:%02d:%02d ", ACT_HOUR, ACT_MIN, ACT_SEC);
M5.Lcd.print(CONVERTED); /* Display converted time string */
M5.Lcd.setCursor(190, 219); /* Position cursor to display date */
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
/* Convert into dispaly string */
sprintf(CONVERTED, "%02d.%02d.%02d ", ACT_DAY, ACT_MONTH, ACT_YEAR);
}
else /*Englishn language chosen ? */
{
/* Convert into dispaly string */
sprintf(CONVERTED, "%02d/%02d/%02d ", ACT_YEAR, ACT_MONTH, ACT_DAY);
}
M5.Lcd.print(CONVERTED); /* Display converted date string */
}
/* Time or date not correctly received */
if ((TIME_VALID == false) || (DATE_VALID == false))
{
if (TIME_DATE_UPDATE == true) /* Update needed ? */
{
M5.Lcd.fillRect(0, 215, 320, 25, 0x439); /* Clear old time and date */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
M5.Lcd.print(F("--:--:--")); /* Dispaly time placeholder */
M5.Lcd.setCursor(190, 219); /* Position cursor to display date */
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
M5.Lcd.print(F("--.--.----")); /* Display date placeholder */
}
else /*Englishn language chosen ? */
{
M5.Lcd.print(F("----/--/--")); /* Display date placeholder */
}
TIME_DATE_UPDATE = false; /* Set date update false */
}
}
}
/****************************************************************************************/
/* SUBROUTINE Display Location */
/* This subroutine displays the location information */
/****************************************************************************************/
void SUB_DISPLAY_LOCATION ()
{
boolean LOC_FAIL_UPDATE; /* True = Needs update, False = Needs no update */
float ACT_LOC_LAT; /* Actual lateral location */
float ACT_LOC_LNG; /* Actual longitudinal location */
float ROUNDED_VAL; /* Rounded floating value */
uint16_t CONVERT_DATA; /* Converted data value */
LOC_FAIL_UPDATE = false; /* No update needed */
if (gps.location.isValid() == true) /* Valid GPS location received ? */
{
LOC_FAIL_UPDATE = true; /* Update needed */
M5.Lcd.setTextSize(3); /* Set text size to 3 */
ACT_LOC_LAT = gps.location.lat(); /* Get lattitude value */
ACT_LOC_LNG = gps.location.lng(); /* Get longitude value */
/* Display lattitude value */
ROUNDED_VAL = SUB_ROUND_FLOAT_VALUE (ACT_LOC_LAT, 5); /* Call subroutine to round float to 5 digits */
/* Value has changed for updating display or location update flag true? */
if ((OLD_LOC_LAT != ROUNDED_VAL) || (LOC_UPDATE_FLAG == true))
{
OLD_LOC_LAT = ROUNDED_VAL; /* Save value */
M5.Lcd.fillRect(114, 40, 169, 44, 0x1E9F); /* Clear old degree of lattitude value */
M5.Lcd.setCursor(115, 50); /* Position cursor */
if (GPS_FORMAT == 0) /* Format 0 selected */
{
M5.Lcd.print(ACT_LOC_LAT, 6); /* Display latitude information */
}
else /* Format 1 selected */
{
CONVERT_DATA = (int)(ACT_LOC_LAT); /* Extract degree value */
M5.Lcd.print(CONVERT_DATA); /* Display degree value */
M5.Lcd.print(" ");
/* Extract Minute value */
ACT_LOC_LAT= ACT_LOC_LAT - CONVERT_DATA;
ACT_LOC_LAT = ACT_LOC_LAT * 60;
CONVERT_DATA = (int)(ACT_LOC_LAT);
M5.Lcd.print(CONVERT_DATA); /* Display minute value */
M5.Lcd.print(" ");
/*Extract Second value */
ACT_LOC_LAT= ACT_LOC_LAT - CONVERT_DATA;
ACT_LOC_LAT = ACT_LOC_LAT * 60;
M5.Lcd.print (ACT_LOC_LAT, 0); /* Dispaly second value */
}
}
/* Display lngitude value */
ROUNDED_VAL = SUB_ROUND_FLOAT_VALUE (ACT_LOC_LNG, 5); /* Call subroutine to round float to 5 digits */
/* Value has changed for updating display or location update flag true? */
if ((OLD_LOC_LNG != ROUNDED_VAL) || (LOC_UPDATE_FLAG == true))
{
OLD_LOC_LNG = ROUNDED_VAL; /* Save value */
M5.Lcd.fillRect(114, 94, 169, 44, 0x1E9F); /* Clear old degree of longitude value */
M5.Lcd.setCursor(115, 104); /* Position cursor */
if (GPS_FORMAT == 0) /* Format 0 selected */
{
M5.Lcd.print(ACT_LOC_LNG, 6); /* Display longitudinal information */
}
else /* Format 1 selected */
{
CONVERT_DATA = (int)(ACT_LOC_LNG); /* Extract degree value */
M5.Lcd.print(CONVERT_DATA); /* Display degree value */
M5.Lcd.print(" ");
/* Extract Minute value */
ACT_LOC_LNG= ACT_LOC_LNG - CONVERT_DATA;
ACT_LOC_LNG = ACT_LOC_LNG * 60;
CONVERT_DATA = (int)(ACT_LOC_LNG);
M5.Lcd.print(CONVERT_DATA); /* Display minute value */
M5.Lcd.print(" ");
/*Extract Second value */
ACT_LOC_LNG= ACT_LOC_LNG - CONVERT_DATA;
ACT_LOC_LNG = ACT_LOC_LNG * 60;
M5.Lcd.print (ACT_LOC_LNG, 0); /* Dispaly second value */
}
}
LOC_UPDATE_FLAG = false; /* Set location update flag false */
}
else /* Not valid GPS location received ? */
{
if (LOC_FAIL_UPDATE == true) /* Update needed ? */
{
M5.Lcd.setTextSize(3);
M5.Lcd.fillRect(114, 40, 169, 44, 0x1E9F); /* Clear old degree of lattitude value */
M5.Lcd.fillRect(114, 94, 169, 44, 0x1E9F); /* Clear old degree of longitude value */
if (GPS_FORMAT == 0) /* Format 0 selected */
{
M5.Lcd.setCursor(115, 50); /* Display location placeholder */
M5.Lcd.print("--.------");
M5.Lcd.setCursor(115, 104);
M5.Lcd.print("--.------");
}
else /* Format 1 selected */
{
M5.Lcd.setCursor(115, 50); /* Display location placeholder */
M5.Lcd.print("----'---");
M5.Lcd.setCursor(115, 104);
M5.Lcd.print("----'---");
}
}
LOC_FAIL_UPDATE = false; /* Set date update false */
}
}
/****************************************************************************************/
/* SUBROUTINE Display Altitude */
/* This subroutine displays the altitude information */
/****************************************************************************************/
void SUB_DISPLAY_ALTITUDE ()
{
boolean ALT_FAIL_UPDATE; /* True = Needs update, False = Needs no update */
float ACT_ALTITUDE; /* Actual laltitude value */
int INTEGER_VAL; /* Integer value */
int STRING_LENGTH; /* Length of string */
ALT_FAIL_UPDATE = false; /* No update needed */
if (gps.altitude.isValid() == true) /* Valid GPS altitude received ? */
{
ALT_FAIL_UPDATE = true; /* Update needed */
M5.Lcd.setTextSize(3); /* Set text size to 3 */
ACT_ALTITUDE = gps.altitude.meters(); /* Get altitude value */
/* Display altitude value */
INTEGER_VAL = (int)(ACT_ALTITUDE); /* Extract integer value of altitude variable */
sprintf(CONVERTED, "%.0f", ACT_ALTITUDE); /* Convert float to a string to determine length */
STRING_LENGTH = strlen(CONVERTED); /* Determine length of string */
/* Value has changed for updating display or location update flag true? */
if ((OLD_ALTITUDE != INTEGER_VAL) || (ALT_UPDATE_FLAG == true))
{
OLD_ALTITUDE = INTEGER_VAL; /* Save value */
M5.Lcd.fillRect(4, 145, 100, 40, 0x1E9F); /* Clear old altitude value */
if (STRING_LENGTH >= 4) /* String length >= 4 ? */
M5.Lcd.setCursor(8, 155); /* Position cursor */
if (STRING_LENGTH == 3) /* String length = 3 ? */
M5.Lcd.setCursor(18, 155); /* Position cursor */
if (STRING_LENGTH == 2) /* String length = 2 ? */
M5.Lcd.setCursor(25, 155); /* Position cursor */
if (STRING_LENGTH<= 1) /* String length <= 1 ? */
M5.Lcd.setCursor(35, 155); /* Position cursor */
M5.Lcd.print(CONVERTED); /* Display value */
M5.Lcd.print("m");
}
ALT_UPDATE_FLAG = false; /* Set altitrude update flag false */
}
else /* Not valid GPS altitude received ? */
{
if (ALT_FAIL_UPDATE == true) /* Update needed ? */
{
M5.Lcd.setTextSize(3); /* Set text size to 3 */
M5.Lcd.fillRect(4, 145, 100, 40, 0x1E9F); /* Clear old altitude value */
M5.Lcd.setCursor(18, 155); /* Position cursor */
M5.Lcd.print("---m"); /* Display altitude placeholder */
}
ALT_FAIL_UPDATE = false; /* Set altitude update false */
}
}
/****************************************************************************************/
/* SUBROUTINE Display Speed */
/* This subroutine displays the speed information */
/****************************************************************************************/
void SUB_DISPLAY_SPEED ()
{
boolean SPEED_FAIL_UPDATE; /* True = Needs update, False = Needs no update */
float ACT_SPEED; /* Actual speed value */
int INTEGER_VAL; /* Integer value */
int STRING_LENGTH; /* Length of string */
SPEED_FAIL_UPDATE = false; /* No update needed */
if (gps.speed.isValid() == true) /* Valid GPS speed received ? */
{
SPEED_FAIL_UPDATE = true; /* Update needed */
M5.Lcd.setTextSize(3); /* Set text size to 3 */
ACT_SPEED = gps.speed.kmph(); /* Get speed value */
/* Display speed value */
INTEGER_VAL = (int)(ACT_SPEED); /* Extract integer value of speed variable */
sprintf(CONVERTED, "%.0f", ACT_SPEED); /* Convert float to a string to determine length */
STRING_LENGTH = strlen(CONVERTED); /* Determine length of string */
/* Value has changed for updating display or location update flag true? */
if ((OLD_SPEED != INTEGER_VAL) || (SPEED_UPDATE_FLAG == true))
{
OLD_SPEED = INTEGER_VAL; /* Save value */
M5.Lcd.fillRect(114, 145, 94, 40, 0x1E9F); /* Clear old speed value */
if (STRING_LENGTH >= 4) /* String length >= 4 ? */
M5.Lcd.setCursor(125, 155); /* Position cursor */
if (STRING_LENGTH == 3) /* String length = 3 ? */
M5.Lcd.setCursor(135, 155); /* Position cursor */
if (STRING_LENGTH == 2) /* String length = 2 ? */
M5.Lcd.setCursor(142, 155); /* Position cursor */
if (STRING_LENGTH<= 1) /* String length <= 1 ? */
M5.Lcd.setCursor(152, 155); /* Position cursor */
M5.Lcd.print(CONVERTED); /* Display value */
}
SPEED_UPDATE_FLAG = false; /* Set speed update flag false */
}
else /* Not valid GPS altitude received ? */
{
if (SPEED_FAIL_UPDATE == true) /* Update needed ? */
{
M5.Lcd.setTextSize(3); /* Set text size to 3 */
M5.Lcd.fillRect(114, 145, 94, 40, 0x1E9F); /* Clear old speed value */
M5.Lcd.setCursor(135, 155); /* Position cursor */
M5.Lcd.print("---"); /* Display speed placeholder */
}
SPEED_FAIL_UPDATE = false; /* Set speed update false */
}
}
/****************************************************************************************/
/* SUBROUTINE Display Sattelites */
/* This subroutine displays the number of sattelites */
/****************************************************************************************/
void SUB_DISPLAY_SAT ()
{
boolean SAT_FAIL_UPDATE; /* True = Needs update, False = Needs no update */
SAT_FAIL_UPDATE = false; /* No update needed */
if (gps.satellites.isValid() == true) /* Valid GPS number of sattllites received ? */
{
SAT_FAIL_UPDATE = true; /* Update needed */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
/* Value has changed for updating display or location update flag true? */
if ((OLD_NO_OF_SAT != NO_OF_SAT) || (SAT_UPDATE_FLAG == true))
{
OLD_NO_OF_SAT = NO_OF_SAT; /* Save value */
M5.Lcd.fillRect(275, 145, 45, 35, 0x1E9F); /* Clear satelite field */
M5.Lcd.setCursor(280, 155); /* Display header info */
M5.Lcd.print(NO_OF_SAT); /* Display number of sattelites */
}
SAT_UPDATE_FLAG = false; /* Set speed update flag false */
}
else /* Not valid GPS altitude received ? */
{
if (SAT_FAIL_UPDATE == true) /* Update needed ? */
{
M5.Lcd.fillRect(275, 145, 45, 35, 0x1E9F); /* Clear satelite field */
M5.Lcd.setCursor(280, 155); /* Display header info */
M5.Lcd.print("-"); /* Display sattelite placeholder */
}
SAT_FAIL_UPDATE = false; /* Set sattelite update false */
}
}
/****************************************************************************************/
/* SUBROUTINE Display HDOP */
/* This subroutine displays the HDOP value */
/****************************************************************************************/
void SUB_DISPLAY_HDOP ()
{
boolean HDOP_FAIL_UPDATE; /* True = Needs update, False = Needs no update */
float ACT_HDOP; /* Actual HDOP value */
unsigned int INTEGER_VAL; /* Integer value */
HDOP_FAIL_UPDATE = false; /* No update needed */
if (gps.hdop.isValid() == true) /* Valid GPS HDOP value received ? */
{
HDOP_FAIL_UPDATE = true; /* Update needed */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
ACT_HDOP = gps.hdop.hdop(); /* Get HDOP value */
INTEGER_VAL = (int)(ACT_HDOP); /* Extract integer value of HDOP variable */
/* Value has changed for updating display or location update flag true? */
if ((OLD_HDOP != INTEGER_VAL) || (HDOP_UPDATE_FLAG == true))
{
OLD_HDOP = INTEGER_VAL; /* Save value */
M5.Lcd.fillRect(275, 180, 45, 28, 0x1E9F); /* Clear satelite field */
M5.Lcd.setCursor(280, 185); /* Display header info */
M5.Lcd.print(INTEGER_VAL); /* Display HDOP value */
}
HDOP_UPDATE_FLAG = false; /* Set HDOP update flag false */
}
else /* Not valid GPS altitude received ? */
{
if (HDOP_FAIL_UPDATE == true) /* Update needed ? */
{
M5.Lcd.fillRect(275, 180, 45, 28, 0x1E9F); /* Clear satelite field */
M5.Lcd.setCursor(280, 185); /* Display header info */
M5.Lcd.print("---"); /* Display sattelite placeholder */
}
HDOP_FAIL_UPDATE = false; /* Set sattelite update false */
}
}
/****************************************************************************************/
/* SUBROUTINE Display Main */
/* This subroutine displays the main menu based on the selected kanguage */
/****************************************************************************************/
void SUB_DISPLAY_MAIN (void)
{
M5.Lcd.fillRect(0, 0, 320, 30, 0x439); /* Upper dark blue area */
M5.Lcd.fillRect(0, 31, 320, 178, 0x1E9F); /* Main light blue area */
M5.Lcd.fillRect(0, 210, 320, 30, 0x439); /* Lower dark blue area */
M5.Lcd.fillRect(0, 30, 320, 4, 0xffff); /* Upper white line */
M5.Lcd.fillRect(0, 208, 320, 4, 0xffff); /* Lower white line */
M5.Lcd.fillRect(0, 84, 320, 4, 0xffff); /* First vertical white line */
M5.Lcd.fillRect(0, 140, 320, 4, 0xffff); /* Second vertical white line */
M5.Lcd.fillRect(106, 140, 4, 72, 0xffff); /* First horizontal white line */
M5.Lcd.fillRect(210, 140, 4, 72, 0xffff); /* First horizontal white line */
M5.Lcd.setTextSize(2); /* Set text size to 2 */
M5.Lcd.setTextColor(WHITE); /* Set text color to white */
M5.Lcd.setCursor(10, 7); /* Display header info */
M5.Lcd.print("GPS");
M5.Lcd.setCursor(200, 7);
M5.Lcd.print("Analyz'Air");
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
M5.Lcd.setCursor(5, 40); /* Display degree of lattitude */
M5.Lcd.print("Lattitude-");
M5.Lcd.setCursor(5, 65);
M5.Lcd.print("degre");
M5.Lcd.setCursor(5, 94); /* Display degree of longitude */
M5.Lcd.print("Longitude-");
M5.Lcd.setCursor(5, 119);
M5.Lcd.print("degre");
M5.Lcd.setCursor(25, 185); /* Display elevation info */
M5.Lcd.print("Alt.");
M5.Lcd.setCursor(125, 185); /* Display hspeed info */
M5.Lcd.print("Vitesse");
}
else /*Englishn language chosen ? */
{
M5.Lcd.setCursor(5, 40); /* Display degree of lattitude */
M5.Lcd.print("Degree");
M5.Lcd.setCursor(5, 65);
M5.Lcd.print("of Lat.");
M5.Lcd.setCursor(5, 94); /* Display degree of longitude */
M5.Lcd.print("Degree");
M5.Lcd.setCursor(5, 119);
M5.Lcd.print("of Long.");
M5.Lcd.setCursor(25, 185); /* Display altitude info */
M5.Lcd.print("Alti.");
M5.Lcd.setCursor(125, 185); /* Display hspeed info */
M5.Lcd.print("Speed");
}
M5.Lcd.setCursor(215, 155); /* Display number of sattelites */
M5.Lcd.println(" Sat.");
M5.Lcd.setCursor(215, 185); /* Display HDOP info */
M5.Lcd.print(" HDOP ");
M5.Lcd.setTextSize(3); /* Set text size to 3 */
M5.Lcd.setCursor(295, 50); /* Display North info */
M5.Lcd.print("N");
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
M5.Lcd.setCursor(295, 104); /* Display East info */
M5.Lcd.print("O");
}
else /* Englishn language chosen ? */
{
M5.Lcd.setCursor(295, 104); /* Display East info */
M5.Lcd.print("E");
}
}
/****************************************************************************************/
/* SUBROUTINE No receiver */
/* This subroutine displays the screen when no GPS receiver is found */
/****************************************************************************************/
void SUB_DISPLAY_NO_REC (void)
{
M5.Lcd.fillRect(0, 0, 320, 30, 0x439); /* Upper dark blue area */
M5.Lcd.fillRect(0, 31, 320, 178, 0x1E9F); /* Main light blue area */
M5.Lcd.fillRect(0, 210, 320, 30, 0x439); /* Lower dark blue area */
M5.Lcd.setTextSize(3); /* Set text size to 3 */
M5.Lcd.setTextColor(WHITE); /* Set text color to white */
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
M5.Lcd.setCursor(80, 80); /* Display message */
M5.Lcd.print(F("Pas de GPS!"));
M5.Lcd.setCursor(40, 120);
M5.Lcd.print(F("Vérification du module!"));
}
else /* Englishn language chosen ? */
{
M5.Lcd.setCursor(100, 80); /* Display message */
M5.Lcd.print(F("No GPS!"));
M5.Lcd.setCursor(40, 120);
M5.Lcd.print(F("Check module!"));
}
}
/****************************************************************************************/
/* SUBROUTINE No GPS signal */
/* This subroutine displays the screen when no or a weak GPS signal is available */
/****************************************************************************************/
void SUB_DISPLAY_NO_GPS (void)
{
M5.Lcd.fillRect(0, 0, 320, 30, 0x439); /* Upper dark blue area */
M5.Lcd.fillRect(0, 31, 320, 178, 0x1E9F); /* Main light blue area */
M5.Lcd.fillRect(0, 210, 320, 30, 0x439); /* Lower dark blue area */
M5.Lcd.setTextSize(3); /* Set text size to 3 */
M5.Lcd.setTextColor(WHITE); /* Set text color to white */
if (MENU_LANGUAGE == 0) /* German language chosen ? */
{
M5.Lcd.setCursor(65, 80); /* Display message */
M5.Lcd.print(F("Signal GPS"));
M5.Lcd.setCursor(60, 120);
M5.Lcd.print(F("Non Valide!"));
}
else /* Englishn language chosen ? */
{
M5.Lcd.setCursor(85, 80); /* Display message */
M5.Lcd.print(F("No valid"));
M5.Lcd.setCursor(60, 120);
M5.Lcd.print(F("GPS signal!"));
}
}
/****************************************************************************************/
/* SUBROUTINE to round floating value */
/* Input to this subroutine is float value amd number of digits after decimal point */
/****************************************************************************************/
float SUB_ROUND_FLOAT_VALUE (float FLOAT_IN, byte DIGITS)
{
float SHIFTS = 1; /* Define shift value */
while (DIGITS--) /* Process until digit value is zero */
{
SHIFTS *= 10; /* Increase shifts value */
}
return floor(FLOAT_IN * SHIFTS + .5) / SHIFTS; /* Calculated rounded value */
}
Programme Baromètre
#include <Dps310.h>
// Dps310 Opject
Dps310 Dps310PressureSensor = Dps310();
void setup() {
Serial.begin(9600);
while (!Serial);
//Call begin to initialize Dps310PressureSensor
//The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
//Dps310PressureSensor.begin(Wire, 0x76);
//Use the commented line below instead to use the default I2C address.
Dps310PressureSensor.begin(Wire);
//temperature measure rate (value from 0 to 7)
//2^temp_mr temperature measurement results per second
int16_t temp_mr = 2;
//temperature oversampling rate (value from 0 to 7)
//2^temp_osr internal temperature measurements per result
//A higher value increases precision
int16_t temp_osr = 2;
//pressure measure rate (value from 0 to 7)
//2^prs_mr pressure measurement results per second
int16_t prs_mr = 2;
//pressure oversampling rate (value from 0 to 7)
//2^prs_osr internal pressure measurements per result
//A higher value increases precision
int16_t prs_osr = 2;
//startMeasureBothCont enables background mode
//temperature and pressure ar measured automatically
//High precision and hgh measure rates at the same time are not available.
//Consult Datasheet (or trial and error) for more information
int16_t ret = Dps310PressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr);
//Use one of the commented lines below instead to measure only temperature or pressure
//int16_t ret = Dps310PressureSensor.startMeasureTempCont(temp_mr, temp_osr);
//int16_t ret = Dps310PressureSensor.startMeasurePressureCont(prs_mr, prs_osr);
if (ret != 0) {
Serial.print("Init FAILED! ret = ");
Serial.println(ret);
} else {
Serial.println("Init complete!");
}
}
void loop() {
uint8_t pressureCount = 20;
float pressure[pressureCount];
uint8_t temperatureCount = 20;
float temperature[temperatureCount];
//This function writes the results of continuous measurements to the arrays given as parameters
//The parameters temperatureCount and pressureCount should hold the sizes of the arrays temperature and pressure when the function is called
//After the end of the function, temperatureCount and pressureCount hold the numbers of values written to the arrays
//Note: The Dps310 cannot save more than 32 results. When its result buffer is full, it won't save any new measurement results
int16_t ret = Dps310PressureSensor.getContResults(temperature, temperatureCount, pressure, pressureCount);
if (ret != 0) {
Serial.println();
Serial.println();
Serial.print("FAIL! ret = ");
Serial.println(ret);
} else {
Serial.println();
Serial.println();
Serial.print(temperatureCount);
Serial.println(" temperature values found: ");
for (int16_t i = 0; i < temperatureCount; i++) {
Serial.print(temperature[i]);
Serial.println(" degrees of Celsius");
}
Serial.println();
Serial.print(pressureCount);
Serial.println(" pressure values found: ");
for (int16_t i = 0; i < pressureCount; i++) {
Serial.print(pressure[i]);
Serial.println(" Pascal");
}
}
//Wait some time, so that the Dps310 can refill its buffer
delay(10000);
}
La prochaine étape sera de réunir ces trois codes différents afin de finaliser notre logiciel puis lorsque l'assemblage sera fini, réalisera le design extérieur.
#include <Dps310.h>
// Dps310 Opject
Dps310 Dps310PressureSensor = Dps310();
void setup()
{
Serial.begin(9600);
while (!Serial);
//Call begin to initialize Dps310PressureSensor
//The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
//Dps310PressureSensor.begin(Wire, 0x76);
//Use the commented line below instead of the one above to use the default I2C address.
//if you are using the Pressure 3 click Board, you need 0x76
Dps310PressureSensor.begin(Wire);
Serial.println("Init complete!");
}
void loop()
{
float temperature;
float pressure;
uint8_t oversampling = 7;
int16_t ret;
Serial.println();
//lets the Dps310 perform a Single temperature measurement with the last (or standard) configuration
//The result will be written to the paramerter temperature
//ret = Dps310PressureSensor.measureTempOnce(temperature);
//the commented line below does exactly the same as the one above, but you can also config the precision
//oversampling can be a value from 0 to 7
//the Dps 310 will perform 2^oversampling internal temperature measurements and combine them to one result with higher precision
//measurements with higher precision take more time, consult datasheet for more information
//Pressure measurement behaves like temperature measurement
//ret = Dps310PressureSensor.measurePressureOnce(pressure);
ret = Dps310PressureSensor.measurePressureOnce(pressure, oversampling);
if (ret != 0)
{
//Something went wrong.
//Look at the library code for more information about return codes
Serial.print("FAIL! ret = ");
Serial.println(ret);
}
else
{
Serial.print("Pre: ");
Serial.print(pressure);
Serial.println(" Pa ");
}
//Wait some time
delay(500);
}