BMS, Etat de charge et santé de batterie lithium, banc cyclage (arduino)

La gestion d’une batterie (BMS : Batterie Management System) numérique permet d’estimer l’état de charge et l’état de santé de la batterie assez facilement pour certaine technologie de batterie lithium. L’objectif final est de connaitre la distance parcourable restante d’un véhicule électrique malgré le vieillissement de la batterie ? Ainsi que de faire un diagnostic de la batterie en temps réel.
Mais de nombreuses questions sont en suspend pour faire l’instrumentation d’une batterie en temps réels : Comment faire le diagnostic d’une batterie lithium ? Quelles sont les ressources que doit avoir le processeur ? Quelles sont les méthodes pour connaitre l’état de charge et l’état de santé d’une batterie ou de chaque élément ? Quel doit le nombre d’échantillon de mesure pour les diagnostics précédents ?

L’article suivant est telechargeable sur le lien suivant

Une carte Méga ou DUE est utilisé et explique les méthodes et le programme

Le fichier ISIS de la simulation pour la carte mega qui permet de tester le programme est téléchargeable sur le lien suivant








L’algo est le suivant ;

Routine d’interruption timer1 tous les 0.1secondes

Mesure courant
Mesure coulomb mètre et Wattheure
Mesure tension chaque élément

Gestion de l’arrêt de la charge 
Gestion de l’arrêt de la décharge avec un flag arrêt

Si 1 A.heure consommé alors calcul par régression linéaire de la pente de la diminution de la tension en fonction de la capacité énergétique pour chaque élément

Calcul de l’état de santé de chaque élément et donne l’état de santé de l’élément le plus faible

Si menu 0, test des résistances internes de chaque élément en décharge

Affichage des données sur l’afficheur LCD
Communication des données par la liaison série

Programme principal
Gestions des 4 boutons poussoirs
- BP1 test résistance en décharge
- BP2 lance la possibilité de décharge
- BP3 ré-autorise la décharge en réinitialisant le drapeau de l’arrêt
- BP4 gère les menus de l’afficheur LCD

Le programme Arduino est en PJ

Pour transférer les données du terminal du microcontrôleur dans Excel, il faut faire un copier-coller des données du terminal de Arduino. Coller dans un fichier doc
Faire un Ctrl+h changer tous les points des chiffres en virgule pour qu’Excel
Refaire un Ctrl+h changer tous les tabulation ^t par un espace.
Enregistrer votre fichier .txt….puis renommer l’extention .txt en .csv
Ouvrir le fichier .csv dans Excel
Si vous utiliser un autre terminal que celui d’arduino, il est possible de copier directement les données en fichier .CSV

Remarques
Attention ouvrir le moniteur série Arduino avant de faire les essais sinon, il y a un reset du programme.
Attention appuyer sur BP5 pendant le off de la charge à cause du calibrage du capteur.

Conclusions et perspectives

Il suffit d’augmenter les variables pour avoir un BMS 13elements séries et la gestion des menus
Un compteur de vitesse (odomètre) à effet hall devrait être rajouté au programme pour mesurer la vitesse et la distance
Il faudrait mémoriser les données de l’état de santé pour chaque cycle
D’autres méthodes d’état de santé (SOH : state of health) de la batterie devrait être testé à partir de cette base de programmation en fonction de la chimie de la batterie
Un enregistrement des données dans une carte SD et une communication extérieur pour faire de la maintenance

on a fait the translate en english here
BMS , State of charge and estimate health battery lithium with Arduino
BMS , State of charge and estimate health battery lithium with Arduino - General Electronics - Arduino Forum
instrumentation_V1.ino (8.33 KB)

1 Like

Dans le BMS précédent, on voudrait ajouter un compteur de vitesse.

Sur le sujet suivant, le compteur de vélo, utilise des afficheurs 7 segments et un delays en scrutation pour compter le temps et définir la vitesse….et un ILS comme capteur.
« Compteur de vitesse avec mesure de puissance et de résistance au roulement »
https://forum.arduino.cc/index.php?topic=288800.0
Donc un afficheur LCD avec une routine d’interruption extérieure serait préférable avec un comptage par timer….

Dans le sujet precedent, Pour la résistance au roulement des pneus, il y a d’autres façons de la déterminer

De plus, pour l’estimation de la puissance de pedalage, il faut prendre en compte le CX et la pente de la route ce n’est pas si simple.

Bref, il y a d’autres sujet, celui-ci affiche sur un smartphone avec le Bluetooth autant prendre le GPS du smarthphone pour connaitre sa vitesse, mais il a prix une cate arduino pro qui consomme peu.
https://create.arduino.cc/projecthub/alan_dewindt/bicycle-odometer-and-speedometer-with-99-lap-period-recorder-331d2b?ref=tag&ref_id=speedometer&offset=0
un autre sujet, bicycle-speedometer qui détermine la vitesse pour chaque tour de roue avec la fonction millis() qui utilise le timer0
https://create.arduino.cc/projecthub/139683/arduino-lcd-display-as-a-bicycle-speedometer-6a6568?ref=tag&ref_id=speedometer&offset=3
un autre sujet qui détermine la vitesse toutes les secondes
Commande et instrumentation de trottinette électrique 500W avec Arduino méga
https://forum.arduino.cc/index.php?topic=473015.0

mais ils ont pris quoi comme capteur et comme aimant ????????
Il esiste de nombreux capteur a effet hall

Cela dépend de la forme de l’aimant, mais proche à l’aimant, le champ magnétique diminue hyperboliquement en fonction de la distance. Donc, pour un aimant fournisant 70mT ou 700 Gaus, la distance est détection maximale est d’environ de 5mm
https://wiki.mchobby.be/index.php?title=Senseur_à_Effet_Hall

remarque : Un aimant disque de 5mm*4mm en néodyme N35 fournit un champ de 900mT

Pour une roue et un pneu de 26x1.5 pouces, de circonférence de 2010mm. Il faut une précision en mm pour la circonférence.
La distance est donné par
Distancekm=nbrdetour*2010/1000000

Pour la vitesse, la précision au dixième près est un affichage à la seconde est seulement necessaire, 2 methodes sont possibles

• Méthode par détermination pour chaque tour de roue avec un comptage à la milliseconde près.
La vitesse est déterminée par l’équation suivante
V=(20103.6)/temps(ms) pour 100ms=>72km/h
S’il y a une interruption extérieure toutes les secondes, la vitesse sera de 7.2km/h
Donc, il faut limiter la mesure à des temps supérieurs à 2 secondes donc à des vitesses supérieurs à 3.6km/h.
La précision de la vitesse est plus faible lorsque la vitesse est grande mais tres honorable
DeltaV=(2010
3.6)/tempsmini2 pour 100ms=>0.72km/h
A grande vitesse, l’affichage va changer à chaque tour, ce qui ne la rend pas lisible. Donc, un filtrage moyenneur numérique sur 5 valeurs est intéressant.

• précision avec la méthode de détermination pour 2 secondes
La vitesse est déterminée par l’équation suivante
V=(nbrdetour20103.6)/temps constant pour 2s=3.6(km/h)/tour
En effet, s’il y a plus ou moins 1 tour toutes les 2 secondes, la précision de la vitesse sera constante à 3.6km/h et va dépendre de la circonférence.
Un filtre passe bas numérique doit être utilisé pour moyenner cette erreur.

