TP02 - Opérateurs de comparaison, opérateurs sur bits, structures conditionnelles, affichage en hexadécimal
📊 Partie 1 – Structures conditionnelles et opérateurs de comparaison⚓︎
Structures contionnelles
En langage C, les structures conditionnelles permettent de tester des situations et d'exécuter du code en conséquence.
Code
Exemple :⚓︎
Code
// Vérifie si le nombre est positif
if (nombre > 0) {
printf("Le nombre est positif.\n");
}
// Sinon, vérifie si le nombre est négatif
else if (nombre < 0) {
printf("Le nombre est négatif.\n");
}
// Si aucune des conditions ci-dessus n'est vraie, le nombre est nul
else {
printf("Le nombre est nul.\n");
}
Opérateurs de comparaison
| Symbole | Signification |
|---|---|
== |
égal à |
!= |
différent de |
< |
strictement inférieur |
<= |
inférieur ou égal |
> |
strictement supérieur |
>= |
supérieur ou égal |
Exercice 1
🎯 Objectif pédagogique : utiliser if - else et les opérateurs de comparaison
- Ouvrir le dossier langage_C dans VS Code
- Créer un dossier tp02 dans le dossier tps
- Créer le fichier tp02_partie_1-2.c ⚠️ ne pas oublier l'extension .c
- Ecrire un programme pour saisir les variables
tempEau1ettempEau2(float) et afficher laquelle des deux est la plus chaude. - Faire de même avec
tempZone1ettempZone2.
✔ Partie 2 – Tests de fonctionnement⚓︎
Exercice 2
Info
Pour cet exercice, copier-coller le code final du tp01 (ou copier-coller la correction donnée plus bas)
🎯 Objectif pédagogique : utiliser if - else, les opérateurs de comparaison et réaliser un affichage clair
✅ Tests à réaliser⚓︎
- Les résultats des tests seront stocker dans les variables :
tempEauStable,tempZonesStable,pressionNormale,debitOk,sondeDefaut,alerteSysteme. Choisir le type adapté pour minimiser la taille en mémoire. -
On leur assignera la valeur 1 si le test est valide, 0 dans le cas contraire.
-
tempEauStable: La température de l'eau est considéré comme stable (Etat logique 1) si :- l'écart de température des eaux de refroidissement est inférieur à 0.4 °C
- ET que la température de l'eau 1 est inférieure à 15 °C
- ET que la température de la zone 2 est inférieure à 15 °C
-
tempZonesStable: La température des zones est considéré comme stable (Etat logique 1) si :- l'écart de température des zones est inférieur à 1 °C
- ET que la température de la zone 1 est supérieure ou égale à 20 °C et inférieur à 25 °C
- ET que la température de la zone 2 est supérieure ou égale à 20 °C et inférieur à 25 °C
-
pressionNormale: La pression est considérée comme normale (Etat logique 1) si elle est supérieure à 100 hPa. -
debitOk: Le débit est correct (Etat logique 1) s’il est compris entre 200 et 300 litres par minute (inclus). -
sondeDefaut: La sonde est considérée comme en défaut de vérification périodique (Etat logique 1) si son identifiant est pair (divisible par 2). -
alerteSysteme: Une alerte est déclenchée si au moins une des conditions suivantes est vraie :- Température eaux instable
- Température zones instable
- Pression anormale
- Débit hors norme
- Sonde défectueuse
-
🖨️ Affichage attendu
Affichez un rapport clair à l'écran :
-----------------------------------------------------
🔍 DIAGNOSTIC DU SYSTÈME SENTINEL
-----------------------------------------------------
🔢 Numéro prochain diagnostic : 235
🆔 Sonde ID : 17
🆔 Numéro sonde pair : 0
📁 Chemin log : 'C:\logs\rapport.txt'
🌡️ Temp. eau 1 : 13.86 °C
🌡️ Temp. eau 2 : 14.12 °C
📊 Ecart temp. eau : 0.26 °C
🌡️ Temp. zone 1 : 23.7 °C
🌡️ Temp. zone 2 : 23.4 °C
📊 Ecart temp. zone : 0.3 °C
🧪 Pression circuit : 11200 Pa
🚿 Débit : 280 L/min
🚿 Niveau de débit : 93.33 %
[Température eaux stable] : 1
[Température zones stable] : 1
[Pression normale] : 1
[Débit correct] : 1
[Défaut Sonde] : 0
-----------------------------------------------------
🛑 Alerte système : 0
Corrigé du tp01
#include <stdio.h>
#include <math.h> // Pour la fonction fabs
// icônes pour affichage (à insérer comme un caractère)
// 🌡️📊🧪🚿🆔📁🔍🛑
int main() {
// Variables de saisie
float tempEau1, tempEau2, tempZone1, tempZone2;
unsigned int pression, debit;
char cheminLog[50]; // Chemin du fichier de log, max 49 caractères + 1 pour le '\0'
unsigned short idSonde, numDiag;
// Saisie
printf("🌡️ Entrer la température de l'eau du circuit 1 (°C) : ");
scanf("%f", &tempEau1);
printf("🌡️ Entrer la température de l'eau du circuit 2 (°C) : ");
scanf("%f", &tempEau2);
printf("🌡️ Entrer la température de la zone 1 (°C) : ");
scanf("%f", &tempZone1);
printf("🌡️ Entrer la température de la zone 2 (°C) : ");
scanf("%f", &tempZone2);
printf("🧪 Entrer la pression du circuit (hPa) : ");
scanf("%d", &pression);
printf("🚿 Entrer le débit mesuré (L/min) : ");
scanf("%d", &debit);
printf("🔢 Entrer le numéro de diagnostic : ");
scanf("%hd", &numDiag);
printf("🆔 Entrer l'identifiant de la sonde : ");
scanf("%hd", &idSonde);
printf("📁 Chemin du fichier de log (sans espace, max 99 caractères) : ");
scanf(" %99s", cheminLog); // Espace avant %s pour ignorer les retours à la ligne
// Calcul de la température moyenne des eaux de refroidissement
float tempMoyenneEaux = (tempEau1 + tempEau2) / 2.0;
// Calcul de la température moyenne des zones
float tempMoyenneZones = (tempZone1 + tempZone2) / 2.0;
// Calcul de l'écart de température des eaux
float ecartTempEaux = fabsf(tempEau1 - tempEau2);
// Calcul de l'écart de température des zones
float ecartTempZones = fabsf(tempZone1 - tempZone2);
// Conversion de la pression en Pa
unsigned int pressionConvertie = pression * 100;
// Calcul du niveau de débit en %
unsigned int debitNiveau = (debit * 100) / 300;
// Incrémentation du numéro de diagnostic
numDiag++;
// parité de l'identifiant de la sonde
// == compare l'égalité des 2 valeurs de chaque de l'opérateur
// si idSonde % 2 = 0 alors idSonde % 2 == 0 sera égale à 1 donc idSonde est un nombre pair
// si idSonde % 2 = 1 alors idSonde % 2 == 0 sera égale à 0 donc idSonde est un nombre impair
// Ici, on utilise un unsigned char pour stocker la parité de l'identifiant de la sonde
unsigned char pair = (idSonde % 2 == 0);
// Affichage formaté
printf("\n-----------------------------------------------------\n");
printf(" 🔍 DIAGNOSTIC DU SYSTÈME SENTINEL\n");
printf("-----------------------------------------------------\n");
printf("\n🔢 Numéro prochain diagnostic : %u\n", numDiag);
printf("\n🆔 Sonde ID : %u\n", idSonde);
printf("🆔 Parité sonde : %hhu\n", pair);
printf("\n📁 Chemin log : %s\n", cheminLog);
printf("\n🌡️ Temp. eau circuit 1 : %.2f °C\n", tempEau1);
printf("🌡️ Temp. eau circuit 2 : %.2f °C\n", tempEau2);
printf("🌡️ Temp. moyenne des eaux : %.2f °C\n", tempMoyenneEaux);
printf("📊 Écart temp. eaux : %.2f °C\n", ecartTempEaux);
printf("\n🌡️ Temp. zone 1 : %.2f °C\n", tempZone1);
printf("🌡️ Temp. zone 2 : %.2f °C\n", tempZone2);
printf("🌡️ Temp. moyenne des zones : %.2f °C\n", tempMoyenneZones);
printf("📊 Écart temp. zones : %.2f °C\n", ecartTempZones);
printf("\n🧪 Pression circuit : %d Pa\n", pressionConvertie);
printf("🚿 Débit : %d L/min\n", debit);
printf("🚿 Niveau de débit : %d %%\n", debitNiveau);
return 0;
}
🔁 Partie 3 – Opérateurs sur bits⚓︎
Opérateurs sur bits
| Opérateur | Nom | Action |
|---|---|---|
& |
ET bit à bit | Garde les bits communs |
| |
OU bit à bit | Active les bits présents dans au moins un opérande |
^ |
OU exclusif | Active les bits différents |
~ |
NON bit à bit | Inverse tous les bits |
<< |
Décalage gauche | Multiplie par \(2^n\) |
>> |
Décalage droit | Divise par \(2^n\) |
Warning
Attention à ne pas confondre les opérateurs de manipulation des bits « et » (&) et « ou inclusif » (|) avec leurs homologues « et » (&&) et « ou » (||) logiques. Il s’agit d’opérateurs totalement différents au même titre que les opérateurs d’affectation (=) et d’égalité (==). De même, l’opérateur de manipulation des bits « et » (&) n’a pas de rapport avec l’opérateur d’adressage (&), ce dernier n’utilisant qu’un opérande.
Les opérateurs « et », « ou inclusif » et « ou exclusif »⚓︎
Chacun de ces trois opérateurs attend deux opérandes entiers et produit un nouvel entier en appliquant une table de vérité à chaque paire de bits formée à partir des bits des deux nombres de départs. Plus précisément :
- L’opérateur « et » (
&) donnera 1 si les deux bits de la paire sont à 1 ; - L’opérateur « ou inclusif » (
|) donnera 1 si au moins un des deux bits de la paire est à 1 ; - L’opérateur « ou exclusif » (
^) donnera 1 si un seul des deux bits de la paire est à 1.
Ceci est résumé dans le tableau ci-dessous, donnant le résultat des trois opérateurs pour chaque paire de bits possible.
| Bit 1 | Bit 2 | Opérateur « et » | Opérateur « ou inclusif » | Opérateur « ou exclusif » |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
🔹 & – ET bit à bit Exemple :
Code
Intérêt : - Sert à tester si un bit est actif sans toucher aux autres
🔹 | – OU bit à bit Exemple :
Code
Intérêt : - Permet d’ajouter un état sans effacer les autres
🔹 ^ – OU exclusif (XOR) Exemple :
Code
Intérêt : - Sert à basculer des bits (inversion sélective) - Peut être utilisé pour comparer deux octets et détecter les différences
🔹 ~ – NON bit à bit (inversion) Exemple :
Intérêt : - Inversion totale de tous les bits
L’exemple ci-dessous utilise ces quatre opérateurs. Les bits des deux opérandes sont pris un à un pour former des paires et chacune d’elle se voit appliquer la table de vérité correspondante afin de produire un nouveau nombre entier.
Code
#include <stdio.h>
int main()
{
int a = 0x63; // 0x63 = 99 = 0110 0011
int b = 0x2A; // 0x2A = 42 = 0010 1010
// 0110 0011 & 0010 1010 = 0010 0010 = 0x22 = 34
printf("%02X\n", a & b);
// 0110 0011 | 0010 1010 = 0110 1011 = 0x6B = 107
printf("%02X\n", a | b);
// 0110 0011 ^ 0010 1010 = 0100 1001 = 0x49 = 73
printf("%02X\n", a ^ b);
// ~(0110 0011) = 1001 1100 = 0x9C = 156
printf("%02X\n", ~a);
return 0;
}
Sortie
22
6B
49
9C
Afficher une valeur en hexadécimal
%Xou%x: lettres capitales ou minuscules- Utiliser
0xen préfixe pour clarifier
- le format %x Une donnée entière affichée en héxadécimal (ff, par exemple).
- le format %X Une donnée entière affichée en héxadécimal et en majuscules (FF, par exemple).
- Le « 02 » devant X demande à
printf()de toujours afficher deux chiffres hexadécimaux. Si la valeur à afficher est inférieure à 10 (en hexadécimal), un zéro sera placé devant.
(crédits : zestedesavoir.com)
🧩 Création d’un module de lecture d’état
📘 Contexte global⚓︎
Dans le cadre du système Sentinel, vous avez précédemment réalisé un outil de diagnostic initial (tp01 et tp02) capable de lire et afficher des valeurs physiques comme :
- température de l’eau de refroidissement
- température des salles serveurs
- pression des circuits
- débit d’eau
- numéro de la sonde, etc.
🛠️ Mission : concevoir un module complémentaire, plus bas niveau⚓︎
Ce nouveau programme agira comme un outil de traitement système :
- Il récupère les données du diagnostic principal (transmises en mémoire ou par fichier)
- Il exploite un octet d’état (
statut) dans lequel sont stockés des signaux binaires internes, comme l’état de certains équipements (ventilateurs, sondes…) - Il permet au centre de supervision de lire, activer ou désactiver certains bits de contrôle, sans modifier les autres
🔢 L’octet de statut⚓︎
L’octet de type unsigned char nommé statut regroupe 8 indicateurs binaires.
Chaque bit représente un état ou un ordre.
| Bit n° | Valeur binaire | État ou commande |
|---|---|---|
| 0 | 0b00000001 |
Ventilateur actif |
| 1 | 0b00000010 |
Sonde en veille |
| 2 | 0b00000100 |
Refroidissement forcé |
| 3 | 0b00001000 |
Mode maintenance |
| 4 | 0b00010000 |
Alerte température critique |
| 5 | 0b00100000 |
Niveau d’eau bas |
| 6 | 0b01000000 |
Surveillance désactivée |
| 7 | 0b10000000 |
Urgence : arrêt immédiat requis |
- Cet octet peut contenir plusieurs états actifs à la fois (par exemple, bits 0, 2 et 4 peuvent être à 1 en même temps).
🔧 Objectif de l’activité⚓︎
Vous allez :
- Lire un état binaire (ex. : est-ce que le ventilateur est allumé ?)
- Activer un état : déclencher un refroidissement forcé
- Désactiver un état : sortir une sonde de la veille
- Fusionner plusieurs états pour créer un statut global
🎓 Pourquoi faire cela ?⚓︎
Ce type de manipulation est fréquent en embarqué et supervision :
un seul octet peut stocker 8 informations booléennes, ce qui est :
- rapide à traiter
- peu coûteux en mémoire
- facile à transmettre en communication réseau
Exercice 3
🎯 Objectif pédagogique : lire un état booléen stocké dans un bit précis (bit 0)
Contexte : Le bit 0 correspond à l’état du ventilateur.
Si ce bit est actif (=1), alors le ventilateur est allumé.
📝 Commencer par créer un fichier tp02_module_statut.c
🔣 traduire en langage C et testé l'algorithme suivant : Il faut déterminer quel opérateur sur bits utiliser.
Algo
Définir une variable statut contenant l'octet de statut : 00001011 (en binaire)
Définir un masque `masqueVentilActif` avec le bit 0 activé : 00000001
SI (bit 0 de statut est actif) ALORS // c'est ici qu'il faut utiliser un opérateur sur bits
Afficher "Ventilateur actif"
SINON
Afficher "Ventilateur inactif"
FIN SI
Exercice 4
🎯 Objectif : activer un bit spécifique sans modifier les autres
Contexte : Le bit 2 est associé à un mode spécial : refroidissement forcé
Le système doit pouvoir activer ce bit à la demande, sans perturber les autres états.
🔣 traduire en langage C et testé l'algorithme suivant :
Algo
// inutile de redéfinir l'octet statut, il a été défini dans le code de l'exercice 3
Définir un masque `masqueForceFroid` approprié
Mettre à jour la variable statut (réafectation) avec le résultat de l'opération sur bit choisie
Afficher le nouveau contenu de statut en hexadécimal (voir le code exemple des opératurs sur bits 🔝)
Tip
Pour vérifier le résultat, il faut convertir la valeur hexadécimale en binaire.
Exercice 5
🎯 Objectif : désactiver un bit sans toucher aux autres
Contexte : Le bit 1 correspond à l'état "sonde en veille". Lors d’un réveil système, ce bit doit être désactivé (=0).
🔣 traduire en langage C et testé l'algorithme suivant :
Algo
// inutile de redéfinir l'octet statut, il a été mise à jour dans le code de l'exercice 4
Définir un masque `masqueReveilSonde` approprié
Mettre à jour la variable statut avec le résultat de l'opération sur bit choisie
Afficher le nouveau contenu de statut en hexadécimal (voir le code exemple des opérateurs sur bits 🔝)
Tip
Si vous n'avez pas utilisé l'opérateur ~, trouvez une autre solution dans laquelle il est utilisé.
Aide : Il faut redéfinir le masque.
Attention à la valeur de statut si vous l'avez modifié dans votre première solution.