Инструкция
Данное зарядное устройство предназначено для зарядки металлгидридных аккумуляторов.
На фотографии видна маркировка металлгидридного аккумулятора (1) и его ёмкость в миллиампер часах (2). Рекомендуем для долговременной работы аккумулятора, для зарядки использовать ток равный 10% его ёмкости.
Перед первым использованием установите зарядный ток. (Power)
Зарядка
Устройство имеет два режима зарядки, автоматический (Auto) и пользовательский (Manually). В пользовательском режиме необходимо установить время зарядки. Чтобы установить время выберите Time и установите время в часах. При зарядном токе 10% мы рекомендуем 11ч - 13ч зарядки. Точное время назвать невозможно, так как потеря ёмкости аккумулятора приводит к уменьшению времени зарядки. Также необходимо включить пользовательский режим. Для этого выберите Mode затем Manually. Для зарядки в автоматическом режиме Вам необходимо установить максимально допустимое напряжение на аккумуляторе, для этого необходимо узнать какое напряжение будет на вашем аккумуляторе на последнем часе зарядки в пользовательском режиме. Для установки напряжения автоматической зарядки выберите Mode, затем выберите Auto stop at, установите нужное напряжение и нажмите Enter. Зарядка будет продолжаться пока не будет достигнуто установленное напряжение.
Для старта зарядки вставьте аккумулятор / аккумуляторы и выберите Charge.
Когда аккумулятор заряжен, устройство выводит сообщение Done под соответствующим аккумулятором и зарядка отключается.
Разрядка
Устройство позволяет разряжать аккумуляторы, при этом рассчитывая их отдаваемую ёмкость в миллиампер часах (mAh), что даёт возможность определить степень износа аккумулятора. Важно: Перед замером ёмкости аккумулятор нужно зарядить.
Для полной зарядки аккумулятора, мы рекомендуем предварительно разряжать аккумуляторы.
Когда аккумулятор разряжен, устройство выводит сообщение Done под соответствующим аккумулятором и разрядка отключается.
Для старта разрядки вставьте аккумулятор / аккумуляторы и выберите Discharge.
К сведенью: Не оставляйте аккумуляторы в отключеном устройстве на длительное время.
Коррекция напряжения
Для корректной работы всех режимов устройства, необходимо убедиться в правильности измеряемых напряжений. Так как невозможно предугадать падения напряжения в цепи аккумулятора, мы добавили возможность ввести коррекции для всех режимов. Чтобы рассчитать необходимую коррекцию, Вам понадобится мультиметр. Включите режим зарядки, установите необходимый ток, замерьте напряжение непосредственно на контактах аккумулятора и сравните его с напряжением которое показано на экране устройства. Разница этих двух напряжений и будет коррекцией которую можно добавить в скетч: строки 9 - 12.
Аналогично для разрядки.
Доп. информация
Мы ограничили максимальный зарядный ток до 300мА. Чтобы изменить этот параметр необходимо переписать константу maxPower в скетче. Важно: Источник питания и прочие элементы схемы должны соответствовать новому току. Также увеличение зарядного тока приведёт к нагреву аккумулятора и возможно потребуется контролировать его температуру при помощи термосенсора, и дополнить условие остановки заряда в скетче (строка 212). Мы оставили два аналоговых пина контроллера свободными для сенсоров.
Константа discharging_mVolt указывает напряжение при достижении которого отключится разрядка аккумулятора.
Пояснения к схеме:
Подстроечный резистор для установки контрастности монитора, вывод V0, можно использовать номиналом от 50 до 500 kОm. Вращайте резистор пока не появится текст на мониторе. Резисторы 5 Оm нужно взять мощные, минимум 2 ватт. Мощность остальных резисторов не имеет значения. Также номиналы этих резисторов (кроме резисторов 5 Оm) можно увеличить до 10 раз. Конденсаторы тоже могут быть больше в 10 раз.
#include <LiquidCrystal.h>
#include <EEPROM.h>
LiquidCrystal lcd(7,6,4,5,3,2); // (RS,E,D4,D5,D6,D7)
// Constants
/////////////////////////////////////////
int maxPower = 30; // Maximal charging power. 30 = 300mA, 1 = 10mA
int discharging_mVolt = 950; // Volt (milli volt) value where the discharging will stop. 900 = 900mV
float correctionCharging1 = 0.0; // Correction of charging first accu (Volt). 0.15 = 0.15V
float correctionCharging2 = 0.0; // Correction of charging second accu (Volt).
float correctionDischarging1 = 0.0; // Correction of discharging first accu (Volt).
float correctionDischarging2 = 0.0; // Correction of discharging second accu (Volt).
/////////////////////////////////////////
boolean mainMenuIsDisplayed = true;
boolean chargingIsDisplayed = false;
boolean disChargingIsDisplayed = false;
boolean powerIsDisplayed = false;
boolean timeIsDisplayed = false;
boolean modeIsDisplayed = false;
boolean changeVoltIsDisplayed = false;
int upButton = 12;
int downButton = 19;
int enterButton = 8;
int resetPin = 11;
int relay1Pin = 13;
int relay2Pin = 18;
int PWM1Pin = 10;
int PWM2Pin = 9;
int volt1_1Pin = 14;
int volt1_2Pin = 21;
int volt2_1Pin = 15;
int volt2_2Pin = 20;
int hours = EEPROM.read(0);
int power = EEPROM.read(1);
float maxVolt = EEPROM.read(3);
int cursorPosition = 1;
byte selectArrow[8] = {
0b11000,
0b11100,
0b11110,
0b11111,
0b11111,
0b11110,
0b11100,
0b11000
};
void setup(){
pinMode(downButton, INPUT_PULLUP);
pinMode(upButton, INPUT_PULLUP);
pinMode(enterButton, INPUT_PULLUP);
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(PWM1Pin, OUTPUT);
pinMode(PWM2Pin, OUTPUT);
// 7.8kHz 10 bit
TCCR1A = 0b00000011;
TCCR1B = 0b00000001;
Serial.begin(115200);
lcd.begin(20, 4); // Initialize the display, (columns, rows)
lcd.createChar(0, selectArrow);
drawMenu();
}
void loop(){
if (digitalRead(upButton) == 0){
upPressed();
delay(300);
}
if (digitalRead(downButton) == 0){
downPressed();
delay(300);
}
if (digitalRead(enterButton) == 0){
enterPressed();
delay(300);
}
}
void charging(){
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Accu 1");
lcd.setCursor(14, 0);
lcd.print("Accu 2");
lcd.setCursor(0, 1);
lcd.print("V:");
lcd.setCursor(0, 2);
lcd.print("mA:");
uint32_t sec;
int timeHours = 0;
int timeMins;
String minsZero;
boolean RUN = true;
boolean accu1Finished = false;
boolean accu2Finished = false;
boolean accu1IsPluggedIn = false;
boolean accu2IsPluggedIn = false;
int PWM1 = 300;
int PWM2 = 300;
int power = EEPROM.read(1);
power *= 10;
analogWrite(PWM1Pin, PWM1);
analogWrite(PWM2Pin, PWM2);
while (RUN){
sec = millis() / 1000ul;
timeHours = (sec / 3600ul);
timeMins = (sec % 3600ul) / 60ul;
float mV1_1 = analogRead(volt1_1Pin);
float mV1_2 = analogRead(volt1_2Pin);
float mV2_1 = analogRead(volt2_1Pin);
float mV2_2 = analogRead(volt2_2Pin);
mV1_1 = mV1_1 * 5000 / 1023;
mV1_2 = mV1_2 * 5000 / 1023;
mV2_1 = mV2_1 * 5000 / 1023;
mV2_2 = mV2_2 * 5000 / 1023;
float voltAccu1 = ((5000 - mV1_1) / 1000) + correctionCharging1;
float voltAccu2 = ((5000 - mV2_1) / 1000) + correctionCharging2;
int mAmpere1 = (mV1_1 - mV1_2) / 5;
int mAmpere2 = (mV2_1 - mV2_2) / 5;
if (mV1_1 < 50){
accu1IsPluggedIn = false;
PWM1 = 0;
showNoAccu(6);
} else {
accu1IsPluggedIn = true;
}
if (mV2_1 < 50){
accu2IsPluggedIn = false;
PWM2 = 0;
showNoAccu(14);
} else {
accu2IsPluggedIn = true;
}
if (!accu1Finished && accu1IsPluggedIn){
if (power != mAmpere1){
if (mAmpere1 < 5){
PWM1 += 100;
} else if (power - mAmpere1 >= 40){
PWM1 += 20;
}
if (mAmpere1 < power){
PWM1++;
} else {
PWM1--;
}
}
}
if (!accu2Finished && accu2IsPluggedIn){
if (power != mAmpere2){
if (mAmpere2 < 5){
PWM2 += 100;
} else if (power - mAmpere2 >= 40){
PWM2 += 20;
}
if (mAmpere2 < power){
PWM2++;
} else {
PWM2--;
}
}
}
analogWrite(PWM1Pin, PWM1);
analogWrite(PWM2Pin, PWM2);
if (!accu1Finished && accu1IsPluggedIn){
showChargingData(6, voltAccu1, mAmpere1);
}
if (!accu2Finished && accu2IsPluggedIn){
showChargingData(14, voltAccu2, mAmpere2);
}
// auto
if (EEPROM.read(2) == 0){
if (voltAccu1 >= maxVolt / 100 && accu1IsPluggedIn){
accu1Finished = true;
PWM1 = 0;
analogWrite(PWM1Pin, PWM1);
lcd.setCursor(6, 2);
lcd.print("Done");
}
if (voltAccu2 >= maxVolt / 100 && accu2IsPluggedIn){
accu2Finished = true;
PWM2 = 0;
analogWrite(PWM2Pin, PWM2);
lcd.setCursor(14, 2);
lcd.print("Done");
}
if ((accu1Finished || !accu1IsPluggedIn) && (accu2Finished || !accu2IsPluggedIn)){
RUN = false;
lcd.setCursor(0, 3);
lcd.print("Press enter to exit");
}
} else { // manually
lcd.setCursor(0, 0);
lcd.print(" ");
if (timeMins < 10){
minsZero = "0";
} else {
minsZero = "";
}
lcd.setCursor(0, 0);
lcd.print(String(timeHours) + ":" + minsZero + String(timeMins));
if (timeHours >= hours){
accu1Finished = true;
accu2Finished = true;
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(6, 2);
lcd.print("Done");
lcd.setCursor(14, 2);
lcd.print("Done");
lcd.setCursor(0, 3);
lcd.print("Press enter to exit");
PWM1 = 0;
PWM2 = 0;
analogWrite(PWM1Pin, PWM1);
analogWrite(PWM2Pin, PWM2);
RUN = false;
} else if (!accu1IsPluggedIn && !accu2IsPluggedIn){
showNoAccu(6);
showNoAccu(14);
lcd.setCursor(0, 3);
lcd.print("Press enter to exit");
PWM1 = 0;
PWM2 = 0;
analogWrite(PWM1Pin, PWM1);
analogWrite(PWM2Pin, PWM2);
RUN = false;
}
}
delay(2000);
}
for(;;){
if (digitalRead(enterButton) == 0){
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, LOW);
}
delay(50);
}
}
void discharge(){
boolean discharging1Finished = false;
boolean discharging2Finished = false;
boolean accu1IsPluggedIn = false;
boolean accu2IsPluggedIn = false;
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Accu 1");
lcd.setCursor(14, 0);
lcd.print("Accu 2");
lcd.setCursor(0, 1);
lcd.print("mAh:");
lcd.setCursor(0, 2);
lcd.print("V:");
lcd.setCursor(0, 3);
lcd.print("mA:");
digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
delay(500);
float mAh1 = 0;
float mAh2 = 0;
for (;;){
// first accu
float mV1_2 = analogRead(volt1_2Pin);
mV1_2 = (mV1_2 * 5000) / 1023;
mV1_2 += correctionDischarging1 * 1000;
if (mV1_2 <= 100 && !discharging1Finished){
accu1IsPluggedIn = false;
showNoAccu(6);
} else {
accu1IsPluggedIn = true;
}
if (!discharging1Finished && accu1IsPluggedIn){
float mAmpere1 = mV1_2 / 5; // 5Ω
mAh1 += mAmpere1 * 0.0027777778;
float V1_2 = mV1_2 / 1000;
showDischargingData(6, int(mAh1), V1_2, int(mAmpere1));
if (mV1_2 < discharging_mVolt && mV1_2 > 100){
discharging1Finished = true;
digitalWrite(relay1Pin, LOW);
lcd.setCursor(6, 2);
lcd.print("Done");
lcd.setCursor(6, 3);
lcd.print(" ");
}
}
// second accu
float mV2_2 = analogRead(volt2_2Pin);
mV2_2 = (mV2_2 * 5000) / 1023;
mV2_2 += correctionDischarging2 * 1000;
if (mV2_2 <= 100 && !discharging2Finished){
accu2IsPluggedIn = false;
showNoAccu(14);
} else {
accu2IsPluggedIn = true;
}
if (!discharging2Finished && accu2IsPluggedIn){
float mAmpere2 = mV2_2 / 5; // 5Ω
mAh2 += mAmpere2 * 0.0027777778;
float V2_2 = mV2_2 / 1000;
showDischargingData(14, int(mAh2), V2_2, int(mAmpere2));
if (mV2_2 < discharging_mVolt && mV2_2 > 100){
discharging2Finished = true;
digitalWrite(relay2Pin, LOW);
lcd.setCursor(14, 2);
lcd.print("Done");
lcd.setCursor(14, 3);
lcd.print(" ");
}
}
if ((discharging1Finished || !accu1IsPluggedIn) && (discharging2Finished || !accu2IsPluggedIn)){
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print("Press enter to exit");
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, LOW);
for (;;){
if (digitalRead(enterButton) == 0){
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, LOW);
}
delay(50);
}
}
delay(10000);
}
}
void drawMenu(){
mainMenuIsDisplayed = true;
lcd.clear();
drawCursor();
lcd.setCursor(1, 0);
lcd.print("Charge");
lcd.setCursor(1, 1);
lcd.print("Discharge");
lcd.setCursor(1, 2);
lcd.print("Power");
lcd.setCursor(7, 2);
lcd.print(String(power) + "0" + "mA");
lcd.setCursor(1, 3);
lcd.print("Time");
lcd.setCursor(7, 3);
lcd.print(String(hours) + "h");
String showMode;
if (EEPROM.read(2) == 0){
showMode = "Auto";
} else {
showMode = "Manu";
}
lcd.setCursor(11, 0);
lcd.print("Mode:" + showMode);
}
void drawCursor(){
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(10, 0);
lcd.print(" ");
if (cursorPosition == 1){
lcd.setCursor(0, 0);
lcd.write(byte(0));
} else if (cursorPosition == 2){
lcd.setCursor(0, 1);
lcd.write(byte(0));
} else if (cursorPosition == 3){
lcd.setCursor(0, 2);
lcd.write(byte(0));
} else if (cursorPosition == 4){
lcd.setCursor(0, 3);
lcd.write(byte(0));
} else if (cursorPosition == 5){
lcd.setCursor(10, 0);
lcd.write(byte(0));
}
}
void upPressed(){
if (mainMenuIsDisplayed){
if (cursorPosition == 1){
cursorPosition = 5;
} else {
cursorPosition--;
}
drawCursor();
}
if (timeIsDisplayed){
if (hours < 99){
hours++;
}
changeTime();
}
if (powerIsDisplayed){
if (power < maxPower){
power++;
}
changePower();
}
if (modeIsDisplayed){
if(cursorPosition == 1){
cursorPosition++;
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.write(byte(0));
} else {
cursorPosition--;
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.write(byte(0));
}
}
if (changeVoltIsDisplayed){
if (maxVolt < 200){
maxVolt++;
lcd.setCursor(10, 0);
maxVolt /= 100;
lcd.print(String(maxVolt) + "V");
maxVolt *= 100;
}
}
}
void downPressed(){
if (mainMenuIsDisplayed){
if (cursorPosition == 5){
cursorPosition = 1;
} else {
cursorPosition++;
}
drawCursor();
}
if (timeIsDisplayed){
if (hours > 1){
hours--;
}
changeTime();
}
if (powerIsDisplayed){
if (power > 1){
power--;
}
changePower();
}
if (modeIsDisplayed){
if(cursorPosition == 1){
cursorPosition++;
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.write(byte(0));
} else {
cursorPosition--;
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.write(byte(0));
}
}
if (changeVoltIsDisplayed){
if (maxVolt > 100){
Serial.print("1:");
Serial.println(maxVolt);
maxVolt--;
Serial.println("2:");
Serial.println(maxVolt);
lcd.setCursor(10, 0);
maxVolt /= 100;
lcd.print(String(maxVolt) + "V");
maxVolt *= 100;
}
}
}
void enterPressed(){
if (powerIsDisplayed){
powerIsDisplayed = false;
drawMenu();
EEPROM.write(1, power);
} else if (changeVoltIsDisplayed){
changeVoltIsDisplayed = false;
EEPROM.write(3, maxVolt);
drawMenu();
} else if (timeIsDisplayed){
timeIsDisplayed = false;
drawMenu();
EEPROM.write(0, hours);
} else if (modeIsDisplayed){
if(cursorPosition == 1){
modeIsDisplayed = false;
changeVoltIsDisplayed = true;
EEPROM.write(2, 0);
lcd.clear();
showInfo();
lcd.setCursor(0,0);
float maxVolt = EEPROM.read(3);
maxVolt /= 100;
lcd.print("charge to " + String(maxVolt) + "V");
maxVolt *= 100;
} else if (cursorPosition == 2){
EEPROM.write(2, 1);
modeIsDisplayed = false;
cursorPosition = 1;
drawMenu();
}
} else if (mainMenuIsDisplayed){
if (cursorPosition == 1){
charging();
chargingIsDisplayed = true;
} else if(cursorPosition == 2){
discharge();
disChargingIsDisplayed = true;
} else if(cursorPosition == 3){
changePower();
powerIsDisplayed = true;
} else if(cursorPosition == 4){
changeTime();
timeIsDisplayed = true;
} else if(cursorPosition == 5){
changeMode();
modeIsDisplayed = true;
}
mainMenuIsDisplayed = false;
}
delay(300);
}
void changeTime(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Charging " + String(hours) + " hours");
showInfo();
}
void changePower(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Charging " + String(power) + "0" " mA");
showInfo();
}
void changeMode(){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Charging mode:");
lcd.setCursor(0, 1);
lcd.write(byte(0));
cursorPosition = 1;
maxVolt /= 100;
String autoText = "Auto stop at " + String(maxVolt) + "V";
maxVolt *= 100;
lcd.setCursor(1, 1);
lcd.print(autoText);
lcd.setCursor(1, 2);
lcd.print("Manually");
}
void showInfo(){
lcd.setCursor(0, 1);
lcd.print("Up = add");
lcd.setCursor(0, 2);
lcd.print("Down = reduce");
lcd.setCursor(0, 3);
lcd.print("Enter = save & exit");
}
void showNoAccu(int col){
lcd.setCursor(col, 1);
lcd.print(" ");
lcd.setCursor(col, 1);
lcd.print("No");
lcd.setCursor(col, 2);
lcd.print("accu");
lcd.setCursor(col, 3);
lcd.print(" ");
}
void showChargingData(int col, float v, int mA){
lcd.setCursor(col, 1);
lcd.print(" ");
lcd.setCursor(col, 1);
lcd.print(String(v));
lcd.setCursor(col, 2);
lcd.print(" ");
lcd.setCursor(col, 2);
lcd.print(String(mA));
}
void showDischargingData(int col, int mAh, float v, int mA){
lcd.setCursor(col, 1);
lcd.print(" ");
lcd.setCursor(col, 1);
lcd.print(String(mAh));
lcd.setCursor(col, 2);
lcd.print(" ");
lcd.setCursor(col, 2);
lcd.print(String(v));
lcd.setCursor(col, 3);
lcd.print(" ");
lcd.setCursor(col, 3);
lcd.print(String(mA));
}
Библиотеки:
LiquidCrystal Версия 1.0.6
Пример готового устройства: