- Conception du Circuit Matériel =================================
Pour la surveillance de la tension d'une batterie 12V à l'aide d'un microcontrôleur STM32F405, il est impératif de réduire la tension à un niveau compatible avec l'entrée de son convertisseur analogique-numérique (ADC), typiquement dans la plage 0-3.3V. Ceci est réalisé par l'utilisation d'un pont diviseur de tension, composé de deux résistances, R1 et R2.
Le principe est simple : la tension de la batterie (Vbat) est appliquée aux bornes de R1 et R2. La tension aux bornes de R2 (Vout) est celle qui sera connectée à l'entrée ADC du STM32. La formule du pont diviseur est la suivante :
Vout = Vbat * (R2 / (R1 + R2))
Pour un rapport de division de 4:1 (par exemple, R1 = 300 kΩ et R2 = 100 kΩ), une tension de batterie de 12V sera ramenée à 3V, ce qui est parfaitement dans la plage de fonctionnement de l'ADC du STM32 (qui utilise généralement une référence de 3.3V).
- Implémentation Logicielle ============================
L'acquisition de la tension nécessite la configuration de l'ADC et du GPIO associé, ainsi qu'une logique pour lire les valeurs, les convertir en tension réelle et évaluer l'état de la batterie. Le code suivant est divisé en deux fichiers : un fichier d'en-tête pour les définitions et prototypes, et un fichier source pour l'implémentation.
2.1 Fichier d'en-tête (gestion_adc.h)
Ce fichier définit les constantes essentielles pour la configurtaion de l'ADC, les seuils de tension de la batterie et les paramètres de calibration.
#ifndef DEF_ADC_MESURE_TENSION_H
#define DEF_ADC_MESURE_TENSION_H
#include "stm32f4xx.h"
#include <stdio.h> // Pour printf, si disponible via une interface UART
// Paramètres de configuration ADC
#define CANAL_ADC_BATTERIE ADC_Channel_12 // PC2 correspond au canal ADC1_12
#define TENSION_REFERENCE_ADC 3.3f // Tension de référence ADC (VREF+)
#define VALEUR_MAX_ADC_12BITS 4095.0f // Valeur maximale pour un ADC 12 bits (2^12 - 1)
// Seuils de tension de batterie 12V (à adapter selon le type de batterie)
#define TENSION_PLEINE_BATTERIE 12.6f // Tension maximale considérée "pleine"
#define TENSION_BASSE_CRITIQUE 10.8f // Tension minimale acceptable avant arrêt
#define SEUIL_ALERTE_FAIBLE 11.0f // Seuil d'alerte de tension faible
// Paramètres de calibration pour une lecture précise (à ajuster empiriquement après mesure)
#define ERREUR_OFFSET_COMPENSATION -0.01f // Décalage à ajouter/soustraire
#define FACTEUR_GAIN_AJUSTEMENT 0.999f // Facteur multiplicatif pour ajuster la pente
// Ratio du pont diviseur de tension (ex: R1=300k, R2=100k -> (R1+R2)/R2 = 4.0)
// Cela signifie que la tension mesurée par l'ADC est 1/4 de la tension réelle de la batterie.
#define RATIO_PONT_DIVISEUR 4.0f
// Prototypes des fonctions publiques
void InitialiserADC_Batterie(void);
void GererAcquisitionTension(void);
#endif // DEF_ADC_MESURE_TENSION_H
2.2 Fichier source (gestion_adc.c)
Ce fichier conitent les implémentations des fonctions d'initialisation, de lecture, de conversion et d'évaluation de la tension.
#include "gestion_adc.h"
#include "delay.h" // Assumer l'existence d'une fonction de délai
#include "hal_usart.h" // Assumer l'existence d'une interface UART pour printf
// Prototypes des fonctions statiques (internes au module)
static void ConfigurerADC_Peripherique(void);
static float LireTensionBatterie_Calibree(void);
static void EvaluerEtatBatterie(float tension);
/**
* @brief Initialise le sous-système d'acquisition ADC pour la tension de la batterie.
*/
void InitialiserADC_Batterie(void)
{
ConfigurerADC_Peripherique();
printf("\r\nSystème de surveillance de tension batterie (sans filtrage) prêt.\r\n");
printf("Paramètres de calibration: Offset=%.2fV, Gain=%.4f\r\n", ERREUR_OFFSET_COMPENSATION, FACTEUR_GAIN_AJUSTEMENT);
printf("Démarrage de la surveillance...\r\n\r\n");
}
/**
* @brief Gère la boucle principale d'acquisition et d'affichage de la tension de la batterie.
* Appelée périodiquement dans la boucle principale de l'application.
*/
void GererAcquisitionTension(void)
{
float tension_actuelle;
tension_actuelle = LireTensionBatterie_Calibree();
printf("Tension actuelle: %.2fV", tension_actuelle);
EvaluerEtatBatterie(tension_actuelle);
delay_ms(1000); // Acquisition toutes les secondes pour l'exemple
}
/**
* @brief Configure le périphérique ADC1 et le GPIO associé (PC2) pour l'acquisition analogique.
* @note Utilise le canal PC2 (ADC1_IN12) en mode entrée analogique.
*/
static void ConfigurerADC_Peripherique(void)
{
ADC_InitTypeDef ADC_StructureInit;
GPIO_InitTypeDef GPIO_StructureInit;
// 1. Activation des horloges pour le port GPIO C et le périphérique ADC1
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 2. Configuration du pin PC2 en mode entrée analogique (sans pull-up/pull-down)
GPIO_StructureInit.GPIO_Pin = GPIO_Pin_2;
GPIO_StructureInit.GPIO_Mode = GPIO_Mode_AN;
GPIO_StructureInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_StructureInit);
// 3. Configuration de base de l'ADC1
ADC_StructureInit.ADC_Resolution = ADC_Resolution_12b; // Résolution 12 bits
ADC_StructureInit.ADC_ScanConvMode = DISABLE; // Mode non-scan (un seul canal à convertir)
ADC_StructureInit.ADC_ContinuousConvMode = DISABLE; // Mode de conversion unique (non continu)
ADC_StructureInit.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // Pas de déclenchement externe
ADC_StructureInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; // Optionnel, non utilisé ici
ADC_StructureInit.ADC_DataAlign = ADC_DataAlign_Right; // Alignement des données à droite
ADC_StructureInit.ADC_NbrOfConversion = 1; // Une seule conversion par séquence
ADC_Init(ADC1, &ADC_StructureInit);
// 4. Configuration du canal ADC régulier (canal 12 pour PC2)
// ADC1, Canal 12, Séquence 1, Temps d'échantillonnage de 480 cycles (adapté pour sources à impédance élevée)
ADC_RegularChannelConfig(ADC1, CANAL_ADC_BATTERIE, 1, ADC_SampleTime_480Cycles);
// 5. Activation du périphérique ADC1
ADC_Cmd(ADC1, ENABLE);
printf("Configuration ADC terminée!\r\n");
}
/**
* @brief Effectue une conversion ADC, applique les facteurs de division et de calibration,
* et retourne la tension réelle de la batterie.
* @retval Tension de la batterie en Volts, après calibration.
*/
static float LireTensionBatterie_Calibree(void)
{
// 1. Lancement d'une conversion ADC logicielle
ADC_SoftwareStartConv(ADC1);
// 2. Attente active de la fin de la conversion (flag End Of Conversion)
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 3. Lecture de la valeur numérique brute convertie par l'ADC
uint16_t valeur_brute_adc = ADC_GetConversionValue(ADC1);
// 4. Calcul de la tension au point de mesure de l'ADC (après le pont diviseur)
// Conversion de la valeur brute en tension réelle mesurée par l'ADC
float tension_divisee = (float)valeur_brute_adc * TENSION_REFERENCE_ADC / VALEUR_MAX_ADC_12BITS;
// 5. Rétablissement de la tension réelle de la batterie avant le pont diviseur
// Application du ratio du pont diviseur pour obtenir la tension réelle de la batterie
float tension_non_calibree = tension_divisee * RATIO_PONT_DIVISEUR;
// 6. Application des paramètres de calibration de précision (offset et gain)
// Ces paramètres compensent les imprécisions du hardware et du diviseur.
return tension_non_calibree * FACTEUR_GAIN_AJUSTEMENT + ERREUR_OFFSET_COMPENSATION;
}
/**
* @brief Évalue la tension actuelle de la batterie et affiche son état correspondant.
* @param tension La tension actuelle mesurée de la batterie en Volts.
*/
static void EvaluerEtatBatterie(float tension)
{
if(tension > TENSION_PLEINE_BATTERIE * 1.02f) { // Marge pour un dépassement "impossible"
printf(" [Dépassement de gamme]\r\n");
}
else if(tension >= TENSION_PLEINE_BATTERIE) {
printf(" [Pleine charge]\r\n");
}
else if(tension <= TENSION_BASSE_CRITIQUE) {
printf(" [Niveau critique]\r\n");
}
else if(tension < SEUIL_ALERTE_FAIBLE) {
printf(" [Faible]\r\n");
}
else {
printf(" [Normale]\r\n");
}
}