Mais à cause de la routine d’interruption timer tous les 0.1s ce n’est pas indiqué d’utiliser cette méthode

On va faire quelques tests, sur le capteur 3144 et 49E

Sujet sur le BMS super intéressant, mais pouvez vous développer ???

schéma arduino / cellules

programme / affichage sur lcd

les données stockées => comment les analyser ? les remèdes en cas de défaut ????

merci

C'est ambitieux comme projet. Toutes mes félicitations. :wink:

Même les fabricants de voiture électrique ont du mal à afficher en temps réel l'autonomie restante de leurs véhicules.

Sur la questions des contrôles/équilibrages individuels de cellule, il y a une starup qui s'est lancée dedans: enerstone.

Pas compris, comment enerstone fait de l’équilibrage actif ? Pas trouvé quelle était le courant d’équilibrage des cartes ?

L’article précèdent donne l’état de santé de la batterie et la consommation mais avec les valeurs moyennes précèdent qui peuvent provoquer des erreurs sur l’estimation futur

Pour connaitre la consommation en fonction de son parcours.
pour ma part, j'utilise l'application suivante qui en fonction du parcours m'indique ma consommation electrique a 5% d’erreur parfois majorée, parfois minorée
https://www.ebikemaps.com/

Pour avoir plus d’information sur les BMS et leurs rôles, il y a un lien suivant.

Un lien pour télécharger l’article precedent a été rajouté, le programme est en pièce jointe mais pour 2 cellules seulement pour savoir comment cela a programmé.

L’article précèdent disait que l’on pouvait faire un banc de test de cyclage de batterie lithium pour connaitre les performances de vieillissement de batterie car les constructeurs sont flous à ce sujet.
Voici un programme qui permet de faire de cyclage de batterie LTO 18650 qui a une tension max de 2.7V, une tension mini de 1.5V avec une capacité énergétique de 1.45A

Difficile de trouver sur le net les caracteristiques des batteries LTO
Mais Voici celle des GTKPower TK18650 NT35 (PDF) LTO 18650 datasheet specs | lecher larry - Academia.edu
Il y a des tests sur ce lien mais rien sur la durée de vie.
maintenance de de batterie, BMS, Chargeur, limitation sur le controleur - Page 3

La durée de vie à 80% du SOC nominal pour les LTO peut atteindre plus de 4000 cycles
Mais, en 24 heures avec le taux de décharge à 4C, il y aura 48 cycles de décharges, un diagnostic complet tous les 500 cycles sera effectuée avec le bouton poussoir BP1.
En 3 mois, les 4000 cycles seront effectués.

2 relais en séries sont utilisés qui permettent de charger la batterie ou de la décharger mais aussi d’arrêter le cyclage à 4C pour mesurer la résistance interne de l’élément.
Un capteur de courant ACS 712 20A est utilisé qui mesure un courant un courant positif et négatif.

Sachant que la tension du chargeur ne peut dépasser 2.7V pour charger l’element LTO, le programme attend que le courant soit inférieur à 0.5A pour arrêter la charge. Dans cette condition, la batterie est presque à 100% de la charge.

Lorsque la batterie LTO a atteint 1.5V, malgré le courant de décharge à 4C, on considéra que l’on est à 0% de décharge et l’on enregistra la valeur du SOC, ainsi que la résistance interne. Le nombre de cycle sera incrémenté.

Evidement avec le nombre de cycle, l’état de charge va diminuer ce qui correspondra à l’état de santé de la batterie.

Les données sont enregistrées dans l’EEPROM en cas de coupure d’electricité les données sont bien sauvegardé. Le petit programme permet d’initialiser correctement l’adresse ou sera enregistrées le cycle.

le programme d'initialisation de l'eeprom en PJ

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
#include <avr/wdt.h>   //chien de garde
#include <EEPROM.h>

#define BP1     30       // 30 BP1
#define BP2     31       // 31 BP2           
#define BP3     32       // 32 BP3
#define BP4     26       // 32 BP3
#define LEDV    33       // 33 led
#define LEDJ    34       // 34 led
#define LEDR    35       // 35 led
#define relays0 21          
#define relays1 20      
#define led13   13  
#define buzzer  25 
#define BP5     12       

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=27, Enable=28, D4=25, D5=24, D6= 23, D7=22, BPpoussoir=30
// Configuration des variables

unsigned int cycle=0;
float SOC1=-1450;


void setup() {
   lcd.begin(20, 4);                   //modifier pour un afficheur 20x4
  Serial.begin(9600); 
EEPROM.put(4000, cycle);    //le cycle est l'adresse de l'enregistrement à 4000 octets initialisé à 0
EEPROM.put(cycle, 1400);  //derneire mesure du SOC
}

void loop() {
lcd.setCursor(0,0);
lcd.print("init EEprom  "); 

EEPROM.get(4000, cycle);    //verification des données
EEPROM.get(cycle, SOC1);  

lcd.setCursor(13,1);
lcd.print(cycle);
lcd.print("Cy  "); 

lcd.setCursor(0,2);
lcd.print(SOC1,0);
lcd.print("mAh  ");

// faut-il reinitialiser toute l'eeprom pour chaque nouvelle batterie 

}

L’algo simplifié du banc de test est le suivant avec programme en PJ

routine d’interruption toutes les 1s, 
mesure et affichage du le courant, la tension, SOC, temps, cycle sont mesurés…
enregistrement eeprom après chaque décharge du SOC

arret de decharge à 1.5V
arret de la charge pour un courant de 0.5A et tension superieur à  2.65V


programme principal gestion des bouton
avec le bouton BP1, diagnostic totale de l’élément, avec tous les 30s, envoie au PC, tension, courant, SOC, résistance interne, la température….qui permet de faire un fichier CSV pour étude 
avec le bouton BP2, on peut choisir de charger ou de décharger.
avec le bouton BP3, on, off
avec le bouton BP4, mettre en automatique le cyclage
BP5 lecture du nombre de cycle et du SOC effectué

Si la température est supérieure à 45°C alors off et attendre une remise en fonctionnement, activation du buzzer pour interpeller un problème

Pour vérifier notre programme, des captures d’écran suivant prouveront le bon fonctionnement de la programmation en simulations dans un premier temps puis une photo du banc de test de batterie

On peut observer que cela charge bien avec la bonne valeur de courant.
Etant donné que le capteur ACS 712 n’est pas simulable, nous avons utilisé une résistance ajustable. De même, pour faire varier la tension de la batterie.
Un simple Arduino nano suffit pour faire de nombreux bancs de test.

Mais une carte Mega permet de gérer de nombreuses batteries en cyclage et le LCD était câblé.
De plus, la carte ATmega 2560 permet d’avoir un chien de garde.
BP3 actionné et BP2, il y a bien une charge, avec les bonnes valeurs de mesures, du temps
Voici le lien pour telecharger le fichier ISIS de ce banc de test


Puis, il arrete la charge.
En décharge, il y a bien un courant negatif, et la capacité energetique et negatif

Il y a bien un arrêt pour une tension inférieur à 1.5V

En mode diagnostic, les mesures sont bien envoyées sur le terminal PC toutes les 30 secondes

Lors de l’appuie sur BP5, les données des SOC sont bien récupérées

