Hysterical MPPT - Solar Charger

This concept just makes the charging algorith much simpler. The battery charges till maximum charge lvl 14.7V is reached and cutoff so long till minimum lvl is reached 13,8V. If the sun goes down the charger sleeps. Consumcion is 5mA asleep thx too a cheap and efficient 2A stepdowner for the Arduino.

Its quite safe (no current control at all or even cycle by cycle), i run it with 180W Solarpanel. Just 20A fuse and metal body if it should burn out. xD

Enjoy.

nb. rename the .asc.txt file in .asc for LTspice

hysterical_mppt.ino (12.2 KB)

IR2104_MPPT_Arduino.asc.txt (6.79 KB)

Maybe you mean "hysteresis".

Weedpharma

AFAIK it's not good to (fast)charge a lead-acid battery to 14.7volt all the time, unless you're desperate for power. Maybe only good once a month for de-sulphating a flooded deep-cycle type.
Gel types should never be float charged over 13.6volt.
Leo..

Hi,
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you please post a copy of your sketch, using code tags?
They are made with the </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

Thanks Tom.. :slight_smile:

Wawa:
AFAIK it's not good to (fast)charge a lead-acid battery to 14.7volt all the time,

My 230Ah batteries are charged at 14.8v routinely and the ones I just replaced lasted 4 years.

...R

My 230Ah batteries are charged at 14.8v routinely

This has to be a grossly oversimplified description of the procedure.

Do you have a charge controller? If so, it is extremely unlikely that the charge controller is providing 14.8V to lead-acid batteries on a continuous basis. That will evolve hydrogen gas and cook them in very short order.

A float charge at 13.8 V is a common protocol, but most smart controllers embody a rather more complicated protocol.

Hmmmm...

Depends on the type of lead acid battery. 'Leisure' batteries are designed to be charged and discharged slowly and can be discharged almost completely without damage. A long float at under 14 volts seems a good compromise between not-quite full charge and overcharging.

Starter batteries can be charged and discharged fast - eg in a car by a high output alternator - but they don't like deep discharges.

regards

Allan

jremington:
This has to be a grossly oversimplified description of the procedure.

Do you have a charge controller?

Yes. If I left the engine running it would drop down to a float charge. However I usually turn the engine off while it is still charging at 14.8v to save fuel. They get about 1 hour's charge morning and evening for 3 days and then they are taken off line for 3 days when they also get the same 2-hours charge but are not supplying any load.

...R

Wawa:
AFAIK it's not good to (fast)charge a lead-acid battery to 14.7volt all the time, unless you're desperate for power. Maybe only good once a month for de-sulphating a flooded deep-cycle type.
Gel types should never be float charged over 13.6volt.
Leo..

I think the point is its 14.7V at high current, so some volts are lost to internal resistance - a good charger
will stop the current and monitor the no-load voltage regularly to get a true indication of SoC. 13.8V is
the normal limit for no-load voltage - any higher and you are manufacturing hydrogen, not charging a battery!

Actualy i have more the problem that becoz the of the slowness of the prog, the hyteresis switch off too slowy so sometimes its 14.7.. sometimes 15.2 or more.. depend how strong the current is. You have too addapt it anyway too ur battery typ and maybie put the limit of the hyst so that it safely switch off before 14,8V max. (i have red about batts with Calcium-Silver who even like 16-17V.. but u have too read it anyway from instruction manual of ur batt).
The real nice effect with tis hyst-charger, when the sun goes down, the last cycle goes slowy down from 14,7V so the batt is really at 100% when night begins and u need it! Perfect for camping. I never have seen a charger that u can buy do this.
Here is an JPG of the shematic:

Image from Reply #9 so we don't have to download it. See this Image Guide

...R

lebreton:
the hyteresis switch off too slowy so sometimes its 14.7.. sometimes 15.2 or more.. depend how strong the current is.

How much current is available and what is the amp-hr capacity of the battery?

...R

How did you calculate IR_SAFE (220ohm).
Did you ever look at VCC of that chip with a scope.
R value seems very high for a power IC, and C3 seems to low.

Which Arduino are you using.
With a 1:5 divider for voltage I expect you're using 2.56volt Aref?
Leo..

Hi,

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom.. :slight_smile:
Also a schematic, including the arduino and how you are powering it.

So i killed my display, now its even simplier :confused:
The sleep functions works how it should.
Faster cycle less then 10ms.
Ye, i should look if the IR_safe resistor is working how it should. Btw it should be done with every new build if all is working lik in the simulator spice. I charge 2x 100Ah batteries. Or they had 100Ah the old charger was not doing a great job.. sometimes he only charged up 13.2 and on good day sometimes 13.8V.. no wonder the batteries loved it. :frowning:

NB. Find a good coil for Stepers is the most tricky part. A friend tested a trafo ferrit ring and cut about 1mm out of it (like tis "C") now it has 40x less "ur" and satures at 20A with 14 windings, it has about 10uH, and keeps absolutly cool. Thos ferrit rings are everywhere too find (choke coils).

