Depuis la dernière fois sur ce forum j'ai continué d'en apprendre sur la programmation des PICs avec quelques petits projets, notamment la réalisation d'un superviseur de charge.
Il fait une mesure de la tension aux bornes des batteries toutes les 15 minutes, et si nécessaire active et relaye le chargeur vers la batterie en besoin, pendant 30 minutes. Le PIC utilisé est un classique 16F684. Les 4 batteries peuvent être indépendantes ou en série, et pour ce faire j'ai clairement copié le câblage des relais du schéma de Mr P. DEMERLIAC ici : http://philippe.demerliac.free.fr/Misc.htm#CP46
Je souhaiterais perfectionner ce projet, hors cette fois-ci je mets la barre vraiment plus haut. Ecran OLED SSD1306 128x64 et ADCs qui communiqueront en SPI avec le PIC via quadruples optocoupleurs, détection du nombre de batteries connectées, comptage du nombre de cycles de charge, réglage de la tension de déclenchement de la charge, réglage du délais entre chaque contrôle de tension, arrêt du chargeur lorsque la tension paramétrée est atteinte, etc.
Pour mener à bien ce projet je prévois de passer de MPLAB IDE v8.91 à MPLAB X. Et j'ai commandé un pickit4 chez Microchip pour remplacer mon pickit2 asiatique actuel. Je pense aussi passer de CCS à un compilateur Microchip pour bénéficier de MCC. XC8 ?
Bref, première question qui se pose : quel PIC utiliser pour ce projet ? Il semble être temps pour moi d'abandonner la série 16F pour passer sur du 18F ou 24F ?
Quelques photos de ma première version fonctionnelle de ce superviseur.



