Plateforme multi-capteurs environnementale MKR1000 – Foudre, Gaz, UV, Temp, Humidité, Pression
Composants et fournitures
| Arduino MKR1000 | × | 1 |
| Capteur de foudre MOD-1016 | × | 1 |
| Capteur de gaz MQ-9 DFRobot | × | 1 |
| Capteur humidité et température Adafruit | × | 1 |
| Capteur pression/altitude/température Adafruit | × | 1 |
| Capteur UV ML8511 SparkFun | × | 1 |
| Chronodot RTC | × | 1 |
| Shield météo Photon SparkFun | × | 1 |
| NeoPixels Adafruit | × | 1 |
| Plaque d'essai (breadboard) | × | 1 |
| Fils de connexion (génériques) | × | 1 |
À propos du projet
J'adore observer la météo et voulais la capturer et la graphiquer. Les stations météo domestiques montrent le « maintenant » et parfois des totaux sur l'heure ou la journée. Je voulais aller plus loin avec un Arduino. Tout le monde commence par température, humidité, parfois pression barométrique, mais je voulais plus ! Vitesse du vent et pluviométrie demandaient des entrées matérielles. Une fois l'I2C maîtrisé, j'ai découvert des capteurs comme le détecteur de foudre AS3935 ! Et là, la déception… pas assez d'interruptions matérielles sur un Arduino basique. SparkFun a bien un shield météo pour le Photon, mais toujours limité. Il fallait choisir et renoncer à certains capteurs. :-(
Puis j'ai vu le MKR1000, et sa MEILLEURE CARACTÉRISTIQUE : il a 8 interruptions matérielles ! Maintenant je peux tout avoir !
Choisir vos capteurs
Les capteurs se divisent en trois catégories :
- Analogiques : lumière (IR, UV), direction du vent, gaz, cellules de charge…
- I2C : température, humidité, pression barométrique, accéléromètre, gyroscope…
- Interruptions : pluviomètres, anémomètres, foudre, timers… (Des fonctions comme série, PWM, horloges, servos utilisent des interruptions de temporisation)
Le MKR1000 a suffisamment d'E/S pour tout ça !
ATTENTION AUX TENSIONS D'E/S SUR I2C ET INTERRUPTIONS ! Par exemple, le MKR1000, le Photon et beaucoup d'Arduino utilisent du 3,3 V au lieu de 5 V. Si votre CPU et vos capteurs utilisent des tensions différentes, vous aurez besoin de convertisseurs de niveau (level-shifters).
Tous mes capteurs sont courants, disponibles chez Adafruit, SparkFun, Element-14, etc., et coûtent généralement 5-10 $US. Les capteurs de gaz coûtent 10-20 $. Pour le détecteur de foudre (puce AS3935), j'ai choisi le MOD-1016 d'Embedded Adventures (26 $US avec antenne intégrée). J'ai aussi acheté le SparkFun Photon Weather Shield pour mes futurs anémomètres. J'ajouterai peut-être un capteur d'humidité du sol une fois l'emplacement du MKR1000 défini. Certains capteurs n'aiment pas les longs câbles.
Attribuer vos capteurs aux broches
Une fois vos capteurs choisis, vous savez quels types d'entrées il vous faut. L'étape suivante est de décider quels capteurs vont sur quelles broches. Je commence sur papier, puis j'ajoute cette liste en commentaire dans mon code.
Voici mes affectations de broches MKR1000 pour ma plateforme de capteurs :
- A0 (réservé pour un éventuel DAC)
- A1 Capteur UV ML8511
- A2 Capteur de lumière visible
- A3 Capteur température local TMP36
- A4 Capteur gaz MQ-9
- A5 Capteur d'humidité
- A6 Capteur vitesse du vent ?
- 0 (INT MATÉRIELLE) Bouton poussoir
- 1 (INT MATÉRIELLE) Détecteur de foudre AS
- 2 (INT MATÉRIELLE) Anémomètre vitesse vent (interruption par rotation)
- 3 (INT MATÉRIELLE) Pluviomètre à bascule…
- 4
- 5
- 6 (partagée avec LED intégrée)
- 7 Sortie NeoPixel…
Démarrage…
Pour les débutants, je suggère de tester chaque capteur un par un : chargez le code d'exemple, installez les bibliothèques nécessaires. Changez la broche du capteur pour correspondre à votre affectation, et sauvegardez une copie du code de démo dans votre dossier de projet.
Quand vous arrivez à lire les résultats sur le Moniteur Série, passez au capteur suivant. Une fois tous testés, ils sont câblés et prêts pour le sketch complet !
Mes essais initiaux incluaient une horloge temps réel (RTC) I2C pour logger sur carte SD. Bien que le MKR1000 ait sa propre RTC et une batterie, je n'ai pas réussi à la faire tenir l'heure sur batterie seule, donc je garde le ChronoDot v2.1 I2C RTC.
Sur la photo de ma plaque d'essai, vous voyez les jumpers orange pour l'alimentation 3,3 V de chaque capteur, qu'on branche seulement quand on veut travailler dessus (facile à désactiver en débranchant le jumper orange).
Note sur les bibliothèques
Certaines bibliothèques installables NE FONCTIONNENT PAS parfaitement avec le MKR1000 et/ou l'IDE Arduino.cc 1.6.7, et peuvent nécessiter des ajustements. Un exemple : les anciennes macros ATOMIC_* de la vieille bibliothèque AVR libc (supprimées dans l'IDE Arduino 1.6.5). Il y a un excellent fil de discussion sur les problèmes et solutions sur le forum Arduino.cc. Faire ces modifications est à la portée d'un bricoleur intermédiaire, mais peut intimider les débutants. Pour les bibliothèques un peu anciennes, l'auteur original n'est peut-être plus là pour les mettre à jour.
Malheureusement, on ne sait généralement pas quelles bibliothèques doivent être corrigées avant d'acheter et tester les capteurs. À ce stade, examinez attentivement les messages d'erreur en orange lors de la compilation pour voir si le problème vient de votre code ou d'une bibliothèque. Si c'est la bibliothèque, cherchez « arduino » + le message d'erreur sur le web. Si pas de solution, essayez d'envoyer un email à l'auteur.
J'ai acheté des puces individuelles pour économiser. J'ai décidé que, jusqu'à ce que je sois prêt à faire mes propres circuits imprimés (probablement avec EagleCAD et OSHPark), il est plus simple d'acheter des modules capteurs chez Adafruit et SparkFun, car ils maintiennent bien leurs bibliothèques à jour.
Un peu sur le WiFi et le chiffrement
J'ai aussi pensé au WiFi pour faire remonter mes capteurs météo vers un site web. Le MKR1000 a même un moteur de chiffrement pour sécuriser les données en transit sur Internet ! Mais c'est au-delà de ce premier projet. C'est sur ma liste pour la version 2. Voici un diagramme du module SAMD au cœur de votre carte.
Un conseil pour démarrer avec le WiFi intégré : Assurez-vous d'utiliser la version la plus récente de la bibliothèque WiFi101 ! Sinon, votre sketch ne reconnaîtra pas le module WiFi. Merci à Charif Mahmoudi pour l'avoir souligné dans son excellent tutoriel « Getting Started with MKR1000 » sur Hackster ! Au moment de mon développement, le GitHub WiFi101 était disponible ici.
Astuces pour capteurs analogiques
La plupart des modules « sortie analogique » produisent une simple tension analogique, lue via analogRead. Mais il faut savoir l'interpréter. Normalement, il faut utiliser map ou faire un peu de maths. Les éléments résistifs demandent souvent un circuit additionnel. Vous pouvez ajouter un potentiomètre pour « affiner » la tension.
Dans d'autres cas, il faut des équations pour transformer la tension de sortie en valeur compréhensible. Le capteur TMP36 en est un bon exemple : conçu pour lire en degrés Celsius, il faut mesurer la tension et faire du calcul pour obtenir °C, puis convertir en °F si souhaité. Lire les fiches techniques explique le fonctionnement, mais il est plus facile de suivre l'expérience d'autres bricoleurs.
D'autres capteurs ont besoin d'un amplificateur pour rendre les faibles variations de tension exploitables par l'ADC. Ces capteurs (cellules de charge, humidité, accéléromètre) sont ceux où je recommande d'investir dans un module avec amplificateur intégré et bibliothèque pour comprendre la plage de sortie.
Astuces pour dispositifs I2C
L'I2C est parfois appelé « interface à deux fils » car il faut un signal d'horloge et un signal de données. (Un seul fil de données car le « maître » et les « esclaves » s'alternent pour l'envoyer.) Bien sûr, vos capteurs I2C ont aussi besoin d'une masse et d'une alimentation, et cette masse doit être reliée à celle du CPU.
Chaque dispositif I2C a une adresse hexadécimale sur le bus. Évitez d'utiliser plusieurs dispositifs à la même adresse. (Si nécessaire, gérez-les avec un circuit additionnel pour « activer » celui avec qui vous communiquez, puis le désactiver avant d'activer un autre.) La documentation doit indiquer quelles adresses un dispositif peut avoir. NOTE : Si deux dispositifs sur le bus I2C ont la même adresse et tous deux une broche « Enable » ou « Shutdown », vous pouvez en désactiver un pendant que l'autre est actif. Mais vous ne pouvez pas simplement couper l'alimentation du VDD, car les capteurs peuvent capter de l'énergie via les broches SDA/SCL, causant de mauvaises lectures. La vérification d'erreur I2C n'est pas assez robuste pour détecter/corriger ce cas.
Les spécifications I2C préconisent une résistance de tirage fort (pull-up) sur l'horloge et les données, sur le capteur le plus loin sur le fil. Certains modules ont déjà ces résistances intégrées, il suffit parfois d'ajouter quelques jumpers. Lisez la documentation du module.
En plus des « résistances de terminaison de bus », j'ai trouvé l'astuce d'ajouter une résistance en série sur les lignes SDA et SCL. Cela a grandement amélioré la fiabilité de lecture de certains capteurs. Avec le MKR1000 en signalisation 3,3 V, j'utilise des résistances de 220 Ω. Sur un CPU 5 V, essayez 330 Ω. Voir le schéma ci-dessous pour la différence de placement.
Que ferez-vous des données ? Pour l'instant, je les envoie au Moniteur Série. Vous pourriez ajouter un LCD. Je voulais ajouter une carte SD, mais avec le WiFi intégré, je veux uploader vers le cloud… Imaginez plusieurs plateformes de capteurs, connaissant leur latitude/longitude, triangulant un éclair en comparant les lectures de puissance de chaque station pour un éclair donné !
NOTE : 2017-11-29 ; Je n'ai pas réussi à faire fonctionner les interruptions matérielles sur le MKR1000. Je prends des notes et fais des expériences pour une classe de 3ème (13-14 ans), basées sur la carte Adalogger M0 qui sauvegarde sur carte SD, avec encore plein de broches pour un module WiFi. https://arduinoclass.pbworks.com
En travaillant sur les capteurs, j'ai aussi repéré le luminaire SODERSVIK chez IKEA. Imaginez remplacer les LED blanches par 20 NeoPixels, ajouter un récepteur IR. Le vent pourrait ressembler à des nuages, la couleur indiquer la température. La télécommande pourrait afficher momentanément d'autres infos, comme la variation de température sur 12h.
Qu'aimeriez-vous surveiller et afficher ?
Code
Sketch complet de surveillance (Arduino)
De nombreux capteurs rapportent dans ce sketch, les bibliothèques fonctionnent bien ensemble. Cependant, les méthodes classiques de verrouillage d'interruption dans AVR-libc ont été supprimées dans les versions récentes de l'IDE Arduino, ce qui a désactivé les bibliothèques NeoPixel et capteur de foudre. Je m'attends à ce que ce soit résolu cette année, mais je les ai exclus du sketch final.
/* RTC-Weather-Sensors_v6_MKR1000 by Zonker Harris Spring 2016
* Hourra ! Une petite carte, avec plus de 2 interruptions matérielles !
* Plus WiFi, *et* crypto (TRÈS nécessaire pour l'IoT !)
* Note aux nouveaux bricoleurs : je mets BEAUCOUP de commentaires dans mon code.
* Au clic sur Téléverser, *les commentaires sont IGNORÉS* et ne consomment pas de mémoire !
* Je recommande d'ajouter plein de commentaires quand vous modifiez/ajoutez,
* pour vous souvenir POURQUOI vous avez fait quoi il y a des mois.
* Ils aideront aussi ceux qui viendront après vous.
* Les bibliothèques *COMPTENT* contre la mémoire programme...
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_HTU21DF.h>
// NeoPixels en placeholder, mais la bibliothèque a besoin de mise à jour pour les vecteurs d'interruption
// #include <Adafruit_NeoPixel.h>
// const int numLeds = 1;
// Adafruit_NeoPixel strip = Adafruit_NeoPixel(numLeds, 6, NEO_GRB + NEO_KHZ800);
/* Le driver BMP085_U utilise la bibliothèque unifiée Adafruit_Sensor... */
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10180);
/* HTU21D-F d'Adafruit */
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
/* Macetech Chronodot v2.1 RTC sur batterie... */
int addrRTC = 0x68;
int seconds, seconds1, seconds10;
int minutes, minutes1, minutes10;
int hours, hours1, hours10;
int day, date, month, years;
int a1secs, a1mins, a1hrs, a1daydate;
int a2mins, a2hrs, a2daydate;
int rtcstatus, aginginfo;
int temprtc, tempfrtc;
int UVOUT = A1;
int lightOut = A2;
int tmp36out = A3;
int mq9out = A4;
int sounderPin = 6;
int neopixelPin = 7;
void setup(void) {
Serial.begin(9600);
delay(1000);
Serial.println("i2c Sensor Deck");
pinMode(UVOUT, INPUT);
pinMode(lightOut, INPUT);
pinMode(tmp36out, INPUT);
pinMode(sounderPin, OUTPUT);
pinMode(neopixelPin, OUTPUT);
if (!bmp.begin()) {
Serial.print("Ooops, pas de BMP085/180 détecté... Vérifiez câblage ou ADDR I2C !");
while (1);
}
displaySensorDetails();
if (!htu.begin()) {
Serial.println("HTU21-DF introuvable !");
while (1);
}
// Initialisation Chronodot RTC (décommentez, modifiez, téléversez pour régler l'heure, puis recommentez)
/* seconds = 0; minutes = 41; hours = 20; day = 7; date = 3; month = 1; years = 16; initChrono(); */
}
void loop(void) {
beep(50, 2);
// NeoPixel en teal... (commenté car lib non fonctionnelle)
// strip.setPixelColor(0, (0, 45, 30)); strip.show();
/**********************************************************************/
/* Récupération Chronodot I2C 0x68 - DS1307 RTC */
/**********************************************************************/
Wire.beginTransmission(0x68);
Wire.write((byte)0);
Wire.endTransmission();
Wire.requestFrom(0x68, 13);
while (Wire.available()) {
seconds = Wire.read();
minutes = Wire.read();
hours = Wire.read();
day = Wire.read();
date = Wire.read();
month = Wire.read();
years = Wire.read();
a1secs = Wire.read(); a1mins = Wire.read(); a1hrs = Wire.read();
a1daydate = Wire.read(); a2mins = Wire.read(); a2hrs = Wire.read();
a2daydate = Wire.read(); rtcstatus = Wire.read(); aginginfo = Wire.read();
temprtc = Wire.read(); tempfrtc = Wire.read();
}
seconds10 = ((seconds & 0b11110000) >> 4); seconds1 = (seconds & 0b00001111);
minutes10 = ((minutes & 0b11110000) >> 4); minutes1 = (minutes & 0b00001111);
hours10 = (((hours & 0b00100000) >> 5) * 2 + ((hours & 0b00010000) >> 4) * 1);
hours1 = (hours & 0b00001111);
years += 2000;
temprtc = ((temprtc & 0b01111111) + (((tempfrtc & 0b11000000) >> 6) * 0.25));
get_date();
Serial.print("ChronoDot - ");
Serial.print(hours10); Serial.print(hours1); Serial.print(":");
Serial.print(minutes10); Serial.print(minutes1); Serial.print(":");
Serial.print(seconds10); Serial.print(seconds1); Serial.print(" 20");
Serial.print(years); Serial.print(" "); Serial.print(month); Serial.print(" ");
Serial.print(date); Serial.print(" \t"); Serial.print(temprtc); Serial.println(" C");
delay(100);
/**********************************************************************/
/* Données BMP180 I2C 0x77 - Pression baro et Temp */
/**********************************************************************/
sensors_event_t event;
bmp.getEvent(&event);
float BMPtemperature;
bmp.getTemperature(&BMPtemperature);
float BMPtempF = (BMPtemperature * 1.8 + 32);
Serial.print("Temp: "); Serial.print(BMPtemperature); Serial.print(" C (");
Serial.print(BMPtempF); Serial.print(" F) \t");
if (event.pressure) {
Serial.print("BMP180 - Pres: "); Serial.print(event.pressure); Serial.print(" hPa\t");
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
Serial.print("Alt: "); Serial.print(bmp.pressureToAltitude(seaLevelPressure, event.pressure)); Serial.println(" m");
delay(100);
} else {
Serial.println("Erreur capteur");
}
/**********************************************************************/
/* Données HTU21-DF I2C 0x40 - Humidité et Temp */
/**********************************************************************/
float HTUtemperature = htu.readTemperature();
float HTUtempF = (HTUtemperature * 1.8 + 32);
Serial.print("HTU21-DF - Temp: "); Serial.print(HTUtemperature); Serial.print(" C (");
Serial.print(HTUtempF); Serial.print(" F)\tHum: "); Serial.print(htu.readHumidity()); Serial.println("%");
delay(100);
/**********************************************************************/
/* TMP36 analogique - Capteur température de précision */
/**********************************************************************/
int reading = averageAnalogRead(tmp36out);
float tmp36voltage = 0.0032258064516129 * reading;
Serial.print("TMP36 - temp: ");
float tmp36temperatureC = (tmp36voltage - 0.5) * 100;
Serial.print(tmp36temperatureC); Serial.print(" C \t");
float tmp36temperatureF = (tmp36temperatureC * 9.0 / 5.0) + 32.0;
Serial.print(tmp36temperatureF); Serial.print(" F, out: "); Serial.print(tmp36voltage); Serial.println("v");
delay(100);
/**********************************************************************/
/* TEMT6000 Lumière visible - Lecture analogique */
/**********************************************************************/
int vLevel = averageAnalogRead(lightOut);
float newVOutVolts = 0.0032258064516129 * vLevel;
Serial.print("TEMT6000 out: "); Serial.println(vLevel);
delay(100);
/**********************************************************************/
/* ML8511 UV - Lecture analogique */
/**********************************************************************/
int uvLevel = averageAnalogRead(UVOUT);
float newOutVolts = 0.0032258064516129 * uvLevel;
float uvIntensity = mapfloat(newOutVolts, 0.99, 2.8, 0.0, 15.0);
Serial.print("ML8511 UV out: "); Serial.print(uvLevel);
Serial.print(" / UV Intensity (mW/cm^2): "); Serial.println(uvIntensity);
delay(100);
/**********************************************************************/
/* MQ-9 Gaz CO/Combustible DFRobot - Lecture analogique */
/**********************************************************************/
int MQ9volts = analogRead(mq9out);
Serial.print("MQ-9 Gaz: "); Serial.println(MQ9volts, DEC);
delay(100);
Serial.println("");
delay(3500); // Boucle ~5 secondes
}
void initChrono() { set_time(); set_date(); }
void set_date() {
Wire.beginTransmission(104); Wire.write(4);
Wire.write(decToBcd(day)); Wire.write(decToBcd(date));
Wire.write(decToBcd(month)); Wire.write(decToBcd(years));
Wire.endTransmission();
}
void get_date() {
Wire.beginTransmission(104); Wire.write(3);
Wire.endTransmission();
Wire.requestFrom(104, 4);
day = bcdToDec(Wire.read()); date = bcdToDec(Wire.read());
month = bcdToDec(Wire.read()); years = bcdToDec(Wire.read());
}
void set_time() {
Wire.beginTransmission(104); Wire.write((byte)0);
Wire.write(decToBcd(seconds)); Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours)); Wire.endTransmission();
}
void get_time() {
Wire.beginTransmission(104); Wire.write((byte)0);
Wire.endTransmission();
Wire.requestFrom(104, 3);
seconds = bcdToDec(Wire.read() & 0x7f);
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0x3f);
}
void get_temp() { get_time(); }
void setHour() { hours++; if (hours > 23) { hours = 0; seconds = 0; minutes = 0; } set_time(); }
void setMinutes() { minutes++; if (minutes > 59) { minutes = 0; } seconds = 0; set_time(); }
byte decToBcd(byte val) { return ((val / 10 * 16) + (val % 10)); }
byte bcdToDec(byte val) { return ((val / 16 * 10) + (val % 16)); }
void displaySensorDetails(void) {
sensor_t sensor;
Serial.println("------------------------------------");
Serial.print("Sensor: "); Serial.println(sensor.name);
Serial.print("Driver Ver: "); Serial.println(sensor.version);
Serial.print("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print("Max Value: "); Serial.print(sensor.max_value); Serial.println(" hPa");
Serial.print("Min Value: "); Serial.print(sensor.min_value); Serial.println(" hPa");
Serial.print("Resolution: "); Serial.print(sensor.resolution); Serial.println(" hPa");
Serial.println("------------------------------------"); Serial.println(""); delay(500);
}
int averageAnalogRead(int pinToRead) {
byte numberOfReadings = 8;
unsigned int runningValue = 0;
for (int x = 0; x < numberOfReadings; x++) runningValue += analogRead(pinToRead);
runningValue /= numberOfReadings;
return runningValue;
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void beep(int duration, int count) {
for (int loop = 0; loop < count; loop++) {
digitalWrite(sounderPin, HIGH); delay(duration);
digitalWrite(sounderPin, LOW); delay(duration);
}
}
Moyenne de lecture analogique (Arduino)
Astuce trouvée dans la bibliothèque SparkFun pour le ML8511, utilisable pour toute lecture analogique. Si vous croisez Nathan Seidl, offrez-lui une bière (licence Beerware).
int averageAnalogRead(int pinToRead) {
byte numberOfReadings = 8;
unsigned int runningValue = 0;
for (int x = 0; x < numberOfReadings; x++) runningValue += analogRead(pinToRead);
runningValue /= numberOfReadings;
return runningValue;
}
Scanner bus I2C (Arduino)
Si vous ne connaissez pas l'adresse de base de vos dispositifs I2C, utilisez ce scanner. Il connaît mes capteurs ; ajoutez des sections pour les vôtres.
// i2c_scanner - Version 5, March 28, 2013
#include <Wire.h>
void setup() { Wire.begin(); Serial.begin(9600); Serial.println("\nI2C Scanner"); }
void loop() {
byte error, address; int nDevices = 0;
Serial.println("Scanning...");
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.print(address, HEX);
if (address == 3) Serial.print(" - AS3935 Lightning Sensor");
if (address == 64) Serial.print(" - HTU21D Humidity and Temp Sensor");
if (address == 104) Serial.print(" - DS1307 RTC (Chrono-Dot?)");
if (address == 119) Serial.print(" - BMP180 Barometric Pressure and Tem Sensor");
Serial.println(""); nDevices++;
} else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0) Serial.println("No I2C devices found\n");
else Serial.println("done\n");
delay(5000);
}
Code démo ML8511 (Arduino)
Adapté pour CPU 3,3 V natif (unités de référence DAC).
/* ML8511 UV Sensor Read Example - Nathan Seidle, SparkFun Electronics
* Licence Beerware. Adapté MKR1000 par Zonker Harris, MAR 2016 */
int UVOUT = A1;
void setup() { Serial.begin(9600); pinMode(UVOUT, INPUT); Serial.println("ML8511 example"); }
void loop() {
int uvLevel = averageAnalogRead(UVOUT);
float newOutVolts = 0.0032258064516129 * uvLevel;
float uvIntensity = mapfloat(newOutVolts, 0.99, 2.8, 0.0, 15.0);
Serial.print("ML8511 out: "); Serial.print(uvLevel);
Serial.print(" / UV Intensity (mW/cm^2): "); Serial.println(uvIntensity);
delay(100);
}
// averageAnalogRead et mapfloat identiques à ci-dessus
Schémas
Je suis trop novice sur Fritzing et n'ai pas trouvé beaucoup de pièces dans la bibliothèque, j'ai fait cette maquette à la place.
Processus de fabrication
- Intégration de données de capteurs sur Raspberry Pi : Guide pratique complet
- Capteur de suivi de ligne KY‑033 avec Raspberry Pi : Détecteur de porte/lignes simple
- Créer une API robuste de température et capteurs sur Raspberry Pi avec le module GY‑91
- Construire un système aéroponique automatisé avec Raspberry Pi et capteur d'humidité
- Maîtriser le GPIO Raspberry Pi : Interfacer un capteur PIR de mouvement sur B+/Modèle 2
- Intégrer le radar pulsé Acconeer A111 à un Raspberry Pi : Guide pratique
- Comment connecter, calibrer et programmer le capteur de mouvement PIR HC‑SR501 avec un Raspberry Pi
- Enregistreur de capteurs Python/MicroPython : Stocker les données de capteurs dans Google Sheets
- Envoyer les données IMU 10DOF Adafruit du Raspberry Pi 2 vers Azure Event Hubs avec Windows 10 IoT Core