Fonctionnalités requises
Pilotage GPIO pour l'allumage de LED, détection de boutons, polling non-bloquant, communication série, gestion de l'écran LCD, capteurs de température/humidité, ADC, module RTC, capteur de fréquence cardiaque, accéléromètre.
Architecture du projet
L'architecture logicielle est organisée en bibliothèques (lib), le dossier projet généré automatiquement, les fichiers de démarrage (startup), le code utilisateur (user contenant main.c et main.h) et les fichiers d'interface (api). Le type de puce utilisé est le STM32F103ZET6. Trois approches de développement sont possibles : la manipulation directe des registres, l'utilisation de la bibliothèque standard (mature mais non mise à jour) ou l'utilisation de la HAL (développement graphique).
Contrôle d'une LED via GPIO
Le premier exercice consiste à piloter une LED. En étudiant le schéma, on identifie que la LED1 verte est connectée au port PE2. Le GPIO se configure dans un des huit modes possibles. Pour allumer la LED, on utilise le mode de sortie Push-Pull. L'étape de configuration est la suivante :
- Activer l'horloge du périphérique GPIOE via le registre RCC.
- Définir la structure de configuration du GPIO en choisissant le mode Push-Pull, le pin correspondant (Pin_2) et la vitesse.
- Initialiser le GPIO avec ces paramètres.
Ensuite, on peut contrôler la LED en modifiant l'état de la sortie. Par exemple, pour alumer la LED (active à l'état bas) :
GPIO_WriteBit(GPIOE, GPIO_Pin_2, Bit_RESET);
Pour plus de commodité, on définit des macros :
#define LED1_ON GPIO_WriteBit(GPIOE, GPIO_Pin_2, Bit_RESET)
#define LED1_OFF GPIO_WriteBit(GPIOE, GPIO_Pin_2, Bit_SET)
Fonctions de temporisation
La temporisation basique peut être réalisée avec des fonctions vides (__nop). Pour une fréquence de 72 MHz, environ 72 instructions __nop sont nécessaires pour un délai d'une microseconde.
void Delai_us(uint32_t duree) {
while(duree--) {
// Boucle d'instructions NOP pour environ 1us
for(volatile int i=0; i<72; i++) {
__NOP();
}
}
}
void Delai_ms(uint32_t duree) {
while(duree--) {
Delai_us(1000);
}
}
Une méthode plus précise utilise les timers matériels, qui seront abordés ultérieurement.
Détection des boutons
Quatre boutons sont disponibles sur la carte. Leur initialisation nécessite de configurer les GPIO correspondants (PA0, PC4, PC5, PC6) en mode Entrée Flottante. La fonction de détection intègre une temporisation anti-rebond :
uint8_t Verifier_Bouton(void) {
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1) {
Delai_ms(15); // Anti-rebond
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1) {
while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1); // Attente du relâchement
return 1; // Appui confirmé
}
}
return 0; // Pas d'appui
}
Inversion d'état d'une LED par registre
Pour basculer l'état d'une LED avec un seul bouton, on utilise l'opérateur XOR sur le registre de données de sortie (ODR). Le code ci-dessous inverse l'état du bit correspondant au pin PE2 (bit 2) sans affecter les autres bits du port.
GPIOE->ODR ^= (0x1 << 2);
Explication : 0x1 << 2 crée un masque (0b00000100). L'opérateur XOR (^=) avec ce masque inverse le bit cible : si le bit était à 0, il passe à 1, et inversement.