37
ECOLE POLYTECHNIQUE UNIVERSITAIRE DE NICE SOPHIA-ANTIPOLIS Parcours des écoles d'ingénieurs Polytech Deuxième année Année scolaire 2015-2016 PROJETS ELECTRONIQUE AVEC ARDUINO Télémesures embarquées dans une fusée Étudiante : Maéva MANUEL Encadrants : Fabien FERRERO et Pascal MASSON

Année scolaire 2015-2016 PROJETS ELECTRONIQUE … · déphasage de 180° entre les ondes émises et réfléchies ainsi qu'un rapport qui tend vers 0 donc un pic qui tend vers moins

Embed Size (px)

Citation preview

ECOLE POLYTECHNIQUE

UNIVERSITAIRE DE

NICE SOPHIA-ANTIPOLIS

Parcours des écoles d'ingénieurs Polytech

Deuxième année

Année scolaire 2015-2016

PROJETS ELECTRONIQUE AVEC ARDUINOTélémesures embarquées dans une fusée

Étudiante : Maéva MANUEL

Encadrants : Fabien FERRERO et Pascal MASSON

2

3

SOMMAIRE

Chapitre 1 : Introduction et cahier des charges ..................................................................... 4

Chapitre 2 : Communication RF 433 MHz ........................................................................... 5

2.1. Présentation des modules .................................................................................................................................................... 5

2.2. Présentation de la librairie « Virtual Wire » ....................................................................................................................... 5

2.3. Envoi des données d’un capteur ......................................................................................................................................... 5

2.3.1. Envoi d’un simple texte .............................................................................................................................................. 5 2.3.2. Envoi d’un nombre ..................................................................................................................................................... 5 2.3.3. Calibrage de l'antenne ................................................................................................................................................. 6

Chapitre 3 : Les capteurs ....................................................................................................... 7

3.1. Le capteur d’humidité/température DHT11........................................................................................................................ 7

3.2. Le capteur de pression barométrique MPL3115A2 ............................................................................................................ 7

3.2.2. Capteur piezoresistif ................................................................................................................................................... 7 3.2.3. Mise en œuvre du capteur et bus I2C .......................................................................................................................... 8 3.2.4. La libraire MPL3115A2 .............................................................................................................................................. 8

3.3. Module RTC ....................................................................................................................................................................... 8

3.4. Le panneau de LED .......................................................................................................................................................... 10

Chapitre 4 : Mise en œuvre de l’ensemble des éléments .................................................... 11

4.1. Récupération des données des capteurs ............................................................................................................................ 11

4.2. Envoi des données au récepteur RF .................................................................................................................................. 11

4.3. Réception des données ...................................................................................................................................................... 11

4.3. Affichage des informations sur le panneau de LED ......................................................................................................... 11

Chapitre 5 : Conclusions et perspectives ............................................................................. 13

Références ........................................................................................................................... 15

Programme : émission des données ..................................................................................... 17

Programme : réception des données .................................................................................... 23

Programme : affichage des données .................................................................................... 31

4

Chapitre 1 : Introduction et cahier des charges

Ce projet Arduino, dans la continuité du projet « Électronique de guidage d’une FUSEE et mesures embarquées »

qui a débuté en octobre 2015, a pour objectif de développer la communication de la fusée avec la Terre et ainsi de

pouvoir envoyer les données de vol qu'elle récolte grâce à ses multiples capteurs intégrés. Du fait des grandes

distances qui séparent la fusée du sol, nous avons recours à un module RF d'envoi et de réception associés à une

antenne spécialement conçue pour la fusée. D'autre part, nous choisissons d'effectuer des mesures de pression

atmosphérique (module MPL3115), de température et d'humidité (capteur DHT11). Afin de déterminer la position

exacte de la fusée en temps réel, nous utilisons la géolocalisation du GPS (altitude, latitude et longitude) ainsi que

le module d'heure RTC. De ce fait, après le très célèbre décompte des 10 secondes avant le lancement, nous

affichons toutes les données récupérées par la fusée en vol grâce à un panneau de LED prévu à cet effet.

5

Chapitre 2 : Communication RF 433 MHz

2.1. Présentation des modules

Les modules de transmission et réception RF présentés

à la figure (2.1) permettent d’envoyer des informations

sur des distances supérieures à 200 m ce qui est bien

plus élevé que le Bluetooth. Les deux modules sont

réglés sur la même fréquence de 433 MHz et ils ont été

conçus pour être alimentés en 5 V (en réalité entre 3 à

12V) ce qui correspond exactement à la tension

d’alimentation de la carte Arduino. Afin de pouvoir les

faire fonctionner, nous avons soudé des fils, jouant le

rôle d'antenne) d'une longueur minimale de 32 cm.

Les informations sont envoyées sans adresse (tous les

modules de réception reçoivent les mêmes informations

ce qui n’est pas problématique car nous n'utilisons

qu’un récepteur) et sans demande de confirmation (la

liaison ne se fait que dans un sens).

Figure 2.1. modules de transmission et réception RF

433 MHz

L’envoie des données est faite avec une modulation d’amplitude de type ASK (Amplitude Shift Keying).

L’amplitude de la porteuse (sinusoïde de fréquence 433 MHz) est maximale pour l’envoi d’un « 1 » logique et

devient nulle lors de l’envoi d’un « 0 » logique.

A noter également que la fréquence 433 MHz est libre de droit et qu’elle est donc fréquemment utilisée pour les

commandes de volets, de portails, de portes de garage mais aussi les stations météo sans fil, les écoutes bébés...

2.2. Présentation de la librairie « Virtual Wire »

La librairie « VirtualWire » est à télécharger sur le site :

www.airspayce.com/mikem/arduino/VirtualWire/VirtualWire-1.27.zip

et le dossier doit être décompressé dans le répertoire "libraries" du logiciel Arduino.

Cette libraire est d’une utilisation simple et nous donnons ici quelques exemples de fonctions :

- vw_setup(2000) : permet de définir la vitesse de transmission, dans cet exemple de 2000 bits par seconde

- vw_send(message, longueur) : envoie un “message” d'une certaine “longueur”

- vw_wait_tx() : arrête le déroulement du programme jusqu’à ce que le message soit envoyé

2.3. Envoi des données d’un capteur

2.3.1. Envoi d’un simple texte

Pour comprendre le fonctionnement des modules RF, nous avons utilisé le premier exemple de la librairie qui

envoie le texte "hello", défini comme une chaîne de caractère. Le message reçu et affiché sur le port série est « 68

65 6C 6C 6F » car le programme impose d’afficher le message en hexadécimal (Serial.print(buf[i], HEX) où buf[i]

est le message reçu). La lecture en hexadécimale n’étant pas intuitive, nous avons décidé de modifier cette ligne de

code afin d'afficher le texte reçu tel quel sur l’écran : Serial.print((char) buf[i]). Nous avons alors vérifié la bonne

réception du message en éloignant les 2 modules, l’émetteur restant dans la salle 388 de TP et le récepteur se

trouvant au niveau du bâtiment administratif.

2.3.2. Envoi d’un nombre

Pour émuler un capteur, nous avons choisi de brancher un potentiomètre sur une des entrées analogiques de la carte

Arduino émettrice. Le nombre à envoyer doit être converti en une chaîne de caractère car la libraire

6

« WirtualWire » ne supporte que ce type de variables. Cette conversion s'effectue à l'aide de la fonction : sprintf(Y,

"%f", X) où X est le chiffre et Y la chaîne de caractère.

Néanmoins, cette fonction (pourtant utilisée dans de nombreux exemples) n’est pas compilée par l'IDE (Integrated

Development Environment) et il nous a été nécessaire de la remplacer. Nous avons finalement utilisé la fonction :

dtostrf(X,4,2,Y) où 4 est le nombre minimum de chiffres composant le nombre à envoyer, et 2 correspond au

nombre de chiffres après la virgule.

Du côté réception, il a fallu transformer la chaîne de caractères reçue en un float. Pour cela, nous utilisons la

fonction atof : float Y = atof(X) où X est la chaîne de caractères reçue et Y le nombre qui lui correspond.

Lors des essais, nous avons fait varier la tension obtenue avec le potentiomètre, puis nous l’avons affichée sur le

moniteur série et comparée avec le nombre obtenu côté réception.

2.3.3. Calibrage de l'antenne

Afin de calibrer au mieux l'antenne (c.f. figure (2.2)), nous avons eu recours à un analyseur de réseau vectoriel

(VNA, Vector Network Analyser). Cet appareil permet de mesurer le défaut d'adaptation d'impédance entre deux

composants radiofréquences et de ce fait d'optimiser l'intégrité d'un signal. Dès qu'une onde quitte un composant

pour entrer dans un autre, elle se divise en une onde réfléchie et une onde transmise. En mesurant le rapport de

l'énergie réfléchie sur l'énergie émise, qui varie avec la fréquence, le VNA détermine les performances du matériel

sous test. Dans le cas présent, c'est le module RF 433MHz qui assure le rôle du DUT (Dispositif Under Test). Nous

nous intéressons donc au coefficient de réflexion, noté S11 (le premier « 1 » indique le numéro du port de l'onde

réfléchie et le deuxième celui du port du signal incident) dont nous donnons la valeur en fonction de la fréquence à

la figure (2.3). Il est représenté en dB en fonction de la fréquence en Hz.

Tout d'abord, nous avons procédé à l'étalonnage SOLT (Short, Open, Load, Through). Le court-circuit induit un

déphasage de 180° entre les ondes émises et réfléchies ainsi qu'un rapport qui tend vers 0 donc un pic qui tend vers

moins l'infini en dB (réflexion quasi nulle que l'on souhaite approcher). A l'inverse, le circuit ouvert implique un

déphasage proche de 0° et un rapport qui tend vers 1 en linéaire donc 0dB (réflexion totale). Pour une impédance

de sortie de 50Ohms, nous avons mesuré -60dB, soit un million de fois moins d'énergie que celle qui a été envoyée.

Le but est ici de déterminer la fréquence exacte du module RF et de dimensionner l'antenne pour approcher au

mieux cette fréquence sur le VNA (l'énergie réfléchie doit être minimale). Nous avons proportionné l'antenne en

déplaçant le plus grand pic négatif vers la fréquence de 433,8 MHz mesurée préalablement.

Dans un premier temps, nous avons pris une antenne dont la taille est d'une demi-fois la longueur d'onde

cm7010.8,43310.3c 68 (2.1)

Nous avons ensuite enroulé l'antenne autour du corps de la fusée et coupé petit à petit le fils (soudé auparavant sur

un port SMA lui-même relié au port 1 du VNA) jusqu'à décaler vers la droite le pic choisi à 433MHz. Nous avons

également rajouté de la masse autour du connecteur afin d'augmenter la différence de potentiel entre la masse et la

borne plus. A la fin du dimensionnement, nous avons noté un gain de 10dB. En effet, au départ le plus grand pic

se trouvait à 30dB et durant la calibration de l'antenne il est descendu jusqu'à la valeur finale de 40dB.

Figure 2.2. Vue de l’antenne fixée au corps de la fusée Figure 2.3. Vue du VNA et de la mesure de S11

7

Chapitre 3 : Les capteurs