En mode, auto, il y bien charge et décharge qui s’enchaine
En mode diagnostique, il y a bien un envoie des données tous les 30 secondes dont la valeur de la résitance

Le cablage fait que cela ne est pas tres propre….mais le prototype tourne depuis 15 jours et a permis de voir les petits problemes de programmation

Remarques : avec les relais, il faut ne pas utiliser l’alimentation USB car lorsque les relais commutent un arret programme peut survenir.
Il faudrait mettre plus de données en eeprom s’il y a un arret programme et utiliser le chien de gardes.

Perspectives : l’ACS712 derive legerement lors de la mesure de courant. Un blindage est souhaitable et une remise à zero de temps en temps comme en mode diagnostic est pertinent. Il faudrait le faire aussi en mode charge et decharge.
l'estimation du SOC par regression lineaire devrait etre mis aussi dans ce banc de test

Conclusion :
il est très facile de faire un banc de test de cyclage pas cher avec des Arduino…..
De les multiplier, pour avoir des statistiques sur l’etat de santé de la batterie….

Des hacheurs abaisseurs et élévateurs permettrait de décharger une batterie pour en recharger une autre mais ceux-ci sera d’autres histoires.

LTO_mega_banc_test_V2.ino (7.99 KB)

EEPROM.ino (1.28 KB)

On a voulu refaire un autre banc de test pour faire un cyclage à 6C
Voici un nouveau programme pour le cyclage de batterie des batteries LTO que l’on a amélioré
De plus, à cause des résistances parasites des relais et du câblage qui est de 0.028ohms+la résistance interne de la batterie qui est d’environ 0.04ohms, la valeur d’arrêt de décharge a été mis à 1.2V.
A cause de ces résistances parasites, il impossible de charger à plus de 4C l’élément en limitant la tension à 2.7V du chargeur.
Une solution est de mettre un troisième relais avec un chargeur à 3V, puis basculer sur le chargeur à 2.7V

Pour améliorer, la simulation le schéma ISIS a été changée à cause du capteur de courant ACS712, qui permet d’observer le calibrage de ce capteur,

L’afficheur LCD bug de temps en temps, mais en appuyant sur BP5, une réinitialisation de l’afficher LCD se fait.
Il faudrait vérifier les temps de programme de la routine d’interruption pour savoir pourquoi cela bug de temps en temps.

Perspectives est de multiplier le nombre de banc de test pour le cyclage avec des Arduino nano pour avoir une étude statistiques de défaillance d’elements

LTO_mega_banc_test_V2.ino (8.27 KB)

En fait, l’ACS712 est simulable dans ISIS, ce qui simplifie le schema precedent, il n’y a donc pas besoin de l’AOP
Pour faire de nouveau banc d’essais de cyclage d’element de battery, des afficheurs LCD avec bus I2C vont etre utilisés.
Il est aussi possible de simuler cet afficheur, pour ameliorer le programme et ne pas faire de betise sur la batterie.

On peut observer le schema simulation sous ISIS

On peut telecharger le fichier ISIS sur ce lien

Voici le programme avec la library du LCD I2C avec le choix de l’adresse du LCD en fonction de A0, A1, A2

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/examples/HelloWorld/HelloWorld.pde
//https://www.gotronic.fr/pj2-sbc-lcd16x2-fr-1441.pdf
//https://wiki.mchobby.be/index.php?title=LCD-I2C
//https://microcontrolere.wordpress.com/2019/04/01/arduino-and-i2c-lcd-in-proteus/
// indiquer (adresse i2c, nombre de colonnes, nombre de lignes)
// il existe des petits programmes pour verifier l'adresse
//LiquidCrystal_I2C lcd(0x27, 20, 4);    //en reel
LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter

#define led13   13  

void setup()
{  // initialise l'afficheur LCD
pinMode(led13, OUTPUT); 
//pinMode(A4, OUTPUT); 
//pinMode(A5, OUTPUT); 


lcd.init();  //et pas lcd begin comme cetraine biblio
// activer l'affichage
  lcd.display();
// allumer retroeclairage
  lcd.backlight(); 
}

void loop()
{
 // ecrire à la position par defaut
  lcd.setCursor(0,0);
  lcd.print("IUT GENIE elect&info");
  lcd.setCursor(5,1);
  lcd.print("Soissons");
digitalWrite(led13,LOW);   //cligotement led 13
  // petite pause
  delay(2000);
  lcd.clear();
  digitalWrite(led13,HIGH); 
  delay(1000);
}

le code pour les caracteres speciaux "symbol" sur l'afficheur LCD
lcd.print((char)223); //le degres de celcius
lcd.print((char)227); //epsilon
lcd.print((char)228); //micro
lcd.print((char)244); //ohm
il n'y a qu'a faire un petit programme qui incrmente le numero des caracteres

A force de mettre des choses dans la routine d’interruption, celle-ci a durée plus de 1ms.
De plus, pour ne plus avoir de bug de l’afficher LCD, entre des affichages que se faisait dans de la boucle principal et l’affichage dans la routine d’interruption.
Toutes les instructions du LCD se fait dans la routine d’interruption.
D’ailleurs à cause de la gestion de l’afficheur LCD, le temps de la durée de la routine est maintenant d’environ 17ms.

Par conséquent, le temps de la routine d’interruption est passé dans ce programme à 0.1secondes.
Mais, il a fallu changer de nombreuses valeurs qui dépendaient de ce temps d’interruption

de plusn Un temps a été rajouté entre la décharge et la charge pour que la batterie ait le temps de redescendre légèrement en température. dans le programme, il est de 60s avec flagway

Le programme en piece jointe

Pour avoir un temps encore plus court de décharge, on a changé de résistance de décharge de 0.2Ω mais, avec l’élévation de température de la résistance de décharge, celle-ci est plutôt à 0.25 Ω.

Sur la figure suivante, on peut observer la tension OCV d’un element LTO et température de la batterie en fonction du temps.
Le temps de la décharge est de 14 minutes et le temps de charge est de 50.5minutes.
Donc un cycle de charge et de décharge est de 64.5minutes.
Pourtant Lors de la charge, il faut seulement 15minutes pour reprendre 1A.h, mais la charge à tension constante est relativement long mais permet à la batterie


L’estimateur par régression linéaire donne une très bonne estimation comme on peut l’observer sur la figure suivante pour une tension 0CV mini de 2,1V.

Sur la figure précédente, une erreur au début du SOC peut être observée à cause de la variation importante de la tension en début de décharge de 2.7V à 2.5V, puis l’erreur se minimise pour redevenir importante à la fin de la décharge.
Evidemment, une régression polynomiale pourrait minimiser ces erreurs.

La figure suivante donne la capacité energetique en fonction du cyclage. La variation de la capacité est du aux petites erreurs du calibrage du capteur de courant qui est de ±0.05A. D’ailleurs, à chaque cycle, le capteur est recalibrer pour minimiser l’erreur. D’ailleurs, c’est pour cela qu’il y a une plus grande d’erreur au début du cyclage.

LTO_mega_banc_test_V3.ino (9.65 KB)

suite à la discution du 13 nov sur les capteurs magnetiques, pour realiser un compteur de velo

On a voulu testé des aimants pour notre compteur de vélo et réalisé un tesla mètre avec un capteur SS49E pour savoir à quel distance l’aimant sera détecté.

