In the previous article, we have learned about the basic operation principle of solar charge controller and besides, we have seen a working circuit with both analog and micro-controller based on/off charge controller. In this article, we are going to learn how to make a PWM charge controller using that same circuit and micro-controller. Here, only some programming skill is applied. So let’s start our PWM Solar Charge Controller.
Disclaimer:
Handling electricity carries inherent risks. It’s essential to have the appropriate skills to manage it safely. Proceed at your own risk, as the author disclaims responsibility for any misuse, harm, or errors. All content on this website is unique and copyrighted; please avoid unauthorized copying. While most articles are open-source for your benefit, feel free to use the knowledge provided. If you find our resources helpful, consider purchasing available materials to support our work.
For assistance or guidance, leave a comment below; the author is committed to helping. Some articles may contain affiliate links that support the author with a commission at no additional cost to you. Thank you for your understanding and support.
Table of Contents
What is a charge controller?
I’ve already discussed about this in the previous article. So I’m not discussing again. Kindly read that article first.
PWM Charge controller circuit diagram:
As mentioned earlier, there is no difference between the on/off and PWM charge controller diagram. Only difference is the charging pulse.
We can use this same diagram. Now, in this circuit, we will modify the programming only.
Coding:
/******************************************************************************* Program for, PWM charge controller Program Written by_ Engr. Mithun K. Das; mithun060@gmail.com MCU:PIC12F675; X-Tal: 4MHz(internal). Compiler: mikroC pro for PIC v7.6.0 Date: 31-03-2021; © labprojectsbd.com *******************************************************************************/ #define charge_pin GP0_bit #define load_pin GP4_bit #define ch_led GP5_bit #define ld_led GP2_bit #define solar_sense GP3_bit #define bulk 1 #define absorbation 2 #define flot 3 unsigned int battery=0; int i=0; bit charge; bit load; short charge_level=0; unsigned int scale=0,duty=0; unsigned int cycle1=0,cycle2=0; void InitTimer0() { OPTION_REG = 0x80; TMR0 = 230; INTCON = 0xA0; } void Timer_interrupt() iv 0x0004 ics ICS_AUTO { if (TMR0IF_bit) { TMR0IF_bit = 0; TMR0 = 230; scale++; if(scale<duty) { charge_pin = 1; } else { charge_pin = 0; } if(scale>100) { scale=0; cycle1++; if(cycle1>5000) { if(cycle2<5001)cycle2++; cycle1=0; } } } } void main() { TRISIO = 0b00001010;//set I/O ; 1=input, 0=output GPIO = 0x00; CMCON = 0x07;//comparator off ANSEL = 0b00000010;//AN1 analog only ADCON0 = 0x05;//AN1 channel selected InitTimer0(); charge_level = bulk; while(1) { //read battery voltage battery=0;//clear previous data for(i=0;i<20;i++) { battery += ADC_Read(1)*27/100; // *5/1023*(10+2.2)/2.2*10*calibration Delay_ms(10);//keep a delay for smooth measurement } battery/=20; // make an average result from 20 samples. //Note: here rather than taking floating point variable, unsigned int //is used and while calculating, eliminated fractions to reduce further //RAM & ROM use. //charge control if(solar_sense) { //charging control if(charge_level==bulk) { duty = 99; if(battery>145) { charge_level = absorbation; } ch_led = ~ch_led; //fast blinking } else if(charge_level == absorbation) { if(battery>138) { if(duty>2)duty--; } else if(battery<137) { if(duty<99)duty++; } if(cycle2>1000) //as we are not sensing current { //we we'll count cycles. charge_level = flot; cycle2=0; } ch_led = ~ch_led;Delay_ms(200);//slow blinking } else //full charge { if(battery>128) { if(duty>1)duty--; } else if(battery<128) { if(duty<15)duty++; } ch_led = 1;//charge is full } } else { charge_pin = 0; //do not charge ch_led = 0; //indicator off charge_level = bulk;//reset level cycle1=0; cycle2=0; } //load control if(battery>126)load = 1;//load reconnect if(battery<116)load = 0;//load disconnect if(load) { load_pin = 1; //load MOSFET on ld_led = 1;//LOAD on indication } else { load_pin = 0; //load MOSFET off ld_led=~ld_led;//LOAD off indication } }//end of while(1) }//end of void main //End
If you need, you can use this hex file directly.
Result:
Simulation result:
PCB layout:
If you want to develop this project in a PCB, you can follow this layout.
Conclusion:
The article is very basic and informative to design a PWM-based solar charge controller. Only a small software trick can make the device more powerful.
I hope this project was helpful to you. If you make one for yourself, it will be a great pleasure for me. Anywhere you need help, let me know. Please share this project and subscribe to my blog. Thank you.
For Professional Designs or Help:
Check this out: 5 coolest multimeters you can buy
42 Comments
Asimiyu · 31/03/2021 at 4:31 pm
Please, sir. When I was going through the PWM source codes, I found a little bit confusion I would like you to throw more light upon sir. (1) you assign 1 to Bulk, 2 to absorpation, and 3 to flot. What does these 1,2 & 3 represent?. (bit or significant number?) And what does each have to do with Pulse.( Or are they represent FLAGs?)
(2) if(battery >138) // battery voltage at 13V
{
if(duty>2)duty–;. // Need comment sir about “2”
}
else
if(battery <137)
{
if(duty<99) duty++; // duty cycle 2) duty–; in the code above I thought, “2” represents 2% duty cycle, it supposed to increment the dutycycle not decriment?. Please put me through.
(3) lastly, what are the functions of variables cycle1 and cycle2 in the codes?. Thank you, looking forward to your response. God bless you.
Mithun K. Das · 01/04/2021 at 3:12 am
1>> Just a variable to select the mode.
2>> we should not turn off the pwm or use very small duty. That is why minimum range is 2
3>> cycle1 & 2 is for creating a time delay without interrupting other works, this time delay is used in absorption mode. as we are not using any current sensing.
Asimiyu · 01/04/2021 at 7:52 am
Thank you. It is now cleared.
Asimiyu · 04/04/2021 at 11:16 am
Good afternoon engr Mithun. Please, I recently built the solar charge controller hardware on a veroboard, and even simulated it on the Proteus and I used mikroc version 7.2 to simulate it. However, I discovered something sir. Without solar panel voltage connected, while Battery was connected, the controller would not trigger the gate of LOAD MOSFET and hence, load remains off. However, if solar panel is connected, and Battery is also connected, the following are what I observed:
(1) pin#1(Vcc)= 4.98v from 7805 reg.
(2) pin#2(GP5), charg_LED = 0.0v
(3) pin#3(GP4), load_pin = 2.38v
(4) pin#4(GP3),solar_sense = 4.3v(here, I have using variable resistor of 5K, with series with 3k9 to form voltage divider to give 5v at 18V solar panel proposed to be used.
(5) pin#5 (GP2), load_LED = 4.98V
(6) pin#6 (GP1), Battery_sense = 2.46v at 13.05V(no-load) and (12.98v when connected to load).
(7) pin#7 (GP0), charg_pin = 0.0v
Pin#8 (GND) normal 0.v.
However, from these data I took, it means the solar is not charging the battery, which I observed from both simulation and the hardware circuit.
What could be the problem sir. I troubleshooting the hardware and the it behave in the simulation, the same way on the hardware too.
Finally, I also observed that, if solar panel voltage is not connected, the controller will not trigger the load MOSFET even at battery Voltage =13.05v. it shouldn’t be so, bcs even the solar Voltage is not present in night, while the battery Voltage is at Max(at least above 11v,) the load MOSFET should connected. Please, look into it. I am just self interested learner. I have already built the hardware,. I also tried to upload everything here, but I was on able to do so, I copy and trying to past it here but it couldn’t be pasted. I will send it through your email.
Mithun K. Das · 05/04/2021 at 3:24 am
Seems like you forgot to do a configuration. Go to edit project from mikroC. Set GP3/MCLR >> disabled.
As this is enabled by default, the micro-controller is not working if GP3 pin is low. Solar is sensed through this pin. So when solar is not available, the MCU is in reset condition. And only when the solar is on, MCU works.
Also, to turn the load on, first you need to charge the battery to higher than the load reconnect voltage. Once it is done, load will be normal.
1> OK, no prob.
2> OK
3> due to MCLR low
4> No need to use any voltage divider, once the mosfet is on, it is 0.7V+B+. Also internal diode cliper protects the pin. Note: MCLR max input range: 12V
5> No prob
6> good
7> ok.
Also if you do not have any license for mikroC, you can use my hex. I always use valid licenses for each compiler & other software.
Joy · 05/04/2021 at 3:21 am
Sir I want use 200 W solar panel (Mono) and output 12V 150A battery. so how to do this increased hardware part.
Mithun K. Das · 05/04/2021 at 3:38 am
Use Diode 10A10 3 nos in parallel, Use MOSFETs 3 in parallel. Increase current-carrying layer thick and pasted with solder lead & wire.
Asimiyu · 05/04/2021 at 6:05 am
Thank you very much sir. I will go to edit project and and do that. Thank you once again.
Joy · 05/04/2021 at 12:34 pm
Soler output voltage 22v When sun light full .But that time 22v Direct 12v battery input. so battery input high current carry . +12v battery charging volt 13.5v fixed but this system not fixed. so It’s problem or not ?
Mithun K. Das · 06/04/2021 at 3:58 am
No problem.
Asimiyu · 05/04/2021 at 2:56 pm
Hello engr Mithun. Thank you for your efforts, free offer knowledge, and your guidance you have been impacted on many people in the world. I have disabled the GP3/MCLR in mikroc project edited and also set INTOSC Oscillator: CLKOUT…… Everything is now working fine, even at the moment I am writing this message, the Battery is still charging and is at 13.04. I really appreciate your efforts.
HOWEVER, please, I am sorry for being asking too much question. I so love embedded systems, and being part of chips programming is my passion, and I have your blogs here as an opportunity for me to learn.
From previous post on IR REMOTE CONTROL WITH SONNY SIRC REMOTE PROTOCOL, I am trying to convert the code to control A.C (220VAC, 50Hz) fan regulator in such a way that, if I press (+vol), the speed should increase sequentially, and decrease it by pressing (-vol). There should be one digit segment to indicate count. I have been cracking my brain, I haven’t succeed since you posted it. Please, I need your guidance sir.
Mithun K. Das · 06/04/2021 at 3:57 am
Thank you.
>> I’ve a plan for that.
Asimiyu · 06/04/2021 at 5:57 am
Looking forward sir. Thank you God bless.
Mahasetra · 12/04/2021 at 12:47 pm
Hello and thank you for this very interesting article. Can the schematic be modified to integrate a current sensor instead of the load control (pin 3), and a synchronous buck topology (with IR2104) to increase the efficiency? I know that the efficiency will be lower than a MPPT but the goal is to keep the small microcontroller and convert the excess voltage into current while charging the battery in 3 steps.
MKDas · 12/04/2021 at 1:11 pm
Thank you for your comment. There is a pin limitation as well as memory limitation. Adding MPPT function is almost impossible to add in this tiny MCU. But I’m keeping a note, if somehow it is possible to increase the efficiency, I’ll try. Thanks. Requesting to subscribe.
Mahasetra · 28/04/2021 at 2:59 pm
Hey, can i use an attiny85 or attiny84 instead of a pic?
And please how does the absorption phase work in your code? How long does the solar controller stay in the phase 2 of charging?
Thanks
MKDas · 29/04/2021 at 10:41 am
Using the same technique, you can use other MCUs rather than PIC. No problem with that.
The absorption phase should be determined sensing current. But as there is no such option in this design, so a timer is used here. Approximate time: timer speed X counters. Around 2~4hrs will be good timing.
Mahasetra · 03/05/2021 at 3:29 am
Thank you for replying.
I’ve done a diagram of what I’had on my mind after reading two of your articles about solar charge controllers.
It’s a basic buck converter with 3 steps charging (but it doesn’t have any mppt algorithm).
(There are some modifications to be done to improve efficiency)
What do you think Sir?
https://drive.google.com/file/d/1vwZKdSB8KVUy655E0h0CBr12mZCQ2rQV/view?usp=sharing
MKDas · 03/05/2021 at 11:41 am
The circuit seems ok. Add capacitor after rectifier on solar side. D4 must be Ultra Fast Diode. There is no need of any buzzer in solar charge controllers. Use on another purpose. Check OP-Amp for resistor values. Best of luck.
Subramanian · 15/08/2021 at 10:28 pm
Hi i have a build error
Line no : 78 Message no : 324 Error : Undeclared identifier ‘ADC_Read’ in expression
MKDas · 16/08/2021 at 11:05 am
Mark the ADC library from the right side of the compiler window.
Subramanian · 16/08/2021 at 11:23 am
Ok Thankyou
Subramanian · 16/08/2021 at 11:20 am
Hi build Error Undeclared identifier ‘ADC_Read’ in expression
MKDas · 16/08/2021 at 12:00 pm
Mark the ADC library from the right side of the compiler window.
Kekea · 29/09/2021 at 8:27 pm
Hi sir
Can we use PIC16F877 microcontroller be used?
MKDas · 29/09/2021 at 8:42 pm
Yes, but why you will use a cannon to kill a mosquito?
Esther Tibaua · 10/10/2021 at 5:22 pm
Hi sir, can the coding converted to C language, Also can the relays used in the design instead of mosfets
thanks
MKDas · 10/10/2021 at 6:48 pm
Coding is in C language. Use a suitable compiler and edit as per that compiler reserved words. It should work fine. But using Relays rather than MOSFET will not be a good choice.
Faustina · 31/10/2021 at 1:41 pm
Hello sir,
I’m doing this project however, our college don’t have PIC12F675 so i will use the PIC16F877 but to change from one PIC to another will it affect the circuit and the coding?
Lab Projects BD · 31/10/2021 at 3:48 pm
You can try
Djalltra · 21/10/2021 at 1:46 pm
Please how did you implement your software pwm and what is your interrupt time.if I want to use more than gpio pin for pwm how do I implement this as I saw this done in a pic16f72 inverter which utilizes 4 pins for pwm
MKDas · 21/10/2021 at 4:25 pm
There is another article [link] on PWM inside this article. You can read that first. Implementing software PWM with more GPIO pins with this small MCU will be tough. If you need more than one PWM pin, better use upper-class MCU.
najmi · 20/06/2022 at 2:28 pm
hello, sir. how to turn on the lamp?
MKDas · 20/06/2022 at 9:13 pm
Trigger the MOSFET.
sher · 20/06/2022 at 6:42 pm
sir , how to turn on the bulb ? i need to increased the voltage of battery or not ? thank u sir
MKDas · 20/06/2022 at 9:14 pm
Trigger the MOSFET. No need, Use 12V battery.
Ludovico · 12/10/2022 at 12:12 am
Sir,
How can we use to add the hex file in pickit3 because it’s not supporting the pic12f675 in pickit3 software.
MKDas · 12/10/2022 at 12:00 pm
It should be. check pickit3 supported IC list or use pickit2 instead. But I think, it will support 12F675. maybe in lower level MCU from device category.
Ludovico · 12/10/2022 at 4:20 pm
Sir,
Thank you for your advice,
Somehow I got cleared with connecting 12f675 with pic kit3 but when the hex file is write to the ic it is successful but it can’t be verified since it give an error of “verification of program memory failed at address 0x000000”.
MKDas · 12/10/2022 at 4:47 pm
try another MCU. maybe that IC is faulty.
Ludovico · 18/10/2022 at 10:36 am
Thank you Sir,
I need to know what are the 2 items which are covered by the heat sink which is shown in the pcb layout.
MKDas · 20/10/2022 at 4:00 pm
MOSFETs