Ce chapitre porte sur les différents capteurs que nous avons placés dans le corps de la fusée.

3.1. Le capteur d’humidité/température DHT11

Le module numérique DHT11 délivre et reçoit un signal

digital sur une entrée/sortie série unique. Ses deux capteurs

analogiques sont une résistance qui détermine le taux

d’humidité et une thermo-résistance de type NTC (Negative

Temperature Coefficient) afin de mesurer la température. La

calibration du module est faite en usine et les paramètres sont

sauvés dans une mémoire OTP (One Time Programming,

comme celle vue en TD de PeiP1 sur les diodes). Le lien

entre l’arduino et les capteurs est assuré par un

microcontrôleur 8 bits. Une communication avec le module

s'effectue sur 40 bits et dure typiquement 4ms. Il coûte

environ 2€ sur eBay.

Figure 3.1. Vue du capteur

d’humidité/température DHT11

Les dimensions du module sans les broches sont de 14 32 8 mm pour une masse de 2 g. Il peut être alimenté

entre 3.5 et 5V. Sa précision et ses caractéristiques de mesures sont :

Humidité de l’air (RH : Relative Humidity) : 20-90 % avec une précision de 4%

Température de l’air : 0-50°C avec une précision de 1°C

La librairie adafruit DHT-sensor-library permet d’utiliser ce module.

3.2. Le capteur de pression barométrique MPL3115A2

3.2.1. Présentation générale

Afin d’évaluer la pression et la température atmosphérique en fonction de

l’altitude durant le vol nous avons recours au capteur MPL3115A2 utilisant

le bus I2C (Inter Integrated Circuit) pour communiquer avec l’arduino. Il

mesure 18mm de longueur, 19mm de largeur et 2mm de profondeur pour

une masse de 1,2g.

Selon la datasheet, il a une gamme de mesure comprise entre 50 et 110kPa

(avec une précision de 1,5Pa) ce qui correspond à une altitude de 10km. Il

donne la température dans la gamme [40 ; + 85 °C] avec une précision de

1 °C. Il coûte environ 12€ sur eBay.

Figure 3.2. Vue de l’altimètre

MPL3115A2

3.2.2. Capteur piezoresistif

Le module MPL311 utilise un capteur MEMS

(MicroElectroMechanical Systems) piezoresistif que l’on

peut observer sur la partie gauche de la figure (3.3).

Des résistances sont intégrées à une membrane posée sur une

cavité et ayant une certaine pression interne. La moindre

pression exercée sur la paroi externe de la membrane induit

une contrainte mécanique sur les résistances qui changent de

valeur. Cette variation permet ainsi de déterminer la pression

qui a été appliquée.

Figure 3.3. Vue du MEMS et du circuit intégré de

l’altimètre MPL3115A2

8

3.2.3. Mise en œuvre du capteur et bus I2C

I2C est un bus de données qui permet de relier un

microprocesseur (ici l’arduino) avec un ou plusieurs

capteurs (dans notre cas le baromètre/thermomètre). Il

nécessite deux fils de communication : SDA (Signal

Data) qui transmet les données et SCL (Signal Clock)

qui transmet un signal d’horloge synchrone.

Sur l’arduino UNO, ces pins correspondent

respectivement aux entrées analogiques A4 et A5 (c.f.

Fig. (3.4)) tandis que sur la MEGA se sont les broches

numériques 20 et 21. Le protocole du bus I2C définit la

succession des différents états possibles sur les lignes

SDA et SCL. Au départ, les deux lignes sont à l’état

haut. Le circuit fait passer la ligne SDA à 0 et le bus

devient occupé. En devenant le maître, le circuit gère le

signal d’horloge et fait passer la ligne SCL à 0.

Figure 3.4. Schéma de câblage de la carte Arduino et

de l’altimètre MPL3115A2

Les échanges de données sur 8 bits peuvent alors commencer sur le principe FIFO (First In First Out). Un bit

d’acquittement ACK doit également être transmis à la ligne SDA pour confirmer que l’esclave s’est bien acquitté

de l’octet qu’il a reçu. Le premier octet représente toujours l’adresse proprement dite de la transmission et son

dernier bit dit "R/W" indique si le maître demande une lecture (0) ou impose une écriture (1) à l’esclave. Toutes ces

étapes sont regroupées sur le chronographe de la figure (3.5).

Figure 3.5. Chronogramme du protocole I2C

3.2.4. La libraire MPL3115A2

L’utilisation de l’altimètre passe par une librairie dédiée à installer dans le logiciel arduino. Voici quelques-unes

des fonctions que nous avons utilisées :

mpl115a2.begin() : initialisation du module de pression

mpl115a2.GetTemperature() : permet d’obtenir la valeur de la température

mpl115a2.getPressure() : permet d’obtenir la valeur de la pression atmosphérique

3.3. Module RTC

A chaque mise sous tension de l’arduino, la carte réinitialise son

module de temps c’est pourquoi nous avons recours à un

module RTC (Real Time Clock) externe permettant de

déterminer des heures absolues. Ce module (c.f. Fig. (3.6))

fournit des informations temporelles en secondes, minutes,

heures, jour, date, mois et année. L’heure est donnée au format

12 ou 24h et il possède une correction automatique des années

bissextiles jusqu’en 2100.

Figure 3.6. Vue du module RTC (Real

Time Clock)

9

Le module de temps contient une puce d’horloge DS1302, une pile bouton CR2032 d’une capacité de 200mAh et

d’une puissance inférieure à 1µW qui permet de sauvegarder l'heure en cas de coupure de courant. Il fonctionne

grâce à un quartz d’une fréquence de 32.768kHz muni lui-même d’une capacité de 6pF. Le circuit doit être