Sur l'excellent article suivant, il dise que le champ magnétique et sur le devant du capteur alors qu’il est plus performant sur le dessus lors de nos essais ?

« Construction of a simple low-cost teslameter and its use with Arduino and MakerPlot software »
https://iopscience.iop.org/article/10.1088/0031-9120/51/2/024001/pdf

De plus, il faut aussi calibrer le capteur ce que ne fait pas le programme ci-dessus.
Sachant que Le champ magnétique terrestre varie de 30µT à 60µT, cela est négligeable par rapport aux champs d’un aimant. En France, il est de 47µTesla , ou encore de 470 mGaus
Pour faire le calibrage, une bobine de diametre 1cm et 4cm de long alimentée en DC aurait pu être réalisé mais cela n’a pas été fait.

Voici le programme

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>
#include <SoftwareSerial.h>
//#include <math.h>

#define led13   13 

LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter 20x4ligne

      signed int entree;
      signed int tesla=0;
      signed int zeromagnet;
      unsigned int TO;
      unsigned int Time;
      unsigned int kph;

void setup()
{  // initialise l'afficheur LCD
pinMode(led13, OUTPUT);
pinMode(3, OUTPUT);

  Timer1.initialize(1000000);         // initialize timer1, and set a 1 second period =>  1000 000  pour 0.01s  10 000
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
  Serial.begin(9600); 


lcd.init();               //et pas lcd begin comme cetraine biblio
lcd.display();            // activer l'affichage
lcd.backlight();          // allumer retroeclairage

zeromagnet=analogRead(A0);
attachInterrupt(0, interrup2, FALLING);   // il vaut mieux utiliser  KY003 tout ou rien   RISING, FALLING
TO = millis();
}//fin setup


void interrup2() // la fonction appelée par l'interruption externe n°0
{
Time=(millis()-TO);  //mesure du temps
TO = millis();
}




// Interruptions  tous les 1s fait par le timer1***********************************
void callback()  {
if (digitalRead(led13)== 1) {digitalWrite(led13,LOW);}  else {digitalWrite(led13,HIGH);}
}//callback



void loop()    
{
//digitalWrite(led13,HIGH);
entree=analogRead(A0);          //test du capteur 49E  teslametre, il faut passer l'aimant au dessus du capteur
tesla=entree-zeromagnet;
lcd.setCursor(0,1);  // (X,Y)  
//tesla=map(entree,0,1023, -167, 167);
tesla=(tesla*100)/307;    
lcd.print(tesla);
//lcd.print((char)228);    //micro
lcd.print("mTesla   ");   
//digitalWrite(led13,LOW);   

//pour faire une detection, du pole nord, 
if (tesla<-10) {lcd.setCursor(0,0); lcd.print("aimant");} else  {lcd.setCursor(0,0); lcd.print("       ");}

//odometre ou compteur de velo en kilometre par heure
if (Time>=2000) {kph=0;   } else {kph=(2.010*1000*3.6)/Time;   }   //2010mm perimetre roue 26 pouces
  lcd.setCursor(0,3);  // (X,Y)
  lcd.print(kph,1);
  lcd.print("kph    ");  

    
}//fin loop

Le capteur magnétique n’est pas simulable dans Isis. Mais il est possible de le remplacer par un potentiomètre.
Donc, un essai avec l’aimant à 1.5cm du capteur donne -3mT en reel avec un de nos aimants.

Un autre essai avec l’aimant à 0.5cm, provoque une augmentation de la valeur à -21mT

Evidemment, si on retourne l’aimant, la valeur du champ magnétique change de signe
Etant donné que sur la plupart les téléphones Android, il y a un capteur magnétique 3 axes, il est aussi possible de vérifier les valeurs donnés par le capteur SSE49 donnée par l'aimant.

On peut observer en simulation qu’à la fréquence de 5Hz pour pneu de 26 pouces, la vitesse est bien de 34kph.
L’interruption n’est pas détecté, ni en falling, ni en rising avec le SS49E
Donc, seul un capteur tout ou rien KY03 ou 3144 pour faire un odometre et un compteur de velo est viable.

D'ailleurs avec l'aimant précedent, il faut 2 cm pour que le 3144 passe à 3.8V à 0.1V.
l'hysteresis fait que le capteur reste à l'etat "0" jusqu'a 3cm.
Attention, le 3144 n'est actionnable que pour un seul sens de champs magnetique, donc il faut choisir la bonne face de l'aimant. Sinon, il est possible de retourner le capteur

Les interrupteurs d’éclairage vélo ont des interrupteurs pour les activés ou désactivés. L’interrupteur doit être le plus léger possible mais ne peut supporter un nombre de manœuvre faible ce qui donne une obsolescence du produit de quelques années.
Les éclairages de vélos commandés par microcontrôleur peuvent être réveiller (après mise en veille) par 2 technologie différente :

  • Interrupteur capacitif tactile
  • Interrupteur magnétique

L’interrupteur capacitif doit avoir une amplification qui consomme un courant de 40mA, bien trop important pour un système alimenté par batterie.

Un interrupteur à aimant est donc préférable
Mais quel type d’aimant faut-il utilisé ? quel sera son prix, sa masse, ces dimensions ?
A cause du boitier, quelle sera la distance minimale pour activer le capteur magnétique dans le boitier ? quel sont les types de capteurs magnétiques ? quel est le courant consommé par le capteur ?

1.Mesure avec smartphone du champs magnétique en fonction de la distance



Etant donné que les mesures du smartphone sont peut-être erronées à cause des parties ferreuse, nous allons réaliser notre propre teslamètre avec le capteur SS49E.

12 Teslamètre avec capteur SS49E

Le capteur à effet Hall linéaire 49E est un petit dispositif à effet Hall linéaire sensible au le champ magnétique. Sa consommation est de 4.5mA pour 5V
La variation linéaire de ce capteur est de 2.5V a 0T et pour 4V on a 100mT.
pour le mesure du champ magnétique en fonction de plusieurs magnets ,nous avons cette courbe suivante

Pour trois magnet on a cette courbe

pour une seule magnet on a celle-ci

D’après les courbes on peut dire que y’a pas de différences entre les mesures effectuées avec le smartphone et le capteur SS49E car on voit bien que les courbes décroissent.

Programme du teslamètre avec Arduino

ça nous avons effectué un petit programme sous Arduino pour lire directement sur un afficheur LCD, la valeur du champs magnetique en fonction de la distance.
La fonction map nous permettra de faire cette calcule comme suite
val=map(entree,0,1023,-167,167);

Dans ce cas, notre variable “val” contiendra donc le résultat de la fonction map() de la valeur de l’entrée, initialement comprise entre 0 et 1023 mais actuellement rééchantillonnée entre -167 et 167.

unsigned int temps = 0;
unsigned int entree = 0;
signed int val = 0;

void setup() {
pinMode(Led, OUTPUT); //led carte arduino
pinMode(LEDV, OUTPUT);
pinMode(LEDR, OUTPUT);
pinMode(LEDJ, OUTPUT);

Timer1.initialize(100000); // initialize timer1, and set a 0,1 second period => 100 000
Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
lcd.begin(20, 4);
// Serial1.begin(9600);

Serial.begin(9600);
interrupts();
}

