Charger for nickel-metal-hydride accumulators
This device allows you to charge batteries according to the parameters you set.
Components and supplies
1
Arduino Nano
1
2 relay module
2
IRF510N MOSFET
1
20x4 LCD
Tools and machines
1
Multimeter
1
Soldering iron (generic)
Apps and platforms
1
Arduino IDE
Project description
Code
Here is the Code for the charger.
cpp
You will need the LiquidCrystal-1.0.6 library
1#include <LiquidCrystal.h> 2#include <EEPROM.h> 3LiquidCrystal lcd(7,6,4,5,3,2); // (RS,E,D4,D5,D6,D7) 4 5// Constants 6///////////////////////////////////////// 7int maxPower = 30; // Maximal charging power. 30 = 300mA, 1 = 10mA 8int discharging_mVolt = 950; // Volt (milli volt) value where the discharging will stop. 900 = 900mV 9float correctionCharging1 = -0.15; // Correction (Volt). 0.15 = 0.15V 10float correctionCharging2 = -0.15; // 11float correctionDischarging1 = 0.05; // 12float correctionDischarging2 = 0.05; // 13///////////////////////////////////////// 14 15boolean mainMenuIsDisplayed = true; 16boolean chargingIsDisplayed = false; 17boolean disChargingIsDisplayed = false; 18boolean powerIsDisplayed = false; 19boolean timeIsDisplayed = false; 20boolean modeIsDisplayed = false; 21boolean changeVoltIsDisplayed = false; 22 23int upButton = 12; 24int downButton = 19; 25int enterButton = 8; 26int resetPin = 11; 27int relay1Pin = 13; 28int relay2Pin = 18; 29int PWM1Pin = 10; 30int PWM2Pin = 9; 31int volt1_1Pin = 14; 32int volt1_2Pin = 21; 33int volt2_1Pin = 15; 34int volt2_2Pin = 20; 35 36int hours = EEPROM.read(0); 37int power = EEPROM.read(1); 38float maxVolt = EEPROM.read(3); 39 40int cursorPosition = 1; 41 42byte selectArrow[8] = { 43 0b11000, 44 0b11100, 45 0b11110, 46 0b11111, 47 0b11111, 48 0b11110, 49 0b11100, 50 0b11000 51}; 52 53void setup(){ 54 pinMode(downButton, INPUT_PULLUP); 55 pinMode(upButton, INPUT_PULLUP); 56 pinMode(enterButton, INPUT_PULLUP); 57 pinMode(relay1Pin, OUTPUT); 58 pinMode(relay2Pin, OUTPUT); 59 pinMode(PWM1Pin, OUTPUT); 60 pinMode(PWM2Pin, OUTPUT); 61 62 // 7.8kHz 10 bit 63 TCCR1A = 0b00000011; 64 TCCR1B = 0b00000001; 65 //Serial.begin(115200); 66 lcd.begin(20, 4); // Initialize the display, (columns, rows) 67 68 lcd.createChar(0, selectArrow); 69 drawMenu(); 70} 71 72void loop(){ 73 if (digitalRead(upButton) == 0){ 74 upPressed(); 75 delay(300); 76 } 77 if (digitalRead(downButton) == 0){ 78 downPressed(); 79 delay(300); 80 } 81 if (digitalRead(enterButton) == 0){ 82 enterPressed(); 83 delay(300); 84 } 85} 86 87void charging(){ 88 lcd.clear(); 89 lcd.setCursor(6, 0); 90 lcd.print("Accu 1"); 91 lcd.setCursor(14, 0); 92 lcd.print("Accu 2"); 93 lcd.setCursor(0, 1); 94 lcd.print("V:"); 95 lcd.setCursor(0, 2); 96 lcd.print("mA:"); 97 98 uint32_t sec; 99 int timeHours = 0; 100 int timeMins; 101 String minsZero; 102 103 boolean RUN = true; 104 boolean accu1Finished = false; 105 boolean accu2Finished = false; 106 boolean accu1IsPluggedIn = false; 107 boolean accu2IsPluggedIn = false; 108 109 int PWM1 = 300; 110 int PWM2 = 300; 111 int power = EEPROM.read(1); 112 power *= 10; 113 analogWrite(PWM1Pin, PWM1); 114 analogWrite(PWM2Pin, PWM2); 115 116 while (RUN){ 117 sec = millis() / 1000ul; 118 timeHours = (sec / 3600ul); 119 timeMins = (sec % 3600ul) / 60ul; 120 121 float mV1_1 = analogRead(volt1_1Pin); 122 float mV1_2 = analogRead(volt1_2Pin); 123 124 float mV2_1 = analogRead(volt2_1Pin); 125 float mV2_2 = analogRead(volt2_2Pin); 126 127 mV1_1 = mV1_1 * 5000 / 1023; 128 mV1_2 = mV1_2 * 5000 / 1023; 129 130 mV2_1 = mV2_1 * 5000 / 1023; 131 mV2_2 = mV2_2 * 5000 / 1023; 132 133 float voltAccu1 = ((5000 - mV1_1) / 1000) + correctionCharging1; 134 float voltAccu2 = ((5000 - mV2_1) / 1000) + correctionCharging2; 135 136 int mAmpere1 = (mV1_1 - mV1_2) / 5; 137 int mAmpere2 = (mV2_1 - mV2_2) / 5; 138 139 if (mV1_1 < 50){ 140 accu1IsPluggedIn = false; 141 PWM1 = 0; 142 showNoAccu(6); 143 } else { 144 accu1IsPluggedIn = true; 145 } 146 147 if (mV2_1 < 50){ 148 accu2IsPluggedIn = false; 149 PWM2 = 0; 150 showNoAccu(14); 151 } else { 152 accu2IsPluggedIn = true; 153 } 154 155 if (!accu1Finished && accu1IsPluggedIn){ 156 if (power != mAmpere1){ 157 if (mAmpere1 < 5){ 158 PWM1 += 100; 159 } else if (power - mAmpere1 >= 40){ 160 PWM1 += 20; 161 } 162 if (mAmpere1 < power){ 163 PWM1++; 164 } else { 165 PWM1--; 166 } 167 } 168 } 169 170 if (!accu2Finished && accu2IsPluggedIn){ 171 if (power != mAmpere2){ 172 if (mAmpere2 < 5){ 173 PWM2 += 100; 174 } else if (power - mAmpere2 >= 40){ 175 PWM2 += 20; 176 } 177 if (mAmpere2 < power){ 178 PWM2++; 179 } else { 180 PWM2--; 181 } 182 } 183 } 184 185 analogWrite(PWM1Pin, PWM1); 186 analogWrite(PWM2Pin, PWM2); 187 188 if (!accu1Finished && accu1IsPluggedIn){ 189 showChargingData(6, voltAccu1, mAmpere1); 190 } 191 192 if (!accu2Finished && accu2IsPluggedIn){ 193 showChargingData(14, voltAccu2, mAmpere2); 194 } 195 196 // auto 197 if (EEPROM.read(2) == 0){ 198 if (voltAccu1 >= maxVolt / 100 && accu1IsPluggedIn){ 199 accu1Finished = true; 200 PWM1 = 0; 201 analogWrite(PWM1Pin, PWM1); 202 lcd.setCursor(6, 2); 203 lcd.print("Done"); 204 } 205 if (voltAccu2 >= maxVolt / 100 && accu2IsPluggedIn){ 206 accu2Finished = true; 207 PWM2 = 0; 208 analogWrite(PWM2Pin, PWM2); 209 lcd.setCursor(14, 2); 210 lcd.print("Done"); 211 } 212 if ((accu1Finished || !accu1IsPluggedIn) && (accu2Finished || !accu2IsPluggedIn)){ 213 RUN = false; 214 lcd.setCursor(0, 3); 215 lcd.print("Press enter to exit"); 216 } 217 } else { // manually 218 lcd.setCursor(0, 0); 219 lcd.print(" "); 220 if (timeMins < 10){ 221 minsZero = "0"; 222 } else { 223 minsZero = ""; 224 } 225 lcd.setCursor(0, 0); 226 lcd.print(String(timeHours) + ":" + minsZero + String(timeMins)); 227 if (timeHours >= hours){ 228 accu1Finished = true; 229 accu2Finished = true; 230 lcd.setCursor(0, 2); 231 lcd.print(" "); 232 lcd.setCursor(6, 2); 233 lcd.print("Done"); 234 lcd.setCursor(14, 2); 235 lcd.print("Done"); 236 lcd.setCursor(0, 3); 237 lcd.print("Press enter to exit"); 238 PWM1 = 0; 239 PWM2 = 0; 240 analogWrite(PWM1Pin, PWM1); 241 analogWrite(PWM2Pin, PWM2); 242 RUN = false; 243 } else if (!accu1IsPluggedIn && !accu2IsPluggedIn){ 244 showNoAccu(6); 245 showNoAccu(14); 246 lcd.setCursor(0, 3); 247 lcd.print("Press enter to exit"); 248 PWM1 = 0; 249 PWM2 = 0; 250 analogWrite(PWM1Pin, PWM1); 251 analogWrite(PWM2Pin, PWM2); 252 RUN = false; 253 } 254 } 255 delay(2000); 256 } 257 for(;;){ 258 if (digitalRead(enterButton) == 0){ 259 pinMode(resetPin, OUTPUT); 260 digitalWrite(resetPin, LOW); 261 } 262 delay(50); 263 } 264} 265 266void discharge(){ 267 boolean discharging1Finished = false; 268 boolean discharging2Finished = false; 269 boolean accu1IsPluggedIn = false; 270 boolean accu2IsPluggedIn = false; 271 lcd.clear(); 272 lcd.setCursor(6, 0); 273 lcd.print("Accu 1"); 274 lcd.setCursor(14, 0); 275 lcd.print("Accu 2"); 276 lcd.setCursor(0, 1); 277 lcd.print("mAh:"); 278 lcd.setCursor(0, 2); 279 lcd.print("V:"); 280 lcd.setCursor(0, 3); 281 lcd.print("mA:"); 282 283 digitalWrite(relay1Pin, HIGH); 284 digitalWrite(relay2Pin, HIGH); 285 delay(500); 286 float mAh1 = 0; 287 float mAh2 = 0; 288 for (;;){ 289 // first accu 290 float mV1_2 = analogRead(volt1_2Pin); 291 mV1_2 = (mV1_2 * 5000) / 1023; 292 mV1_2 += correctionDischarging1 * 1000; 293 294 if (mV1_2 <= 100 && !discharging1Finished){ 295 accu1IsPluggedIn = false; 296 showNoAccu(6); 297 } else { 298 accu1IsPluggedIn = true; 299 } 300 301 if (!discharging1Finished && accu1IsPluggedIn){ 302 float mAmpere1 = mV1_2 / 5; // 5Ω 303 mAh1 += mAmpere1 * 0.0027777778; 304 305 float V1_2 = mV1_2 / 1000; 306 307 showDischargingData(6, int(mAh1), V1_2, int(mAmpere1)); 308 309 if (mV1_2 < discharging_mVolt && mV1_2 > 100){ 310 discharging1Finished = true; 311 digitalWrite(relay1Pin, LOW); 312 lcd.setCursor(6, 2); 313 lcd.print("Done"); 314 lcd.setCursor(6, 3); 315 lcd.print(" "); 316 } 317 } 318 319 // second accu 320 float mV2_2 = analogRead(volt2_2Pin); 321 mV2_2 = (mV2_2 * 5000) / 1023; 322 mV2_2 += correctionDischarging2 * 1000; 323 324 if (mV2_2 <= 100 && !discharging2Finished){ 325 accu2IsPluggedIn = false; 326 showNoAccu(14); 327 } else { 328 accu2IsPluggedIn = true; 329 } 330 331 if (!discharging2Finished && accu2IsPluggedIn){ 332 float mAmpere2 = mV2_2 / 5; // 5Ω 333 mAh2 += mAmpere2 * 0.0027777778; 334 float V2_2 = mV2_2 / 1000; 335 336 showDischargingData(14, int(mAh2), V2_2, int(mAmpere2)); 337 338 if (mV2_2 < discharging_mVolt && mV2_2 > 100){ 339 discharging2Finished = true; 340 digitalWrite(relay2Pin, LOW); 341 lcd.setCursor(14, 2); 342 lcd.print("Done"); 343 lcd.setCursor(14, 3); 344 lcd.print(" "); 345 } 346 } 347 348 if ((discharging1Finished || !accu1IsPluggedIn) && (discharging2Finished || !accu2IsPluggedIn)){ 349 lcd.setCursor(0, 1); 350 lcd.print(" "); 351 lcd.setCursor(0, 2); 352 lcd.print(" "); 353 lcd.setCursor(0, 3); 354 lcd.print(" "); 355 lcd.setCursor(0, 3); 356 lcd.print("Press enter to exit"); 357 digitalWrite(relay1Pin, LOW); 358 digitalWrite(relay2Pin, LOW); 359 for (;;){ 360 if (digitalRead(enterButton) == 0){ 361 pinMode(resetPin, OUTPUT); 362 digitalWrite(resetPin, LOW); 363 } 364 delay(50); 365 } 366 } 367 delay(10000); 368 } 369} 370 371void drawMenu(){ 372 mainMenuIsDisplayed = true; 373 lcd.clear(); 374 375 drawCursor(); 376 377 lcd.setCursor(1, 0); 378 lcd.print("Charge"); 379 lcd.setCursor(1, 1); 380 lcd.print("Discharge"); 381 lcd.setCursor(1, 2); 382 lcd.print("Power"); 383 lcd.setCursor(7, 2); 384 lcd.print(String(power) + "0" + "mA"); 385 lcd.setCursor(1, 3); 386 lcd.print("Time"); 387 lcd.setCursor(7, 3); 388 lcd.print(String(hours) + "h"); 389 String showMode; 390 if (EEPROM.read(2) == 0){ 391 showMode = "Auto"; 392 } else { 393 showMode = "Manu"; 394 } 395 lcd.setCursor(11, 0); 396 lcd.print("Mode:" + showMode); 397} 398 399void drawCursor(){ 400 lcd.setCursor(0, 0); 401 lcd.print(" "); 402 lcd.setCursor(0, 1); 403 lcd.print(" "); 404 lcd.setCursor(0, 2); 405 lcd.print(" "); 406 lcd.setCursor(0, 3); 407 lcd.print(" "); 408 lcd.setCursor(10, 0); 409 lcd.print(" "); 410 411 if (cursorPosition == 1){ 412 lcd.setCursor(0, 0); 413 lcd.write(byte(0)); 414 } else if (cursorPosition == 2){ 415 lcd.setCursor(0, 1); 416 lcd.write(byte(0)); 417 } else if (cursorPosition == 3){ 418 lcd.setCursor(0, 2); 419 lcd.write(byte(0)); 420 } else if (cursorPosition == 4){ 421 lcd.setCursor(0, 3); 422 lcd.write(byte(0)); 423 } else if (cursorPosition == 5){ 424 lcd.setCursor(10, 0); 425 lcd.write(byte(0)); 426 } 427} 428 429void upPressed(){ 430 if (mainMenuIsDisplayed){ 431 if (cursorPosition == 1){ 432 cursorPosition = 5; 433 } else { 434 cursorPosition--; 435 } 436 drawCursor(); 437 } 438 439 if (timeIsDisplayed){ 440 if (hours < 99){ 441 hours++; 442 } 443 changeTime(); 444 } 445 446 if (powerIsDisplayed){ 447 if (power < maxPower){ 448 power++; 449 } 450 changePower(); 451 } 452 453 if (modeIsDisplayed){ 454 if(cursorPosition == 1){ 455 cursorPosition++; 456 lcd.setCursor(0, 1); 457 lcd.print(" "); 458 lcd.setCursor(0, 2); 459 lcd.write(byte(0)); 460 } else { 461 cursorPosition--; 462 lcd.setCursor(0, 2); 463 lcd.print(" "); 464 lcd.setCursor(0, 1); 465 lcd.write(byte(0)); 466 } 467 } 468 469 if (changeVoltIsDisplayed){ 470 if (maxVolt < 200){ 471 maxVolt++; 472 lcd.setCursor(10, 0); 473 maxVolt /= 100; 474 lcd.print(String(maxVolt) + "V"); 475 maxVolt *= 100; 476 } 477 } 478} 479 480void downPressed(){ 481 if (mainMenuIsDisplayed){ 482 if (cursorPosition == 5){ 483 cursorPosition = 1; 484 } else { 485 cursorPosition++; 486 } 487 drawCursor(); 488 } 489 490 if (timeIsDisplayed){ 491 if (hours > 1){ 492 hours--; 493 } 494 changeTime(); 495 } 496 497 if (powerIsDisplayed){ 498 if (power > 1){ 499 power--; 500 } 501 changePower(); 502 } 503 504 if (modeIsDisplayed){ 505 if(cursorPosition == 1){ 506 cursorPosition++; 507 lcd.setCursor(0, 1); 508 lcd.print(" "); 509 lcd.setCursor(0, 2); 510 lcd.write(byte(0)); 511 } else { 512 cursorPosition--; 513 lcd.setCursor(0, 2); 514 lcd.print(" "); 515 lcd.setCursor(0, 1); 516 lcd.write(byte(0)); 517 } 518 } 519 520 if (changeVoltIsDisplayed){ 521 if (maxVolt > 100){ 522 //Serial.print("1:"); 523 //Serial.println(maxVolt); 524 maxVolt--; 525 //Serial.println("2:"); 526 //Serial.println(maxVolt); 527 lcd.setCursor(10, 0); 528 maxVolt /= 100; 529 lcd.print(String(maxVolt) + "V"); 530 maxVolt *= 100; 531 } 532 } 533} 534 535 536void enterPressed(){ 537 if (powerIsDisplayed){ 538 powerIsDisplayed = false; 539 drawMenu(); 540 EEPROM.write(1, power); 541 } else if (changeVoltIsDisplayed){ 542 changeVoltIsDisplayed = false; 543 EEPROM.write(3, maxVolt); 544 drawMenu(); 545 } else if (timeIsDisplayed){ 546 timeIsDisplayed = false; 547 drawMenu(); 548 EEPROM.write(0, hours); 549 } else if (modeIsDisplayed){ 550 if(cursorPosition == 1){ 551 modeIsDisplayed = false; 552 changeVoltIsDisplayed = true; 553 EEPROM.write(2, 0); 554 lcd.clear(); 555 showInfo(); 556 lcd.setCursor(0,0); 557 float maxVolt = EEPROM.read(3); 558 maxVolt /= 100; 559 lcd.print("charge to " + String(maxVolt) + "V"); 560 maxVolt *= 100; 561 } else if (cursorPosition == 2){ 562 EEPROM.write(2, 1); 563 modeIsDisplayed = false; 564 cursorPosition = 1; 565 drawMenu(); 566 } 567 } else if (mainMenuIsDisplayed){ 568 if (cursorPosition == 1){ 569 charging(); 570 chargingIsDisplayed = true; 571 } else if(cursorPosition == 2){ 572 discharge(); 573 disChargingIsDisplayed = true; 574 } else if(cursorPosition == 3){ 575 changePower(); 576 powerIsDisplayed = true; 577 } else if(cursorPosition == 4){ 578 changeTime(); 579 timeIsDisplayed = true; 580 } else if(cursorPosition == 5){ 581 changeMode(); 582 modeIsDisplayed = true; 583 } 584 mainMenuIsDisplayed = false; 585 } 586 delay(300); 587} 588 589void changeTime(){ 590 lcd.clear(); 591 lcd.setCursor(0, 0); 592 lcd.print("Charging " + String(hours) + " hours"); 593 showInfo(); 594} 595 596void changePower(){ 597 lcd.clear(); 598 lcd.setCursor(0, 0); 599 lcd.print("Charging " + String(power) + "0" " mA"); 600 showInfo(); 601} 602 603void changeMode(){ 604 lcd.clear(); 605 lcd.setCursor(0, 0); 606 lcd.print("Charging mode:"); 607 lcd.setCursor(0, 1); 608 lcd.write(byte(0)); 609 cursorPosition = 1; 610 maxVolt /= 100; 611 String autoText = "Auto stop at " + String(maxVolt) + "V"; 612 maxVolt *= 100; 613 lcd.setCursor(1, 1); 614 lcd.print(autoText); 615 lcd.setCursor(1, 2); 616 lcd.print("Manually"); 617} 618 619void showInfo(){ 620 lcd.setCursor(0, 1); 621 lcd.print("Up = add"); 622 lcd.setCursor(0, 2); 623 lcd.print("Down = reduce"); 624 lcd.setCursor(0, 3); 625 lcd.print("Enter = save & exit"); 626} 627 628void showNoAccu(int col){ 629 lcd.setCursor(col, 1); 630 lcd.print(" "); 631 lcd.setCursor(col, 1); 632 lcd.print("No"); 633 lcd.setCursor(col, 2); 634 lcd.print("accu"); 635 lcd.setCursor(col, 3); 636 lcd.print(" "); 637} 638 639void showChargingData(int col, float v, int mA){ 640 lcd.setCursor(col, 1); 641 lcd.print(" "); 642 lcd.setCursor(col, 1); 643 lcd.print(String(v)); 644 lcd.setCursor(col, 2); 645 lcd.print(" "); 646 lcd.setCursor(col, 2); 647 lcd.print(String(mA)); 648} 649 650void showDischargingData(int col, int mAh, float v, int mA){ 651 lcd.setCursor(col, 1); 652 lcd.print(" "); 653 lcd.setCursor(col, 1); 654 lcd.print(String(mAh)); 655 lcd.setCursor(col, 2); 656 lcd.print(" "); 657 lcd.setCursor(col, 2); 658 lcd.print(String(v)); 659 lcd.setCursor(col, 3); 660 lcd.print(" "); 661 lcd.setCursor(col, 3); 662 lcd.print(String(mA)); 663}
Downloadable files
Circuit
Here is the circuit for the charger.
circuit.png

Documentation
User manual:
User_manual.pdf
Comments
Only logged in users can leave comments