alimenté avec une tension comprise entre 2 et 5.5V et consomme un courant de 300nA. Il mesure 44mm de long

pour 24mm de large. D’autre part, sa plage de fonctionnement s’étend de 40°C à +85°C pour un prix de 6€ sur le

site Hobby Electronic.

Le circuit communique grâce à son unique entrée/sortie (I/O)

série synchrone et possède 31 octets de SRAM (Static Random

Access Memory). Les données peuvent ainsi être transférées

vers et depuis l'horloge ou la RAM à raison de 1 octet à la fois,

ou par rafale de 31 octets. 3 fils sont donc nécessaires pour

échanger avec le DS1302 (cf. Fig.3.7):

CE (RST) contenant une résistance interne de

40kΩ

I/O (DATA) correspondant aux lignes de données

SCLK (Serial Clock) disposant d’une résistance

interne de 40 kΩ

Quartz

CPU

X1 X2

CE

I/O

SCLK

GND

3.3 V

Pile

VCCVCC2

VCC1

DS1302

Figure 3.7. Schéma des connexions du module

RTC

CE donne d'une part accès au registre de décalage, ensemble de bascules synchrones, selon l'adresse ou la

commande passé en paramètre mais aussi le choix de communiquer sur un ou plusieurs octets. Pour entamer le

transfert de données, la ligne CE passe de 0 à 1. SCLK jouant le rôle d’horloge permet de synchroniser le transfert

de données série. Par exemple pour une transmission entre le module RTC et la carte Arduino s'effectuant sur un

octet, l'échange n'a lieu qu'après 8 cycles complets de SCLK. (c. f. Fig (3.8)).

Figure 3.8. Chronogramme du transfert de données

L’implémentation du module d'heure s'effectue au travers de la librairie « DS1032 ». Nous présentons dans ce

paragraphe les fonctions qui nous ont été utiles :

rtc.time() : initialisation du module d'horloge

X.hr : permet d’obtenir l'heure

X.min : permet d’obtenir les minutes

10

X.sec : permet d’obtenir les secondes

X.date : permet d’obtenir la date

X.mon : permet d'obtenir le mois

X.yr : permet d'obtenir l'année

3.4. Le panneau de LED

Figure 3.4.1. Vue du panneau RGB de LED en

fonctionnement

La figure (3.4.1) illustre le panneau utilisé dans ce projet pour l'affichage des informations récoltées par la fusée en

vol. Nous n'avons trouvé qu'une unique librairie fonctionnelle qui permet d'afficher du texte et des géométries

simples comme par exemple des rectangles et des cercles. La superposition de textes sur le panneau implique

d'imposer un écran noir avant de réécrire un autre texte à la même position.

11

Chapitre 4 : Mise en œuvre de l’ensemble des éléments

4.1. Récupération des données des capteurs

Les données stockées dans des variables. En effet, à chaque tour de boucle, l'arduino stocke les données de chaque

capteur dans ces variables du type float (latitude, longitude, altitude, pression, humidité et température) et integer

(date et heure). En raison du nombre important de capteurs et d'entrées/sorties nécessaires, nous avons dû utiliser

une carte Arduino MEGA. Le principal problème rencontré reste néanmoins la synchronisation du GPS avec les

satellites auxquels il doit s’appareiller ainsi que la communication série de la carte qui est de 9600 bits par seconde

et non 4800 comme il est souvent cité dans les exemples pour ce GPS.

4.2. Envoi des données au récepteur RF

A la fin de chaque boucle, la fusée envoie grâce à la carte arduino les données au récepteur. A chaque début d'envoi

le code « 9999 » est envoyé afin d'identifier l'arrivée chronologique des différentes variables. Le module RF envoie

des integer et des float castés en chaînes de caractères.

4.3. Réception des données

La réception des données s'effectue par une deuxième carte arduino MEGA du fait du nombre de variables à traiter

et à stocker dans la mémoire de carte. Initialement, nous avons débuté les tests avec une simple carte arduino UNO

et la réception de 3 variables mais la carte a très vite planté lorsque nous sommes passés à 12 variables. La

condition principale (i.e. « if ») détecte l'arrivée du code « 9999 » ce qui implique le stockage des données avec la

conversion inverse (donc chaîne de caractères vers des float ou des int). Cette étape a été une des plus difficiles car

il a fallu trouver les bonnes fonctions de conversion sachant que certaines étaient proposées mais non compatibles

avec l'IDE. Les données sont affichées sur le moniteur série de l'ordinateur.

4.3. Affichage des informations sur le panneau de LED

Afin de rendre l'affichage un peu plus design et attractif, nous avons fait le choix d'afficher les données sur un

panneau de LED RGB 32*64. Cependant, nous nous sommes très vites aperçus de l'incompatibilité des librairies du

panneau de LED et du module RF. Il a donc fallu utiliser une troisième carte MEGA reliée à la seconde par une

liaison RX/TX. L'envoie des données à ce panneau se fait sur le même principe que celui choisi pour envoyer les

données entre la fusée et la Terre (code « 9999 »). La carte de réception envoie en continu les informations qui ne

sont affichées alternativement par paquets de 3 toutes les 2 secondes. En effet, les données du GPS sont affichées

en premier suivies des données des capteurs de pression, d'humidité et de température.

12

13

Chapitre 5 : Conclusions et perspectives

Le cahier des charges a donc été respecté avec la modification, entreprise à la première séance, de comprendre et

d'utiliser un module GSM pour communiquer avec un téléphone sur la position de la fusée après atterrissage. Nous

avons axé notre travail dans cette partie du projet sur la liaison RF mais le module GSM s'inclut plus largement