// Interruptions tous les 0.1s
void callback() {
temps++;
//toogle state ledv for check

//************************

if (temps>=1 ) { //
if ( digitalRead(LEDV)== 1 ) {digitalWrite(LEDV,LOW);} else {digitalWrite(LEDV,HIGH);}
entree=analogRead(A0); //

temps=0;
} // fin temps

}//fin routine interruption

// Boucle correspondant à la fonction main
void loop() {

val=map(entree,0,1023,-167,167);
lcd.setCursor(0,0); // (X,Y)
lcd.print(val); //duree 10ms
lcd.print("Tesla ");

} // fin loop

On a simuler notre programme et sur l’écran lcd nous avons bien pour 2.5V, la valeur de 0 Testla, et pour 4V, 100mT.

ETUDE DE BATTERIE NIMH
En moyenne il y aurait 106 piles et batteries présentes dans chaque foyer français et la plupart sont jetées alors qu’elles sont encore utilisables.
Pourquoi ??? la raison est toute simple les personnes lambda ont rarement accès à des outils de diagnostic de batterie. Une solution consiste à utiliser un Arduino avec le code libre accès et les schémas de câblage sur le forum sans oublier les tutos, tout le monde peut diagnostiquer sa batterie.

D’autres se sont tournés vers les batteries rechargeables espérant trouver une issue de secours mais se sont vite heurté à un problème. Mais lequel me direz-vous : les batteries rechargeables sont plus écologiques et sont réutilisables plusieurs fois sans oublier qu’elles ont une grande durée de vie. oui oui et oui mais la plupart des pub et des affiches sont mensongères et les fabricants vous disent rarement la vérité. La grande majorité des batteries n’atteignent même pas la durée affichée sur l’emballage. Saviez-vous par exemple que les batteries perdent 10% de leurs capacités dès qu’elles sortent d’usine ensuite 10 à 15% par mois. Cette étude-ci porte sur les batteries rechargeables Nimh (Nichel-Hydure métallique).
Voici quelques caractéristiques de batterie :
Tension nominale : 1.2v
Nombre de cycles : 500 à 1000
Rendement charge-décharge : 66%
Pour une charge optimale il faut le faire en I=0.1C (capacité en A.h)

Pour la charge et la décharge il est plus judiciable d’utiliser des relays qui sont des interrupteurs commandés en courant donc directement commandé à partir de l’Arduino.

Voici le code :

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/examples/HelloWorld/HelloWorld.pde
//https://www.gotronic.fr/pj2-sbc-lcd16x2-fr-1441.pdf
//https://wiki.mchobby.be/index.php?title=LCD-I2C
//https://microcontrolere.wordpress.com/2019/04/01/arduino-and-i2c-lcd-in-proteus/

LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter

#define led13   13 
#define relays0 12          
#define relays1 11   
#define Charge    9     
#define Decharge  10       
            


    float tension,tension1=0;       // Initialisation 
    float courant=0;
    float sensible=0.066;          // Sensibilité du capteur 
    float offset=2.5;              // Valeur de tension lorsque le courant=0
    float zeroint=512;
    float var,var1=0;  

void setup()
{  // initialise l'afficheur LCD
  ////////// DEFINITION DES E/S //////////////////
pinMode(led13, OUTPUT);
//pinMode(A4, OUTPUT);
//pinMode(A5, OUTPUT);
pinMode(A0, INPUT); // On défini A0 en entrée
pinMode(relays1, OUTPUT);           // On défini relay1 en sortie
pinMode(relays0, OUTPUT);           // On défini relay0 en sortie
 
////////////////*********/////////////////////////

lcd.init();  //et pas lcd begin comme cetraine biblio
// activer l'affichage
  lcd.display();
// allumer retroeclairage
  lcd.backlight();
    lcd.clear();
}

void loop()
{
   digitalWrite(led13,LOW);   //cligotement led 13
   delay(100);
   digitalWrite(led13,HIGH);


  /////////////////*VERSION_2*///////////////////////
 tension=analogRead(A0);           // Lecture de la tension aux bornes de la batterie
 tension1=analogRead(A1);          // Lecture de la tension aux bornes du capteur de courant
 tension= (tension/204);           // Calcul de la tension batterie 
 //tension1=(tension1*5.0)/1023;     // calcul de la tension capteur de courant 
 courant= (tension1-zeroint)/20.4; // Calcul du courant 

////////////////////////////////////////////
 

   //////////////FONCTIONNEL////////////////
 if (digitalRead(Charge)==1)  {digitalWrite(relays0,HIGH);}      // Charge on
 if (digitalRead(Decharge)==1)  {digitalWrite(relays1,HIGH);digitalWrite(relays0,HIGH);}   // décharge on  
 lcd.setCursor(0,0);                 
  lcd.print("Tension : ");         // Affichage de la tension batterie 
  lcd.print(tension,2);
  lcd.setCursor(0,1);
  lcd.print("Courant : ");         // Affichage du courant
  lcd.print(courant,2);
  if (digitalRead(Charge)==0)  {digitalWrite(relays0,LOW);}      // Charge off
 if (digitalRead(Decharge)==0)  {digitalWrite(relays1,LOW);digitalWrite(relays0,LOW); }   // décharge off 

 var=courant+var;            //etat de charge en mA.h
var1=var/36;          //division par 36 si tempsechatillon 100ms    //division par 3.6 pour 1s
lcd.setCursor(0,3);
lcd.print(var1,0);
lcd.print("mAh   ");

  ////////////////////////////////////////
  
    delay(100);
}

Voici quelques résultats de simulation :

Belle introduction, mais quelle est la tension de charge ?

Expliquer pourquoi la valeur 36 pour la mesure de la capacité énergétique et le choix du delay de 0.1s
mais combien de temps dure votre programme ? car il va y avoir une erreur dans la capacité energetique

Ici, c’est les lithiums et pas les Ni-MH, mais ce n’est pas si grave

Ce serait bien de mettre le fichier ISIS.dsn dans votre drive et mettre le lien pour qu’il soit téléchargeable

Vous allez détruire la batterie car :
Pour quelle tension ou courant, on arrête la charge ?
Pour quelle tension, on arrête la décharge ?
Il faudrait mettre à 0 la mesure de la capacité énergétique ma.h entre la charge et la décharge ?
La mesure de la résistance interne de la batterie de l’élément NIMH est un élément crucial pour savoir si la batterie est correcte ou pas.
Vous avez choisi un ACS712 de 20 ampère alors qu’avec un 5 ampère, la précision serait bien meilleur.
D’ailleurs, avec le 20A vous avez 0.05A de precison, don inutile de mettre 3 chiffres après la virgule

Ce n’est pas si mal mais vous êtes seulement à 35% d’un programme final et utile.
pourquoi une resistance R2 de 5ohms ????? il va y avoir des pertes lors de la charge ?

**kobarose, elle confond, tesla et millitesla, **
pire ce quel croit des telsla, ce sont des volts?????? 2.5V correspond à 0Tesla sur le 3144