So heres the code witout TFT now:

// THIS MPPT SLOPECLIMBER ALGORITH WORKS FINE! EFFICIENCY 90% @  Solarpanel = 180W 22V 36Cells
// It sleeps for 8s then wake up some ms too check if there is sun
// In SLEEP MODE consumes only 5mA with TFT ON, thx too a little step-downer that makes the 5V for arduino and TFT.
// NB my wiring is bad and long, i lose a lot of power on the lines. my gain is 10% compared too normal regulator.

#define MinStartV 18.5           // Min solarpanel volt value for ON Charger
#define LOW_SOL_WATTS 5          //value of solar watts // this is 5.00 watts -> PWM_START
#define MIN_SOL_WATTS 1          //value of solar watts // this is 1.00 watts -> OFF      
#define MAX_BAT_VOLTS 14.7       // upper hysteresis -> OFF
#define BATT_HYS 13.6            // low   hysteresis -> ON
#define MAX_TEMP 70
#define OK_TEMP  40
#define SOL_AMPS_SCALE  0.012734          //LM324 680k 10k -> Gain = 68 with 5mOhm shunt placed ground side withou a bridge
#define SOL_VOLTS_SCALE 0.027107422       // the scaling value for raw adc reading to get solar volts  // (5/1024)*(R1+R2)/R2 // R1=100k and R2=20k max. +30V -> +5V arduino
#define BAT_VOLTS_SCALE 0.0261            // the scaling value for raw adc reading to get battery volts 
#define TEMP_SCALE 0.13125                // the scaling value for raw adc reading to get temperatur 

#define PWM_MAX 254                  // 254 60ns off; 1= 60ns coz of 16Mhz     
#define PWM_START 240                // max dutycycle tat maks sense with an irfz44
#define PWM_MIN 170                  // 68% min duty cyle NB. My normal avarage dutycycle is 210 normaly 16,5V solar and batt at 13,5V. rarely goes under 200.
#define AVG_NUM 55

#include <avr/sleep.h>
#include <avr/wdt.h>

// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

// global variables
float old_sol_watts,sol_watts,sol_volts,sol_amps,bat_volts,celsius;
int pwm, old_pwm,delta=-1;
unsigned int rzz,charger_state,old_charger_state,k; //65.535max

 //PINS
#define SOL_VOLTS_CHAN 0            // defining the adc channel to read solar volts 
#define SOL_AMPS_CHAN 1             // Defining the adc channel to read solar amps
#define BAT_VOLTS_CHAN 2            // defining the adc channel to read battery volts
#define CELSIUS_CHAN 3              // defining the adc channel to read temperatur of mosfett
#define PWM_PIN 5                   // the output pin for the pwm (only pin 5 or 6 at 63kHz)
#define PWM_ENABLE_PIN 6            // pin used to control shutoff function of the IR2104 MOSFET driver (hight the mosfet driver is on)

#define TURN_ON_MOSFETS analogWrite(PWM_ENABLE_PIN, 255)      // enable MOSFET driver
#define TURN_OFF_MOSFETS analogWrite(PWM_ENABLE_PIN, 0)      // disable MOSFET driver
#define LON digitalWrite(13, HIGH)
#define LOF digitalWrite(13, LOW)
#define TOG digitalWrite(13,!digitalRead(13))


void setup() {
  pinMode(SOL_AMPS_CHAN, INPUT);
  pinMode(SOL_VOLTS_CHAN, INPUT);
  pinMode(BAT_VOLTS_CHAN, INPUT);
  pinMode(CELSIUS_CHAN, INPUT);
  pinMode(13,OUTPUT);
  
    //For Fast PWM of 62.500 kHz (prescale factor of 1) pins 5 and 6
    //Use these two lines in the setup function: (16Mhz/253 steps):
    TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);  //(16Mhz/255 steps)
    TCCR0B = _BV(CS00); 
    
  TURN_OFF_MOSFETS;
  charger_state = 0;
  pwm = PWM_START;
  set_pwm_duty(); 
}

void loop() {
  read_adc();                      
  run_charger();
}

//------------------------------------------------------------------------------------------------------
// This reads and average, temperatur, solar volts, solar amps and battery volts. 
//------------------------------------------------------------------------------------------------------
void read_adc(void){
  celsius  += (28+TEMP_SCALE* (1024-analogRead(CELSIUS_CHAN) - 460)); celsius=celsius/2; //460 bei 28°C
  for (k=0; k<AVG_NUM; k++) {//NB: 55x3x(100us+16us) = 165x116u = 19ms
    sol_amps  += (analogRead(SOL_AMPS_CHAN)-19)  * SOL_AMPS_SCALE  ;      //input of solar amps, 100us read time
    sol_volts += analogRead(SOL_VOLTS_CHAN) * SOL_VOLTS_SCALE;       //input of solar volts
    bat_volts += analogRead(BAT_VOLTS_CHAN) * BAT_VOLTS_SCALE;       //input of battery volts
     delay(5);//wait some ms. -> delay(10000); super! <
    }
    sol_volts = sol_volts  /(AVG_NUM+1);
    bat_volts = bat_volts  /(AVG_NUM+1);
    sol_amps  = sol_amps   /(AVG_NUM+1);
    sol_watts = sol_amps * sol_volts;  //calculations of solar watts                       
  }         