dans le projet fusée qui se poursuivra en département électronique à Sophia.

Toutes les difficultés rencontrées ont été surmontées et/ou contournées et proviennent essentiellement des

problèmes de compatibilité de librairies, de conversion de variables et de librairies elles-mêmes.

Nous envisageons de plus d’intégrer les différents capteurs et modules utilisés dans ce projet au futur projet

ExoMars qui débutera en 3ème année du cycle ingénieur à Sophia en spécialité électronique.

14

15

Références

Le capteur d’humidité/température DHT11

Datsheet : www.micropik.com/PDF/dht11.pdf

Librairie : github.com/adafruit/DHT-sensor-library

L'antenne

http://www.bde.enseeiht.fr/clubs/ieee/documents/arv.pdf

http://www.ni.com/white-paper/11640/fr/

http://f6crp.pagesperso-orange.fr/ba/minivna.htm

Le capteur de pression barométrique MPL3115A2

Datasheet : cache.freescale.com/files/sensors/doc/data_sheet/MPL115A2.pdf

Librairie : github.com/adafruit/Adafruit_MPL115A2

Capteur pression piézorésistif : www.microsystems.metu.edu.tr/piezops/piezops.html

16

17

Programme : émission des données

#include <VirtualWire.h> // inclusion de la librairie VirtualWire

//communication RF 433 MHz

#include <Adafruit_MPL115A2.h>//librairie du module de pression atmosphérique

#include <Wire.h>

#include "DHT.h"//librarie du module d'humidité

#include <stdio.h>

#include <DS1302.h>

#include <TinyGPS.h>//librairie du GPS

//fonctions nécessaires à l'utilisation du GPS

TinyGPS gps;

static void smartdelay(unsigned long ms);

//module dhumidité

#define DHTPIN 22//pin de signal

#define DHTTYPE DHT11//instancie le module DHT 11

DHT dht(DHTPIN, DHTTYPE);

//module d'horloge

const int kCePin = 5; // Chip Enable

const int kIoPin = 6; // Input/Output

const int kSclkPin = 7; // Serial Clock

DS1302 rtc(kCePin, kIoPin, kSclkPin);// Create a DS1302 object

Adafruit_MPL115A2 mpl115a2;//capteur de pression

//définition de toutes les variables utilisées pour les mesures

float humidite = 0;

char message_humidite[4];

//taille max de 4 caractères pour la mesure

float pressureKPA = 0;

char message_pressureKPA[4];

float temperatureC = 0;

char message_temperatureC [4];

int heures = 0;

18

char message_heures[4];

int minutes = 0;

char message_minutes[4];

int secondes = 0;

char message_secondes[4];

int jour = 0;

char message_jour[4];

int mois = 0;

char message_mois[4];

int annee = 0;

char message_annee[4];

char *Jsemaine = "HHH";

char *separ = "9999";//séparateur entre chaque salve d'envoi des données

float flat, flon, falt; // latitude, longitude, altitude

char message_flat[10];

char message_flon[10];

char message_falt[10];

unsigned long age; // ne sert que pour la lecture d'une des fonctions du GPS

void setup()

vw_setup(2000); //correspond au nombre de bits par sec pour la communication RF 433 MHz

Serial3.begin(9600); //vitesse de communication du GPS brancher sur le com série n°3

dht.begin();//initialisation du module d'humidité

mpl115a2.begin();//initialisation du module de pression

void loop()

//lecture de différentes mesures et attributions des variables

smartdelay(1000); //attente de la réception de données GPS

gps.f_get_position(&flat, &flon, &age); //lecture latitude, longitude

falt = gps.f_altitude(); // lecture altitude

19

humidite = dht.readHumidity();

temperatureC = mpl115a2.getTemperature();

pressureKPA = mpl115a2.getPressure();

//date et heure

Time X = rtc.time();

heures = X.hr;

minutes = X.min;

secondes = X.sec;

jour = X.date;

mois = X.mon;

annee = X.yr;

// envoi du code "9999" pour la détetcion de l'arrivée des données

vw_send((uint8_t *)separ, strlen(separ));

vw_wait_tx();// attendre jusqu'à ce que le message soit enovyé entièrement

// envoi de la latitude

dtostrf(flat,4,6,message_flat); //largeur mimimale 4, 2 chiffres après la virgule

vw_send((uint8_t *)message_flat, strlen(message_flat));

vw_wait_tx();

// envoi de la longitude

dtostrf(flon,4,6,message_flon); //largeur mimimale 4, 2 chiffres après la virgule

vw_send((uint8_t *)message_flon, strlen(message_flon));

vw_wait_tx();

// envoi de l'altitude

dtostrf(falt,4,6,message_falt); //largeur mimimale 4, 2 chiffres après la virgule

vw_send((uint8_t *)message_falt, strlen(message_falt));

vw_wait_tx();

// envoi du pourcentage d'humidité

dtostrf(humidite,4,2,message_humidite); //largeur mimimale 4, 2 chiffres après la virgule

vw_send((uint8_t *)message_humidite, strlen(message_humidite));

vw_wait_tx();

// envoi de la température

20

dtostrf(temperatureC,4,2,message_temperatureC);

vw_send((uint8_t *)message_temperatureC, strlen(message_temperatureC));

vw_wait_tx();

// envoi de la pression

dtostrf(pressureKPA,4,2,message_pressureKPA);//convertit les float en char

vw_send((uint8_t *)message_pressureKPA, strlen(message_pressureKPA));

vw_wait_tx();

// envoi de l'heure

itoa(heures,message_heures,10);//convertit les int en char

vw_send((uint8_t *)message_heures, strlen(message_heures));

vw_wait_tx();

// envoi des minutes

