Table of Contents
ToggleIf you are planning to install an off-grid solar system with a battery bank, you’ll need a Solar Charge Controller. It is a device that is placed between the Solar Panel and the Battery Bank to control the amount of electric energy produced by Solar panels going into the batteries. The main function is to make sure that the battery is properly charged and protected from overcharging.
As the input voltage from the solar panel rises, the charge controller regulates the charge to the batteries preventing any overcharging and disconnects the load when the battery is discharged.
Types of solar charge controllers
There are currently two types of charge controllers commonly used in PV power systems :
1. Pulse Width Modulation (PWM) controller
2. Maximum Power Point Tracking (MPPT) controller
In this tutorial, I will explain to you the PWM Solar Charge Controller. I have posted few articles on Arduino solar charge controllers earlier too. The earlier version of my solar charge controllers is quite popular on the internet and useful for people all around the globe.
By considering the comments and questions from my earlier versions, I have modified my existing V2.0 Arduino Charge Controller to make the new version 2.02.
The following are the changes in V2.02 w.r.t V2.0:
1. The low efficient linear voltage regulator is replaced by buck converter MP2307 for a 5V power supply.
2. One additional current sensor to monitor the current coming from the solar panel.
3. MOSFET-IRF9540 is replaced by IRF4905 for better performance.
4. On-board LM35 temp-sensor is replaced by a DS18B20 probe for accurate battery temperature monitoring.
5. USB port for charging smart devices.
6. Use of single fuse instead of two
7. One additional LED to indicate Solar Power Status.
8.Implementation of 3 stages charging algorithm.
9. Made a custom PCB for the project
Specification
1.Charge controller as well as energy meter
2. Automatic Battery Voltage Selection (6V/12V)
3.PWM charging algorithm with auto charge setpoint according to the battery voltage
4.LED indication for the state of charge and load status
5. 20×4 character LCD display for displaying voltages, current, power, energy, and temperature.
6.Lightning protection
7.Reverse current flow protection
8.Short Circuit and Overload protection
9. Temperature Compensation for Charging
10. USB port for Charging Gadgets
Materials and Tools Required:
1. Arduino Nano (Amazon / Banggood)
2.P-MOSFET – IRF4905 ( Amazon / Banggood )
3.Power diode -MBR2045( Amazon / Aliexpress)
4.Buck Converter-MP2307( Amazon / Banggood)
5.Temperature Sensor – DS18B20 ( Amazon / Banggood)
6.Current Sensor – ACS712 ( Amazon / Banggood)
7.TVS diode- P6KE36CA ( Amazon / Aliexpress)
8.Transistors – 2N3904 (Amazon / Banggood )
9.Resistors ( 100k x 2, 20k x 2,10k x 2,1k x 2, 330ohm x 7) ( Amazon / Banggood )
10.Ceramic Capacitors (0.1uF x 2) ( Amazon / Banggood )
11. 20×4 I2C LCD ( Amazon / Banggood)
12.RGB LED ( Amazon / Banggood)
13.Bi-Color LED ( Amazon )
15.Jumper Wires/Wires ( Amazon / Banggood)
16.Header Pins ( Amazon / Banggood )
17.Heat Sinks ( Amazon / Aliexpress)
18.Fuse Holder and fuses ( Amazon )
19.Push Button ( Amazon / Banggood )
22.Screw terminals 1×6 pin ( Aliexpress)
23.PCB Standoffs ( Banggood )
24. USB Socket ( Amazon / Banggood )
Tools :
1.Soldering Iron ( Amazon )
2. Desoldering Pump ( Amazon )
2.Wire Cutter and Stripper ( Amazon )
3.Screw Driver ( Amazon )
Working Principle of a PWM Charge Controller
PWM stands for Pulse Width Modulation, which stands for the method it uses to regulate charge. Its function is to pull down the voltage of the solar panel to near that of the battery to ensure that the battery is properly charged. In other words, they lock the solar panel voltage to the battery voltage by dragging the Solar panel Vmp down to the battery system voltage with no change in the current.
It uses an electronics switch ( MOSFET ) to connect and disconnect the solar panel with the battery. By switching the MOSFET at high frequency with various pulse widths, a constant voltage can be maintained. The PWM controller self-adjusts by varying the widths (lengths) and frequency of the pulses sent to the battery.
When the width is at 100%, the MOSFET is at full ON, allowing the solar panel to bulk charge the battery. When the width is at 0% the transistor is OFF open circuiting the Solar panel preventing any current from flowing to the battery when the battery is fully charged.
How the Circuit Work?
Download the Schematic : Schematic_Arduino+Solar+Charge+Controller+V2.0_Sheet_1_20200320104815
The heart of the Arduino solar charge controller is an Arduino Nano board. The Arduino senses the solar panel and battery voltages by using two voltage divider circuits. According to these voltage levels, it decides how to charge the battery and control the load.
Note: In the above picture, there is a typographical error in the power and control signal. The red line is for power and the yellow line is for the control signal.
The whole schematic is divided into the following circuits:
1. Power Distribution Circuit:
The power from the battery ( B+ & B- ) is step down to 5V by the X1 ( MP2307) buck converter. The output from the buck converter is distributed to
1. Arduino Board
2. LEDs for indication
3. LCD display
4. USB port to charge gadgets.
2. Input Sensors:
The solar panel and battery voltages are sensed by using two voltage divider circuits consisting of resistors R1-R2 & R3- R4. C1 and C2 are filter capacitors to filter out the unwanted noise signals. The output from the voltage dividers is connected to Arduino analog pins A0 and A1 respectively.
The solar panel and battery currents are sensed by using two ACS712 modules. The output from the current sensors is connected to Arduino analog pin A3 and A2 respectively.
The battery temperature is measured by using a DS18B20 temperature sensor. R16 (4.7K ) is a pull-up resistor. The output of the temperature sensor is connected to Arduino Digital pin D12.
3. Control Circuits:
The control circuits are basically formed by two p-MOSFETs Q1 and Q2. The MOSFET Q1 is used to send the charging pulse to the battery and MOSFET Q2 is used to drive the load. Two MOSFET driver circuits are consist of two transistors T1 and T2 with pull-up resistors R6 and R8. The base current of the transistors is controlled by resistors R5 and R7.
4. Protections Circuits:
The input overvoltage from the solar panel side is protected by using a TVS diode D1. The reverse current from the battery to the solar panel is protected by a Schottky diode D2. The overcurrent is protected by a fuse F1.
5. LED Indication:
LED1, LED2, and LED3 are used to indicate solar, battery, and load status respectively. Resistors R9 to R15 are current limiting resistors.
7. LCD Display:
An I2C LCD display is used to display various parameters.
8. USB Charging:
The USB socket is hooked up to 5V output from the Buck Converter.
9. System Reset:
SW1 is a push button to reset the Arduino.
You can download the schematic in PDF format attached below.
Main Functions of Solar Charge Controller
The charge controller is designed by taking care of the following points.
1. Prevent Battery Overcharge: To limit the energy supplied to the battery by the solar panel when the battery becomes fully charged. This is implemented in charge_cycle() of my code.
2. Prevent Battery Over-discharge: To disconnect the battery from electrical loads when the battery reaches a low state of charge. This is implemented in load_control() of my code.
3. Provide Load Control Functions: To automatically connect and disconnect an electrical load at a specified time. The load will ON when the sunset and OFF when sunrise. This is implemented in load_control() of my code. 4.Monitoring Power and Energy: To monitor the load power and energy and display it.
5. Protect from abnormal Condition: To protect the circuit from the different abnormal situations like lightning, over-voltage, over current, and short circuit, etc.
6.Indicating and Displaying: To indicate and display the various parameters
7.Serial Communication: To print various parameters in the serial monitor
8. USB Charging: To charge smart devices
Voltage Measurement
The voltage sensors are used to sense the voltage of solar panel and battery. It is implemented by using two voltage divider circuits. It consists of two resistors R1=100k and R2=20k for sensing the solar panel voltage and similarly R3=100k and R4=20k for battery voltage. The output from the R1 and R2 is connected to Arduino analog pin A0 and output from the R3 and R4 is connected to Arduino analog pin A1.
Voltage Measurement :
Arduino’s analog inputs can be used to measure DC voltage between 0 and 5V (when using the standard 5V analog reference voltage) and this range can be increased by using a voltage divider network. The voltage divider steps down the voltage being measured within the range of the Arduino analog inputs.
For a voltage divider circuit Vout = R2/(R1+R2) x Vin
Vin = (R1+R2)/R2 x Vout
The analogRead() function reads the voltage and converts it to a number between 0 and 1023
Calibration :
We’re going to read the output value with one of the analog inputs of Arduino and its analogRead() function. That function outputs a value between 0 and 1023 that is 0.00488V for each increment (As 5/1024 = 0.00488V)
Vin = Vout*(R1+R2)/R2 ; R1=100k and R2=20k
Vin= ADC count*0.00488*(120/20) Volt // Highlighted part is Scale factor
Note: This leads us to believe that a reading of 1023 corresponds to an input voltage of exactly 5.0 volts. In practice, you may not get 5V always from the Arduino pin 5V. So during calibration first measure the voltage between the 5v and GND pins of Arduino by using a multimeter, and use scale factor by using the below formula:
Scale factor = measured voltage/1024
Current Measurement
For current measurement, I used a Hall Effect current sensor ACS 712 -5A variant. There are three variants of ACS712 Sensor based on the range of its current sensing. The ACS712 sensor reads the current value and converts it into a relevant voltage value, The value that links the two measurements is Sensitivity. The output sensitivity for all variant are as follows:
ACS712 Model – > Current Range- > Sensitivity
ACS712 ELC-05 – > +/- 5A – > 185 mV/A
ACS712 ELC-20 – > +/- 20A – > 100 mV/A
ACS712 ELC-30 – > +/- 30A – > 66 mV/A
In this project, I have used the 5A variant, for which sensitivity is 185mV/A and the middle sensing voltage is 2.5V when no current.
Calibration:
analog read value = analogRead(Pin);
Value = (5/1024)*analog read value // If you are not getting 5V from Arduino 5V pin then,
Current in amp = (Value – offsetVoltage) / sensitivity
But as per data sheets offset voltage is 2.5V and sensitivity is 185mV/A
Current in amp = (Value-2.5)/0.185
Temperature Measurement
Why Temperature monitoring is Required?
The battery’s chemical reactions change with temperature. As the battery gets warmer, the gassing increases. As the battery gets colder, it becomes more resistant to charging. Depending on how much the battery temperature varies, it is important to adjust the charging for temperature changes. So it is important to adjust charging to account for the temperature effects. The temperature sensor will measure the battery temperature, and the Solar Charge Controller uses this input to adjust the charge set point as required. The compensation value is – 5mv /degC/cell for lead-acid type batteries. (–30mV/ºC for 12V and 15mV/ºC for 6V battery). The negative sign of temperature compensation indicates an increase in temperature requires a reduction in charge set point. For more details, you may follow this article.
Temperature Measurement by DS18B20
I have used an external DS18B20 probe for measuring the battery temperature. It uses a one-wire protocol to communicate with the microcontroller. It can be hooked up in port-J4 on the board.
To interface with the DS18B20 temperature sensor, you need to install the One Wire library and the Dallas Temperature library.
You can read this article for more details on the DS18B20 sensor.
USB Charging Circuit
The buck converter MP2307 used for power supply can deliver current up to 3A. So it has a sufficient margin for charging the USB gadgets. The USB socket VCC is connected to 5V and GND is connected to GND. You can refer to the above schematic.
Note: The USB output voltage not maintained to 5V when the load current exceeds 1A. So I would recommend limiting the USB load below 1A.
Charging Algorithm
When the controller is connected to the battery, the program will start the operation. Initially, it checks if the panel voltage is sufficient for charging the battery. If yes, then it will enter into the charge cycle. The Charge Cycle consists of 3 stages.
Stage 1 Bulk charge:
Arduino will connect the Solar Panel to the battery directly ( 99 % duty cycle). The battery voltage will increase gradually. When the battery voltage reaches 14.4V, stage 2 will begin.
In this stage, the current is almost constant.
Stage 2 Absorption charge:
In this stage, Arduino will regulate the charging current by maintaining the voltage level at 14.4 for one hour. The voltage is kept constant by adjusting the duty cycle.
Stage 3 Float charge:
The controller generates the trickle charge to maintain the voltage level at 13.5V. This stage keeps the battery to be fully charged. If the battery voltage is less than 13.2V for 10mins.
The charge cycle will be repeated.
Load Control
To automatically connect and disconnect the load by monitoring dusk/dawn and battery voltage, load control is used.
The primary purpose of load control is to disconnect the load from the battery to protect it from deep discharging. Deep discharging could damage the battery.
The DC load terminal is designed for low power DC load such as street light.
The PV panel itself is used as the light sensor.
Assuming solar panel voltage > 5V means dawn and when < 5V dusk.
ON Condition: In the evening, when the PV voltage level falls below 5V and the battery voltage is higher than the LVD setting, the controller will turn on the load and the load green led will glow.
OFF Condition: The load will cut off in the following two conditions.
1. In the morning when the PV voltage is larger than 5v,
2.When the battery voltage is lower than the LVD setting The load red led ON indicates that the load is cut off.
LVD is referred to as Low Voltage Disconnect
Power and Energy
Power:
Power is the product of voltage (volt) and current (Amp)
P=VxI Unit of power is Watt or KW
Energy:
Energy is the product of power (watt) and time (Hour)
E= Pxt Unit of Energy is Watt Hour or Kilowatt Hour (kWh)
To monitor the power and energy above logic is implemented in software and the parameters are displayed in a 20×4 char LCD.
Protections
1.Reverse polarity and reverse current protection for solar panel
For reverse polarity and reverse current flow protection a Schottky diode (MBR2045) is used.
2. Overcharge & Deep discharge protection
Overcharge and deep discharge protection are implemented by the software.
3. Short circuit and overload protection
Short circuit and overload protection is realized by a fuse F1.
4.Overvoltage protection at solar panel input
Temporary overvoltages occur in power systems for a variety of reasons, but lightning causes the most severe overvoltages. This is particularly true with PV systems due to the exposed locations and system connecting cables. In this new design, I used a 600-watt bidirectional TVS diode (P6KE36CA ) to suppress the lightning and overvoltage at the PV terminals.
LED Indications
1. Solar LED: LED1
A bi-color (red/green ) led is used for indicating the solar power status i.e dusk or dawn.
Solar LED ———————>Solar Status
GREEN ————————-> Day
RED —————————> Night
2. Battery State Of Charge (SOC) LED: LED2
One important parameter that defines the energy content of the battery is the State of Charge (SOC). This parameter indicates how much charge is available in the battery. RGB LED is used to indicate the battery state of charge. For connection refer to the above schematic.
Battery LED ————>Battery Status
RED ——————–> Voltage is LOW
GREEN ——————–> Voltage is Healthy
BLUE ——————–> Fully Charged
2. Load LED: LED3
A bi-color (red/green) led is used for load status indication. Refer to the above schematic for connection.
Load LED ———————>Load Status
GREEN ————————-> Connected (ON)
RED —————————> Disconnected (OFF)
LCD Display
A 20X4 char LCD is used for monitoring solar panel, battery and load parameters.
For simplicity, an I2C LCD display is chosen for this project. It needs only 4 wires to interface with the Arduino.
The connection is below:
LCD–> Arduino
VCC–> 5V ,
GND–>GND,
SDA–>A4,
SCL–>A5
Row-1: Solar panel voltage, Current and Power
Row-2: Battery Voltage, Temperature, and Charger status ( Charging / Not Charging )
Row-3: Load current, power, and load status
Row-4: Input Energy from Solar panel and Energy consumed by the load.
You have to download the library from LiquidCrystal_I2C.
PCB Design
I have drawn the schematic by using EasyEDA online software after that switched to the PCB layout. The PCB size is 10 x 10 cm.
You can download the Gerber files from PCBWay
When you place an order from PCBWay, I will get a 10% donation from PCBWay for a contribution to my work. Your little help may encourage me to do more awesome work in the future. Thank you for your cooperation.
Soldering the Components
After receiving the board from the PCB fab house, you have to solder the components.
For Soldering, you will need a decent Soldering Iron, Solder, Nipper, Desoldering Wicks or Pump, and a multimeter.
It is good practice to solder the components according to their height. Solder the lesser height components first.
You can follow the following steps to solder the components :
1. Push the component legs through their holes, and turn the PCB on its back.
2. Hold the tip of the soldering iron to the junction of the pad and the leg of the component.
3. Feed solder into the joint so that it flows all around the lead and covers the pad. Once it has flowed all around, move the tip away.
4. Trim the extra legs by using a Nipper.
Mounting the ACS712 Current Sensor
The ACS712 current sensor I have received has a pre-soldered screw terminal for connection. To solder the module directly on the PCB board, you have to desolder the screw terminal first.
I desolder the screw terminal with the help of a desoldering pump as shown above.
Then I solder the ACS712 module upside down.
To connect the Ip+ and Ip- terminal to the PCB, I used the diode terminal legs.
Adding the Buck Converter
To solder the Buck Converter module, you have to prepare 4 straight header pins as shown above.
Solder the 4 header pins at the X1, 2 are for output and the remaining two are for inputs.
Adding the Arduino Nano
When you purchase the straight headers, they’ll be too long for the Arduino Nano. You’ll need to trim them down to an appropriate length. This means 15 pins each.
The best way to trim the female header pieces is to count out 15 pins, pull the 16th pin, then use a nipper to cut the gap between the 15th and 17th pin.
Now we need to install the female headers onto the PCB. Take your female headers and place them on the male headers on the Arduino Nano board.
Then solder the female header pins to the Arduino solar Charge Controller PCB.
Preparing the MOSFETs & Diode
Before soldering the MOSFETs Q1 Q2 and diode D1 onto the PCB, it is better to attach the heat sinks to them first. Heat sinks are used to move heat away from the device in order to maintain a lower device temperature.
Apply a layer of heat sink compound over the MOSFET metal base plate. Then place the thermally conductive pad in between the MOSFET and heat sink and tighten the screw. You can read this article about why a heat sink is essential.
Finally, solder them onto the charge controller PCB.
Mounting the Standoffs
After soldering all the parts, mount the standoffs at 4 corners. I used M3 Brass Hex Standoffs.
The use of standoffs will provide sufficient clearance to the soldering joints and wires from the ground.
Software & Libraries
First, download the attached Arduino Code. Then download the following libraries and install them.
1. One Wire
The entire code is broken into a small functional block for flexibility. Suppose the user is not interested to use an LCD display and happy with the led indication. Then just disable the lcd_display() from the void loop(). That’s all. Similarly, according to the user requirement, he can enable and disable the various functionality.
After installing all the above libraries, upload the Arduino Code.
Download Arduino Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
///////////////////////////////ARDUINO PWM SOLAR CHARGE CONTROLLER V-2.02/////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------- // Author: Debasish Dutta // Website : www.opengreenenergy.com Youtube : www.youtube.com/c/opengreenenergy // This code is for an arduino based Solar PWM charge controller ( V-2.0) // Credit :logic of 3 stage charging taken from http://jamesoid.com/pwm_charger_project/pwm_charger.ph // Last updated on 01/04/2020 //---------------------------------------------------------------------------------------------------- // Arduino pins Connections---------------------------------------------------------------------------- // A0 - Voltage divider to measure solar panel voltage // A1 - Voltage divider to measure battery voltage // A2 - ACS712 to monitor load current // A3 - ACS712 to monitor solar current // A4 - LCD SDA // A5 - LCD SCL // D0- Not used // D1- Not used // D2 - Control Load MOSFET Q2 // D3 - PWM Output to control MOSFET Q1 // D4 - Not Used // D5 - Battery Red LED // D6 - Battery Green LED // D7 - Battery Blue LED // D8 - Load Red Led // D9 - Load Green Led // D10- Solar Red LED // D11- Solar Green LED // D12- DS18B20 Temp. Sensor // D13-not used // Include Libraries #include <OneWire.h> #include <DallasTemperature.h> #include <LiquidCrystal_I2C.h> #include <PID_v1.h> // Definitions : #define solar_volt_sense 0 // defining the analog pin A0 to read solar panel Voltage #define bat_volt_sense 1 //defining the analog pin A1 to read battery voltage #define load_current_sense 2 //defining the Analog pin A2 to measure load current #define solar_current_sense 3 //defining the Analog pin A2 to measure load current #define AVG_NUM 10 // number of iterations of the adc routine to average the adc readings #define ONE_WIRE_BUS 12 // Data wire of DS18B20 temp sensor is plugged into pin 3 on the Arduino #define pwm_pin 3 // defining digital pin D9 to drive the main MOSFET Q1 @ 1KHz #define load_pin 2 // Defining load control pin to drive MOSFET Q2 //Defining led pins for indication #define bat_low_led 5 #define bat_normal_led 6 #define bat_full_led 7 #define load_red_led 8 #define load_green_led 9 #define solar_red_led 10 #define solar_green_led 11 #define BULK_CHRARGE_SP 14.4 #define FLOAT_CHARGE_SP 13.5 #define Charge_Restart_SP 13.2 #define MIN_SOLAR_VOLT 10 #define LVD 11.5 #define LVR 12.5 #define ABSORPTION_LIMIT 3600000 // 1 hour in milliseconds #define NIGHT_TIME 3600000 // 1 hour in milliseconds #define CHARGER_RESTART_TIME 600000 // 10 mins in milliseconds #define EVENING_TIME 300000 // 5mins in milliseconds #define MORNING_TIME 180000 // 3mins in milliseconds #define offsetVoltage 2.5 // for ACS712 sensor #define Sensitivity 0.185 // 185mV/A for ACS712-5A variant //-------------------------------------------------------------------------------------------------------------------------- ///////////////////////DECLARATION OF ALL BIT MAP ARRAY FOR FONTS//////////////////////////////////////////////////////////////// //-------------------------------------------------------------------------------------------------------------------------- byte solar[8] = //icon for solar panel { 0b11111,0b10101,0b11111,0b10101,0b11111,0b10101,0b11111,0b00000 }; byte battery[8] = //icon for battery { 0b01110,0b11011,0b10001,0b10001,0b10001,0b10001,0b10001,0b11111 }; byte energy[8] = // icon for power { 0b00010,0b00100,0b01000,0b11111,0b00010,0b00100,0b01000,0b00000 }; /*byte alarm[8] = // icon for alarm { 0b00000,0b00100,0b01110,0b01110,0b01110,0b11111,0b00000,0b00100 };*/ byte temp[8] = //icon for termometer { 0b00100,0b01010,0b01010,0b01110,0b01110,0b11111,0b11111,0b01110 }; byte charge[8] = // icon for battery charge { 0b01010,0b11111,0b10001,0b10001,0b10001,0b01110,0b00100,0b00100, }; byte not_charge[8]= { 0b00000,0b10001,0b01010,0b00100,0b01010,0b10001,0b00000,0b00000, }; //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //Declaring the global variables float solar_volt=0; // solar panel voltage float bat_volt=0; // battery voltage float load_current=0; float solar_current=0; float temperature=0; // temperature float temp_change=0; // temperature difference between current and refrence ( 25 degC) float pwm_duty=0; // PWM Duty Cycle (0 to 1024) float bulk_charge_sp=0; // Bulk charging set point float error=0; // calculate the difference between battery voltage and bulk charge set point float float_charge_sp=0; // Float charging set point int load_status; // 0-off, 1- on const int bat_type = 0; //Flooded=0,AGM=1 unsigned long absorption_time; // to keep track of today's time in absorption state unsigned long charger_millis; // to keep track of time for charger unsigned long restart_time; unsigned long morn_timer; unsigned long even_timer; unsigned long load_millis; float load_watts=0; float load_wattHours=0; float solar_watts=0; float solar_wattHours=0; unsigned long time =0; unsigned long last_time=0; unsigned long current_time=0; // Variables for PID Controller //Define Variables we'll be connecting to double Setpoint, Input, Output; OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature sensor //Specify the links and initial tuning parameters PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT); // Here Kp= 2 , Ki= 5 and Kd=1 // aggKp=4, aggKi=0.2, aggKd=1; // Set the pins on the I2C chip used for LCD connections: // addr, en,rw,rs,d4,d5,d6,d7,bl,blpol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address // In my case 0x27 enum charger_state {off, bulk,absorption,Float} charger_state ; //---------------------------------------- Set Up Function---------------------------------------------------------------------------------------------------------------------------------- void setup() { Serial.begin(9600); // open the serial port at 9600 bps: pinMode(pwm_pin,OUTPUT); pinMode(load_pin,OUTPUT); pinMode(bat_low_led,OUTPUT); pinMode(bat_normal_led,OUTPUT); pinMode(bat_full_led,OUTPUT); pinMode(load_red_led,OUTPUT); pinMode(load_green_led,OUTPUT); pinMode(solar_red_led,OUTPUT); pinMode(solar_green_led,OUTPUT); TCCR2B = TCCR2B & B11111000 | 0x03; // pin 3 PWM frequency of 980.39 Hz sensors.begin(); //initialize the variables we're linked to Input = 12; Setpoint = 14.5; //turn the PID on myPID.SetMode(AUTOMATIC); sensors.requestTemperatures(); // get temperature readings temperature = sensors.getTempCByIndex(0) ; // 0 refers to the first IC on the wire get_setpoint(); // get the temperature compensated charging set point while ((temperature > 50 ) || (temperature < -20 ) || (bat_volt < 9)) // If the temperature is beyond the permisible limit or battery is damaged/disconnected { Serial.println(" Error "); } charger_state = off; // start the charger from off charger_millis = millis() ; // initialise the local clock load_millis =millis(); lcd.begin(20,4); // initialize the lcd for 16 chars 2 lines, turn on backlight lcd.backlight(); // finish with backlight on lcd.createChar(1,solar); lcd.createChar(2, battery); lcd.createChar(3, energy); //lcd.createChar(4,alarm); lcd.createChar(5,temp); lcd.createChar(6,charge); lcd.createChar(7,not_charge); lcd.clear(); delay(1000); // pause to properly start up the Arduino } //-----------------------------------------------------------Main Loop--------------------------------------------------- void loop() { read_sensors_data(); // Reading voltage temp from the sensors get_setpoint(); // Reading temp compensated charging set point run_charger(); load_control(); power(); led_indication(); lcd_display(); serial_print(); } //----------------------------------------------------------------Function Definition---------------------------------------- //--------------------------------------------------------------------------------------------------------------------------- ////////////////////////////////////READING DIFFERENT SENSORS DATA ////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------------------------------- /* This function read the voltage dividers and temperature sensor (DS18B20 probe),gives row adc values in between 0-1023 Then adc value is calibrated to get the actual voltages and currents */ //------------------------------------------------------------------------------------------------------ ////////////////// READS AND AVERAGES THE ANALOG INPUTS (SOLRAR VOLTAGE,BATTERY VOLTAGE)//////////////// //------------------------------------------------------------------------------------------------------ int read_adc(int adc_parameter) { int sum = 0; int sample ; for (int i=0; i<AVG_NUM; i++) { // analogWrite(pwm_pin,0); // disconnect battery to read accurate battery voltage // loop through reading raw adc values AVG_NUM number of times sample = analogRead(adc_parameter); // read the input pin sum += sample; // store sum for averaging delay(1); // pauses for 1 milli seconds } return(sum / AVG_NUM); // divide sum by AVG_NUM to get average and return it } //------------------------------------------------------------------------------------------------------------- ////////////////////////////////////READ THE DATA////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------------------- void read_sensors_data(void){ //--------------------------------Reading Voltages--------------- //5V = ADC value 1024 => 1 ADC value = (5/1024)Volt= 0.0048828Volt // Vout=Vin*R2/(R1+R2) => Vin = Vout*(R1+R2)/R2 R1=100 and R2=20 solar_volt = read_adc(solar_volt_sense)*0.00461*(120/20); bat_volt = read_adc(bat_volt_sense)*0.00461*(120/20); //--------------------------------Reading Currents--------------- load_current = ((analogRead(load_current_sense)*0.00461 - offsetVoltage)/Sensitivity ); solar_current = ((analogRead(solar_current_sense)*0.00461 - offsetVoltage)/ Sensitivity ); if (load_current <0) { load_current = 0; } if (solar_current <0) { solar_current = 0; } //--------------------------------Reading Temperature--------------- sensors.requestTemperatures(); // get temperature readings temperature = sensors.getTempCByIndex(0) ; // 0 refers to the first IC on the wire } //--------------------------------------------------------------------------------------------------------------------------- ////////////////////////////////////CHARGE SET POINT /////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------------------------------- // temperature compensation = -20mv/degC // If temperature is above the room temp ;Charge set point should reduced // If temperature is bellow the room temp ;Charge set point should increased void get_setpoint(void) { read_sensors_data(); // for measuring voltage and currents from sensors temp_change =temperature-25.0; // 25deg cel is taken as standard room temperature ( STC) // for floaded battery if (bat_type == 0){ bulk_charge_sp =BULK_CHRARGE_SP-(0.020*temp_change) ; float_charge_sp=FLOAT_CHARGE_SP-(0.020*temp_change) ; } // for AGM battery // set point is lowered to avoid excess gassing else{ bulk_charge_sp =(BULK_CHRARGE_SP-0.2)-(0.020*temp_change) ; float_charge_sp=(FLOAT_CHARGE_SP-0.2)-(0.020*temp_change) ; } } //--------------------------------------------------------------------------------------------------------------------------- //////////////////////////////////// MAIN CHARGING CYCLE /////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------------------------------- void run_charger(){ switch (charger_state) { case off : if ( ( bat_volt < float_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) ){ charger_millis = millis() ; charger_state = bulk ; } else if ( ( bat_volt > float_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) && ( absorption_time > ABSORPTION_LIMIT ) ){ charger_millis = millis() ; restart_time = 0 ; charger_state = Float ; } else{ if (millis() - charger_millis > NIGHT_TIME) absorption_time = 0 ; pwm_duty = 0; analogWrite(pwm_pin, pwm_duty); //generate PWM from D3 @ 0% duty // Shut down the charger } break; // end of case off condition /////////////////////////////////// STAGE-1 (BULK CHARGING)////////////////////////////////////////////////////// // During this stage the MOSFET is fully on by setting the duty cycle to 100% // Constant Current Charging ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// case bulk : if ( solar_volt < bat_volt ){ charger_millis = millis() ; charger_state = off ; } else if ((bat_volt > bulk_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) && ( absorption_time < ABSORPTION_LIMIT )){ charger_millis = millis() ; charger_state = absorption ; } else if ( ( bat_volt > float_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) && ( absorption_time > ABSORPTION_LIMIT )){ charger_millis = millis() ; restart_time = 0 ; charger_state = Float ; } else{ pwm_duty = 255; analogWrite(pwm_pin,pwm_duty); //generate PWM from D3 @ 100% duty // MOSFET Q1 is ON if( bat_volt > bulk_charge_sp ) { charger_state = absorption ; } } break; // end of case bulk condition /////////////////////////////////// STAGE-2 (ABSORPTION CHARGING)////////////////////////////////////////////////////// // During this stage the MOSFET is partially on by setting the duty cycle to between 0% and 100% // Constant voltage ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// case absorption : if ( solar_volt < bat_volt ){ charger_millis = millis() ; charger_state = off ; } else if ( ( bat_volt > float_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) && ( absorption_time > ABSORPTION_LIMIT )){ charger_millis = millis() ; charger_state = Float ; } else{ // increment absorption timer and test for duration in absorption state absorption_time = absorption_time + millis() - charger_millis ; charger_millis = millis(); /* error = (bat_volt - bulk_charge_sp); // duty cycle reduced when the battery voltage approaches the charge set point and vice versa if (abs(error) < 0.3){ pwm_duty = pwm_duty - error*25.5; } else{ pwm_duty = pwm_duty - error*255; } */ Input = bat_volt; Setpoint = bulk_charge_sp; myPID.Compute(); // Compute PID Output pwm_duty = Output*5 ; // Output = kp * error + ki * errSum + kd * dErr if(pwm_duty < 0)pwm_duty=0; if(pwm_duty >255)pwm_duty=255; analogWrite(pwm_pin, pwm_duty); } break; // end of case absorption condition /////////////////////////////////// STAGE-3 (FLOAT CHARGING)////////////////////////////////////////////////////// // During this stage the MOSFET is partially on by setting the duty cycle between 0% and 100% // Constant Voltage Charging ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// case Float : if ( solar_volt < bat_volt ){ charger_millis = millis() ; charger_state = off ; } else if ( ( bat_volt < Charge_Restart_SP) && ( solar_volt > ( bat_volt + 0.5) ) && (restart_time > CHARGER_RESTART_TIME)){ charger_millis = millis() ; charger_state = bulk ; } else if ( ( bat_volt >float_charge_sp) && ( solar_volt > ( bat_volt + 0.5) ) && ( absorption_time < ABSORPTION_LIMIT )){ charger_millis = millis() ; charger_state = absorption ; } else{ if (bat_volt > float_charge_sp){ pwm_duty--; if(pwm_duty <0)pwm_duty=0; analogWrite(pwm_pin, pwm_duty); } else{ pwm_duty = 12.75; // setting duty cycle = 5% for trickle charge analogWrite(pwm_pin, pwm_duty); //generate PWM from D3 @ 5% duty // Q1 is driving @ 5% duty cycle } if ( bat_volt < Charge_Restart_SP){ restart_time = restart_time + millis() - charger_millis ; charger_millis = millis(); } } break; // end of case float condition } } // end of run_charger //------------------------------------------------------------------------------------------------------------ /////////////////////////////////POWER AND ENERGY CALCULATION ////////////////////////////////////////////// //------------------------------------------------------------------------------------------------------------ void power(void){ last_time = current_time; current_time = millis(); load_watts = load_current * bat_volt; //load Watts now solar_watts = solar_current * solar_volt; //solar Watts now load_wattHours = load_wattHours + load_watts*(( current_time -last_time) /3600000.0) ; // calculating energy in Watt-Hour solar_wattHours = solar_wattHours+ solar_watts*(( current_time -last_time) /3600000.0) ; // calculating energy in Watt-Hou } //--------------------------------------------------------------------------------------------------------------------------- //////////////////////////////////// LOAD CONTROL /////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------------------------------------------------------- void load_control(){ read_sensors_data(); // for measuring voltages sensors if ( (solar_volt < 8.0) && ( bat_volt > LVD ) ){ //msec = millis(); //evening_time = msec - last_msec; //Calculate how long has past since last call of this function //Serial.print("Evening Time:"); //Serial.println(evening_time/60000); // if (((evening_time) > 1000) && ( bat_volt > LVD )){ // check if the solar panel voltage falls below 8V for more than 5mins and battery voltage is above LVD load_status = 1; digitalWrite(load_pin,HIGH); // load will turn on during evening //Serial.println("LOAD is ON "); // } //last_msec = millis(); //Store 'now' for next time } else if ( solar_volt > MIN_SOLAR_VOLT){ //unsigned long morning_time=millis(); //Serial.print("Morning Time:"); //Serial.println(morning_time/60000); //if ((millis()- morning_time) > 1000){ // check if the solar panel voltage rise above minimum solar volt ( 10V ) for more than 53mins load_status = 0; digitalWrite(load_pin,LOW); // load will turn off during morning //Serial.println("LOAD is OFF "); // } } } //--------------------------------------------------------------------------------------------------------------------------- //////////////////////////////////// LED INDICATION /////////////////////////////////////////////////////////////////////// ///////////This function display the current state of charge of the battery,Charging status and load status via LED//////// //-------------------------------------------------------------------------------------------------------------------------- void led_indication(void){ //Solar leds indication //---------------------------------------- if (solar_volt > bat_volt) { digitalWrite(solar_red_led,LOW); digitalWrite(solar_green_led,HIGH); // Sun Light is available and charger is ready for charging // Serial.println("SOL_GREEN_LED ON"); } else { digitalWrite(solar_green_led,LOW); digitalWrite(solar_red_led,HIGH); //Sun light is not available for charging // Serial.println("SOL_RED_LED ON"); } //Battery leds indication //--------------------------------------------- if(bat_volt > LVR) { leds_off_all(); digitalWrite(bat_normal_led,HIGH); // battery voltage is healthy } else if(bat_volt > float_charge_sp ) { leds_off_all(); digitalWrite(bat_full_led,HIGH); //battery is fully charged } else { leds_off_all(); digitalWrite(bat_low_led,HIGH); // battery voltage low } //Load leds indication if(load_status==1) { digitalWrite(load_red_led, LOW); digitalWrite(load_green_led ,HIGH); } else if(load_status==0) { digitalWrite(load_green_led, LOW); digitalWrite(load_red_led ,HIGH); } } //------------------------------------------------------------------------------------------------------ //////////////////////// TURN OFF ALL THE LED/////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------------ void leds_off_all(void) { digitalWrite(bat_low_led,LOW); digitalWrite(bat_normal_led,LOW); digitalWrite(bat_full_led,LOW); } //--------------------------------------------------------------------------------------------------------------------------- //////////////////////////////////// SERIAL PRINTING /////////////////////////////////////////////////////////////////////// //-------------------------------------------------------------------------------------------------------------------------- void serial_print(){ Serial.print("Temp: " ); Serial.print ( temperature); Serial.print(" Bulk Voltage SP: "); Serial.print(bulk_charge_sp); Serial.print(" Float Voltage SP: "); Serial.print(float_charge_sp); Serial.print(" Solar Volt: "); Serial.print(solar_volt); // Serial.print(" Solar Current: "); // Serial.print(solar_current); Serial.print(" Bat Volt: "); Serial.print(bat_volt); // Serial.print(" Load Current: "); // Serial.print(load_current); Serial.print(" PWM : "); Serial.print((pwm_duty /255 )*100); // convert a number between 0 -1024 to 0-1024 then convert float to intiger Serial.print("%"); Serial.print(" Charge : "); if (charger_state == off) Serial.print("off "); else if (charger_state == bulk) Serial.print("bulk "); else if (charger_state == absorption) Serial.print("absorption "); else if (charger_state == Float) Serial.print("Float"); Serial.print(" Absorp time:"); Serial.print(absorption_time); Serial.print(" Restart time:"); Serial.println(restart_time); //Serial.println("************************************"); //delay(1000); } //------------------------------------------------------------------------------------------------------ //////////////////////// LCD DISPLAY/////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------------ void lcd_display() { // Display Solar Panel Parameters lcd.setCursor(0, 0); lcd.write(1); lcd.setCursor(2, 0); lcd.print(solar_volt,1); lcd.print("V"); lcd.setCursor(8, 0); lcd.print(solar_current,1); lcd.print("A"); lcd.setCursor(14,0); lcd.print(solar_watts,1); lcd.print("W"); // Display Battery Parameters lcd.setCursor(0,1); lcd.write(2); lcd.setCursor(2, 1); lcd.print(bat_volt,1); lcd.print("V"); lcd.setCursor(8, 1); lcd.write(5); lcd.setCursor(9, 1); lcd.print(temperature,0); lcd.write(0b11011111); lcd.print("C"); lcd.setCursor(14, 1); lcd.write(2); if((charger_state==1) | (charger_state== 2) | (charger_state== 3)) { lcd.write(6); } else { lcd.write(7); } // Display Load Parameters lcd.setCursor(0,2); lcd.print("L"); lcd.setCursor(2,2); lcd.print(load_current,1); lcd.print("A"); lcd.setCursor(8,2); lcd.print(load_watts,1); lcd.print("W"); lcd.setCursor(14,2); if(load_status==1) { lcd.print(" "); // clear the OFF lcd.setCursor(14,2); lcd.print("ON"); } else if(load_status==0) { lcd.print("OFF"); } // Display Energy lcd.setCursor(0,3); lcd.write(3); lcd.setCursor(2,3); lcd.print(solar_wattHours,1); lcd.print("WH"); lcd.setCursor(12,3); lcd.print(load_wattHours,1); lcd.print("WH"); } |
Final Testing
Connect the Charge Controller battery terminals ( BAT ) to a 12V battery. Be sure the polarity is correct. After connection, the LED and LCD will start working immediately. You will also notice the battery voltage and temperature on the 2nd row of the LCD display.
Then connect a Solar Panel to the solar terminal ( SOL ), you can see the solar voltage, current, and power on the first row of the LCD display. I have used a Lab Power supply to simulate the Solar Panel.
I used my Power Meters to compare the Voltage, Current, and Power values with the LCD display.