//------------------------------------------------------------------------------------------------------
// Set the pwm duty cycle.
//------------------------------------------------------------------------------------------------------
void set_pwm_duty(void) {
  if (pwm > PWM_START) {             // check limits of PWM duty cyle and set to PWM_START
    pwm = PWM_START;    
  }
  else if (pwm < PWM_MIN) {          // if pwm is less than PWM_MIN then set it to PWM_MIN
    pwm = PWM_MIN;
  }
analogWrite(PWM_PIN,pwm);                     
} 

//------------------------------------------------------------------------------------------------------
// Hysterischer-MPPT Charger
//------------------------------------------------------------------------------------------------------
void run_charger(void){
  switch (charger_state) {

case 0://Charger Off
      if ((bat_volts < BATT_HYS) & (sol_volts>MinStartV) ) {                // hysteresis: on
        charger_state = 1; //ON
        rzz=0;
        pwm = PWM_START;
        set_pwm_duty();
        TURN_ON_MOSFETS;
      }
    else {rzz++; if(rzz>12)sleep8s();else {LON;sleep0dot5s();LOF;sleep0dot5s();}} //test
break;
    
case 1://Charger On                                        
      if (bat_volts > (MAX_BAT_VOLTS)) {                                   //  hysteresis max: off
        TURN_OFF_MOSFETS;
        charger_state = 0; //OFF
        pwm = PWM_START;
        set_pwm_duty();
 break;}

      else if (celsius > (MAX_TEMP)) {                                  //  hysteresis max_temp: off
        TURN_OFF_MOSFETS;
        charger_state = 2; //OVERHEATED
        pwm = PWM_START;
        set_pwm_duty();for(k=0; k<10; k++){TOG;sleep0dot5s();}
break;}
      else if (sol_watts < MIN_SOL_WATTS) {                              // no sun -> off
        TURN_OFF_MOSFETS;
        charger_state = 0; //OFF
        pwm = PWM_START;       
        set_pwm_duty();digitalWrite(13,LOW);sleep1s();
break;}  
       else if (sol_watts < LOW_SOL_WATTS) {                           // very low watts -> max duty
        pwm = PWM_START;        
        set_pwm_duty();digitalWrite(13,LOW);
break;}
       else if (old_sol_watts > sol_watts)  {                       // MPPT against flat tops: ">"                                      
          delta = -delta;                       
      }
        pwm += delta;                        
        old_sol_watts = sol_watts;                       
        set_pwm_duty();                                   
break;
    
case 2://Charger Overheated
      if (celsius < (OK_TEMP) ) {                                  // Temp ok -> go off
        charger_state = 0; //OFF
      }
      else {
              for(k=0; k<10; k++){TOG;sleep0dot5s();}
break;}

default: //never happens
        TURN_OFF_MOSFETS;
        charger_state = 0;
        pwm = PWM_START;set_pwm_duty();     
        sleep8s();
break;
      }//END of switch()
}//END of run_charger()


// SLEEP..
//------------------------------------------------------------------------------------------------------
// SLEEP
//------------------------------------------------------------------------------------------------------
void sleep8s(void){ //in sleep consumes ~5mA http://www.gammon.com.au/power
  // disable ADC
  //ADCSRA = 0;  
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); //sleep 8seconds
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();              // cancel sleep as a precaution
   }

   void sleep1s(void){ //in sleep consumes ~5mA http://www.gammon.com.au/power
  // disable ADC
  //ADCSRA = 0;  
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); //1sec 
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();              // cancel sleep as a precaution
   }

   
   void sleep0dot5s(void){ //in sleep consumes ~5mA http://www.gammon.com.au/power
  // disable ADC
  //ADCSRA = 0;  
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP0); //0.5sec 
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();              // cancel sleep as a precaution
   }

allanhurst:
Hmmmm...

Depends on the type of lead acid battery. 'Leisure' batteries are designed to be charged and discharged slowly and can be discharged almost completely without damage. A long float at under 14 volts seems a good compromise between not-quite full charge and overcharging.

The old deep-cycle myth again - lead-acid chemistry simply does not tolerate 100% discharge, it
trashes the battery capacity:

(2nd para - note the recommendation of only using 55% of capacity for regular use, never more than 80%)

Vehicle batteries have strengthened plates to withstand very high discharge rates (1000A is not uncommon
spec). Deep cycle are not specially ruggedized for high current.