Carregador Avançado de Bateria 9V NiMH – Inteligente, Preciso e Confiável – Versão 1
Componentes e Materiais
| Componente | Quantidade | Observações |
|---|---|---|
| Arduino UNO | 1 | |
| SparkFun I2C DAC Breakout - MCP4725 | 1 | |
| Regulador Linear Ajustável (LM317) | 1 | |
| Amplificador Operacional Dual LM358 (TI) | 1 | |
| Resistor 6.8k ohm | 2 | |
| Resistor 3.3k ohm | 1 | |
| Resistor 5.1k ohm | 1 | |
| Resistor 1k ohm | 1 | |
| Resistor 10 ohm (sensor corrente) | 1 | |
| Relé (genérico, 5V) | 1 | |
| Resistor 20k ohm | 1 | |
| Fonte Protoboard 5V/3.3V (SparkFun) | 1 | |
| Fonte 17V | 1 | |
| Módulo LCD I2C 1602 YwRobot | 1 |
Sobre o Projeto
Procurei carregador inteligente que carregue bateria 9V NiMH em poucas horas e não encontrei. Todos eram "burros": corrente de carga desconhecida, sem término automático ao completar carga. Isso sobrecarrega e reduz vida útil. Decidi criar carregador "inteligente".
Versão 1 mantém simplicidade: carga corrente constante, término automático (dV/dt), carga de manutenção (trickle), medição de carga transferida.
Próxima versão: descarga, medição de capacidade, ciclagem.
AVISO: Carregar bateria com corrente alta pode causar explosão ou incêndio. Não deixe carregador sem supervisão. Não tente carregar baterias não recarregáveis (alcalinas). Testado apenas com NiMH (uso por sua conta e risco; sem responsabilidade por danos por bugs no design/código). Outros tipos de bateria exigem modificação no código.
Teoria
Fatos úteis para entender parâmetros do carregador:
- C = corrente igual à capacidade nominal da bateria
- Carregando a taxa C, tensão de célula única pode chegar a 1.6V (mais alta em baterias velhas)
- Tensão nominal célula = 1.2V; célula carregada = até 1.5V circuito aberto
- Trickle recomendado < 0.025 C (C/40) após carga completa
- Duas opções principais para NiMH:
- Carga rápida: 0.5C–1C. Monitorar estado e terminar por dV/dt (taxa variação tensão) ou dT/dt (taxa variação temperatura)
- Carga lenta: 0.1C. Tempo 14–16h. Término por timer. dT/dt impossível em correntes baixas. dV/dt pode ser confiável abaixo de 0.5C

Parâmetros Básicos do Circuito de Carga
Bateria 9V geralmente tem 7 células em série (às vezes 6 ou 8). Regulador deve prover tensão de carga até 8×1.6=12.8V. Dropout do LM317 ~2V → fonte ~15V (sem contar queda no resistor sensor).
Para corrente máxima 200mA e resistor sensor 10Ω, queda adicional = 2V → fonte 17V necessária.
Célula totalmente descarregada pode ter tensão muito baixa, até negativa. Tensão mínima do regulador idealmente 0, mas LM317 mínimo ~1.2V.
Circuito


Explicação do Circuito
Ideia base: medir corrente de carga e ajustar tensão do regulador até corrente desejada. Corrente medida pela queda de tensão no resistor sensor R5. I = V/R.
- MCP4725 (DAC I2C 12-bit): controla tensão via I2C (0–5V). Para faixa 0–15V, usa amplificador operacional LM358. Ganho = 1 + R4/R3 = 1 + 6800/3300 = 3.06 → saída ~0–15V.
- LM317: regulador ajustável para corrente alta. Saída do op-amp no terminal ADJ. LM317 mantém 1.2V entre ADJ e OUT → tensão na bateria configurável 1.2–16.2V. Precisa 3.5mA mínimos para regulação → resistor 1kΩ (R6) garante regulação se bateria desconectada. Capacitor C1 filtra saída e melhora estabilidade.
- Medição tensão em 2 pontos:
- R5 no pino A2 do Arduino. Tensão no resistor → corrente: I_carga = V/R
- Tensão bateria até 16.2V → divisor resistivo R1/R2 traz abaixo de 5V (limite Arduino). Saída no pino A0. R1=5.1k, R2=20k → Vout = Vin/5
- Relé: desconecta bateria do circuito de carga. Use contatos Normalmente Abertos (mais seguro).
- LCD I2C YwRobot 1602: mostra status. Não suportado pela LiquidCrystal_I2C padrão → usei biblioteca New LiquidCrystal. Se usar outro LCD, altere:
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); - Alimentação DAC e LCD: SparkFun Breadboard Power Supply 5V/3.3V (ou 5V do Arduino).
- Fonte 17V: se não tiver, use conversor DC/DC ajustável step-up (ex: XL6009).



