Capteur CO2 intérieur
| Projet | Durée | Difficulté | Âge |
|---|---|---|---|
| SteamCity | 2-3 heures | Intermédiaire | 12-16 ans |
Matériel
- 1 carte programmable (NUCLEO-L476RG, Arduino ou micro:bit)
- 1 capteur de CO2 SCD30
- 1 écran LCD RGB 16x2
- 1 bandeau NeoPixel (30 LED)
- Câbles de connexion
- Ordinateur + éditeur Vittascience
De quoi parle-t-on ?
Cette fiche technique accompagne la ressource Indoor Air Quality. Elle décrit cinq fiches pratiques successives : lire le taux de CO2 avec le capteur SCD30, configurer les couleurs de l'écran LCD, afficher des seuils de CO2 via un bandeau NeoPixel, combiner affichage et indicateur lumineux, puis exporter les données pour les visualiser en graphique.
Objectifs d'apprentissage
- Lire la valeur de CO2 d'un capteur I2C (SCD30)
- Contrôler un écran LCD RGB avec couleur et texte
- Piloter un bandeau NeoPixel selon des seuils
- Structurer un programme avec conditions
if/else if/else - Exporter les données pour une analyse graphique
Fiche 1 : Afficher le taux de CO2 sur écran LCD (capteur SCD30)
Éditeurs : vittascience.com/l476, vittascience.com/arduino ou vittascience.com/microbit.

Code
#include <Wire.h>
#include <rgb_lcd.h>
#include <SCD30.h>
rgb_lcd lcdRgb;
float t_scd;
float scd30_co2 = 0;
float scd30_t = 0;
float scd30_h = 0;
void serial_setupConnection(int baudrate) {
Serial.begin(baudrate);
while (!Serial) {
Serial.println("En attente de l'ouverture du port série...");
delay(1000);
}
Serial.println("Port série activé. Baudrate: " + String(baudrate));
delay(50);
}
float scd30_read(uint8_t dataSelect) {
t_scd = millis() - t_scd;
if (t_scd > 1000 && scd30.isAvailable()) {
float result[3] = {0};
scd30.getCarbonDioxideConcentration(result);
scd30_co2 = result[0];
scd30_t = result[1];
scd30_h = result[2];
}
switch (dataSelect) {
case 0: return scd30_co2;
case 1: return scd30_t;
case 2: return scd30_h;
}
}
void setup() {
lcdRgb.begin(16, 2);
serial_setupConnection(9600);
Wire.begin();
scd30.initialize();
t_scd = millis();
lcdRgb.setCursor(0, 0);
lcdRgb.print(String("CO2 level (ppm)"));
lcdRgb.setCursor(0, 0);
lcdRgb.print(String(scd30_read(0)));
}
void loop() {}

Fiche 2 : Configurer la couleur de l'écran LCD RGB

Code
#include <Wire.h>
#include <rgb_lcd.h>
rgb_lcd lcdRgb;
void setup() {
lcdRgb.begin(16, 2);
lcdRgb.setRGB(255, 96, 0);
}
void loop() { }

Fiche 3 : Indicateur LED CO2 (NeoPixel)
Ce programme combine le capteur SCD30 et le bandeau NeoPixel. Des structures conditionnelles if/else if/else permettent d'allumer les LED d'une couleur différente selon le taux de CO2.
On stocke la valeur mesurée dans une variable Taux de CO2 (via le menu Variables > Créer une variable) pour éviter de la recalculer à chaque test.

Code
#include <Wire.h>
#include <SCD30.h>
#include <rgb_lcd.h>
#include <Adafruit_NeoPixel.h>
#define NP_LED_COUNT_2 30
rgb_lcd lcdRgb;
Adafruit_NeoPixel Neopixel_2(NP_LED_COUNT_2, 2, NEO_GRB + NEO_KHZ800);
float t_scd;
float scd30_co2 = 0;
float scd30_t = 0;
float scd30_h = 0;
float CO2_rate;
void serial_setupConnection(int baudrate) {
Serial.begin(baudrate);
while (!Serial) {
Serial.println("En attente de l'ouverture du port série...");
delay(1000);
}
Serial.println("Port série activé. Baudrate: " + String(baudrate));
delay(50);
}
float scd30_read(uint8_t dataSelect) {
t_scd = millis() - t_scd;
if (t_scd > 1000 && scd30.isAvailable()) {
float result[3] = {0};
scd30.getCarbonDioxideConcentration(result);
scd30_co2 = result[0];
scd30_t = result[1];
scd30_h = result[2];
}
switch (dataSelect) {
case 0: return scd30_co2;
case 1: return scd30_t;
case 2: return scd30_h;
}
}
void neopixel_showAllLed(Adafruit_NeoPixel *neoPx, uint8_t ledCount, uint8_t r, uint8_t g, uint8_t b) {
for (int i=0; i<ledCount; i++) {
neoPx->setPixelColor(i, neoPx->Color(r, g, b));
}
neoPx->show();
}
void setup() {
serial_setupConnection(9600);
Wire.begin();
scd30.initialize();
t_scd = millis();
lcdRgb.begin(16, 2);
Neopixel_2.begin();
}
void loop() {
CO2_rate = scd30_read(0);
lcdRgb.setCursor(0, 0);
lcdRgb.print(String("CO2 rate (ppm) :"));
lcdRgb.setCursor(0, 1);
lcdRgb.print(String(CO2_rate));
if (CO2_rate <= 600) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 51, 204, 0);
} else if (CO2_rate > 600 && CO2_rate < 800) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 255, 0);
} else if (CO2_rate >= 800 && CO2_rate < 1000) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 102, 0);
} else {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 0, 0);
}
delay(250);
}

Fiche 4 : Affichage du CO2 avec temporisation
On ajoute une pause d'une seconde pour limiter la fréquence d'affichage à l'écran et faciliter la lecture des mesures.
Code
#include <Wire.h>
#include <SCD30.h>
#include <rgb_lcd.h>
#include <Adafruit_NeoPixel.h>
#define NP_LED_COUNT_2 30
rgb_lcd lcdRgb;
Adafruit_NeoPixel Neopixel_2(NP_LED_COUNT_2, 2, NEO_GRB + NEO_KHZ800);
float t_scd;
float scd30_co2 = 0;
float scd30_t = 0;
float scd30_h = 0;
float CO2_rate;
void serial_setupConnection(int baudrate) {
Serial.begin(baudrate);
while (!Serial) {
Serial.println("En attente de l'ouverture du port série...");
delay(1000);
}
Serial.println("Port série activé. Baudrate: " + String(baudrate));
delay(50);
}
float scd30_read(uint8_t dataSelect) {
t_scd = millis() - t_scd;
if (t_scd > 1000 && scd30.isAvailable()) {
float result[3] = {0};
scd30.getCarbonDioxideConcentration(result);
scd30_co2 = result[0];
scd30_t = result[1];
scd30_h = result[2];
}
switch (dataSelect) {
case 0: return scd30_co2;
case 1: return scd30_t;
case 2: return scd30_h;
}
}
void neopixel_showAllLed(Adafruit_NeoPixel *neoPx, uint8_t ledCount, uint8_t r, uint8_t g, uint8_t b) {
for (int i=0; i<ledCount; i++) {
neoPx->setPixelColor(i, neoPx->Color(r, g, b));
}
neoPx->show();
}
void setup() {
serial_setupConnection(9600);
Wire.begin();
scd30.initialize();
t_scd = millis();
lcdRgb.begin(16, 2);
Neopixel_2.begin();
CO2_rate = scd30_read(0);
delay(1000*1);
Serial.println(String(CO2_rate));
lcdRgb.setCursor(0, 0);
lcdRgb.print(String("CO2 rate (ppm)"));
lcdRgb.setCursor(0, 1);
lcdRgb.print(String(CO2_rate));
if (CO2_rate <= 600) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 51, 204, 0);
} else if (CO2_rate > 600 && CO2_rate < 800) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 255, 0);
} else if (CO2_rate >= 800 && CO2_rate < 1000) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 102, 0);
} else {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 0, 0);
}
delay(250);
}
void loop() { }

Fiche 5 : Visualisation des données
- Dans la console d'affichage Vittascience, sélectionnez Mode graphique à droite.
- À partir du graphique, exportez les données au format
.csv(bouton Exporter en bas de la fenêtre). Les données s'ouvrent alors dans Excel, LibreOffice Calc, Google Sheets ou Numbers, où la fonction Graphique permet de tracer l'évolution du CO2 au cours du temps.
Code (compatible avec la visualisation graphique de Vittascience)
#include <Wire.h>
#include <SCD30.h>
#include <rgb_lcd.h>
#include <Adafruit_NeoPixel.h>
#define NP_LED_COUNT_2 30
rgb_lcd lcdRgb;
Adafruit_NeoPixel Neopixel_2(NP_LED_COUNT_2, 2, NEO_GRB + NEO_KHZ800);
float t_scd;
float scd30_co2 = 0;
float scd30_t = 0;
float scd30_h = 0;
float CO2_rate;
void serial_setupConnection(int baudrate) {
Serial.begin(baudrate);
while (!Serial) {
Serial.println("En attente de l'ouverture du port série...");
delay(1000);
}
Serial.println("Port série activé. Baudrate: " + String(baudrate));
delay(50);
}
float scd30_read(uint8_t dataSelect) {
t_scd = millis() - t_scd;
if (t_scd > 1000 && scd30.isAvailable()) {
float result[3] = {0};
scd30.getCarbonDioxideConcentration(result);
scd30_co2 = result[0];
scd30_t = result[1];
scd30_h = result[2];
}
switch (dataSelect) {
case 0: return scd30_co2;
case 1: return scd30_t;
case 2: return scd30_h;
}
}
void neopixel_showAllLed(Adafruit_NeoPixel *neoPx, uint8_t ledCount, uint8_t r, uint8_t g, uint8_t b) {
for (int i=0; i<ledCount; i++) {
neoPx->setPixelColor(i, neoPx->Color(r, g, b));
}
neoPx->show();
}
void setup() {
serial_setupConnection(9600);
Wire.begin();
scd30.initialize();
t_scd = millis();
lcdRgb.begin(16, 2);
Neopixel_2.begin();
CO2_rate = scd30_read(0);
delay(1000*1);
Serial.print("@Graph:");
Serial.print("CO2 rate (in ppm):");
Serial.print(CO2_rate);
Serial.print("|");
Serial.print("\n");
delay(50);
lcdRgb.setCursor(0, 0);
lcdRgb.print(String("CO2 rate (ppm)"));
lcdRgb.setCursor(0, 1);
lcdRgb.print(String(CO2_rate));
if (CO2_rate <= 600) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 51, 204, 0);
} else if (CO2_rate > 600 && CO2_rate < 800) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 255, 0);
} else if (CO2_rate >= 800 && CO2_rate < 1000) {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 102, 0);
} else {
neopixel_showAllLed(&Neopixel_2, NP_LED_COUNT_2, 255, 0, 0);
}
delay(250);
}
void loop() { }

Cette fiche fait partie du projet SteamCity, financé par le programme Erasmus+. Contenu sous licence CC BY-SA 4.0.