Photovoltaic charge controller

Discussion in 'The Projects Forum' started by xavierpereira, Sep 8, 2011.

  1. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
    hey Guys I m working on PHOTOVOLTAIC CHARGE CONTROLLER using DsPIC 30F4011..

    I have actually completed calcultion simulations and Code testing :

    I have written this code on PWM

    #include <libpic30.h>
    #include <p30f4011.h>

    // Configuration settings
    _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
    _FWDT(WDT_OFF); // Watchdog timer off
    _FBORPOR(MCLR_DIS); // Disable reset pin

    // Function prototypes
    void configure_pins();
    unsigned int read_analog_channel(int n);

    int main()
    {
    int voltage;

    // Set up which pins are which
    configure_pins();

    while(1)
    {
    // Analog input 0 controls PWM 1 duty cycle.
    voltage = read_analog_channel(0);
    PDC1 = (int)((voltage / 1023.0) * 2 * PTPER);


    }

    return 0;
    }

    void configure_pins()
    {
    // Configure RD0 as a digital output
    LATD = 0;
    TRISD = 0b11111110;

    // Configure analog inputs
    TRISB = 0x01FF; // Port B all inputs
    ADPCFG = 0xFF00; // Lowest 8 PORTB pins are analog inputs
    ADCON1 = 0; // Manually clear SAMP to end sampling, start conversion
    ADCON2 = 0; // Voltage reference from AVDD and AVSS
    ADCON3 = 0x0005; // Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us
    ADCON1bits.ADON = 1; // Turn ADC ON

    // Configure PWM for free running mode
    // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
    PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
    PTCON = 0;
    _PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9470; // 20ms PWM period (15-bit period value)
    PDC1 = 0; // 0% duty cycle on channel 1 (max is 65536)
    PTMR = 0; // Clear 15-bit PWM timer counter
    _PTEN = 1; // Enable PWM time base
    }

    // This function reads a single sample from the specified
    // analog input. It should take less than 2.5us if the chip
    // is running at about 30 MIPS.

    unsigned int read_analog_channel(int channel)
    {
    ADCHS = channel; // Select the requested channel
    ADCON1bits.SAMP = 1; // start sampling
    __delay32(30); // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0; // start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
    return ADCBUF0;
    }

    this code works fine :

    Now I working on the control loop:
    In voltage-mode control the output voltage increases and decreases as the duty ratio increases and decreases.
    The output voltage is sensed and used for feedback. it has two-stage regulation,
    it will first hold the voltage to a safe maximum for the battery to
    reach full charge. Then it will drop the voltage lower to sustain a "finish" or "trickle" charge.

    Has anyone done this or can help me to write the control loop..

    it will be a grt help

    Thanks !!
     
  2. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
    any one with any Ideas are welcome ...
     
  3. wayneh

    Expert

    Sep 9, 2010
    12,093
    3,031
    You're looking for a battery charging strategy/algorithm? The answer depends on what type of battery. The pros here need more detail about the mechanicals of your system, not the code please. ;)
     
  4. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
  5. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
    In voltage-mode control the output voltage increases and decreases as the duty ratio increases and decreases.
    The output voltage is sensed and used for feedback. it has two-stage regulation,
    it will first hold the voltage to a safe maximum for the battery to
    reach full charge. Then it will drop the voltage lower to sustain a "finish" or "trickle" charge.
     
  6. colinb

    Active Member

    Jun 15, 2011
    351
    35
    Might you want to be able to charge the battery even when the solar panel output is 12 V or less? If you can still get usable current from it, then you would want something different than a buck converter so you can step the voltage either up or down: a buck-boost or SEPIC converter.

    Also, consider implementing maximum power-point tracking (MPPT) to achieve maximum efficiency, if you haven't already.
     
  7. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
    Yeah i was thinking about the MPPT but due to time contraints I m not able to spend more time on this project..
    I have already finished my Working model Now the only part that is killing me is the the control Loop in the programming.

    I just need a view how the control loop looks like and I m writing the code in C
    I was wondering If Switch-Break or if -else Loop would me needed and as a Begineer in Programming i m finding that difficult.

    If u have any examples on it it would be very helpful!!
    thanks and have a grt Day
     
  8. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
  9. colinb

    Active Member

    Jun 15, 2011
    351
    35
    Well, hopefully you can familiarize yourself a bit more with the C language first, perhaps on a PC with some “Hello, World” type test applications.

    You will probably end up with a program that has an infinite loop (the top-level control loop) with some conditional statements inside this top-level loop.

    For instance, based on your block diagram, I would write something like this (this is pseudo-code and would need to be adapted to real code for your environment):

    Code ( (Unknown Language)):
    1.  
    2. // Example of translating the flow chart Algorithm.JPG into C code.
    3.  
    4. // Start
    5. initialise();
    6. set_duty(0);    // Set OFF
    7.  
    8. // Control loop - an infinite loop
    9. while (1)
    10. {
    11.     if (read_input_voltage_mV() < 3200)
    12.     {
    13.         // Decrease duty cycle.
    14.         set_duty(get_duty() - duty_step);
    15.     }
    16.     else
    17.     {
    18.         // Check output voltage.
    19.         if (read_output_voltage_mV() < 12000)
    20.         {
    21.             // Increase duty cycle.
    22.             set_duty(get_duty() + duty_step);
    23.         }
    24.     }
    25. }
    26.  
    27. // Global variables
    28. static int duty;
    29. static int duty_step = 1;
    30.  
    31.  
    32. void set_duty(int new_duty)
    33. {
    34.     if (new_duty < min_duty)
    35.         duty = min_duty;
    36.     else if (new_duty > max_duty)
    37.         duty = max_duty;
    38.     else
    39.         duty = new_duty;
    40. }
    41.  
    42. int get_duty(void)
    43. {
    44.     return duty;
    45. }
    46.  
     
  10. xavierpereira

    Thread Starter New Member

    Sep 8, 2011
    8
    1
    thanks a lot for the Pseudo Code

    Hopefully I can implement this by tomorrow with some changes .

    I will keep u guys updated with my project and If I need some more help in Programming

    and I have some Knowledge of C progamming But at a basic Level ... my weakness has always been the statements in loop .. it was like 4 yrs ago..
    hopefully I will be well versed by the end of my project ... Buy ur guys help ofcourse

    Thanks for the help !! have a grt Day !!!;)
     
  11. russpatterson

    Member

    Feb 1, 2010
    351
    16
    I've written the control code and it seems to be working ok for me. FWIW here it is:

    #define VOLTAGE_FLUX 0.01 // allow voltage to fluctuation within this amount
    #define FLOAT_CHARGE_LOW_VOLTAGE_SWITCH_TIME 5 // seconds
    #define FLOAT_CHARGE_LOW_VOLTAGE_DRIFT_VOLTS (0.5)
    /***********************************************************************
    *
    * chargerTest()
    *
    ************************************************************************/
    void chargerTest()
    {

    if (adc_battv.new_flag == 1)
    {
    // first calculate average voltage using low pass filter

    lastAvgBatteryVoltage = batteryVoltage; // save average voltage from last time around
    batteryVoltage = calcVoltage();
    avgBatteryVoltage = (lastAvgBatteryVoltage * 6/8) + (batteryVoltage * 2/8);

    /**** CHARGING LOGIC *********/
    // logic for charging

    // check for SATURATION charge level
    if(battery.state == BS_BULK)
    {
    if(avgBatteryVoltage >= (battery.target_voltage - 0.1))
    {
    saturation_charge_timer.state = ON; // just start it running
    setBlinkRate(2); // saturation timer on
    }
    else
    {
    // voltage not high enough turn off saturation charge level timer
    saturation_charge_timer.state = OFF;
    setBlinkRate(16); // just bulk mode
    }
    // check if enough SATURATION charge time reached
    if(saturation_charge_timer.minutes > battery.saturation_time_minutes)
    { // time reached so change to FLOAT state (seconds only for test)
    setBatteryChargeState(BS_FLOAT);
    }
    }
    else if(battery.state == BS_FLOAT)
    {
    // check for low voltage to switch back to BULK charge mode
    if(avgBatteryVoltage < (battery.target_voltage - FLOAT_CHARGE_LOW_VOLTAGE_DRIFT_VOLTS))
    {
    charge_timer.state = ON; // start low voltage timer
    if(charge_timer.seconds >= FLOAT_CHARGE_LOW_VOLTAGE_SWITCH_TIME)
    { // reached the max time during low voltage so change to BULK charge mode
    setBatteryChargeState(BS_BULK);
    }
    }
    else // float charge is above low voltage drift amount, so just floating, not low
    {
    reset_timer(&charge_timer, OFF); // don't run low voltage timer
    }
    }

    /**** PWM ADJUST *********/
    // adjust PWM based on actual battery voltage and target voltage
    if(avgBatteryVoltage <= battery.target_voltage) // ADC_MIN)
    {
    // increase panel duty cycle;
    panelDutyCycle -= 1; // getDutyCycleChangeAmount(1);
    }
    else if(batteryVoltage > battery.target_voltage + VOLTAGE_FLUX) // it's greater than
    {
    // decrease panel duty cycle;
    panelDutyCycle += 1;// getDutyCycleChangeAmount(-1);
    }

    // panelDutyCycle = 32;
    if(panelDutyCycle > max_panel_duty_cycle)panelDutyCycle=max_panel_duty_cycle;
    if(panelDutyCycle < min_panel_duty_cycle)panelDutyCycle=min_panel_duty_cycle;
    CCPR2L = panelDutyCycle;

    // set duty cycle least 2 significant bits

    DC2B1 = low_dc & 0x01;
    DC2B0 = (low_dc >> 1) & 0x01;

    adc_battv.new_flag = 0; // reset flag
    }
    }

    /************************************************************************
    *
    * setBatteryChargeState() - handle charge state
    *
    *************************************************************************/
    #define UNKNOWN_VOLTAGE_POSITIVE_OFFSET
    void setBatteryChargeState(uint8 nstate)
    {
    switch(nstate)
    {
    case BS_SETUP:
    { // change for support of different battery model
    #define SIMPLE_DRIVER_COMP 0.56 // unknown why this is necessary, RDP 9/3/11
    battery.saturation_voltage = 14.5 - SIMPLE_DRIVER_COMP; // 14.5
    battery.float_voltage = 13.6 - SIMPLE_DRIVER_COMP; // 13.6
    //battery.saturation_time_minutes = 15;
    battery.saturation_time_minutes = 5;
    break;
    }
    case BS_BULK:
    { // this is like reset mode
    battery.state = BS_BULK;
    battery.target_voltage = battery.saturation_voltage; // set to sat. voltage level
    reset_timer(&charge_timer, ON);
    reset_timer(&saturation_charge_timer, ON);
    setBlinkRate(16);
    break;
    }
    case BS_FLOAT:
    { // set float charge level
    battery.state = BS_FLOAT;
    battery.target_voltage = battery.float_voltage; // set to float voltage level
    reset_timer(&charge_timer, OFF);
    setBlinkRate(32);
    break;
    }
    }
    }

    Looks like you'll have to put the tabs back in, sorry. I attached a source file, which'll be easier to look at. Apparently .c extension won't work so it's a .txt
     
    Last edited: Sep 13, 2011
Loading...