Time to close the loop and put battery voltage maintenance under control of the Arduino. Bit of maths, bit of programming and it sort of works.

By Julian

Youtuber, shed dweller, solar charge controller aficionado

16 thoughts on “Arduino pwm solar charge controller #4 – closing the loop”
  1. Avataaar/Circle Created with python_avatars MikesAllotment says:

    Hi Julian – on the 'latest' / 'official' circuit diagram with the 82K + 20K voltage divider you have a 220pF smoothing capacitor. All of the parts lists I've seen elsewhere (Adam Welch & arduined.eu) state that this needs to be rated at 100V – is this correct? If so – why? As far as I can see at this point in the circuit the voltage should never be more than 5v (that's the whole point of the voltage divider – to limit the voltage hitting the analog pin A0 to the Arduino). Can you please confirm my thinking – that a standard 50v rated ceramic cap will suffice?

  2. Avataaar/Circle Created with python_avatars Vishnu says:

    What is frequency of pwm

  3. Avataaar/Circle Created with python_avatars Nicholas2011ist says:

    Dumb question but couldn't you use a switching buck converter as a crude solar regulator?

  4. Avataaar/Circle Created with python_avatars Jatin Patel says:

    Hello sir,
    I am final year electrical engg. student and in my final year project I am working on ARDUINO BASED PMW solar charge controller and i am working with same circuit as your PWM5 circuit. I completed all connection and programing also done (run sucessfully) as per circuit of PWM5. But i am getting some problem in "high side driver" in which MOSFET (irf 3205) are not turned ON ( not trigger) that is why current are not flowing in the circuit so my battery is not going to charge.
    so i request to give me some solution for this as soon as possible………
    I apologise to my poor english..

  5. Avataaar/Circle Created with python_avatars Link Smith says:

    Small jumps in voltages to a lead acid battery (13.58 for less then a second for example) will not really do any significant harm to a lead acid battery. First off some car alternators put out 14.5 volts when charging the starting battery until a relay switches them off. Second, I've seen spikes up to ~15 volts for less then a second when headlights are switched off in running older model vehicles.

  6. Avataaar/Circle Created with python_avatars Gadget Addict says:

    Why are you stopping production and sale of the PWM5 ? Are you planning to focus on a similar MPPT project?

  7. Avataaar/Circle Created with python_avatars David Pilling says:

    Use the ATMega built in voltage reference Google "arduino secret voltmeter"?

  8. Avataaar/Circle Created with python_avatars oreubens says:

    I guess part of your problem is loosing precision on the measuring side… ย By dividing the analog read (0..1023) by 16 (1..63), you're effectively limiting the precision of the measurement to 63 discrete values. ย  unless I'm misunderstanding some bits. that means you can for example measure 13.4 volts or 13.5 volts but nothing in between.
    Personally, I think it might be better to keep the measurement as is (0..1023) but adjust your comparands in the if to scale to the measurement rather than the other way around.
    so something like:
    const int WantedDeciVolts = 135;
    const int ZenerDropDeciVolts = 91;
    const int R1 = 56; ย  // scale R1 and R2 down to be in range for int
    const int R2 = 200;
    const int MaxMeasurement = 1023;
    const int RefDeciVolts = 50;
    const int Reference = (int)((double)((WantedDeciVoltsย -ZenerDropDeciVoltsย ) * R2 / (R1+R2) * MaxMeasurement / RefDeciVolts) + 0.5);
    and in the loop.

    int Measured =analogread(A1);

    if (Measured<Reference)
    {
    // increment PWM
    }
    else if (Measured>Reference)
    {
    // decrement PWM
    }

    before you cry fire and murder over the usage of double. ย Note that we are letting the COMPILER calculate the reference value as precise as posible, then we round it and convert to int. ย if you look at code, all of the above stuff will simply get compiled into: ย Reference = 703;
    none of the intermediate consts will end up in the compiler binary, they're not needed. ย (use a define if you have to, const is better/cleaner).
    At no time during runtime will a double ever get used.
    STILL don't believe me, simply hardcode Reference to 703 (and add a comment telling how the value it's derived). ย 

    It's even more optimal because you have removed entirely from the loop the /16 and + 91 ย yes, the compare is now an int compare rather than a byte compare, but it'll still be faster.

    the 'problem' in that code is the analogRead (which takes 100ยตs or you can measure at 10Khz at most) this is an order of magniture more than the code in your loop. ย (don't optimize where it don't matter).

    And as the above shows… don't try to outsmart the compiler, let the compiler do the work for you rather than precalculating everything yourself and getting code that's full of "magic numbers".

  9. Avataaar/Circle Created with python_avatars Christopher Obbard says:

    You shouldn't need the chargepump with these ultra-modern logic-level mosfets, you can get a TO-252 or D2PAK fet that will turn fully on at 5Vgs at a couple of amps :). The onyl problem I've found is the total gate charge is a little on the high side so the frequency might matter….

  10. Avataaar/Circle Created with python_avatars Stuart McConnachie says:

    Hi Julian. Probably if you take out your serial writes your control loop will run much faster and you'll get less overshoot.

  11. Avataaar/Circle Created with python_avatars xanataph says:

    This is all looking very good Julian…! Indeed I might make putting one ov these together my first serious Arduino project. I have two Arduino boards (both given to me as pressies from my partner) but as yet I have not put any to serious use. Just modded those LED flash programs to emulate the character ov my favourite Lighthouses…! I seem to enjoy being stuck in the analogue domain with my development work! ๐Ÿ™‚

    That code you have published there also controls the pins to create that boost rail for the Mosfet, yeah?ย 

    Only one thing I want to suggest though, is that adding a tungsten lightbulb ov a suitable wattage to a PSU can mimic the "sag" ov a solar panel even better. Although you already proly have plenty with those little unreg'd wall warts though…! ๐Ÿ˜‰

  12. Avataaar/Circle Created with python_avatars superdau says:

    I guess the overshoot is coming from the fact, that you only "single step" the pulsewidth until you find the right one. This can take quite a few loop iterations, if the load change is too big. You need some "P" in your closed loop.

    [EDIT]
    Dang, I should really watch the video completely AND read the comments before posting…

  13. Avataaar/Circle Created with python_avatars superdau says:

    If you're using an ATmega/tiny divide by 16 can be done faster: swap the nibbles and AND 0b00001111 . div by 16 done in two clocks.

    [EDIT] Ah, I forgot you don't use assembly. It's more of a hassle in C because the nibble swap is only useful, if you're directly working with registers, not C-variables. (although it could be that the compiler will have this optimization for div16 implemented anyway)

  14. Avataaar/Circle Created with python_avatars Chris says:

    Oh, I forgot to ask – if I understand you correctly, you're working with an older design which used a Zener diode but the new one does not. Could you tell me why you eliminated it please? I'm thinking of adding one to get more resolution on the much smaller interesting range of 10 – 15 volts, rather than stretching all 1023 values over an entire 0 – 15 volts as a potential divider would, but since you're coming the other way, I'm now a bit cautious.ย ย 

  15. Avataaar/Circle Created with python_avatars Chris says:

    Great video Julian – close to my project and very useful for me – thank you.

    It seems the world is not completely as one on how best to charge a lead acid battery, but in the end I looked at he behaviour of a well-known commercial unit and emulated it in software.

    On the great 1023/4 debate – it's 1023. That's what all 10 bits set to one is equal to – the largest number which 10 bits can represent. 1024 can't be represented in 10 bits. 10 bits allows 1024 combinations but one of them is zero. Of course it makes little practical difference.

  16. Avataaar/Circle Created with python_avatars lez briddon says:

    just a thought for running off solar with a bank that if the pwm ever gets >200 then you could have a warning that your starting to draw more than you have incoming etc for people that have to budget their power use.

    taking shape nicley, I've had to delay my build as my expected windfall didnt, but i will get some small panels set up 'just for fun' for when i can buy a roof full…

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.