L’idée initiale du projet était d’utiliser une carte Arduino Méga qui met à disposition un grand nombre d’entrée/sortie numérique et analogique. Il nous aurait été donc possible de tester la durée de vie de plusieurs éléments sur un même montage, malheureusement, on a pu observer que le montage pour un seul éléments été déjà très lourd en termes de câble. On s’est donc tourné vers une utilisation du même montage mais en utilisant un Arduino Nano qui possède bien moins d’entrer sortie ce qui entraine un cout bien moins élevé. L’idée est donc de reproduire le montage avec une multitude d’Arduino nano.
Pour limiter les entrée/sortie on avait à la base décider d’utiliser une liaison I2C pour relier l’écran et la carte Arduino Nano. Tout semblait bien marcher mais une fois qu’il fallait appliquer le programme au montage plus rien ne marchait. Il s’est avéré qu’une liaison I2C empêchait toute commande d’affichage dans l’interruption. 2 choix s’offrait alors à nous soit déplacer toutes les commandes d’affichage de l’interruption dans le programme principale ou tout simplement garder la liaison en parallèle. Nous sommes donc parties sur le choix numéros 2. Problème, il n’y avait pas assez de pin numérique, on a alors juste à utiliser des entrée/sortie analogique. Ces pins fonctionneront comme des Entrée/Sortie numérique.
C’est dans cette optique que j’ai modifier le câblage et l’es donc simuler, tout en veillant à modifier l’initialisation des PIN dans le programme.

Une fois la simulation faite, on a pu commencer à mettre en place le projet dans le réel. Il m’a donc fallu réaliser le câblage de l’écran en parallèle.

Malheureusement la carte des boutons que nous utilisons et sur laquelle on appose l’écran, ne possède pas les dimensions nécessaires, car c’est une carte fabriquer en série. Il me fallait donc faire 2 trous pour dimensionner la carte à l’afficheur. Même comme cela, il fallait que je relis deux pin à la masse et un pin au VCC.

Après avoir réalisé la liaison entre l’Arduino et l’écran en parallèle j’ai joint un petit programme pour tester le fonctionnement.

[ Code]#include "LiquidCrystal.h" // on inclut la librairie
// initialise l'écran avec les bonnes broches
// ATTENTION, REMPLACER LES NOMBRES PAR VOS BRANCHEMENTS À VOUS !
LiquidCrystal lcd(9, 8, 4, 5, 6, 7);
void setup() {
lcd.begin(20, 4);
lcd.print("Salut ca zeste ?");
}
void loop() {
}[ /Code]

Après avoir tester le bon fonctionnement de l’écran je me suis mis à réaliser le câblage du système notamment des 2 relaies.

Malheureusement je n’ai pas pu finir du au confinement, il me reste donc à finir le câblage du système ainsi que la réalisation d’une deuxième liaison série pour relier les boutons de la carte avec l’Arduino nano. Une fois le tout réaliser il faudrait tester le programme et voire si l’intégralité de celui-ci fonctionne.

LTO_nano_banc_test_V3.ino (9.49 KB)

Etat de la charge et de la decharge de la batterie nimh.

Durée de vie
une durée de vie de 500 cycles de charge et de décharge et plus
Un modèle au Li-ion, par exemple, a une durée de vie de 300 à 500 cycles, soit environ deux ans de service dans un ordinateur portable. Bien utilisés, les

En fin de vie, l’impédance interne augmente, le chargeur doit donc être équipé de fonction de contrôle de la température et de la tension permettant d’éviter un échauffement anormal.

Le calcul de leur durée de charge exige de prendre en compte la capacité de la batterie, expri-mée en mAh et l'intensité du courant fourni par le chargeur, en mA. Il suffit ensuite de diviser la capacité par la valeur du courant puis de multiplier par 1,4 pour obtenir la durée requise pour recharger votre accumulateur.
Par exemple, pour un accu de 1600 milliampères par heure rechargée à l'aide d'un chargeur 600 mA, il faudra réaliser la formule suivante :
• 1600 / 600 x 1,4 = 3,73 heures = 3 h 45 minutes environ.
Certains joueurs font alors le choix de se procurer des chargeurs offrant une plus grande inten-sité, afin de réduire le temps de chargement. Cela peut s'avérer utile, mais il faut tout de même respecter certaines limites, sous peine d'endommager le produit et de réduire sa durée de vie.

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
#include <avr/wdt.h> //chien de garde
#include <EEPROM.h>

#define BP1 30 // 30 BP1
#define BP2 31 // 31 BP2
#define BP3 32 // 32 BP3
#define BP4 26 // 32 BP3
#define LEDV 33 // 33 led
#define LEDJ 34 // 34 led
#define LEDR 35 // 35 led
#define relays0 21
#define relays1 20
#define led13 13
#define buzzer 25
#define BP5 12

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=27, Enable=28, D4=25, D5=24, D6= 23, D7=22, BPpoussoir=30
// Configuration des variables

unsigned int cycle=0;
float SOC1=-1450;

void setup() {
lcd.begin(20, 4); //modifier pour un afficheur 20x4
Serial.begin(9600);
EEPROM.put(4000, cycle); //le cycle est l'adresse de l'enregistrement à 4000 octets initialisé à 0
EEPROM.put(cycle, 1400); //derneire mesure du SOC
}

void loop() {
lcd.setCursor(0,0);
lcd.print("init EEprom ");

EEPROM.get(4000, cycle); //verification des données
EEPROM.get(cycle, SOC1);

lcd.setCursor(13,1);
lcd.print(cycle);
lcd.print("Cy ");

lcd.setCursor(0,2);
lcd.print(SOC1,0);
lcd.print("mAh ");

// faut-il reinitialiser toute l'eeprom pour chaque nouvelle batterie

}



SALLMairame:
Etat de la charge et de la decharge de la batterie nimh.

Durée de vie
une durée de vie de 500 cycles de charge et de décharge et plus
Un modèle au Li-ion, par exemple, a une durée de vie de 300 à 500 cycles, soit environ deux ans de service dans un ordinateur portable. Bien utilisés, les

En fin de vie, l’impédance interne augmente, le chargeur doit donc être équipé de fonction de contrôle de la température et de la tension permettant d’éviter un échauffement anormal.

Le calcul de leur durée de charge exige de prendre en compte la capacité de la batterie, expri-mée en mAh et l'intensité du courant fourni par le chargeur, en mA. Il suffit ensuite de diviser la capacité par la valeur du courant puis de multiplier par 1,4 pour obtenir la durée requise pour recharger votre accumulateur.
Par exemple, pour un accu de 1600 milliampères par heure rechargée à l'aide d'un chargeur 600 mA, il faudra réaliser la formule suivante :
• 1600 / 600 x 1,4 = 3,73 heures = 3 h 45 minutes environ.
Certains joueurs font alors le choix de se procurer des chargeurs offrant une plus grande inten-sité, afin de réduire le temps de chargement. Cela peut s'avérer utile, mais il faut tout de même respecter certaines limites, sous peine d'endommager le produit et de réduire sa durée de vie.

https://i65.servimg.com/u/f65/20/18/97/94/a37010.jpg

https://i65.servimg.com/u/f65/20/18/97/94/a37010.jpg

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
#include <avr/wdt.h> //chien de garde
#include <EEPROM.h>

#define BP1 30 // 30 BP1
#define BP2 31 // 31 BP2
#define BP3 32 // 32 BP3
#define BP4 26 // 32 BP3
#define LEDV 33 // 33 led
#define LEDJ 34 // 34 led
#define LEDR 35 // 35 led
#define relays0 21
#define relays1 20
#define led13 13
#define buzzer 25
#define BP5 12

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=27, Enable=28, D4=25, D5=24, D6= 23, D7=22, BPpoussoir=30
// Configuration des variables

unsigned int cycle=0;
float SOC1=-1450;

void setup() {
lcd.begin(20, 4); //modifier pour un afficheur 20x4
Serial.begin(9600);
EEPROM.put(4000, cycle); //le cycle est l'adresse de l'enregistrement à 4000 octets initialisé à 0
EEPROM.put(cycle, 1400); //derneire mesure du SOC
}

void loop() {
lcd.setCursor(0,0);
lcd.print("init EEprom ");

EEPROM.get(4000, cycle); //verification des données
EEPROM.get(cycle, SOC1);

lcd.setCursor(13,1);
lcd.print(cycle);
lcd.print("Cy ");

lcd.setCursor(0,2);
lcd.print(SOC1,0);
lcd.print("mAh ");

// faut-il reinitialiser toute l'eeprom pour chaque nouvelle batterie

}

Bonsoir, j'ai continué le projet qu'avait commencé Adama(22AS99).

  • J'ai ajouté une ligne de code pour le calcul de la résistance interne de la batterie. Cette dernière est obtenue en divisant la différence entre la tension mesurée de la batterie et sa tension électrochimique par l'intensité du courant délivré par le capteur de courant.

  • Etant donné que les caractristiquse d’une batterie NIMH type AA ne
    peut pas decharger à plus de 1A, du coup j'ai pris un capteur ACS712ELCTR-5A

  • J'ai utilisé des leds (vert et rouge). Le led rouge clignote à une fréquence de 1/8s, si la tension d'arret (m=0.9v) et atteinte. Le vert clignote à la meme fréquence si la tension maximale de charge(1.5v) est atteinte.

  • La charge charge et la décharge sont toujours gérées par le bouton poussoir mais il faut avoir un oeil sur
    les leds pour toujours etre dans la plage de tension de batterie.

Voici le code :

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define led13   13 
#define relays1 12          
#define relays0 11   
#define charge_decharge    9     
#define on_off             10  
#define ledV 8   
#define ledR 7   
LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter        
/**********************************************************************************************/
float tension,tensionACS=0;       // Initialisation 
float courant=0;
float sensible=0.185;           // Sensibilité du capteur 
float ACSoffset=2.5;           // Valeur de tension de sortie du capteur lorsque le courant=0
float zeroint=512;
float var,var1=0;  
float R;
float m=0.9; // tension limite minimum
float M=1.5; // tension limite maximum
float E=1.2 ;
/********************************************************************************************/    
void setup()
{
pinMode(led13, OUTPUT);
pinMode(ledV,OUTPUT);
pinMode(ledR,OUTPUT);
pinMode(A0, INPUT); // On défini A0 en entrée
pinMode(relays1, OUTPUT);           // On défini relay1 en sortie
pinMode(relays0, OUTPUT);           // On défini relay0 en sortie
Serial.begin(9600);
lcd.init();         //et pas lcd begin comme cetraine biblio
lcd.display();     // activer l'affichage
lcd.backlight();   // allumer retroeclairage
lcd.clear();      // Effacer le l'écran
}
/******************************************************************************************/
void loop()
{/***********************************Cligotement LED************************************/
 
 digitalWrite(led13,LOW);   //cligotement led 13
 delay(100);
 digitalWrite(led13,HIGH);
/**********Mesure de la tension, du courant et de la capacité********/
 tension=analogRead(A0); // Lecture de la valeur récupèrée de A0
 tension=tension*(5.0/1023.0); // Conversion de cette valeur en une tension comprise entre 0 et 5V (Batterie)
 
 tensionACS=analogRead(A1); // Lecture de la valeur récupèrée de A1
 tensionACS=(tensionACS*5.0)/1023; // Conversion de cette valeur en une tension comprise entre 0 et 5V (Capteur ASC)
 courant=(tensionACS-ACSoffset)/sensible; // Calcul du courant 
 var=courant+var;   //etat de charge en mA.h
 var1=var/360;  //division par 36 si tempsechatillon 100ms    //division par 3600 pour 1s
/**************************La gestion de la charge et décharge*************************/
 if(digitalRead(on_off)==0)  
 {digitalWrite(relays0,LOW);} // off
  else 
 {digitalWrite(relays0,HIGH);} // on  
 if (digitalRead(charge_decharge)==0)  
 {digitalWrite(relays1,LOW); // charge 
 R=(tension-E)/courant;  // Calcul de la résistance interne de la batterie état charge
 if(tension>=M){digitalWrite(ledV,HIGH);
                delay(125);
                digitalWrite(ledV,LOW);}}   
 else
 {digitalWrite(relays1,HIGH); // décharge
 R=(tension-E)/courant;  // Calcul de la résistance interne de la batterie état décharge
 if(tension<=m){digitalWrite(ledR,HIGH); 
                delay(125);
                digitalWrite(ledR,LOW);}} 
/*****************************Affichage sur l'écran LCD*******************************/
 lcd.setCursor(0,0);                 
 lcd.print("Ubat : "); // Affichage de la tension batterie 
 lcd.print(tension,2);
 lcd.print("V");
 lcd.setCursor(0,1);
 lcd.print("Ibat : "); // Affichage du courant
 lcd.print(courant,2);
 lcd.print("A");
 lcd.setCursor(0,2);
 lcd.print("Ri : "); // Affichage de la résistance interne 
 lcd.print(R,2);
 lcd.print("ohm");
 lcd.setCursor(0,3);
 lcd.print(var1,0);
 lcd.print("mAh   ");
}

Voici le lien pour télécharger le schéma isis :

https://drive.google.com/drive/folders/11QPJlObjtTCaNw1ZXwGG7oc1HeF2KfU0

Bonjour, j'apporte des modifications sur mon post du 19 avril
j'ai utilisé le TimerOne à une routine de 100ms.