Funcionalidade
Sem botões para configurar (evitar fios). Corrente de carga configurada apenas no código (charger.ino):
//*************************** Parâmetros de Carga *****************************************
//*****************************************************************************************
float target_current_mA = 30; // Corrente de carga mA
float battery_nominal_capacity_mA = 170; // Capacidade nominal bateria mA
float max_time_for_trickle_charge = 6; // Tempo máximo trickle em minutos
//*****************************************************************************************
//*****************************************************************************************
target_current_mA — corrente constante de cargamax_time_for_trickle_charge — minutos máximos trickle (até 600 = 10h)battery_nominal_capacity_mA — capacidade para calcular corrente trickle
Corrente de carga até capacidade nominal. Bateria 170mAh → máx 170mA. Mínimo usual C/10 = 17mA.
Ao ligar: verifica se bateria conectada. Se sim, carrega com corrente constante até completa. Término por dV/dt negativo detectado por 5 min. Após completar, muda para trickle C/40. Desconecta após tempo máximo trickle.

1 = dV/dt | 2 = tempo de carga (min)


1 = Tempo carga | 2 = Carga transferida (mAh)
Referências sobre baterias NiMH:
Código
charger.ino (Arduino) - Arquivo Principal
// Carregador 9V NiMH
// Bateria pode ter 6, 7 ou 8 células 1.25V → tensão nominal 7.5–10V
#include
#include
#include
#include
#include
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// Hardware
#define MCP4725_ADDR 0x60
#define DAC_REF_VOLTAGE 5.0
#define CHARGE_RELAY_PIN 2
#define DISCONNECT_CHARGE_RELAY HIGH
#define CONNECT_CHARGE_RELAY LOW
#define CURRENT_SENSING_SESISTOR_PIN A2
#define CURRENT_SENSING_SESISTOR 10.2 // Ohm
#define BATTERY_VOLTAGE_PIN A0
#define R1 5090
#define R2 19910
#define ADC_REF_VOLTAGE 4.89
#define R3 3300.0
#define R4 6800.0
#define AMP_GAIN (1+R4/R3)
#define BATTERY_GOOD_VOLTAGE_THRESHOLD 7.0
#define MAXIMIM_ALLOWED_CURRENT 200
#define MAXIMUM_BATTERY_VOLTAGE 15.0
#define VOLTAGE_STEP 0.001
#define POINTS_FOR_AVERAGING 100
#define MEASURE2MEASURE_US 5000
#define VOLTAGE_LOG_TIME_MIN 30.0
#define MINUTES_TO_LOG 5
#define TRICKLE_CURRENT_RATIO 40
// Estados
#define INITIALIZATION 0
#define NO_BATTERY 5
#define BATTERY_CONNECTED 10
#define BATTERY_VOLTAGE_LOW 15
#define CURRENT_RAMP_UP 20
#define CHARGING 30
#define CURRENT_RAMP_DOWN 32
#define TRICKLE 35
#define END_OF_TRICKLE 37
#define UNEXPECTED_CURRENT_FALL 40
#define UNABLE_TO_REACH_CURRENT 60
#define FULLY_CHARGED 70
#define CURRENT_TOO_HIGH 80
#define REGULATION_FAILED 90
#define OVERCURRENT 100
#define OVERVOLTAGE 101
#define FINAL_STATE 200
unsigned int voltage_readings[POINTS_FOR_AVERAGING], current_sensing_resistor_readings[POINTS_FOR_AVERAGING], averaging_index;
long unsigned int voltage_sum, current_sum;
float regulator_voltage_code, resistor_voltage, csr_voltage_code, regulator_voltage, current_mA, battery_voltage;
float tmp_resistor_voltage, tmp_current_mA, tmp_regulator_voltage, tmp_battery_voltage;
int i, j, charger_state;
short unsigned int last_second, lcd_last_second, log_last_second;
String lcd_last_string1, lcd_last_string2, empty_string = "";
String msg, eoc_line1, eoc_line2;
unsigned char sec_index, min_index;
float sec_log[60], min_log[MINUTES_TO_LOG], last_blf;
float trickle_current_mA;
int total_minutes_average = 0;
elapsedMillis ChargingTimeMillis, TrickleChargingTimeMillis;
float wanted_dac_voltage = 0, last_dac_voltage = 0;
// Mensagens em PROGMEM
const char msg_battery_detected[] PROGMEM = "Bateria detectada";
const char msg_no_battery[] PROGMEM = "Sem bateria";
const char msg_battery_ok[] PROGMEM = "Bateria OK";
const char msg_voltage_too_low[] PROGMEM = "Tensao bateria muito baixa";
const char msg_voltage_too_low_short[] PROGMEM = "V Bateria baixa";
const char msg_ramp_up[] PROGMEM = "Ramp up";
const char msg_charging[] PROGMEM = "Carregando";
const char msg_space[] PROGMEM = " ";
const char msg_ramp_down[] PROGMEM = "Ramp down";
const char msg_trickle_charge[] PROGMEM = "Trickle charge";
const char msg_no_current[] PROGMEM = "Sem corrente";
const char msg_current_unreachable[] PROGMEM = "I inalcancavel";
const char msg_current_unreachable_long[] PROGMEM = "Nao consegue atingir corrente desejada";
const char msg_completed[] PROGMEM = "Completo";
const char msg_charge[] PROGMEM = "Carga";
const char msg_high_current[] PROGMEM = "Corrente alta";
const char msg_regulation_fault[] PROGMEM = "Falha regulacao";
const char msg_overcurrent[] PROGMEM = "Corrente excessiva";
const char msg_overvoltage[] PROGMEM = "Tensao excessiva";
const char msg_trickle_completed[] PROGMEM = "Trickle finalizado";
struct mytime {
unsigned char hours;
unsigned char minutes;
unsigned int total_minutes;
} elapsed_time;
void setup() {
pinMode(CHARGE_RELAY_PIN, OUTPUT);
disconnect_charging_circuit();
Wire.begin();
dac_write_voltage(0);
Serial.begin(115200);
last_second = second();
lcd_last_second = second();
log_last_second = second();
Timer1.initialize(MEASURE2MEASURE_US);
Timer1.attachInterrupt(read_hw);
averaging_index = 0;
sec_index = 0; min_index = 0;
charger_state = 0;
wanted_dac_voltage = 0;
last_blf = 1.0;
trickle_current_mA = battery_nominal_capacity_mA / TRICKLE_CURRENT_RATIO;
lcd.begin(16, 2);
lcd.backlight();
lcd.clear();
update_lcd(F("Ligando..."), empty_string);
delay(1000);
}
float log_battery_voltage() {
if (log_last_second == second()) return last_blf;
log_last_second = second();
sec_log[sec_index] = battery_voltage;
if (sec_index < 59) sec_index++;
else {
if (min_index >= MINUTES_TO_LOG) min_index = 0;
sec_index = 0;
float sum_v = 0;
for (i = 0; i < 60; i++) sum_v += sec_log[i];
float min_average = sum_v / 60.0;
for (i = 1; i < MINUTES_TO_LOG; i++) min_log[i-1] = min_log[i];
min_log[MINUTES_TO_LOG-1] = min_average;
last_blf = best_linear_fit(min_log);
min_index++;
total_minutes_average++;
}
return last_blf;
}
main.ino (Arduino)
void loop() {
String msg1;
switch(charger_state) {
case INITIALIZATION:
disconnect_charging_circuit();
dac_write_voltage(0);
wanted_dac_voltage = 0;
delay(100);
read_status();
if (battery_voltage > 0.1) {
charger_state = BATTERY_CONNECTED;
update_lcd(M2S(msg_battery_detected), empty_string);
Serial.println(M2S(msg_battery_detected));
delay(2000);
} else {
Serial.println(M2S(msg_no_battery));
update_lcd(M2S(msg_no_battery), construct_status_string());
charger_state = NO_BATTERY;
delay(1000);
}
break;
case NO_BATTERY:
read_status();
if (battery_voltage > 0.1) {
charger_state = BATTERY_CONNECTED;
Serial.println(M2S(msg_battery_detected));
update_lcd(M2S(msg_battery_detected), construct_status_string());
delay(1500);
} else {
update_lcd(M2S(msg_no_battery), construct_status_string());
delay(1100);
}
break;
case BATTERY_CONNECTED:
dac_write_voltage(0);
wanted_dac_voltage = 0;
delay(100);
read_status();
if (battery_voltage > BATTERY_GOOD_VOLTAGE_THRESHOLD) {
charger_state = CURRENT_RAMP_UP;
update_lcd(M2S(msg_battery_ok), construct_status_string());
Serial.println(M2S(msg_battery_ok));
delay(2000);
wanted_dac_voltage = get_approximated_dac_voltage(battery_voltage);
connect_charging_circuit();
delay(200);
} else {
charger_state = BATTERY_VOLTAGE_LOW;
Serial.println(M2S(msg_voltage_too_low));
update_lcd(M2S(msg_voltage_too_low_short), construct_status_string());
delay(1000);
}
break;
case BATTERY_VOLTAGE_LOW:
update_lcd(M2S(msg_voltage_too_low_short), construct_status_string());
Serial.println(M2S(msg_voltage_too_low));
charger_state = FINAL_STATE;
break;
case CURRENT_RAMP_UP:
read_status();
update_lcd(M2S(msg_ramp_up), construct_status_string());
delay(50);
if (current_mA < target_current_mA) {
if (wanted_dac_voltage < 4.99) {
wanted_dac_voltage += VOLTAGE_STEP;
dac_write_voltage(wanted_dac_voltage);
} else charger_state = UNABLE_TO_REACH_CURRENT;
} else {
charger_state = CHARGING;
ChargingTimeMillis = 0;
}
break;
case CHARGING:
delay(200);
read_status();
if (current_mA < 1.0) charger_state = UNEXPECTED_CURRENT_FALL;
if (battery_voltage > MAXIMUM_BATTERY_VOLTAGE) charger_state = OVERVOLTAGE;
if (abs(current_mA - target_current_mA) > 0.2) {
if (current_mA < target_current_mA) {
if (wanted_dac_voltage < 4.99) wanted_dac_voltage += VOLTAGE_STEP;
else charger_state = UNABLE_TO_REACH_CURRENT;
} else {
if (wanted_dac_voltage > 0.01) wanted_dac_voltage -= VOLTAGE_STEP;
else charger_state = CURRENT_TOO_HIGH;
}
}
if (abs(current_mA - target_current_mA) > 5) charger_state = REGULATION_FAILED;
dac_write_voltage(wanted_dac_voltage);
if (total_minutes_average < MINUTES_TO_LOG) msg = String(M2S(msg_charging) + M2S(msg_space) + "---");
else msg = String(M2S(msg_charging) + M2S(msg_space) + String(last_blf, 3));
update_lcd(msg, construct_status_string());
log_battery_voltage();
if (last_blf < 0) charger_state = FULLY_CHARGED;
break;
case CURRENT_RAMP_DOWN:
read_status();
update_lcd(M2S(msg_ramp_down), construct_status_string());
Serial.println(M2S(msg_ramp_down));
delay(50);
if (current_mA > trickle_current_mA) {
if (wanted_dac_voltage > VOLTAGE_STEP) {
wanted_dac_voltage -= VOLTAGE_STEP;
dac_write_voltage(wanted_dac_voltage);
} else charger_state = CURRENT_TOO_HIGH;
} else {
charger_state = TRICKLE;
TrickleChargingTimeMillis = 0;
Serial.println(M2S(msg_trickle_charge));
}
break;
case TRICKLE:
delay(200);
read_status();
if (current_mA < 0.2) charger_state = UNEXPECTED_CURRENT_FALL;
if (battery_voltage > MAXIMUM_BATTERY_VOLTAGE) charger_state = OVERVOLTAGE;
if (abs(current_mA - trickle_current_mA) > 0.2) {
if (current_mA < trickle_current_mA) {
if (wanted_dac_voltage < 4.99) wanted_dac_voltage += VOLTAGE_STEP;
else charger_state = UNABLE_TO_REACH_CURRENT;
} else {
if (wanted_dac_voltage > 0.01) wanted_dac_voltage -= VOLTAGE_STEP;
else charger_state = CURRENT_TOO_HIGH;
}
}
if (abs(current_mA - trickle_current_mA) > 5) charger_state = REGULATION_FAILED;
dac_write_voltage(wanted_dac_voltage);
if ((second() % 8) < 4) update_lcd(M2S(msg_trickle_charge), construct_status_string());
else update_lcd(eoc_line1, eoc_line2);
elapsed_time = mills2time(TrickleChargingTimeMillis);
if (elapsed_time.total_minutes > max_time_for_trickle_charge) {
update_lcd(eoc_line1, eoc_line2);
charger_state = END_OF_TRICKLE;
disconnect_charging_circuit();
}
break;
case END_OF_TRICKLE:
if ((second() % 8) < 4) update_lcd(M2S(msg_trickle_completed), construct_status_string());
else update_lcd(eoc_line1, eoc_line2);
break;
case UNEXPECTED_CURRENT_FALL:
Serial.println(F("Corrente caiu inesperadamente"));
disconnect_charging_circuit();
wanted_dac_voltage = 0;
update_lcd(M2S(msg_no_current), construct_status_string());
charger_state = FINAL_STATE;
delay(1000);
break;
case UNABLE_TO_REACH_CURRENT:
Serial.println(M2S(msg_current_unreachable_long));
disconnect_charging_circuit();
wanted_dac_voltage = 0;
dac_write_voltage(0);
delay(1000);
update_lcd(M2S(msg_current_unreachable), construct_status_string());
charger_state = FINAL_STATE;
break;
case FULLY_CHARGED:
elapsed_time = mills2time(ChargingTimeMillis);
int charge_mAh = calculate_charge(ChargingTimeMillis);
msg = String(M2S(msg_completed) + M2S(msg_space) + construct_time_string(elapsed_time));
msg1 = String(M2S(msg_charge) + M2S(msg_space) + String(charge_mAh) + "mAh");
eoc_line1 = msg; eoc_line2 = msg1;
update_lcd(msg, msg1);
Serial.println(msg);
delay(3000);
charger_state = CURRENT_RAMP_DOWN;
break;
case CURRENT_TOO_HIGH:
Serial.println(F("Nao consegue baixar corrente alvo"));
disconnect_charging_circuit();
wanted_dac_voltage = 0;
dac_write_voltage(0);
update_lcd(M2S(msg_high_current), construct_status_string());
delay(1000);
charger_state = FINAL_STATE;
break;
case REGULATION_FAILED:
Serial.println(M2S(msg_regulation_fault));
disconnect_charging_circuit();
wanted_dac_voltage = 0;
dac_write_voltage(0);
update_lcd(M2S(msg_regulation_fault), construct_status_string());
delay(1000);
charger_state = FINAL_STATE;
break;
case OVERCURRENT:
disconnect_charging_circuit();
Serial.println(M2S(msg_overcurrent));
wanted_dac_voltage = 0;
dac_write_voltage(wanted_dac_voltage);
update_lcd(M2S(msg_overcurrent), construct_status_string());
delay(1000);
charger_state = FINAL_STATE;
break;
case OVERVOLTAGE:
disconnect_charging_circuit();
Serial.println(M2S(msg_overvoltage));
wanted_dac_voltage = 0;
dac_write_voltage(wanted_dac_voltage);
update_lcd(M2S(msg_overvoltage), construct_status_string());
delay(1000);
charger_state = FINAL_STATE;
break;
case FINAL_STATE:
delay(10000);
break;
default:
wanted_dac_voltage = 0;
charger_state = 0;
}
read_status();
if (last_second != second()) {
Serial.print(current_mA); Serial.print(","); Serial.println(battery_voltage);
last_second = second();
}
}
hw.ino (Arduino)
float get_approximated_dac_voltage(float vbat) {
float offset_voltage = 1.2;
float adc_voltage = (vbat - offset_voltage) / AMP_GAIN - 0.5;
if (adc_voltage < 0) adc_voltage = 0;
return adc_voltage;
}
int voltage_to_code(float voltage) {
return 4095.0 / DAC_REF_VOLTAGE * voltage;
}
void dac_write(int code) {
Wire.beginTransmission(MCP4725_ADDR);
Wire.write(64);
Wire.write(code >> 4);
Wire.write((code & 15) << 4);
Wire.endTransmission();
}
void read_status() {
voltage_sum = 0; current_sum = 0;
for (i = 0; i < POINTS_FOR_AVERAGING; i++) {
voltage_sum += voltage_readings[i];
current_sum += current_sensing_resistor_readings[i];
}
regulator_voltage_code = (float)voltage_sum / POINTS_FOR_AVERAGING;
csr_voltage_code = (float)current_sum / POINTS_FOR_AVERAGING;
regulator_voltage = regulator_voltage_code * (ADC_REF_VOLTAGE / 1023.0) * (R1 + R2) / R1;
resistor_voltage = csr_voltage_code * (ADC_REF_VOLTAGE / 1023.0);
current_mA = resistor_voltage / CURRENT_SENSING_SESISTOR * 1000;
battery_voltage = regulator_voltage - resistor_voltage;
}
void dac_write_voltage(float voltage) {
if (last_dac_voltage == voltage) return;
last_dac_voltage = voltage;
dac_write(voltage_to_code(voltage));
}
void read_hw() {
voltage_readings[averaging_index] = analogRead(BATTERY_VOLTAGE_PIN);
current_sensing_resistor_readings[averaging_index] = analogRead(CURRENT_SENSING_SESISTOR_PIN);
tmp_resistor_voltage = current_sensing_resistor_readings[averaging_index] * (ADC_REF_VOLTAGE / 1023.0);
tmp_current_mA = tmp_resistor_voltage / CURRENT_SENSING_SESISTOR * 1000;
tmp_regulator_voltage = voltage_readings[averaging_index] * (ADC_REF_VOLTAGE / 1023.0) * (R1 + R2) / R1;
tmp_battery_voltage = tmp_regulator_voltage - tmp_resistor_voltage;
averaging_index++;
if (averaging_index >= POINTS_FOR_AVERAGING) averaging_index = 0;
if (tmp_battery_voltage > MAXIMUM_BATTERY_VOLTAGE) {
disconnect_charging_circuit();
charger_state = OVERVOLTAGE;
}
if (tmp_current_mA > MAXIMIM_ALLOWED_CURRENT) {
disconnect_charging_circuit();
charger_state = OVERCURRENT;
}
}
void disconnect_charging_circuit() { digitalWrite(CHARGE_RELAY_PIN, DISCONNECT_CHARGE_RELAY); }
void connect_charging_circuit() { digitalWrite(CHARGE_RELAY_PIN, CONNECT_CHARGE_RELAY); }
lcd.ino (Arduino)
void update_lcd(String first_line, String second_line) {
if (lcd_last_string1 != first_line) {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(first_line);
lcd_last_string1 = first_line;
lcd.setCursor(0, 1); lcd.print(second_line);
lcd_last_string2 = second_line;
}
if (lcd_last_second != second()) {
if (lcd_last_string2 != second_line) {
lcd.setCursor(0, 1); lcd.print(second_line);
lcd_last_string2 = second_line;
}
}
lcd_last_second = second();
}
String construct_status_string() {
String v = (battery_voltage < 10) ? String(battery_voltage, 2) : String(battery_voltage, 1);
String i = (current_mA < 10) ? String(current_mA, 2) : String(current_mA, 1);
mytime elapsed; String msg, msg_time;
switch (charger_state) {
case CHARGING: elapsed = mills2time(ChargingTimeMillis); break;
case TRICKLE: elapsed = mills2time(TrickleChargingTimeMillis); break;
}
if (charger_state == CHARGING || charger_state == TRICKLE) {
if (elapsed.total_minutes < 10) msg_time = String(elapsed.total_minutes) + " ";
else if (elapsed.total_minutes < 100) msg_time = String(elapsed.total_minutes) + " ";
else msg_time = String(elapsed.total_minutes);
}
switch (charger_state) {
case CHARGING: msg = v + "V " + i + "mA " + msg_time; break;
case TRICKLE: msg = v + "V " + i + "mA " + msg_time; break;
default: msg = v + "V " + i + "mA";
}
msg.replace("-", "");
return msg;
}
String construct_time_string(mytime timeinfo) {
return String(timeinfo.hours, DEC) + ":" + String(timeinfo.minutes, DEC);
}
calculations.ino (Arduino)
float best_linear_fit(float y[MINUTES_TO_LOG]) {
float sx = 0, sy = 0, sxx = 0, sxy = 0;
for (i = 0; i < MINUTES_TO_LOG; ++i) {
sx += (float)i;
sy += y[i];
sxx += (float)i * (float)i;
sxy += (float)i * y[i];
}
float delta = MINUTES_TO_LOG * sxx - sx * sx;
float slope = (MINUTES_TO_LOG * sxy - sx * sy) / delta;
return slope;
}
mytime mills2time(unsigned long time_mills) {
mytime result;
result.total_minutes = time_mills / 1000 / 60;
result.hours = result.total_minutes / 60;
result.minutes = result.total_minutes % 60;
return result;
}
int calculate_charge(unsigned long time_mills) {
unsigned int elapsed_sec = time_mills / 1000;
float elapsed_hours = elapsed_sec / 60.0 / 60.0 * target_current_mA;
return (int)elapsed_hours;
}
String M2S(const char signMessage[]) {
int k, len = strlen_P(signMessage);
String mess;
for (k = 0; k < len; k++) mess += (char)pgm_read_byte_near(signMessage + k);
return mess;
}
Biblioteca New LiquidCrystal
Usada para o display LCD I2C YwRobot. (Download apenas)
Esquemáticos
charger_AgK96zxw2T.zip
Processo de manufatura
- Alerta Inteligente de Sede para Plantas – Sensor DIY para Hidratação Ideal
- Relógio de Palavras em Italiano com Arduino Nano, NeoPixel, LCD e RTC
- Economize Pinos do Arduino: Conecte Teclado 4x3 com Apenas Três Conexões
- Medidor kWh Confiável com Sigfox e Arduino MKR Fox 1200
- Monitor de Temperatura com Bluetooth usando Arduino Nano
- Fechadura por Gestos Sem Toque: Acesso Seguro com APDS-9960 e Arduino
- Companion IC: Relógio, Ohmímetro, Capacímetro e Testador de Diodos com Arduino Nano
- Kit Adaptador USB-MIDI para Arduino Micro/Leonardo – Lista Completa de Peças
- Circuito de Entrada Analógica Isolada para Arduino
- Teste de Tempo de Reação Preciso com Arduino UNO