Et le code en C, certainement perfectible mais néanmoins fonctionnel.
//////////////////////////////////////////////////////////
//// CARTE SUPERVISEUR 4 BATTERIES ////
//// COMPILATEUR CCS ////
//// DEVELOPPEMENT MPLAB IDE v8.91 ////
//// 10/01/2021 ////
//////////////////////////////////////////////////////////
#include <16F684.h>
#use delay(clock=4000000) //fréquence de l'oscillateur interne : 4MHz
#fuses INTRC_IO,NOWDT,NOPUT,NOBROWNOUT,NOMCLR,NOPROTECT,NOCPD,NOPUT,NOIESO,NOFCMEN,BROWNOUT_NOSL //il faut tous les mettre sinon ça marche pas
#use fast_io(A) // permet d'utiliser set_tris_X(), sinon CCS affecte automatiquement les ports.
#use fast_io(C) // permet d'utiliser set_tris_X(), sinon CCS affecte automatiquement les ports.
#byte ANSEL = 0x91
#byte CMCON0 = 0x19
#byte ADCON0 = 0x1F
#byte ADCON1 = 0x9F
#byte ADRESH = 0x1E
#byte ADRESL = 0x9E
//////ADRESSES PORTS ET BITS E/S//////
#byte portA=5 //adresse du port A
#byte WPUA=95 //adresse WPUA
#byte IOCA=96 //adresse IOCA
#bit RAPU = 0x81.7
#byte portC=7 //adresse du port C
#bit relais_bat_4=portA.0 //affectation du RA0
#bit relais_bat_3=portA.1 //affectation du RA1
#bit relais_bat_2=portA.2 //affectation du RA2
#bit RA3=portA.3 //affectation du RA3
#bit RA4=portA.4 //affectation du RA4
#bit RA5=portA.5 //affectation du RA5
#bit relais_bat_1=portC.0 //affectation du RC0
#bit relais_chargeur_230V=portC.1 //affectation du RC1
#bit relais_chargeur_12V=portC.2 //affectation du RC2
#bit mesure_tension=portC.3 //affectation du RC3
#bit RC4=portC.4 //affectation du RC4
#bit RC5=portC.5 //affectation du RC5
//////TIMER1 REGISTRES//////
#byte INTCON = 0x0B //INTCON REGISTER adresse 10h
#byte T1CON = 0x10 //T1CON REGISTER adresse 10h
#byte TMR1L = 0x0E //TMR1L REGISTER adresse 0Eh
#byte TMR1H = 0x0F //TMR1H REGISTER adresse 0Fh
#bit TMR1IF = 0x0C.0 //adresse du bit Flag quand le timer déborde
#bit TMR1IE = 0x8C.0 //adresse du bit d'activation des interruptions
#bit GIE = 0x0B.7
#bit PEIE = 0x0B.6
//////DECLARATION VARIABLES//////
long adresult;
long ref;
int hi;
int lo;
int demisec,min,hr;
//////INTERRUPTION TIMER1//////
#int_timer1
void interrupt_timer1() //routine d'interruption Timer1 (if TMR1IF==1)
{
TMR1IF=0; //flag du Timer1 à 0
T1CON=0x34; //0b00110100 Timer1 arrêté
TMR1L=0xDB; //config précharge compteur 16 bits
TMR1H=0x0B; //0x0BDB (3035 en decimal) (pour compter de 3035 à 65535 pour avoir 0.5 seconde)
T1CON=0x35; //0b00110101 Timer1 démarré
demisec++;
if (demisec==120) {demisec=0,min++;}
if (min==60) {min=0,hr++;}
if (hr==24) {hr=0;}
}
void main()
{
//////PORTS ET BITS E/S//////
ANSEL=0x80; //entrée analogique AN7 (RC3) uniquement
ADCON0=0b10011100; //
ADCON1=0b01010000; //Fosc/16
CMCON0=0xFF; //désactive les comparateurs
SET_TRIS_A(0x00); //tout le portA en sortie
SET_TRIS_C(0x08); //tout le portC en sortie sauf RC3 -> 0b00001000
RAPU=1; //1 = PORTA pull-ups are disabled
WPUA=0x00; //0 = Pull-up disabled
IOCA=0x00; //0 = Interrupt-on-change disabled
//////VALEURS VARIABLES//////
adresult=0;
ref=0b0000001010000101; //seuil 12.61V -> 645(decimal) //20V -> 1023
demisec=0;
min=0;
hr=0;
//////TIMERS (GENERAL)//////
INTCON=0xC0; //GIE et PEIE à 1 pour activer interruptions (bits 7 et 6)du Timer1
//T0IE : 0 = Disables the TMR0 interrupt
//INTE : 0 = Disables the BP_Ton_RA2/INT external interrupt
//RAIE : 0 = Disables the PORTA change interrupt
//T0IF : 0 = TMR0 register did not overflow
//INTF : 0 = The BP_Ton_RA2/INT external interrupt did not occur
//RAIF : 0 = None of the PORTA <5:0> pins have changed state
//////TIMER1 REGISTRES//////
T1CON=0x34; //0b00110100 Timer1 arrêté
TMR1L=0xDB; //config précharge compteur 16 bits
TMR1H=0x0B; //0x0BDB (3035 en decimal) (pour compter de 3035 à 65535 pour avoir 0.5 seconde)
TMR1IF=0; //flag du Timer1 à 0
TMR1IE=1; //1 = Enables the Timer1 overflow interrupt
T1CON=0x35; //0b00110101 Timer1 démarré
//////INITIALISATION RELAIS//////
relais_bat_1=0;
relais_bat_2=0;
relais_bat_3=0;
relais_bat_4=0;
relais_chargeur_230V=0;
relais_chargeur_12V=0;
//////////////////Boucle principale/////////////////////
while(1)
{
///////////Batterie 1///////////
relais_bat_1=1;
delay_ms (5000);
ADCON0=0b10011101; //allume le can
delay_ms (10);
ADCON0=0b10011111; //démarre une conversion
delay_ms (10);
// adresult=ADRESH<<8;
// adresult=adresult|ADRESL;
hi=ADRESH;
lo=ADRESL;
adresult=make16(hi,lo);
if (adresult<=ref && adresult>153) //Si tension comprise entre 3V et ref
{
demisec=0;
min=0;
hr=0;
while (min<30) //temps de charge = 30 minutes
{
relais_chargeur_230V=1;
delay_ms (1000);
relais_chargeur_12V=1;
}
relais_chargeur_12V=0;
delay_ms (500);
relais_chargeur_230V=0;
delay_ms (500);
relais_bat_1=0;
}
else {
demisec=0;
min=0;
hr=0;
while (min<15) //temps repos entre 2 contrôles de tension = 15min
{
relais_bat_1=0;
}
}
///////////Batterie 2///////////
relais_bat_2=1;
delay_ms (5000);
ADCON0=0b10011101; //allume le can
delay_ms (10);
ADCON0=0b10011111; //démarre une conversion
delay_ms (10);
// adresult=ADRESH<<8;
// adresult=adresult|ADRESL;
hi=ADRESH;
lo=ADRESL;
adresult=make16(hi,lo);
if (adresult<=ref && adresult>153)
{
demisec=0;
min=0;
hr=0;
while (min<30) //temps de charge = 30 minutes
{
relais_chargeur_230V=1;
delay_ms (1000);
relais_chargeur_12V=1;
}
relais_chargeur_12V=0;
delay_ms (500);
relais_chargeur_230V=0;
delay_ms (500);
relais_bat_2=0;
}
else {
demisec=0;
min=0;
hr=0;
while (min<15) //temps repos entre 2 contrôles de tension = 15min
{
relais_bat_2=0;
}
}
///////////Batterie 3///////////
relais_bat_3=1;
delay_ms (5000);
ADCON0=0b10011101; //allume le can
delay_ms (10);
ADCON0=0b10011111; //démarre une conversion
delay_ms (10);
// adresult=ADRESH<<8;
// adresult=adresult|ADRESL;
hi=ADRESH;
lo=ADRESL;
adresult=make16(hi,lo);
if (adresult<=ref && adresult>153)
{
demisec=0;
min=0;
hr=0;
while (min<30) //temps de charge = 30 minutes
{
relais_chargeur_230V=1;
delay_ms (1000);
relais_chargeur_12V=1;
}
relais_chargeur_12V=0;
delay_ms (500);
relais_chargeur_230V=0;
delay_ms (500);
relais_bat_3=0;
}
else {
demisec=0;
min=0;
hr=0;
while (min<15) //temps repos entre 2 contrôles de tension = 15min
{
relais_bat_3=0;
}
}
///////////Batterie 4///////////
relais_bat_4=1;
delay_ms (5000);
ADCON0=0b10011101; //allume le can
delay_ms (10);
ADCON0=0b10011111; //démarre une conversion
delay_ms (10);
// adresult=ADRESH<<8;
// adresult=adresult|ADRESL;
hi=ADRESH;
lo=ADRESL;
adresult=make16(hi,lo);
if (adresult<=ref && adresult>153)
{
demisec=0;
min=0;
hr=0;
while (min<30) //temps de charge = 30 minutes
{
relais_chargeur_230V=1;
delay_ms (1000);
relais_chargeur_12V=1;
}
relais_chargeur_12V=0;
delay_ms (500);
relais_chargeur_230V=0;
delay_ms (500);
relais_bat_4=0;
}
else {
demisec=0;
min=0;
hr=0;
while (min<15) //temps repos entre 2 contrôles de tension = 15min
{
relais_bat_4=0;
}
}
}
}



un projet tres interessant ..