Photovoltaic charge controller

Thread Starter

xavierpereira

Joined Sep 8, 2011
8
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 !!
 

Thread Starter

xavierpereira

Joined Sep 8, 2011
8
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.
 

colinb

Joined Jun 15, 2011
351
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.
 

Thread Starter

xavierpereira

Joined Sep 8, 2011
8
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
 

colinb

Joined Jun 15, 2011
351
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):

Rich (BB code):
// Example of translating the flow chart Algorithm.JPG into C code.

// Start
initialise();
set_duty(0);    // Set OFF

// Control loop - an infinite loop
while (1)
{
    if (read_input_voltage_mV() < 3200)
    {
        // Decrease duty cycle.
        set_duty(get_duty() - duty_step);
    }
    else
    {
        // Check output voltage.
        if (read_output_voltage_mV() < 12000)
        {
            // Increase duty cycle.
            set_duty(get_duty() + duty_step);
        }
    }
}

// Global variables
static int duty;
static int duty_step = 1;


void set_duty(int new_duty)
{
    if (new_duty < min_duty)
        duty = min_duty;
    else if (new_duty > max_duty)
        duty = max_duty;
    else
        duty = new_duty;
}

int get_duty(void)
{
    return duty;
}
 

Thread Starter

xavierpereira

Joined Sep 8, 2011
8
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 !!!;)
 

russpatterson

Joined Feb 1, 2010
353
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
 

Attachments

Last edited:
Top