itoa(minutes,message_minutes,10);

vw_send((uint8_t *)message_minutes, strlen(message_minutes));

vw_wait_tx(); // Wait until the whole message is gone

// envoi des secondes

itoa(secondes,message_secondes,10);

vw_send((uint8_t *)message_secondes, strlen(message_secondes));

vw_wait_tx();

// envoi du jour

itoa(jour,message_jour,10);

//10 signifie que l'on est en base 10 donc en décimal

vw_send((uint8_t *)message_jour, strlen(message_jour));

vw_wait_tx();

// envoi du mois

itoa(mois,message_mois,10);

vw_send((uint8_t *)message_mois, strlen(message_mois));

vw_wait_tx();

// envoi de l'année

itoa(annee,message_annee,10);

vw_send((uint8_t *)message_annee, strlen(message_annee));

vw_wait_tx();

21

delay(2000);

static void smartdelay(unsigned long ms)

unsigned long start = millis();

do

while (Serial3.available())

gps.encode(Serial3.read());

while (millis() - start < ms);

22

23

Programme : réception des données

#include <VirtualWire.h>

// Detection des données

int separ;

char message[VW_MAX_MESSAGE_LEN];

//données GPS

//latitude, longitude, altitude

float flat=1.11, flon=2.22, falt=3.33;

char message_flat[VW_MAX_MESSAGE_LEN];

char message_flon[VW_MAX_MESSAGE_LEN];

char message_falt[VW_MAX_MESSAGE_LEN];

//VW_MAX_MESSAGE_LEN est de 80 par défaut

//nombre maximum de bytes dans le message

// création des variables relatives aux capteurs

float humidite=4.44;

char message_humidite[VW_MAX_MESSAGE_LEN];

float temperatureC;

char message_temperatureC[VW_MAX_MESSAGE_LEN];

float pressureKPA;

char message_pressureKPA[VW_MAX_MESSAGE_LEN];

int heures=0;

char message_heures[VW_MAX_MESSAGE_LEN];

int minutes=0;

char message_minutes[VW_MAX_MESSAGE_LEN];

int secondes=0;

char message_secondes[VW_MAX_MESSAGE_LEN];

int jour=0;

24

char message_jour[VW_MAX_MESSAGE_LEN];

int mois=0;

char message_mois[VW_MAX_MESSAGE_LEN];

int xm=0;

char message_m[VW_MAX_MESSAGE_LEN];

int annee=0;

char message_annee[VW_MAX_MESSAGE_LEN];

void setup()

Serial.begin(9600);

//initialisation de la vitesse de communication dans le moniteur série numéro 1

Serial2.begin(4800);//communication série numéro 2

Serial.println("debut");

vw_set_ptt_inverted(true);

//par défaut le PTT prend la valeur HIGH

//cette fonction permet de forcer la valeur à LOW

//si on lui passe en paramètre true

vw_setup(2000);

vw_rx_start();//début de la réception

void loop()

vw_wait_rx();

uint8_t buf[VW_MAX_MESSAGE_LEN];

uint8_t buflen = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf, &buflen))

//If a message is available

//copies up to buflen octets to buf

int i;

for (i = 0; i < buflen; i++)

message[i] = char(buf[i]);

message [buflen] = '\0';

//pour les problèmes de conversion en char

//conversion du char en int

separ= atoi(message);

25

// on teste si le message reçu correspond à l'envoi d'une série de données

if (separ==9999)

vw_wait_rx_max(200);

uint8_t buf_flat[VW_MAX_MESSAGE_LEN];

uint8_t buflen_flat = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_flat, &buflen_flat))

int i1;

for (i = 0; i < buflen_flat; i++)

message_flat[i] = char(buf_flat[i]);

message_flat[buflen_flat] = '\0';

flat = atof(message_flat);

Serial.print("Latitude : ");

Serial.println(message_flat);

// end if latitude

vw_wait_rx_max(200);

uint8_t buf_flon[VW_MAX_MESSAGE_LEN];

uint8_t buflen_flon = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_flon, &buflen_flon))

int i1;

for (i = 0; i < buflen_flon; i++)

message_flon[i] = char(buf_flon[i]);

message_flon[buflen_flon] = '\0';

flon = atof(message_flon);

Serial.print("Longitude : ");

Serial.println(message_flon);

// end if longitude

vw_wait_rx_max(200);

uint8_t buf_falt[VW_MAX_MESSAGE_LEN];

uint8_t buflen_falt = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_falt, &buflen_falt))

int i1;

for (i = 0; i < buflen_falt; i++)

message_falt[i] = char(buf_falt[i]);

26

message_falt[buflen_falt] = '\0';

falt = atof(message_falt);

Serial.print("Altitude : ");

Serial.println(falt);

// end if altitude

vw_wait_rx_max(200);

uint8_t buf_humidite[VW_MAX_MESSAGE_LEN];

uint8_t buflen_humidite = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_humidite, &buflen_humidite))

int i1;

for (i = 0; i < buflen_humidite; i++)

message_humidite[i] = char(buf_humidite[i]);

message_humidite[buflen_humidite] = '\0';

float humidite = atof(message_humidite);

Serial.print("Humidite : ");

Serial.println(humidite);

// end if humidite

vw_wait_rx_max(200);

uint8_t buf_temperatureC[VW_MAX_MESSAGE_LEN];

uint8_t buflen_temperatureC = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_temperatureC, &buflen_temperatureC))

int i;

for (i = 0; i < buflen_temperatureC; i++)

message_temperatureC[i] = char(buf_temperatureC[i]);

message_temperatureC[buflen_temperatureC] = '\0';

float temperatureC = atof(message_temperatureC);

