Programmation en C: Série 4
Exercice 1: Le capteur SHT3x
Les capteurs de température et humidité SHT3x de Sensirion sont très répandus dans l'industrie. Après chaque mesure, ces capteurs nous fournissent 3 valeurs de 2 bytes:
statusH | statusL | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
H | E |
temperatureH | temperatureL | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
· | · | · | · | · | · | · | · | · | · | · | · | · | · | · | · |
humiditeH | humiditeL | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
· | · | · | · | · | · | · | · | · | · | · | · | · | · | · | · |
A l'aide d'un petit programme, on aimerait convertir et afficher ces valeurs. Vous pouvez commencer avec le code suivant:
#include <stdio.h> #include <inttypes.h> int main(int argc, char * argv[]) { // Valeurs venant du capteur uint8_t statusH = 0x90; uint8_t statusL = 0x10; uint8_t temperatureH = 0x58; uint8_t temperatureL = 0xd7; uint8_t humiditeH = 0x81; uint8_t humiditeL = 0xe5; // A. Vérifier le status ... // B. Temperature int temperatureHL = ((int) temperatureH << 8) | temperatureL; // C. Humidité relative // D. Point de rosée return 0; }
A. Vérifier la mesure
Vérifiez que le bit E = 0 (mesure OK, pas d'erreur), et quittez le programme sinon. Affichez si le chauffage du capteur est enclenché (H = 1) ou pas (H = 0).
Vous pouvez utiliser les valeurs suivantes pour tester votre code:
uint8_t statusH = 0xa0; uint8_t statusL = 0x12;
B. Calcul de la température
Calculez et affichez la température selon la formule correspondante à la page 14 du datasheet. Dans cette formule, ST est la valeur 16-bit fourni par le capteur.
C. Calcul de l'humidité relative
Calculez et affichez l'humidité relative selon la formule correspondante à la page 14 du datasheet. Dans cette formule, SRH est la valeur 16-bit fourni par le capteur.
D. Calcul du point de rosée
Calculez et affichez le point de rosée.
#load solutions/capteur.c
Le chauffage est étaint. Temperature: 15.7 °C Humidité: 50.7 % Point de rosée: 5.5 °C
Plusieurs m'ont demandé pourquoi on peut écrire
int temperatureHL = (temperatureH << 8) | temperatureL;
Vu que temperatureH est un entier 8 bit (sans signe), le résultat de temperatureH << 8
devrait être 0. Pourtant, cette ligne fonctionne parfaitement. Visiblement, les opérations << et | sont exécutées sur plus que 8 bits.
Effectivement, C fait une integer promotion ici. Les valeurs temperatureH et temperatureL sont silencieusement converties en int
. Ce qui est exécuté correspond donc à ça:
int temperatureHL = ((int) temperatureH << 8) | (int) temperatureL;
Exercice 2: Terrain
En topographie, on utilise des modèles numériques de terrain (MNT) pour représenter l'altitude. On dispose d'un MNT de la suisse romande et une partie de l'Italie, de la France et de l'Allemagne:
- mnt-suisse-romande (données)
- mnt-suisse-romande.png (visualisation)
Les données ont été acquit par la NASA Space Shuttle Radar Topography Mission (SRTM), et forment un maillage de 2501 sur 3601 points espacés 90 m:
Chaque point du maillage indique l'altitude (de type double) à cet endroit.
Le code suivant peut servir comme point de départ. Il crée un tableau unidimensionnel de 2501 * 3601 cases, et lit le fichier mnt-suisse-romande:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> int main(int argc, char * argv[]) { // Tableau avec les altitudes: 2501 valeurs en x (largeur), 3601 valeurs en y (hauteur) double * altitudes = malloc(2501 * 3601 * sizeof(double)); // Lire les données du fichier "mnt-suisse-romande" et les mettre dans le tableau "altitudes" FILE * fileToRead = fopen("mnt-suisse-romande", "r"); fread(altitudes, sizeof(double), 2501 * 3601, fileToRead); fclose(fileToRead); // L'altitude d'un point (x, y) se trouve dans la case altitudes[y * 2501 + x] // TON CODE // Libérer le tableau free(altitudes); return 0; }
A. Le point le plus haut
Cherchez le point le plus haut, et affichez
- son altitude
- ses coordonnées (x, y) dans le tableau
Vérification
Le point le plus haut se trouve à la position (1555, 1001) avec un altitude de 4679.0 m.
Il s'agit du sommet du Mont Blanc, qui a une altitude de 4810 m. Donc nos données ne sont pas exceptionnelles.
Altitude max 4679.0 m à la position 1555, 1001
B. Interpolation linéaire
Entre les points de mesure, on doit estimer l'altitude à partir des points voisins. Une méthode souvent utilisée est l'interpolation linéaire:
Ecrivez une fonction qui estime et retourne l'altitude d'un point X, Y avec cette méthode. Si le point se trouve en dehors de la carte, le fonction returne NaN comme altitude (return nan("")
).
Vérification
altitude(1555.2, 1001.5) | 4625.700 |
altitude(1554.86 1001.37) | 4662.211 |
altitude(5000.0 1001.5) | NaN |
Altitude au point 1555.200 1001.500 => 4625.700
C. Les sommets

Admettons qu'un point est un sommet ssi dans un voisinage circulaire de 10 cases (voir schéma à droite):
- il n'y a aucune mesure plus élevée
- le point est au moins 100 m plus haut que l'altitude moyenne du voisinage
Ecrivez une fonction qui vérifie si un point (x, y) est un sommet.
Vérification
Le point (1555, 1001) est un sommet (Mont Blanc). Les points autour, comme (1550, 1001), ne sont pas des sommets.
D. Liste des sommets
A l'aide la fonction précédente, affichez une liste des sommets. Vouez pouvez ignorer les 10 cases de chaque coté du terrain où le voisinage dépasse les bords du tableau.
Vérification
Il y a environ 2430 sommets sur notre MNT. Voici quelques positions (x, y):
309 13 1176 15 617 16 ... 1669 3587 1620 3590
Vérification visuelle
Si votre programme affiche la liste des sommets sous le format en haut (un sommet par ligne, valeurs X et Y séparées par une espace), vous pouvez générer une image terrain.png avec vos sommets (petites croix) afin de vérifier votre algorithme.
Pour cela, téléchargez le fichiers suivants:
Compilez le code:
$$ gcc terrain2image.c image.c -lpng -ljpeg -lm -o terrain2image
Sauvegardez la sortie de votre programme dans un fichier sommets:
$$ ./ex4 > sommets
et lancez terrain2image pour générer l'image terrain.png:
$$ ./terrain2image mnt-suisse-romande < sommets Lire les altitudes du fichier 'mnt-suisse-romande' ... Générer le terrain ... Lire les sommets de STDIN ... Ecrire terrain.png ...
309 13 1176 15 617 16 1259 16 617 17 1496 19 1586 20 186 21 1587 21 564 22 ...