Added new float state; Some fixes
Typical charge cycle: MPPT until 14.4V, then switch to CV and hold 14.4V. After 2 hours switch to float charging at 13.8V.
This commit is contained in:
parent
c3c33b3753
commit
d41c63f948
154
src/main.c
154
src/main.c
|
@ -17,7 +17,7 @@
|
|||
#include "lcd.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define CONV_PWM_PERIOD 960
|
||||
#define CONV_PWM_PERIOD 360
|
||||
#define CONV_PWM_MAX (98*CONV_PWM_PERIOD/100)
|
||||
|
||||
#define TIM_CH_CONV TIM_OC1
|
||||
|
@ -31,6 +31,7 @@
|
|||
enum OperState {
|
||||
Bootstrap,
|
||||
ConvConstVoltage,
|
||||
ConvFloat,
|
||||
ConvConstCurrent,
|
||||
ConvMPP,
|
||||
Idle,
|
||||
|
@ -358,6 +359,21 @@ struct PowerState {
|
|||
fxp_t power_avg;
|
||||
};
|
||||
|
||||
static void load_on(void)
|
||||
{
|
||||
gpio_set(GPIOA, GPIO15);
|
||||
}
|
||||
|
||||
static void load_off(void)
|
||||
{
|
||||
gpio_clear(GPIOA, GPIO15);
|
||||
}
|
||||
|
||||
static bool load_status(void)
|
||||
{
|
||||
return gpio_get(GPIOA, GPIO15) != 0;
|
||||
}
|
||||
|
||||
static void report_status(struct PowerState *power_state,
|
||||
int32_t pwm, enum OperState operState)
|
||||
{
|
||||
|
@ -387,6 +403,10 @@ static void report_status(struct PowerState *power_state,
|
|||
|
||||
fxp_format(power_state->temp_avg, number, 1);
|
||||
debug_send_string(number);
|
||||
debug_send_string(":");
|
||||
|
||||
fxp_format_int(load_status(), number);
|
||||
debug_send_string(number);
|
||||
debug_send_string("\r\n");
|
||||
}
|
||||
|
||||
|
@ -415,7 +435,7 @@ struct MPPState {
|
|||
#define MPP_TEST_DURATION (MPP_TEST_IGNORE_DURATION + MPP_TEST_ACCU_DURATION)
|
||||
|
||||
#define MPP_TEST_STEPS 6
|
||||
const int32_t mpp_pwm_offsets[MPP_TEST_STEPS] = {-3, 4, -16, 15};
|
||||
const int32_t mpp_pwm_offsets[MPP_TEST_STEPS] = {-1, 2, -6, 5};
|
||||
|
||||
static void mpp_run(
|
||||
uint32_t time_in_state, struct MPPState *mpp_state,
|
||||
|
@ -522,16 +542,6 @@ static void mpp_run(
|
|||
}
|
||||
}
|
||||
|
||||
static void load_on(void)
|
||||
{
|
||||
gpio_set(GPIOA, GPIO15);
|
||||
}
|
||||
|
||||
static void load_off(void)
|
||||
{
|
||||
gpio_clear(GPIOA, GPIO15);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
//uint32_t cpuload = 0;
|
||||
|
@ -554,6 +564,8 @@ int main(void)
|
|||
fxp_t pErr = 0, iErr = 0;
|
||||
fxp_t controlAction = 0;
|
||||
|
||||
fxp_t setPoint = 0;
|
||||
|
||||
uint32_t sleep_time = 10;
|
||||
uint64_t force_display_update_time = 1000;
|
||||
|
||||
|
@ -569,11 +581,13 @@ int main(void)
|
|||
fxp_t AVG_FACT = fxp_from_float(0.01f);
|
||||
fxp_t AVG_FACT_INV = fxp_sub(fxp_from_int(1), AVG_FACT);
|
||||
|
||||
fxp_t MAX_VOLTAGE = fxp_from_float(14.400f);
|
||||
fxp_t CONST_VOLTAGE = fxp_from_float(13.800f);
|
||||
fxp_t MPP_MAX_VOLTAGE = fxp_from_float(14.400f);
|
||||
fxp_t CONST_VOLTAGE = MPP_MAX_VOLTAGE;
|
||||
fxp_t CONST_FLOAT_VOLTAGE = fxp_from_float(13.800f);
|
||||
fxp_t MAX_CURRENT = fxp_from_float( 5.000f);
|
||||
|
||||
fxp_t MPP_VOLTAGE_THR = fxp_sub(CONST_VOLTAGE, fxp_from_float(0.500f));
|
||||
fxp_t VOLTAGE_THR_CV_TO_MPP = fxp_sub(CONST_VOLTAGE, fxp_from_float(0.300f));
|
||||
fxp_t VOLTAGE_THR_FLOAT_TO_MPP = fxp_sub(CONST_FLOAT_VOLTAGE, fxp_from_float(0.300f));
|
||||
fxp_t MPP_CURRENT_THR = fxp_sub(MAX_CURRENT, fxp_from_float(0.500f));
|
||||
|
||||
// input voltage must exceed output voltage by this value to leave idle mode
|
||||
|
@ -584,21 +598,21 @@ int main(void)
|
|||
//
|
||||
// If the battery voltage is below LOAD_LOW_VOLTAGE_THRESHOLD, the battery
|
||||
// voltage is monitored more closely during idle mode.
|
||||
fxp_t LOAD_ON_THRESHOLD = fxp_from_float(13.000f);
|
||||
fxp_t LOAD_OFF_THRESHOLD = fxp_from_float(11.200f);
|
||||
fxp_t LOAD_LOW_VOLTAGE_THRESHOLD = fxp_from_float(11.600f);
|
||||
fxp_t LOAD_ON_THRESHOLD = fxp_from_float(13.500f);
|
||||
fxp_t LOAD_OFF_THRESHOLD = fxp_from_float(12.500f);
|
||||
fxp_t LOAD_LOW_VOLTAGE_THRESHOLD = fxp_from_float(12.600f);
|
||||
|
||||
// Calculated values
|
||||
//fxp_t VIN_SCALE = fxp_from_float(3.3f * (100 + 10.0f) / 10.0f / 4095.0f);
|
||||
//fxp_t VOUT_SCALE = fxp_from_float(3.3f * (100 + 12.0f) / 12.0f / 4095.0f);
|
||||
|
||||
// Calibrated from measurements
|
||||
fxp_t VIN_SCALE = fxp_from_float(36.41f / 4096.0f);
|
||||
fxp_t VOUT_SCALE = fxp_from_float(30.87f / 4096.0f);
|
||||
fxp_t VIN_SCALE = fxp_from_float(36.23f / 4096.0f);
|
||||
fxp_t VOUT_SCALE = fxp_from_float(30.75f / 4096.0f);
|
||||
|
||||
// current = adc • 0.00166 + -0.0725 = adc • m + t
|
||||
fxp_t ADC2CURRENT_M = fxp_from_float( 0.00166f);
|
||||
fxp_t ADC2CURRENT_T = fxp_from_float(-0.07250f);
|
||||
fxp_t ADC2CURRENT_M = fxp_from_float( 0.00225f);
|
||||
fxp_t ADC2CURRENT_T = fxp_from_float(-0.2255f);
|
||||
|
||||
/* if power changes by more than this factor, MPP is tested again */
|
||||
MPP_MAX_POWER_CHANGE_FACTOR = fxp_from_float(0.2f);
|
||||
|
@ -739,14 +753,18 @@ int main(void)
|
|||
timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 24);
|
||||
|
||||
if(time_in_state >= 10) { // bootstrap duration in ms
|
||||
//iErr = 0;
|
||||
// bootstrap off
|
||||
timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0);
|
||||
|
||||
// go to next state
|
||||
operState = nextState;
|
||||
}
|
||||
break;
|
||||
|
||||
case ConvConstVoltage:
|
||||
// bootstrap off
|
||||
timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0);
|
||||
if(time_in_state == 0) {
|
||||
iErr = 0;
|
||||
}
|
||||
|
||||
// calculate error values
|
||||
pErr = fxp_sub(CONST_VOLTAGE, power_state.vout_avg);
|
||||
|
@ -771,6 +789,76 @@ int main(void)
|
|||
|
||||
timer_set_oc_value(TIM1, TIM_CH_CONV, pwm);
|
||||
|
||||
#ifdef DEBUG
|
||||
if((time_in_state % 100) == 0) {
|
||||
debug_send_string("pErr: ");
|
||||
fxp_format(pErr, msg, 3);
|
||||
debug_send_string(msg);
|
||||
debug_send_string(" iErr: ");
|
||||
fxp_format(iErr, msg, 3);
|
||||
debug_send_string(msg);
|
||||
debug_send_string(" controlAction: ");
|
||||
fxp_format(controlAction, msg, 3);
|
||||
debug_send_string(msg);
|
||||
sentSomething = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(time_in_state > 3600*1000) {
|
||||
operState = ConvFloat;
|
||||
}
|
||||
|
||||
if(time_in_state > 5000 && fxp_to_int(controlAction) > CONV_PWM_MAX && power_state.current_avg < CURRENT_THRESHOLD) {
|
||||
operState = Bootstrap;
|
||||
nextState = ConvConstVoltage;
|
||||
}
|
||||
|
||||
if(time_in_state > 1000 && power_state.vout_avg < VOLTAGE_THR_CV_TO_MPP) {
|
||||
pwm = CONV_PWM_MAX * 8 / 10;
|
||||
operState = ConvMPP;
|
||||
}
|
||||
|
||||
if(power_state.current_avg > MAX_CURRENT) {
|
||||
operState = ConvConstCurrent;
|
||||
}
|
||||
|
||||
if(power_state.vin_avg < power_state.vout_avg) {
|
||||
operState = Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case ConvFloat:
|
||||
if(time_in_state < 120000) {
|
||||
setPoint =
|
||||
fxp_add(CONST_VOLTAGE,
|
||||
fxp_mult(fxp_sub(CONST_FLOAT_VOLTAGE, CONST_VOLTAGE), fxp_div(time_in_state, 120000)));
|
||||
} else {
|
||||
setPoint = CONST_FLOAT_VOLTAGE;
|
||||
}
|
||||
|
||||
// calculate error values
|
||||
pErr = fxp_sub(setPoint, power_state.vout_avg);
|
||||
iErr = fxp_add(iErr, pErr);
|
||||
|
||||
// limit integral error range
|
||||
if (iErr > IERR_LIMIT) iErr = IERR_LIMIT;
|
||||
else if(iErr < -IERR_LIMIT) iErr = -IERR_LIMIT;
|
||||
|
||||
// calculate the controller output ("action")
|
||||
controlAction = fxp_add(
|
||||
fxp_mult(pErr, PGAIN_CV),
|
||||
fxp_mult(iErr, IGAIN_CV));
|
||||
|
||||
pwm = fxp_to_int(controlAction);
|
||||
|
||||
if(pwm > CONV_PWM_MAX) {
|
||||
pwm = CONV_PWM_MAX;
|
||||
} else if(pwm < 0) {
|
||||
pwm = 0;
|
||||
}
|
||||
|
||||
timer_set_oc_value(TIM1, TIM_CH_CONV, pwm);
|
||||
|
||||
#ifdef DEBUG
|
||||
if((time_in_state % 100) == 0) {
|
||||
debug_send_string("pErr: ");
|
||||
|
@ -791,7 +879,8 @@ int main(void)
|
|||
nextState = ConvConstVoltage;
|
||||
}
|
||||
|
||||
if(time_in_state > 1000 && power_state.vout_avg < MPP_VOLTAGE_THR) {
|
||||
if(time_in_state > 1000 && power_state.vout_avg < VOLTAGE_THR_FLOAT_TO_MPP) {
|
||||
pwm = CONV_PWM_MAX * 8 / 10;
|
||||
operState = ConvMPP;
|
||||
}
|
||||
|
||||
|
@ -809,9 +898,6 @@ int main(void)
|
|||
iErr = 0;
|
||||
}
|
||||
|
||||
// bootstrap off
|
||||
timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0);
|
||||
|
||||
// calculate error values
|
||||
pErr = fxp_sub(MAX_CURRENT, power_state.current_avg);
|
||||
iErr = fxp_add(iErr, pErr);
|
||||
|
@ -844,15 +930,12 @@ int main(void)
|
|||
operState = ConvMPP;
|
||||
}
|
||||
|
||||
if(power_state.vout_avg > MAX_VOLTAGE) {
|
||||
if(power_state.vout_avg > MPP_MAX_VOLTAGE) {
|
||||
operState = ConvConstVoltage;
|
||||
}
|
||||
break;
|
||||
|
||||
case ConvMPP:
|
||||
// bootstrap off
|
||||
timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0);
|
||||
|
||||
mpp_run(time_in_state, &mpp_state, &power_state, &pwm);
|
||||
|
||||
if(pwm > mpp_state.mppMaxPWM) {
|
||||
|
@ -883,7 +966,7 @@ int main(void)
|
|||
pwm = mpp_state.mppMaxPWM;
|
||||
}
|
||||
|
||||
if(power_state.vout_avg > MAX_VOLTAGE) {
|
||||
if(power_state.vout_avg > MPP_MAX_VOLTAGE) {
|
||||
operState = ConvConstVoltage;
|
||||
}
|
||||
|
||||
|
@ -984,6 +1067,9 @@ int main(void)
|
|||
case ConvConstVoltage:
|
||||
lcd_send_string("CV ");
|
||||
break;
|
||||
case ConvFloat:
|
||||
lcd_send_string("FLT");
|
||||
break;
|
||||
case ConvMPP:
|
||||
lcd_send_string("MPP");
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue