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:
Thomas Kolb 2019-09-21 16:00:33 +02:00
parent c3c33b3753
commit d41c63f948
1 changed files with 120 additions and 34 deletions

View File

@ -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;