Serial.print("Temperature : ");

Serial.println(temperatureC);

// end if temperature

vw_wait_rx_max(200);

uint8_t buf_pressureKPA[VW_MAX_MESSAGE_LEN];

uint8_t buflen_pressureKPA = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_pressureKPA, &buflen_pressureKPA))

27

int i1;

for (i1 = 0; i1 < buflen_pressureKPA; i1++)

message_pressureKPA[i1] = char(buf_pressureKPA[i1]);

message_pressureKPA[buflen_pressureKPA] = '\0';

float pressureKPA = atof(message_pressureKPA);

Serial.print("Pression : ");

Serial.println(pressureKPA);

// end if pressureKPA

vw_wait_rx_max(200);

uint8_t buf_heures[VW_MAX_MESSAGE_LEN];

uint8_t buflen_heures = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_heures, &buflen_heures))

int i2;

for (i2 = 0; i2 < buflen_heures; i2++)

message_heures[i2] = char(buf_heures[i2]);

message_heures[buflen_heures] = '\0';

heures = atoi(message_heures);

Serial.print("Heure : ");

Serial.print(heures);

Serial.print(":");

// end if heures

vw_wait_rx_max(200);

uint8_t buf_minutes[VW_MAX_MESSAGE_LEN];

uint8_t buflen_minutes = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_minutes, &buflen_minutes))

int i3;

for (i3 = 0; i3 < buflen_minutes; i3++)

message_minutes[i3] = char(buf_minutes[i3]);

message_minutes[buflen_minutes] = '\0';

minutes = atoi(message_minutes);

Serial.print(minutes);

Serial.print(":");

// end if minutes

28

vw_wait_rx_max(200);

uint8_t buf_secondes[VW_MAX_MESSAGE_LEN];

uint8_t buflen_secondes = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_secondes, &buflen_secondes))

int i4;

for (i4 = 0; i4 < buflen_secondes; i4++)

message_secondes[i4] = char(buf_secondes[i4]);

message_secondes[buflen_secondes] = '\0';

secondes = atoi(message_secondes);

Serial.println(secondes);

// end if secondes

vw_wait_rx_max(200);

uint8_t buf_jour[VW_MAX_MESSAGE_LEN];

uint8_t buflen_jour = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_jour, &buflen_jour))

int i5;

for (i5 = 0; i5 < buflen_jour; i5++)

message_jour[i5] = char(buf_jour[i5]);

message_jour[buflen_jour] = '\0';

jour = atoi(message_jour);

Serial.print("Jour : ");

Serial.print(jour);

Serial.print("/");

// end if jour

vw_wait_rx_max(200);

uint8_t buf_mois[VW_MAX_MESSAGE_LEN];

uint8_t buflen_mois = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_mois, &buflen_mois))

int i6;

for (i6 = 0; i6 < buflen_mois; i6++)

message_mois[i6] = char(buf_mois[i6]);

message_mois[buflen_mois] = '\0';

mois = atoi(message_mois);

Serial.print(mois);

29

Serial.print("/");

// end if mois

vw_wait_rx_max(200);

uint8_t buf_annee[VW_MAX_MESSAGE_LEN];

uint8_t buflen_annee = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf_annee, &buflen_annee))

int i7;

for (i7 = 0; i7 < buflen_annee; i7++)

message_annee[i7] = char(buf_annee[i7]);

message_annee[buflen_annee] = '\0';

annee = atoi(message_annee);

Serial.println(annee);

// end if mois

// end if Separ

Serial.println(" ");

//end if message

Serial2.println(separ);

delay(200);

Serial2.println(flat);

delay(200);

Serial2.println(flon);

delay(200);

Serial2.println(falt);

delay(200);

Serial2.println(message_humidite);

delay(200);

Serial2.println(message_temperatureC);

delay(200);

Serial2.println(message_pressureKPA);

delay(1000);

// end loop

30

31

Programme : affichage des données

#include <Adafruit_GFX.h> // Core graphics library

#include <RGBmatrixPanel.h> // Hardware-specific library

//définition des pins correspondant au panneau de LED

#define OE 9

#define LAT 10

#define CLK 11

#define A A0

#define B A1

#define C A2

#define D A3

//initialisation du panneau de lED

RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, false, 64);

char message[20];

//variable qui va contenir le message du récepteur RF

int separ;

//variable du séparateur

int i=0;

//indice du tableau que l'on lit pour récupérer les données du récepteur

unsigned long temps=0;

//variable qui permet d'attendre un certain temps pour afficher un message

//visible sur le panneau de LED

int vtest=1;

//variable qui permet de différencier la première ou la seconde salve d'affichage des données

//les doonnées GPS pour la première avec vtest=1

//les autres capteurs pour la deuxième avec vtest=2

int ini=0;

//variable qui permet de n'afficher le décompteur qu'une seule fois

int i2=9;//début du décompteur

//création des variables de données

float flat=0.0;//latitude

char message_flat[20];

32

float flon=0.0;//longitude

char message_flon[20];

float falt=0.0;//altitude

char message_falt[20];

float humidite=0.0;//humidité

char message_humidite[20];

float temperature=0.0;//température

char message_temperature[20];

float pression=0.0;//pression

char message_pression[20];

void setup()

matrix.begin(); // initialisation du la matrice de LED

matrix.setTextSize(1); // size 1 == 8 pixels high

matrix.setTextWrap(false);

matrix.setCursor(20, 10); // start at top left, with 8 pixel of spacing

matrix.setTextColor(matrix.Color333(7,7,7));//détermine la couleur d'écriture

matrix.println("SETUP");

Serial2.begin(4800);//initialisation de la vitesse d'écriture sur le port série 2

