Files

706 lines
42 KiB
C

//**********************************************************************************************************************************************************************************
// Fichier BATTERIES.C
//
// Contient toutes les fonctions liées aux batteries de ShipHeart
//**********************************************************************************************************************************************************************************/
//#define __DEBUG_BATTERIES
// Includes :
#include "main.h"
// Prototypes :
int8_t init_batteries(void);
void gestion_batteries(void);
int16_t batterie_cle_primaire(uint16_t cle_primaire);
int16_t variable_batterie_cle_primaire(uint16_t cle_primaire);
// Variables globales :
struct Struct_batteries batteries;
/**********************************************************************************************************************************************************************************
Fonction : Initialise les différents paramètres des batteries au démarrage de l'application
Reçoit : Rien
Retour : -1 si erreur, 0 sinon.
**********************************************************************************************************************************************************************************/
int8_t init_batteries(void)
{
//------------------------------------------------------------------------------------------------------
// Init des variables générales :
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_INIT;
batteries.sequenceur.compteur = BATTERIES_TEMPO_INIT;
// Affichage du message de débug :
affichage_debug(__FILE__, __LINE__, "Initialisation des batteries\t: OK", TYPE_MESSAGE_DEBUG_OK);
return(0);
}
/**********************************************************************************************************************************************************************************
Fonction : Fonction de plus haut niveau de gestion batteries
Reçoit : Rien
Retour : Rien
**********************************************************************************************************************************************************************************/
void gestion_batteries(void)
{
uint16_t i, j;
float soc;
float tension_a_vide;
float resistance_interne;
float efficacite;
float delta_energie;
float capacite_reelle;
float duree_decharge_corrigee;
float courant_differentiel_corrige;
bool flag_erreur;
char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG];
if (!systeme.flag_cm3p_ready) return; // Evite que le traitement soit fait au milieu d'une reconfiguration...
switch(batteries.sequenceur.etat)
{
//--------------------------------------------------------
case ETAT_SEQUENCEUR_BATTERIES_INIT :
{
if ((systeme.flag_cm3p_ready) && // Permet de s'assurer que le cycle d'init système est terminé. En particulier, on est sûr que 'init_bdd()' puis 'annuaire_k_bus()' ont été traités.
(batteries.sequenceur.compteur == 0))
{
affichage_debug(__FILE__, __LINE__, "------------------BATTEREIES INIT", TYPE_MESSAGE_DEBUG_WARNING);
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_REPOS;
}
break;
}
//--------------------------------------------------------
case ETAT_SEQUENCEUR_BATTERIES_REPOS :
{
if (batteries.sequenceur.compteur == 0)
{
batteries.sequenceur.compteur = BATTERIES_PERIODE_MESURES;
#ifdef __DEBUG_BATTERIES
batteries.sequenceur.compteur = 10;
// Valeur passée de 300ms à 1s pour les tests (cf batteries.h)
#endif
for (i = 0; i < batteries.nb; i ++)
{
if (batteries.batteries[i].flag_validite == FALSE) continue;
flag_erreur = FALSE;
// Acquisition des dernières valeurs et mémorisation du nouveau niveau :
switch(batteries.batteries[i].type_entrees)
{
//--------------------------------------------------------------------------
case TYPE_ENTREES_VOLTAGE :
{
// Récupération de l'état de l'entrées Voltage configurée sur cette batterie et calcul de la nouvelle moyenne de tension à partir de l'ancienne et de la valeur lue :
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante = (((batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (batteries.batteries[i].tension_coeff_filtrage - 1))) + entrees.volt.entrees[batteries.batteries[i].no_entrees].valeur) / batteries.batteries[i].tension_coeff_filtrage;
break;
}
//--------------------------------------------------------------------------
case TYPE_ENTREES_PREDEFINIES :
{
// Récupération de l'état de l'entrées Prédéfinie configurée sur cette batterie et calcul de la nouvelle moyenne de tension à partir de l'ancienne et de la valeur lue :
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante = (((batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (batteries.batteries[i].tension_coeff_filtrage - 1))) + entrees.predefinies.entrees[batteries.batteries[i].no_entrees].valeur) / batteries.batteries[i].tension_coeff_filtrage;
break;
}
//--------------------------------------------------------------------------
case TYPE_ENTREES_IBS :
{
break;
}
default :
{
sprintf(tmp, "Le 'Type_entrées' de la batterie #%i est invalide [%i]. La batterie est dévalidée", (i+1), batteries.batteries[i].type_entrees);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
batteries.batteries[i].flag_validite = FALSE;
flag_erreur = TRUE;
break;
}
}
// Traitement :
if (flag_erreur == FALSE)
{
//-------------------------------------
// Tension :
//-------------------------------------
// Calcul de l'impact de Gain_tension sur la tension courante :
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante *= batteries.batteries[i].tension_gain;
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante;
//-------------------------------------
// Courant de décharge :
//-------------------------------------
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante = 0;
for (j = 0; j < circuits.nb; j ++)
{
if (! circuits.circuits[j].flag_validite) continue;
if (circuits.circuits[j].id_batterie != batteries.batteries[i].cle_primaire) continue;
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante -= circuits.circuits[j].variables[CIRCUIT_VARIABLE_COURANT].valeur_courante; // Cumul du courant dans chaque circuit. En négatif car le courant de chaque circuit est comptabilisé de façon positive alors que le courant de décharge est forcément négatif.
}
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
//-------------------------------------
// Puissance :
//-------------------------------------
// SDIR #199 : suppression du (-1) dans le produit (tension x courant) afin de laisser la puissance consommée toujours négative :
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante = batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante;
//================================================
// Entrée de type Entrée Prédéfinie ou Voltage :
//================================================
if (batteries.batteries[i].type_entrees != TYPE_ENTREES_IBS)
{
//-------------------------------------
// SOC :
//-------------------------------------
// Calcul du SOC :
soc = calcul_niveau(batteries.batteries[i].points_tension_soc, MAX_NOMBRE_POINTS_TENSION_SOC_BATTERIE, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante);
if (soc >= 0) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = soc;
else
{
sprintf(tmp, "Erreur de calcul de SOC de la batterie #%i avec tension=%.3fV. La valeur lue n'est pas exploitée.\n", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
}
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
//-------------------------------------
// Mise à jour BDD :
//-------------------------------------
// Mise à jour dans la BDD si les valeurs ont suffisemment évolué :
// if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TENSION].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DECHARGE].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOC].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_PUISSANCE].marge))
if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) > 0))
{
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
/*#ifdef __DEBUG_BATTERIES
sprintf(tmp, "Batterie #%i : Tension = %.3fV, courant de décharge = %.3fA (donc puissance = %.3fW) et SOC = %.2f%% (coeff filtrage tension = %i)",
i, batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante,
(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante * (-1) * batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante),
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante,
batteries.batteries[i].tension_coeff_filtrage);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
*/
}
//================================================
// Entrée de type IBS :
//================================================
else
{
//-------------------------------------
// Température :
//-------------------------------------
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante;
//-------------------------------------
// Courant différentiel :
//-------------------------------------
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante;
//-------------------------------------
// Calcul du courant de charge :
//-------------------------------------
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante = batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante;
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante < 0) // Normalement, impossible car cela induirait un courantd e charge négatif...
{
#ifdef __DEBUG_BATTERIES
// sprintf(tmp, "Batterie #%i : Le courant de charge est calculé avec une valeur négative [%.3f A], ce qui n'est pas possible. Il est ramené à 0 mA", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante);
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
#endif
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante = 0; // Par défaut, on écrête...
}
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante;
//-------------------------------------
// Calcul du SOC :
//-------------------------------------
// Calcul de la résistance interne en fonction de la température :
resistance_interne = calcul_niveau(batteries.batteries[i].points_temperature_resistance_interne, MAX_NOMBRE_POINTS_TEMPERATURE_RESISTANCE_INTERNE_BATTERIE, batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante);
if (resistance_interne != -1) resistance_interne = resistance_interne * batteries.batteries[i].resistance_interne / 1000; // Le '/1000' permet de passer de valeurs de résistance interne en mOhms à Ohms.
else resistance_interne = batteries.batteries[i].resistance_interne / 1000; // Le '/1000' permet de passer de valeurs de résistance interne en mOhms à Ohms.
#ifdef __DEBUG_BATTERIES
// sprintf(tmp, "Valeur brute de résistance interne = %.2f mOhms, température batterie = %.2f °C, soit résistance interne corrigée = %.2f mOhms", batteries.batteries[i].resistance_interne, batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante, (resistance_interne * 1000));
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
// Estimation de la tension à vide (en tenant compte de la chute de tension due à la résistance interne de la batterie) :
tension_a_vide = batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante - (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante * resistance_interne);
if ((batteries.batteries[i].sequenceur.etat != ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE) && // Le calcul de l'EOD, et, in fine, du SOC n'est pas effectué tant qu'on est à l'état de charge nulle...
(batteries.batteries[i].sequenceur.etat != ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE)) // ... ou de pleine charge.
{
// Calcul de l'EOD :
// Calculs fonction d'une charge ou d'une décharge :
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante < 0) // Il est important de ne PAS prendre la valeur 0 (sinon le calcul de 'duree_decharge_corrigee' va planter via division par 0)
{
efficacite = 1 / batteries.batteries[i].efficacite_decharge;
// Effet Peukert :
duree_decharge_corrigee = batteries.batteries[i].heures_capacite * powf(((batteries.batteries[i].capacite / batteries.batteries[i].heures_capacite) / (-batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante)), batteries.batteries[i].coeff_peukert); // Le signe - devant le courant permet d'avoir une valeur positive (sinon POWF va générer une erreur)
courant_differentiel_corrige = -(float)batteries.batteries[i].capacite / duree_decharge_corrigee; // Le signe '-' permet de revenir à un courant négatif en cas de décharge
}
else
{
efficacite = batteries.batteries[i].efficacite_charge;
courant_differentiel_corrige = batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante; // Pas de correction de Peukert en charge...
}
// Calculs intermédiaires (facilite la lecture et le debug) :
delta_energie = courant_differentiel_corrige * efficacite * (BATTERIES_PERIODE_MESURES * 0.1 / 3600); // La dernière () permet de passer en heures.
// SDIR #337 : capacite_reelle = batteries.batteries[i].capacite * batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante / 100; // Le '100' permet de tenir compte du fait que le SOH est en pourcents
capacite_reelle = batteries.batteries[i].capacite; // SDIR #337
// Calcul de l'EOD proprement dit :
batteries.batteries[i].eod += delta_energie;
if (batteries.batteries[i].eod > 0) batteries.batteries[i].eod = 0; // SDIR #337
//printf("Courant diff = %.3f, efficacité = %.3f, Delta T = %.6f secondes donc Delta Energie = %.6fAh => energie_dechargee = %.6fAh. Capacite_reelle = %.2fAh\n", batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante, efficacite, (BATTERIES_PERIODE_MESURES * 0.1 / 3600), delta_energie, batteries.batteries[i].eod, capacite_reelle);
// Mise à jour du SOC à partir de l'EOD :
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = (1 + (batteries.batteries[i].eod / capacite_reelle)) * 100; // EOD est négative par nature. Le 'x100' permet de revenir d'une fraction en pourcents
}
else
{
efficacite = 0; // Permet d'éviter un warning losqu'il n'est pas calculé (état de pleine charge ou de charge nulle) mais utilisé par le message de debug
courant_differentiel_corrige = 0; // Idem
}
//--------------------------------
// Mode repos :
//--------------------------------
/* if (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) < batteries.batteries[i].courant_repos)
{
soc = calcul_niveau(batteries.batteries[i].points_tension_soc, MAX_NOMBRE_POINTS_TENSION_SOC_BATTERIE, tension_a_vide);
if (soc >= 0)
{
// batteries.batteries[i].soc_coeff_filtrage = 50;
// float old = batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
// float new;
// new = moyenne_mobile(old, soc, batteries.batteries[i].soc_coeff_filtrage);
// sprintf(tmp, "Old = %.3f%%, Add=%.3f%%, New = %.3f%% et le coeff %i. ", old, soc, new, batteries.batteries[i].soc_coeff_filtrage);
// affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = moyenne_mobile(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante, soc, batteries.batteries[i].soc_coeff_filtrage);
sprintf(tmp, "La batterie #%i est en mode REPOS. Son nouveau SOC = %.1f%%, il a été mis à jour via moyenne mobile avec la nouvelle valeur %.1f%% et le coeff %i. ", i, batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante, soc, batteries.batteries[i].soc_coeff_filtrage);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
}
// Sinon, on n'utilise pas la valeur calculée car il ne sert à rien de corriger avec une valeur erronée...
}
*/
//--------------------------------
// Mode Décharge :
//--------------------------------
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante < 0)
{
// Vérification du passage en "charge nulle" :
switch(batteries.batteries[i].sequenceur.etat)
{
//......................................
case ETAT_SEQUENCEUR_BATTERIE_NORMAL:
{
if (tension_a_vide <= batteries.batteries[i].tension_charge_nulle)
{
batteries.batteries[i].sequenceur.compteur = batteries.batteries[i].temporisation_charge_nulle;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE;
}
break;
}
//......................................
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE:
{
if (tension_a_vide > batteries.batteries[i].tension_charge_nulle) // Cas où on n'a pas eu le temps d'attendre la tempo de confirmation avant remontée de la tension.
{
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
if (batteries.batteries[i].sequenceur.compteur == 0) // Cas où le passage à charge nulle est confirmé :
{
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 0;
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = -(batteries.batteries[i].eod * 100) / batteries.batteries[i].capacite;
sprintf(tmp, "La Batterie [%i] est confirmée en CHARGE NULLE. EOD = %.3fAh et Capacité = %.2fAh donc SOH = %.3f%%", (i+1), batteries.batteries[i].eod, batteries.batteries[i].capacite, batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE;
}
break;
}
//......................................
case ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE:
{
if (tension_a_vide > (batteries.batteries[i].tension_charge_nulle + BATTERIES_HYSTERESIS_CHARGE_NULLE))
{
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
break;
}
//......................................
default :
{
#ifdef __DEBUG_BATTERIES
sprintf(tmp, "L'état du séquenceur de la Batterie [%i] est inconnu pour ce mode [%i]. Il est repositionné à NORMAL", (i+1), batteries.batteries[i].sequenceur.etat);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
#endif
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
}
}
//--------------------------------
// Mode Charge :
//--------------------------------
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > 0)
{
switch(batteries.batteries[i].sequenceur.etat)
{
//......................................
case ETAT_SEQUENCEUR_BATTERIE_NORMAL:
{
// Détection d'un passage à l'état "Pleine charge" :
if ((tension_a_vide >= batteries.batteries[i].tension_pleine_charge) &&
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante <= batteries.batteries[i].courant_pleine_charge))
{
#ifdef __DEBUG_BATTERIES
sprintf(tmp, "Les conditions du mode PLEINE CHARGE ont été détectées sur la Batterie [%i]. La temporisation de vérification (%is) est lancée ", (i+1), batteries.batteries[i].temporisation_pleine_charge);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
#endif
batteries.batteries[i].sequenceur.compteur = batteries.batteries[i].temporisation_pleine_charge;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE;
}
break;
}
//......................................
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE:
{
// Détection de sortie de l'état "Pleine charge" avant d'avoir été confirmé :
if ((tension_a_vide < batteries.batteries[i].tension_pleine_charge) || // Si la tension est redescendue...
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > batteries.batteries[i].courant_pleine_charge)) // ... ou le courant remonté avant l'expiration de la tempo :
{
sprintf(tmp, "Les conditions du mode PLEINE CHARGE ont disparu sur la Batterie [%i]. La batterie est repositionnée en mode NORMAL ", (i+1));
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
// Confirmation du passage à l'état "Pleine charge" :
if (batteries.batteries[i].sequenceur.compteur == 0) // Cas où le passage à pleine charge est confirmé :
{
sprintf(tmp, "La Batterie [%i] est confirmée en PLEINE CHARGE ", (i+1));
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
batteries.batteries[i].eod = 0;
// batteries.batteries[i].tension_pleine_charge = tension_a_vide - BATTERIES_DELTA_TENSION_PLEINE_CHARGE_AUTO; // Ajustement auto de la tension pleine charge
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE;
}
break;
}
//......................................
case ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE:
{
// Détection de sortie de l'état "Pleine charge" :
if ((tension_a_vide < batteries.batteries[i].tension_pleine_charge) || // Si la tension est redescendue...
(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante > batteries.batteries[i].courant_pleine_charge)) // ... ou le courant remonté :
{
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
// Etat "pleine charge" :
// batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
// batteries.batteries[i].eod = 0;
break;
}
//......................................
default :
{
#ifdef __DEBUG_BATTERIES
sprintf(tmp, "L'état du séquenceur de la Batterie [%i] est inconnu pour ce mode [%i]. Il est repositionné à NORMAL", (i+1), batteries.batteries[i].sequenceur.etat);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING);
#endif
batteries.batteries[i].sequenceur.compteur = 0;
batteries.batteries[i].sequenceur.etat = ETAT_SEQUENCEUR_BATTERIE_NORMAL;
break;
}
}
}
// Vérification du SOC :
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante > 100) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 100;
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante < 0) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante = 0;
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante;
//--------------------------------------------
// Calcul des nombres de cycles :
//--------------------------------------------
if (batteries.batteries[i].flag_increment_cycles == 0) // Le compteur est armé et n'a pas encore été incrémenté :
{
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante <= BATTERIES_SEUIL_SOC_BAS_NOMBRE_CYCLES)
{
batteries.batteries[i].flag_increment_cycles = 1; // Blocage du flag jusqu'au prochain passage par 100%
batteries.batteries[i].nombre_cycles ++; // Incrémentation du compteur
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
}
else // Le compteur "Nombre_cylces" a été incrémenté, on attend maintenant de revenir à 100% pour le réarmer :
{
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 100)
{
batteries.batteries[i].flag_increment_cycles = 0; // Réarmement du flag pour le prochain cycle
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
}
//--------------------------------------------
// Calcul du nombre de décharges complètes :
//--------------------------------------------
if (batteries.batteries[i].flag_increment_decharges_completes == 0) // Le compteur est armé et n'a pas encore été incrémenté :
{
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 0)
{
batteries.batteries[i].flag_increment_decharges_completes = 1; // Blocage du flag jusqu'au prochain passage par 100%
batteries.batteries[i].nombre_decharges_completes ++; // Incrémentation du compteur
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
}
else // Le compteur "Nombre_cylces" a été incrémenté, on attend maintenant de revenir à 100% pour le réarmer :
{
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante == 100)
{
batteries.batteries[i].flag_increment_decharges_completes = 0; // Réarmement du flag pour le prochain cycle
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
}
//-------------------------------------
// Calcul du SOH :
//-------------------------------------
// Vérification du SOH :
// if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante > 100) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = 100;
if (batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante < BATTERIES_SEUIL_MINI_SOH) batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante = BATTERIES_SEUIL_MINI_SOH;
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante;
//-------------------------------------
// Calcul de l'autonomie :
//-------------------------------------
// Mise à jour du cumul :
batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].cumul += batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante;
//-------------------------------------
// Mise à jour BDD :
//-------------------------------------
// Mise à jour dans la BDD si les valeurs ont suffisemment évolué :
// if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TEMPERATURE].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_TENSION].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_CHARGE].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_COURANT_DECHARGE].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOH].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_SOC].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_AUTONOMIE].marge) ||
// (fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) >= batteries.variables[BATTERIE_VARIABLE_PUISSANCE].marge))
if ((fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante) > 0) ||
(fabs(batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_bdd - batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante) > 0))
{
batteries.batteries[i].flag_dde_maj_bdd = TRUE; // Flag pour mise à jour dans la BDD
}
#ifdef __DEBUG_BATTERIES
char texte_etat[200];
if (++ batteries.compteur_affichage_debug == 6) // Comme BATTERIES_PERIODE_MESURES = 300ms, cela donne un affichage toutes les 1.8s
{
batteries.compteur_affichage_debug = 0;
switch(batteries.batteries[i].sequenceur.etat)
{
case ETAT_SEQUENCEUR_BATTERIE_NORMAL: { strcpy(texte_etat, "NORMAL"); break; }
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_CHARGE_NULLE: { strcpy(texte_etat, "ATTENTE_CONFIRMATION_CHARGE_NULLE"); break; }
case ETAT_SEQUENCEUR_BATTERIE_CHARGE_NULLE: { strcpy(texte_etat, "CHARGE_NULLE"); break; }
case ETAT_SEQUENCEUR_BATTERIE_ATTENTE_CONFIRMATION_PLEINE_CHARGE: { strcpy(texte_etat, "ATTENTE_CONFIRMATION_PLEINE_CHARGE"); break; }
case ETAT_SEQUENCEUR_BATTERIE_PLEINE_CHARGE: { strcpy(texte_etat, "PLEINE_CHARGE"); break; }
default: { strcpy(texte_etat, "Inconnu"); break; }
}
sprintf(tmp, "Batterie #%i : Etat = %s, Température = %.2f°C, Tension = %.3fV, Courant diff = %.3fA, courant charge = %.3fA, Courant décharge = %.3fA, SOH = %.2f%%, SOC = %.2f%%, Autonomie = %.2fh et puissance = %.3fW. Tension à vide = %.3fV, résistance interne corrigée = %.2fmOhms, efficacité = %.3f, courant_differentiel_corrigé = %.3fA, capacité = %.2fAh, EOD (énergie déchargée depuis démarrage) = %.5fAh", i,
texte_etat,
batteries.batteries[i].variables[BATTERIE_VARIABLE_TEMPERATURE].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_CHARGE].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DECHARGE].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOH].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_SOC].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_AUTONOMIE].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_PUISSANCE].valeur_courante,
tension_a_vide,
(resistance_interne * 1000), // Pour passer de Ohms à mOhms
efficacite,
courant_differentiel_corrige,
batteries.batteries[i].capacite,
batteries.batteries[i].eod
);
/*sprintf(tmp, "Batterie #%i : Etat = %s, Tension = %.3fV, Courant diff = %.3fA. Tension à vide = %.3fV, efficacité = %.3f, courant_differentiel_corrigé = %.3fA, capacité = %.2fAh, duree_decharge_corrigee = %.2fh, EOD = %.5fAh", i,
texte_etat,
batteries.batteries[i].variables[BATTERIE_VARIABLE_TENSION].valeur_courante,
batteries.batteries[i].variables[BATTERIE_VARIABLE_COURANT_DIFFERENTIEL].valeur_courante,
tension_a_vide,
efficacite,
courant_differentiel_corrige,
batteries.batteries[i].capacite,
duree_decharge_corrigee,
batteries.batteries[i].eod
);
*/
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_PAR_DEFAUT);
}
#endif
} // Fin du traitement pour batterie sur IBS
batteries.batteries[i].cumuls_nb_val ++; // MàJ du nombre d'échantillons dans le cumul
// Mise à jour des valeurs BDD des variables :
if (batteries.batteries[i].flag_dde_maj_bdd)
{
for (j = 0; j < MAX_NOMBRE_VARIABLES_BATTERIES; j ++) batteries.batteries[i].variables[j].valeur_bdd = batteries.batteries[i].variables[j].valeur_courante;
}
}
}
}
break;
}
//--------------------------------------------------------
default :
{
sprintf(tmp, "L'état du séquenceur Batteries est inconnu [%i]. Il est repositionné au REPOS", batteries.sequenceur.etat);
affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR);
batteries.sequenceur.etat = ETAT_SEQUENCEUR_BATTERIES_REPOS;
break;
}
}
}
//**********************************************************************************************************************************************************************************
// Fonction : Recherche la batterie dont la Clé_primaire est reçue en paramètre
// Reçoit : La Cle_primaire de la batterie à rechercher
// Retourne : le numéro de batterie correspondant (ou -1 si aucun circuit valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_BATTERIES - 1.
//**********************************************************************************************************************************************************************************
int16_t batterie_cle_primaire(uint16_t cle_primaire)
{
uint16_t i;
if (cle_primaire == 0) return (-1); // Inutile de chercher si le n° à chercher est nul...
for (i = 0; i < batteries.nb; i ++)
{
if (batteries.batteries[i].flag_validite == FALSE) continue;
if (batteries.batteries[i].cle_primaire == cle_primaire) return(i);
}
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
}
//**********************************************************************************************************************************************************************************
// Fonction VARIABLE_BATTERIE_CLE_PRIMAIRE
// Reçoit en paramètre :
// - La Cle_primaire de la variable à rechercher
// Retourne :
// - le numéro de variable correspondant (ou -1 si aucune variable valide ne correspond). La numérotation allant de 0 à MAX_NOMBRE_VARIABLES_BATTERIES-1.
//**********************************************************************************************************************************************************************************
int16_t variable_batterie_cle_primaire(uint16_t cle_primaire)
{
uint16_t i;
for (i=0; i<MAX_NOMBRE_VARIABLES_BATTERIES; i++)
{
if (batteries.variables[i].cle_primaire == cle_primaire) return(i);
}
return (-1); // Si on est arrivé au bout de la boucle, on renvoi le code de 'non trouvé'.
}