#include <Wire.h>
#include <SoftwareSerial.h> 
#include <TimerOne.h>
#include <LiquidCrystal_I2C.h>
#define led13   13 
#define relays1 12          
#define relays0 11   
#define charge_decharge    9     
#define on_off             10  
#define ledV 8   
#define ledR 7   
LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter        
/**********************************************************************************************/
float tension,tensionACS=0;       // Initialisation 
float courant=0;
float sensible=0.185;           // Sensibilité du capteur 
float ACSoffset=2.5;           // Valeur de tension de sortie du capteur lorsque le courant=0
float zeroint=512;
float var,var1=0;  
float R;
float m=0.9; // tension limite minimum
float M=1.5; // tension limite maximum
float E=1.2 ; // tension électrochimique
int n=0; // le nombre de fois de 1s
int Cbat=1500; // la capacité nominale de la batterie=1500mAh
float SOC;
int minute;
/********************************************************************************************/    
void setup()
{
  Timer1.initialize(100000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
pinMode(led13, OUTPUT);
pinMode(ledV,OUTPUT);
pinMode(ledR,OUTPUT);
pinMode(A0, INPUT); // On défini A0 en entrée
pinMode(relays1, OUTPUT);           // On défini relay1 en sortie
pinMode(relays0, OUTPUT);           // On défini relay0 en sortie
Serial.begin(9600);
lcd.init();         //et pas lcd begin comme cetraine biblio
//lcd.display();     // activer l'affichage
//lcd.backlight();   // allumer retroeclairage
lcd.clear();      // Effacer le l'écran
}
// Interruptions  tous les 0.1s fait par le timer1***********************************
void callback()  
{
  n++;
  if ( digitalRead(13)== 1 ) {digitalWrite(13,LOW);}  else {digitalWrite(13,HIGH);}
  minute++;
}
/******************************************************************************************/
void loop()
{
 /************************Mesure de la tension, du courant et de la capacité******************/
 if(n>=10){
 n=0;
 tension=analogRead(A0); // Lecture de la valeur récupèrée de A0
 tension=tension*(5.0/1023.0); // Conversion de cette valeur en une tension comprise entre 0 et 5V (Batterie)
 tensionACS=analogRead(A1); // Lecture de la valeur récupèrée de A1
 tensionACS=(tensionACS*5.0)/1023; // Conversion de cette valeur en une tension comprise entre 0 et 5V (Capteur ASC)
 courant=(tensionACS-ACSoffset)/sensible; // Calcul du courant 
 var1=(courant/3.6)+var1;  //division par 3600 si tempsechatillon 1000ms,division par 3600 pour 1s
 //var1=var1*1000; // conversion de la quantité de charge en mAh
 //SOC=var1/Cbat; // état de charge
 //SOC=SOC*100; // état de charge en pourcentage
/******************************La gestion de la charge et décharge****************************/
 
if(digitalRead(on_off)==0) // interrupteur
 {digitalWrite(relays0,LOW);} // off
  else 
 {digitalWrite(relays0,HIGH);} // on  
 if (digitalRead(charge_decharge)==0)  
 {digitalWrite(relays1,LOW); // charge 
//if(minute>600){} // arret de la charge et decharge pendant 4s et mesure de E, calcul de la resistance
 
 R=(tension-E)/courant;  // Calcul de la résistance interne de la batterie état charge
 /*if(tension>=M){digitalWrite(ledV,HIGH);
                delay(125);
                digitalWrite(ledV,LOW);}*/}   
 else
 {digitalWrite(relays1,HIGH); // décharge
 R=(tension-E)/courant;  // Calcul de la résistance interne de la batterie état décharge
 /*if(tension<=m){digitalWrite(ledR,HIGH); 
                delay(125);
                digitalWrite(ledR,LOW);}*/} 
/*****************************Affichage sur l'écran LCD*******************************/
 lcd.setCursor(0,0);                 
 //lcd.print("Ubat : "); // Affichage de la tension batterie 
 lcd.print(tension,2);
 lcd.print("V");
 lcd.print("  "); // Affichage du courant
 lcd.print(courant,2);
 lcd.print("A");
 lcd.setCursor(0,1);
 //lcd.print("Ri : "); // Affichage de la résistance interne 
 lcd.print(R,2);
 lcd.print("ohm");
 lcd.print("  ");
 lcd.print(var1,0);
 lcd.print("mAh   ");
 //lcd.setCursor(0,2);
 //lcd.print("SOC : ");
 //lcd.print(SOC,2);
 //lcd.print("%");
    }//fin if(n>=10)
    
} //fin loop ;

Voici le lien pour télécharger le schéma isis

Cela manque d’explication Mr Touré
Faire un cahier des charges et un algo permettrait d’etre plus explicite dans la gestion du testeur

Apres 1500 commutation du relais, charge et décharge, la résistance interne qui doit être bien inférieur à 0.5 ohms a fortement augmenté et ne permettais plus ni de déchargé à 8A, mais surtout de rechargé à 4A le contact normalement ouvert
C’était un relais Songle

aliexpress

Je pensais que les contacts étaient charbonné mais pas du tout

Donc plutôt, un problème de ressort

Je ne sais pas ce que vaut les autres relais chinois tel que BESTEP….meilleur ou pas ????
Est-ce qu’il y a des copies ?????
Est-ce que je n’ai pas eu de chance ? Ou est ce que cela manque de fiabilité ?

Ces relais ne sont pas chers…mais je prefere payer 3 fois plus et que cela soit fiable

Ce serait bien que ton testeur niMH soit valable pour les 2 types de batteries AA et AAA,
mais il va vous falloir regler le courant de charge et de decharge.....

Mais il va falloir utiliser nombreux boutons poussoirs

Voila les tensions, avec les résistances precedentes du shield precedent

Voici le code

#include <Wire.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
#include <Keypad.h>


#define PWM3       3      //   timer2 
#define LED13     13       

LiquidCrystal lcd(9, 8, 4, 5, 6, 7);   // LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// Configuration des variables
//LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter 20x4ligne


unsigned    int    temps=0; 
unsigned    int    temps1=0;
unsigned    int    Time=0;
unsigned    int    TO=0; 
unsigned    int BoutonP;
String btnStr = "None";



const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}   };
            
byte rowPins[ROWS] = {A1, A2, A3, A4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {12, 11, 10}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


void setup() {
  pinMode(LED13, OUTPUT);
  pinMode(PWM3,OUTPUT);


  Timer1.initialize(1000);           //  
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
  lcd.begin(20, 4);                   //modifier pour un afficheur 20x4
  
  Serial.begin(9600); 
  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 3  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet

attachInterrupt(0, interrup2, FALLING);   // broche2
TO = millis();  

  lcd.setCursor(0,0);    
  lcd.print("IUT GEII Soissons");

//interrupts();  sei ();    //http://gammon.com.au/interrupts 
//noInterrupts(); cli (); 
}


void interrup2() // la fonction appelée par l'interruption externe n°0
{
Time=(millis()-TO);  //mesure du temps
TO = millis();
}

// Interruptions  tous les 1ms fait par le timer1    fe=1000Hz***********************************
void callback()  {
//if ( digitalRead(13)== 1 ) {digitalWrite(13,LOW);}  else {digitalWrite(13,HIGH);}

}//fin routine


///////////////////////////////////////////// Boucle correspondant à la fonction main 
void loop() { 
   
//if ( digitalRead(13)== 1 ) {digitalWrite(13,LOW);}  else {digitalWrite(13,HIGH);}
delay(10); 
BoutonP=analogRead(A7);

 if ((BoutonP <= 1000) ){
    if (BoutonP > 720 && BoutonP < 760){    
       btnStr="Select";                        //741
    } else if (BoutonP > 450 && BoutonP < 550){
      btnStr="Left";                           //506
    } else if (BoutonP < 10){
      btnStr="Right";                         //0             
    } else if (BoutonP > 100 && BoutonP < 200){
      btnStr="Up";
    } else if (BoutonP > 250 && BoutonP < 350){
      btnStr="Down";
    } else if (BoutonP > 820 && BoutonP < 870){
      btnStr="Efface";                        //850
    }
      //update button pressed
      lcd.setCursor(0,1);
      lcd.print(btnStr);
      lcd.print(" "); 
//      lcd.print(BoutonP);
//      lcd.print("    ");  
            }

 //gestion du keypad
char key = keypad.getKey();

  if (key != NO_KEY){
      lcd.setCursor(0,2);
      lcd.print("keypad "); 
      lcd.print(key);
  }  

                
} // fin loop