Serial.begin(9600);

delay(500);

void loop()

if(ini<1)

uint8_t w = 0;

int j=20;

for (i2=9; i2>0; i2--)//boucle du décompteur

for (j=20; j>0; j--) //boucle relative au cercle qui diminue de volume

for (w=0; w<16; w++) //boucle relative au tracé du cercle

matrix.setTextColor(Wheel(w));

matrix.print(i2);//affiche le nombre du décompteur

matrix.setCursor(29,13);

matrix.drawCircle(31,16,j--, matrix.Color333(0, 0, 7));//trace le cercle d'une couleur bleue

delay(30);

matrix.fillScreen(matrix.Color333(0, 0, 0));// fill the screen with black

33

matrix.fillScreen(matrix.Color333(0, 0, 0));

matrix.setTextSize(1);//taille de 8px

matrix.setCursor(25,13);

matrix.print("GO !");//affichage de GO sur le pannel

delay(500);

matrix.fillScreen(matrix.Color333(0, 0, 0));

matrix.setTextSize(2);//grande taille *

matrix.setCursor(15,10);

matrix.print("GO !");

delay(500);

matrix.fillScreen(matrix.Color333(0, 0, 0));

matrix.setTextSize(1);

matrix.setCursor(5,13);

matrix.print("Decollage");//affichage du mot 'Decollage'

matrix.setTextSize(1);

temps=millis();

ini=1;

//fin du décompte pour éviter au prochain passage dans le loop d'afficher de nouveau le décompteur

Serial.println("loop");

if (Serial2.available()>0)

while (Serial2.available()>0)

for (i = 0; i < 20; i++)//tableau initial d'une longeur de 20

message[i] = char(Serial2.read());//lecture des données sur le port série 2

separ= atoi(message);//conversion du message en int

Serial.println(separ);

//---------------------------------------------

if (separ==9999) //si on rencontre le séparateur

delay(200);

if (Serial2.available()>0)

while (Serial2.available()>0)

34

for (i = 0; i < 20; i++)

message_flat[i] = char(Serial2.read());//on ajoute la valeur à la variable de latitude

flat = atof(message_flat);

//end if flat -----------------------------------------------

delay(200);

if (Serial2.available()>0)

while (Serial2.available()>0)

for (i = 0; i < 20; i++)

message_flon[i] = char(Serial2.read());

flon = atof(message_flon);

//end if flon -----------------------------------------------

delay(200);

if (Serial2.available()>0)

while (Serial2.available()>0)

for (i = 0; i < 20; i++)

message_falt[i] = char(Serial2.read());

falt = atof(message_falt);

//end if falt ------------------------------------------------

delay(200);

if (Serial2.available()>0)

while (Serial2.available()>0)

for (i = 0; i < 20; i++)

message_humidite[i] = char(Serial2.read());

humidite = atof(message_humidite);

//end if humidite ---------------------------------------------

delay(200);

if (Serial2.available()>0)

35

while (Serial2.available()>0)

for (i = 0; i < 20; i++)

message_temperature[i] = char(Serial2.read());

temperature = atof(message_temperature);

//end if temperature ------------------------------------------

delay(200);

if (Serial2.available()>0)

while (Serial2.available()>0)

for (i = 0; i < 20; i++)

message_pression[i] = char(Serial2.read());

pression = atof(message_pression);

//end if pression -------------------------------------------

//end if separ

//end if serial2.available()

//affichage des données récupérées sur le terminal

Serial.println(flat);

Serial.println(flon);

Serial.println(falt);

Serial.println(humidite);

Serial.println(temperature);

Serial.println(pression);

delay(100);

if ((millis()>(temps+2000))*(vtest==1))//première salve d'affiche

matrix.fillScreen(matrix.Color333(0, 0, 0));

matrix.setTextColor(matrix.Color333(3,3,3));

matrix.setCursor(0, 0);// start at top left, with 8 pixel of spacing

matrix.println("lat:");//latitude

matrix.setCursor(0, 10);

matrix.println("lon:");//longitude

matrix.setCursor(0, 20);

matrix.println("alt:");//altitude

matrix.setTextColor(matrix.Color333(1,0,5));

36

matrix.setCursor(28, 0);

matrix.println(flat);

matrix.setCursor(28, 10);

matrix.println(flon);

matrix.setCursor(28, 20);

matrix.println(falt);

temps=millis();

vtest=2;//asure de passer à la deuxième salve d'affichage

if ((millis()>(temps+2000))*(vtest==2))//deuxième affichage

matrix.fillScreen(matrix.Color333(0, 0, 0));

matrix.setTextColor(matrix.Color333(3,3,3));

matrix.setCursor(0, 0);// start at top left, with 8 pixel of spacing

matrix.println("hum:");//humidité

matrix.setCursor(0, 10);

matrix.println("tem:");//température

matrix.setCursor(0, 20);

matrix.println("pre:");//pression

matrix.setTextColor(matrix.Color333(1,0,5));

matrix.setCursor(28, 0);

matrix.println(humidite);

matrix.setCursor(28, 10);

matrix.println(temperature);

matrix.setCursor(28, 20);

matrix.println(pression);

temps=millis();

vtest=1;//réaffiche la premère salve de données

// end loop

//fonction qui renvoi un hexadécimal pour tracer un cercle sur le panneau de LED

uint16_t Wheel(byte WheelPos)

if(WheelPos < 8)

return matrix.Color333(7 - WheelPos, WheelPos, 0);

else if(WheelPos < 16)

WheelPos -= 8;

return matrix.Color333(0, 7-WheelPos, WheelPos);

37

else

WheelPos -= 16;

return matrix.Color333(0, WheelPos, 7 - WheelPos);