Buongiorno a tutti , ho realizzato per il mio lavoro (riparazione bici) un semplice battery test per le batterie delle E-bike .
Il sistema è composto da 6 resistenze 100 Watt 4,7 Ohm (nominali , reali sono 5,2 ) messe in serie/parallelo per simulare un carico di circa 350 watt su una batteria Li-On da 36 Volt nominali .
Arduino mi è servito per misurare tensione (tramite un partitore di tensione) e amperaggio tramite l'apposito sensore (20A di limite)
Con un display 1602 I2C tengo sotto controllo tensione e amperaggio , e tramite il monitor seriale registro il tutto per trasferirlo graficamente su un foglio Excel e vedere come si comporta la batteria .
Il sistema funziona bene , ma vorrei implementare degli automatismi , ovvero vorrei attivare il "carico" tramite relè e pulsante , ma le schede che trovo in commercio hanno solo relè da 30V/10A in continua , ora mi chiedevo se usandone due insieme che isolino sia il polo positivo che negativo protrebbero reggere correnti di 10-12 A però a 36 Volt ?
Copio e incollo i dati di voltaggio e amperaggio ricavati dal monitor seriale .
Ecco lo sketch , non avendo mai programmato sono autodidatta copiando e provando a capire quello che trovano in internet sono approdato a questo .
""
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
int PinBatt = A1;
int ValPinBatt;
float Vpin_perc;
float Vbatt;
float calc_res;
float R1 = 82000; //modificare questi valori con i valori realmente utilizzati.
float R2 = 11400;
const int pin = A3; // analog pin
float celsius = 0; // temperature variables
float millivolts; //dichiarazione di variabile tensione (float è per i numeri con la virgola)
int temperatura;
void setup() {
pinMode (PinBatt, INPUT);
calc_res = (R1 + R2)/R2 ;
lcd.init(); // initialize the lcd
// Print a message to the LCD.
lcd.backlight();
lcd.print("BATTERY TEST 1.0");
lcd.setCursor(0,1);
lcd.print("---Trailbike---");
delay(3000);
lcd.clear();
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A1);
// Serial.println(sensorValue);
ValPinBatt = analogRead(PinBatt);
Vpin_perc = map (ValPinBatt, 0, 1023, 0, 500);
//leggerò 1023 quando ho 5 volt sul pin, quindi scalo 0-1023 in 0-500.
Vbatt = Vpin_perc * calc_res / 100 ;
//ora divido tutto per 100 perchè sopra ho scalato da 0 a 500 anzichè da 0 a 5V
// Serial.print("Tensione batteria:");
Serial.print(Vbatt);Serial.print("/");
//int sensorValue = analogRead(A1);
//Serial.println(sensorValue);
float average = 0;
for(int i = 0; i < 1000; i++) {
average =( average + (.049 * analogRead(A0) -25) / 1000);
delay(1);
}
//Serial.print("Amperaggio:");
Serial.println(average);
lcd.print ("AMPERE ");
lcd.print (average);
lcd.setCursor(0,1);
lcd.print (Vbatt);
lcd.print ("VOLT ");
lcd.print(celsius);lcd.print("C");
// lcd.print(average);
delay(1000);
lcd.clear();
temperatura = analogRead(pin); //lettura valore del sensore LM35 messo sull'ingresso analogico A0
millivolts = ( temperatura/1023.0)*5000; //formula per ottenere la tensione di uscita dell'LM35 in millivolts
celsius =millivolts/10; // valore espresso in gradi Celsius (l'out del sensore è 10mv per grado)
/*Serial.println(temperatura); //stampa su serial monitor del valore restituito dal conv. A/D a 10 bit di Arduino(da 0 a 1024)
Serial.print(millivolts); //stampa su serial monitor del valore di tensione in millivolts
Serial.println(" millivolts");
//Il codice
Serial.print(celsius);Serial.println(" C"); // stampa su serial monitor del valore di temperatura in gradi Celsius
Serial.print(farhenheit);Serial.println(" F"); //stampa su serial monitor del valore di temperatura in gradi Farhenheit
*/
}
Il sistema usa anche un sensore LM35DZ per controllare la temperatura delle resistenze e del radiatore . anche se mi da valori molto oscillanti , mi passa da 40 gradi a 75 gradi in un secondo ...forse dovrei usare la media dei valori ...
Ciao, puoi utilizzare un relè allo stato solido per carichi in DC (scegli bene il prodotto) così lo piloti direttamente da arduino.
P.S.: mettendo un relè su positivo e negativo la corrente che scorre è sempre la stessa quindi i 12A passerebbero in ogni relè (in pratica li metti in serie).
Sarebbero da mettere in parallelo MA dato che sono componenti elettromeccanici non staccherebbero/attaccherebbero nello stesso momento quindi comunque non va bene: un relè solo di prestazioni adeguate
Per l'LM35 devi fornirgli una tensione molto pulita e mediare sulle misure.
Meglio che usi dei relé per automobili. Hanno portate dei contatti maggiori e contatti Faston facilmente reperibili. Purtroppo Serve 12V per pilotarli.
Ciao Uwe
Trailbike:
... ora mi chiedevo se usandone due insieme che isolino sia il polo positivo che negativo protrebbero reggere correnti di 10-12 A però a 36 Volt ?
NO, non si fa, si cerca un relè che sopporti le correnti adatta e e si usa quello. Comunque NON ti aspettare di spendere poco, relè che commutano max 25A e che siano almeno in grado di lavorare a 50V, costano sui 35/40 € e poi devi farci il circuito per pilotarli.
Ma, dato che lavori in cc, non ti conviene usare dei MOSFET (naturalmente logic-level così li piloti direttamente da Arduino) ?
Un comunissimo IRL540, montato su una bella aletta di raffreddamento, è in grado di lavorare sino a max. 100Vcc e di commutare carichi fino a max. 25A ! E comunque, se fai una riceca con Google per "logic level MOSFET" ne trovi un'infinità che commutano correnti anche ben superiori.
Sapevo di trovare grazie a voi molte soluzioni .... Avevo anche pensato a relè per auto ma di solito lavorano a 12 volt.... L idea del MOSFET o del relè a stato solido nn l avevo presa in considerazione .
Per lm 35 credo che farò la media mi serve solo per tenere sotto controllo la temperatura del dissipatore che è alla interno della scatola (plastica) con le due ventole a far da ventilazione forzata, nn mi serve una precisione elevata.
gpb01:
...
Un comunissimo IRL540, montato su una bella aletta di raffreddamento, è in grado di lavorare sino a max. 100Vcc e di commutare carichi fino a max. 25A !
...
Io come al solito faccio l'avvocato del diavolo (proprio non resisto :D), e consiglio un mosfet da almeno 100A ... il motivo come al solito e' la potenza dissipata dal componente a pieno carico, e non il fatto che quello indicato da Guglielmo non sia adatto (ho la personale mania del sovradimensionare tutto per evitare problemi a lungo termine :P) ... esempio:
IRL540 ... RdsON = 77 milliohm ... a 10A, caduta di circa 0.77V con dissipazione di circa 7.7W (calduccio, a meno di non usare un dissipatore robusto o ventilato)
BUK954R8-60E (solo come esempio, 60V, 100A) ... RdsON = 4 milliohm ... a 10A avresti una caduta di tensione di 0.04V con una dissipazione in calore di 0.4W (non servirebbe neppure il dissipatore, il case TO220 dissipa fino ad 1W senza problemi gia di suo) ...
Ho trovato questo relè a stato solido dato per 25 amp in AC ....posso usarlo anche in DC con correnti e voltaggio più bassi o nn c'è un rapporto diretto tra i due valori?
Etemenanki:
BUK954R8-60E (solo come esempio, 60V, 100A) ... RdsON = 4 milliohm ... a 10A avresti una caduta di tensione di 0.04V con una dissipazione in calore di 0.4W (non servirebbe neppure il dissipatore, il case TO220 dissipa fino ad 1W senza problemi gia di suo) ...
Rincaro la dose
SIR662, 60V, 100A continui, 350A per 60us, Rdssat 4.8 mohm con 5V sul gate, solo 2.6 mohm con 10V sul gate, li sto usando su uno switching da 100A (si avete letto bene 100 A) e sono ottimi.
Con 30A continui, gate @10V, devono dissipare solo 2.34W, se ben progettato il pc non serve nessun dissipatore aggiuntivo, ovviamente i mos diventano belli caldi, il delta rispetto a Ta è circa 40°, con 20A continui devono dissipare solo 1W e rimangono tiepidi.
Ho trovato questo relè a stato solido dato per 25 amp in AC ....posso usarlo anche in DC con correnti e voltaggio più bassi o nn c'è un rapporto diretto tra i due valori?
Quel tipo di relé al stato solido con corrente continua lo accendi 1 volta e poi non lo spegni piú.
Grazie Uwe , mi sono informato e letto la differenza di funzionamento .
Al momento la soluzione più rapida e il relè a stato solido DC/DC lo acquisto e ci lavoro su così posso anche temporizzate la durata del test con millis se nn vado errato giusto...
Sto ripensando il codice per far sì che premendo un pulsante di avvio test si attivi il carico per 120 secondi e poi si disattivi.
Pensavo di usare millis ma credo si "scontri" con il delay di 1 secondo che ho impostato nelle letture di voltaggio e amperaggio....ho detto una castroneria oppure no?
Penso che il delay di un secondo mi sballera la lettura di 120 secondi da parte di millis....
Ho iniziato a pulire e correggere il codice usando millis al posto di delay , mi potete controllare se ho fatto qualche cavolata , l' IDE mi da tutto corretto e una volta caricato funziona , ho solo cancellato la riga "lcd .clear() " in quanto mi faceva lampeggiare il display LCD e lo rendeva illegibile e non capisco il motivo ...
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
int PinBatt = A1; //pin partitore di tensione per la misurazione
const int pin = A3; // pin del sensore LM35DZ Temperatura
int ValPinBatt;
float Vpin_perc;
float Vbatt;
float calc_res;
float R1 = 82000; //modificare questi valori con i valori realmente utilizzati.
float R2 = 11400;
float celsius = 0; // temperature variables
float millivolts; //dichiarazione di variabile tensione (float è per i numeri con la virgola)
int temperatura;
unsigned long previousMillis = 0;
const long interval = 1000;
void setup() {
pinMode (PinBatt, INPUT);
calc_res = (R1 + R2) / R2 ;
lcd.init(); // initialize the lcd
// Scrive il messaggio di avvio sullo schermo lcd
lcd.backlight();
lcd.print("BATTERY TEST 1.0");
lcd.setCursor(0, 1);
lcd.print("---Trailbike---");
delay(3000);
lcd.clear();
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A1);
ValPinBatt = analogRead(PinBatt);
Vpin_perc = map (ValPinBatt, 0, 1023, 0, 500);
Vbatt = Vpin_perc * calc_res / 100 ;
float average = 0;
for (int i = 0; i < 1000; i++) {
average = ( average + (.049 * analogRead(A0) - 25) / 1000);
}
unsigned long currentMillis = millis();
celsius = (analogRead(pin) / 1023.0) * 500; //calcolo temperatura considerando 10Mv per °
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis ;
Serial.print(Vbatt); Serial.print("/");
Serial.println(average);
lcd.print ("AMPERE ");
lcd.print (average);
lcd.setCursor(0, 1);
lcd.print (Vbatt);
lcd.print ("VOLT ");
lcd.print(celsius); lcd.print("C");
//lcd.clear();
}
}
Ora ho scoperto un piccolo BUG che ho risolto , ovvero mi si bloccava la prima riga del display e non aggiornava i valori .... cosi ho inserito un lcd.clear prima di dichiarare cosa scrivere e mi funziona correttamente , lampeggia solo un pochino quando aggiorna la lettura ma niente di fastidioso .
Inoltre ho riscritto la parte relativa al sensore di temperatura per fare la media su 8 letture .
Ultimo aggiornamento , usando il codice preso dalla pagina di Luca Dentella , ho elaborato un paio di modifiche interessanti , ovvero tramite due pulsanti posso avviare il test per 4 minuti (pulsante verde) oppure stoppare il tutto (pulsante rosso) , attualmente al posto del relè a stato solido che mi avete consigliato ho inserito un led che simula .
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
int PinBatt = A1; //pin partitore di tensione per la misurazione
const int pin = A3; // pin del sensore LM35DZ Temperatura
int ValPinBatt;
float Vpin_perc;
float Vbatt;
float calc_res;
float R1 = 82000; //modificare questi valori con i valori realmente utilizzati.
float R2 = 11400;
float temp = 0; // temperature variables
float millivolts; //dichiarazione di variabile tensione (float è per i numeri con la virgola)
//int temperatura;
unsigned long previousMillis = 0;
const long interval = 1000;
//Gestione temporizzazione test con pulsante
const int button1Pin = 12;
const int button2Pin = 10;
const int led1Pin = 7; // al post del led inserisco un relè
const int led2Pin = 5;
unsigned long led1OnTime;
unsigned long led2OnTime;
bool led1On;
bool led2On;
void setup() {
pinMode (PinBatt, INPUT);
calc_res = (R1 + R2) / R2 ;
lcd.init(); // initialize the lcd
// Scrive il messaggio di avvio sullo schermo lcd
lcd.backlight();
lcd.print("BATTERY TEST 1.5");
lcd.setCursor(0, 1);
lcd.print("---Trailbike---");
delay(3000);
//lcd.clear();
Serial.begin(9600);
//pulsante e led avvio ciclo
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(button1Pin, INPUT);
pinMode(button2Pin, INPUT);
led1On = false;
led2On = false;
}
void loop() {
//calcolo sensore tramite partitore di tensione
int sensorValue = analogRead(A1);
ValPinBatt = analogRead(PinBatt);
Vpin_perc = map (ValPinBatt, 0, 1023, 0, 500);
Vbatt = Vpin_perc * calc_res / 100 ;
//calcolo amperaggio tramite sensore
float ampere = 0;
for (int i = 0; i < 1000; i++) {
ampere = ( ampere + (.049 * analogRead(A0) - 25) / 1000);
/*Calcolo la temperatura media =============================================*/
temp = 0;
for (byte i = 0; i < 10; i++) { //Esegue l'istruzione successiva 10 volte
temp += (analogRead(pin) / 1023.0)*500; //Calcola la temperatura e la somma alla variabile 'temp'
}
temp /= 10; //Calcola la media dei valori di temperatura
//gestione tempo del test con avvio tramite pulsante
{
if (digitalRead(button1Pin) == HIGH) {
digitalWrite(led1Pin, HIGH);lcd.clear() ;lcd.print ("Avvio Test 4 MIN");
delay(1000);
led1On = true;
led1OnTime = millis();
}
if (digitalRead(button2Pin) == HIGH) {
digitalWrite(led1Pin, LOW);lcd.clear();lcd.print("--Test Fermato--");delay(1000);
led2On = true;
led2OnTime = millis();
}
if(led1On)
if(millis() - led1OnTime > 240000) {
digitalWrite(led1Pin, LOW);lcd.clear();lcd.print ("---Fine Test---");delay(2000);
led1On = false;
}
if(led2On)
if(millis() - led2OnTime > 3000) {
digitalWrite(led2Pin, LOW);
led2On = false;
}
}
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis ;
Serial.print(Vbatt); Serial.print("/");
Serial.println(ampere);
lcd.clear();
lcd.print ("AMPERE ");
lcd.print (ampere);
lcd.setCursor(0, 1);
lcd.print (Vbatt);
lcd.print ("VOLT ");
lcd.print(temp); lcd.print("C");
}
}
Il sistema funziona bene , solo che inizio ad avere un po di "casino" all'interno del box che contiene il tutto ... ho tanti fili e mi comincia a diventare complicato gestire i tanti cavi positivi e negativi ..e sto pensando se prendere una screw shield cosi per ogni modifica non mi metto a saldare , è valida come idea ?