Hochschule München
/
H2M_2014_race
Shell Eco Fuelcell controller
Revision 0:adf68d4b873f, committed 2014-01-07
- Comitter:
- HMFK03LST1
- Date:
- Tue Jan 07 12:02:52 2014 +0000
- Commit message:
- work in Progress
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastPWM.lib Tue Jan 07 12:02:52 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/Sissors/code/FastPWM/#a7b9f778c4b4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components.cpp Tue Jan 07 12:02:52 2014 +0000 @@ -0,0 +1,170 @@ +#include "mbed.h" + +typedef struct +{ + uint16_t voltage_act; // Actual CAP Voltage + uint16_t voltage_low; // Switch to full current + uint16_t voltage_mid; // Switch to medium current + uint16_t voltage_high; // Switch to minimum current + uint16_t voltage_max; // Stopp loading + uint16_t voltage_down; // reduce Voltage (CAP down) + uint16_t current_low; // minimum current + uint16_t current_mid; // medium current + uint16_t current_high; // high current +} struct_cap; + +typedef struct +{ + uint16_t air_needed; + uint16_t current_act; + uint16_t current_load; + uint16_t temp_act; + uint16_t temp_max; + uint16_t voltage_act; + uint16_t voltage_max; +} struct_fuelcell; + +typedef struct +{ + bool fan_override; + uint16_t fan_over_pwm; //name + uint16_t fan_p; + uint16_t fan_i; + uint16_t fan_thr; + short fan_up; //add + short fan_up_count; //add + short fan_pwm; + uint16_t fan_pwm_act; + bool pump_override; + uint16_t pump_over_pwm; //name + uint16_t pump_min; + uint16_t pump_p; + uint16_t pump_i; + short pump_up; //add + short pump_up_count; //add + short pump_pwm; + uint16_t pump_pwm_act; + uint16_t temp_out; +} struct_h2o; + +typedef struct +{ + uint16_t current_act; + uint16_t current_delta; + uint16_t current_load; + uint16_t i; // added + uint16_t pwm; + uint16_t pwm_act; + uint16_t temp_act; + uint16_t temp_max; +} struct_mosfet; + +typedef struct +{ + uint16_t air_current; + uint16_t air_needed; + uint16_t water_created; //name + uint16_t back_lower; + uint16_t delta_t; + uint16_t lambda; + uint16_t lambda_max; + uint16_t lambda_min; + short lambda_delta; + short lambda_delta_sum; + bool pump_on; + bool pump_override; + uint16_t pump_over_load; //name + uint16_t pump_load; //name + uint16_t pump_load_act; //name + short pump_up; + short pump_up_count; + uint16_t pump_pwm_1; + uint16_t pump_pwm_2; + bool pump_dual; //name + uint16_t pump_dual_on; //added + uint16_t pump_dual_off; //added + uint16_t rh_out_delta + uint16_t rh_pump_load; + uint16_t rh_pump_min; + uint16_t rh_pump_max; + uint16_t rh_out_min; + uint16_t rh_out_max; + uint16_t rh_back_p; + uint16_t rh_in; + uint16_t rh_out; + uint16_t temp_in; + uint16_t temp_out; // added + uint16_t temp_calc; + uint16_t water_extracted; + uint16_t water_in; + uint16_t water_out; + +} struct_o2; + +typedef struct +{ + bool capdown; + bool drive; + bool master; + bool safety; +} struct_switch; + +typedef struct +{ + bool cap_down_load; + bool cap_down_reset; + bool cap_load; + bool cap_voltage_reset; + bool fuelcell; + bool fc_overtemp; + bool fc_overvoltage; + bool load; + bool load_act; + bool load_reset; + bool mosfet; + bool mos_overtemp; + bool run; + bool temp; + bool voltage; + uint16_t count; + uint16_t h2_analog; + uint16_t safety_V; + uint16_t current_out; +} struct_system; + +typedef struct +{ + bool o2_in; + bool o2_out; + bool mosfet_temp; + bool fc_voltage; + bool cap_voltage; + bool mosfet_cur; + bool h2o_temp_out; + bool t_1; + bool t_2; + bool t_3; + bool t_4; + bool t_5; + bool t_6; + bool t_7; + bool t_8; + bool o_1; + bool o_2; + bool o_3; + bool o_4; + bool o_5; + bool o_6; + bool o_7; +}struct_error; + +/* +struct_cap cap; +struct_fuelcell fuelcell; +struct_h2o h2o; +struct_mosfet mosfet; +struct_o2 o2; +struct_switch switches; +struct_system sys; +struct_error error; +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Jan 07 12:02:52 2014 +0000 @@ -0,0 +1,565 @@ +#include "mbed.h" +#include "math.h" +#include <string> +#include "FastPWM.h" +#include "components.cpp" + + +const char I2C_IN = 4; +const char I2C_OUT = 8; + +const int PWM_Frequenz = 10000; + +DigitalOut led_1(LED1); +DigitalOut led_2(LED2); +DigitalOut led_3(LED3); +DigitalOut led_4(LED4); + +DigitalOut i2c_cs(p29); +DigitalOut xb_rst(p11); +DigitalOut mp_A(p15); +DigitalOut mp_B(p16); + +AnalogIn current(p19); +AnalogIn mp1yA(p20); +AnalogIn mp2yA(p18); +AnalogIn mp2xA(p17); +DigitalIn mp2xD(p12); + +FastPWM pwm_6(p21,-1); //Mosfet +DigitalOut h2_purge(p22); +FastPWM pwm_4(p23,-1); //H2O Fan +FastPWM pwm_3(p24,-1); //H20 Pump +FastPWM pwm_2(p25,-1); //Air Pump 2 +FastPWM pwm_1(p26,-1); //Air Pump 2 + + +Serial xbee(p9,p10); +Serial gps(p13,p14); +Serial pc(USBTX,USBRX); + +SPI ext_spi(p5, p6, p7); + +I2C i2c(p28, p27); + +LocalFileSystem local("local"); //init Flashdrive for reading config file +FILE *fp; + +struct_cap cap; +struct_fuelcell fc; +struct_h2o h2o; +struct_mosfet mosfet; +struct_o2 o2; +struct_switch switches; +struct_system sys; +struct_error error; + + +//Standard Funktions +//---------------------------------------------------------------------------------------------- +void read_val(const char* name,const char* value); + + +double clamp(double value, double val_min, double val_max, bool* has_clamped) +{ + *has_clamped = true; + if(value < val_min) return val_min; + if(value > val_max) return val_max; + *has_clamped = false; + return value; +} + + + + +void load_cfg() +{ + char name_val[2][20]; + char i = 0; + char name = 1; + int c = 50; + + fp = fopen("/local/power.cfg", "r"); + if ( fp != NULL ) + { + while(c != EOF) + { + + c = fgetc(fp); + + if (c == 10){ + name_val[name][i+1] = '\0'; + name = 1; + i = 0; + read_val(&name_val[1][0], &name_val[0][0]); + } + else + { + if (c == '='){ + name_val[name][i+1] = '\0'; + name = 0; + i = 0; + } + else + { + name_val[name][i] = c; + i++; + } + } + } + fclose(fp); + } +} + + +void read_val(const char* name,const char* value) +{ + float temp; + + sscanf(value, "%f", &temp ); + pc.printf("Input : %-18s Value : %6d ", name, int(temp)); + + if (string(&name[0]) == "O2_air_current" ){ o2.air_current = temp; pc.printf("Value read: %6d \n\r", o2.air_current );} + if (string(&name[0]) == "O2_water_created" ){ o2.water_created = temp; pc.printf("Value read: %6d \n\r", o2.water_created);} + if (string(&name[0]) == "O2_lambda_max" ) o2.lambda_max = temp; + if (string(&name[0]) == "O2_lambda_min" ) o2.lambda_min = temp; + if (string(&name[0]) == "O2_pump_over_load") o2.pump_over_load = temp; + if (string(&name[0]) == "O2_pump_up" ) o2.pump_up = temp; + if (string(&name[0]) == "O2_pump_dual_on" ) o2.pump_dual_on = temp; + if (string(&name[0]) == "O2_pump_dual_off" ) o2.pump_dual_off = temp; + + if (string(&name[0]) == "CAP_voltage_low" ) cap.voltage_low = temp; + if (string(&name[0]) == "CAP_voltage_mid" ) cap.voltage_mid = temp; + if (string(&name[0]) == "CAP_voltage_high" ) cap.voltage_high = temp; + if (string(&name[0]) == "CAP_voltage_max" ) cap.voltage_max = temp; + if (string(&name[0]) == "CAP_voltage_down" ) cap.voltage_down = temp; + if (string(&name[0]) == "CAP_current_low" ) cap.current_low = temp; + if (string(&name[0]) == "CAP_current_mid" ) cap.current_mid = temp; + if (string(&name[0]) == "CAP_current_high" ) cap.current_high = temp; + + if (string(&name[0]) == "FC_temp_max" ) fc.temp_max = temp; + if (string(&name[0]) == "FC_voltage_max" ) fc.voltage_max = temp; + + if (string(&name[0]) == "H2O_fan_over_pwm" ) h2o.fan_over_pwm = temp; + if (string(&name[0]) == "H2O_fan_p" ) h2o.fan_p = temp; + if (string(&name[0]) == "H2O_fan_i" ) h2o.fan_i = temp; + if (string(&name[0]) == "H2O_fan_thr" ) h2o.fan_thr = temp; + if (string(&name[0]) == "H2O_fan_up" ) h2o.fan_up = temp; + if (string(&name[0]) == "H2O_pump_over_pwm") h2o.pump_over_pwm = temp; + if (string(&name[0]) == "H2O_pump_p" ) h2o.pump_p = temp; + if (string(&name[0]) == "H2O_pump_i" ) h2o.pump_i = temp; + if (string(&name[0]) == "H2O_pump_min" ) h2o.pump_min = temp; + if (string(&name[0]) == "H2O_pump_up" ) h2o.pump_up = temp; + + if (string(&name[0]) == "MOSFET_temp_max" ) mosfet.temp_max = temp; +} + + +// T - Funktions +//---------------------------------------------------------------------------------------------- + +void T_1() + { + o2.water_in = 13235 * o2.rh_in / (o2.temp_in + 2731) * pow(10.0,(7.5 * o2.temp_in)/((2373 + o2.temp_in))-1); + + o2.water_in = clamp(o2.water_in,0,4000,&error.t_1); + } + +void T_2() + { + if (o2.pump_load_act > 0) { + o2.delta_t = o2.temp_out - h2o.temp_out; + o2.temp_calc = o2.temp_out; + } + else + { + o2.temp_calc = o2.delta_t + h2o.temp_out; + } + + o2.temp_calc = clamp(o2.temp_calc,0,800,&error.t_2); + } + +void T_3() + { + o2.water_out = 13235000 / (o2.temp_calc + 2731) * pow(10.0,(7.5 * o2.temp_calc)/((2373 + o2.temp_calc))-1); + + o2.water_out = clamp(o2.water_out,0,30000,&error.t_3); + } + +void T_4() + { + o2.water_extracted = o2.water_out - o2.water_in; + o2.air_needed = o2.water_created * 10000 / o2.water_extracted; + o2.lambda = o2.air_needed * 100 / o2.air_current; + + o2.lambda = clamp(o2.lambda,100,500,&error.t_4); + } + +void T_5() + { + o2.lambda_delta = ((o2.lambda_max + o2.lambda_min) / 2) - o2.lambda; + + o2.lambda_delta_sum = o2.lambda_delta_sum + (o2.lambda_delta * 0.1); + o2.lambda_delta_sum = clamp(o2.lambda_delta_sum,-2000,7000,&error.t_5); + + h2o.fan_pwm = ((h2o.fan_p * o2.lambda_delta) ) + ((h2o.fan_i * o2.lambda_delta_sum / 10) ); + h2o.fan_pwm = clamp( h2o.fan_pwm,0,1000,&error.t_5); + } + +void T_6() + { + h2o.pump_pwm = ((h2o.pump_p * o2.lambda_delta) ) + ((h2o.pump_i * o2.lambda_delta_sum / 10) + h2o.pump_min ); + h2o.pump_pwm = clamp( h2o.pump_pwm,h2o.pump_min,1000,&error.t_6); + } + +void T_7() + { + if(h2o.fan_override) { + h2o.fan_pwm_act = h2o.fan_over_pwm; + } + else + { + if ((h2o.fan_pwm_act == 0) && (h2o.fan_pwm >= h2o.fan_thr)) + { + h2o.fan_up_count = h2o.fan_up; + } + else + { + h2o.fan_pwm_act = h2o.fan_pwm; + } + } + + if (h2o.fan_up_count > 0) {h2o.fan_up_count--; h2o.fan_pwm_act = 1000;} + + if (!((h2o.fan_pwm_act >= h2o.fan_thr) & sys.run)){h2o.fan_pwm_act = 0;} + + h2o.fan_pwm_act = clamp( h2o.fan_pwm_act,0,1000,&error.t_7); + + pwm_4.write(h2o.fan_pwm_act * 0.001); + } + + +void T_8() +{ + if(h2o.pump_override){ + h2o.pump_pwm_act = h2o.pump_over_pwm; + } + else + { + if ((h2o.pump_pwm_act == 0) && (h2o.pump_pwm > 0)) + { + h2o.pump_up_count = h2o.pump_up; + } + else + { + h2o.pump_pwm_act = h2o.pump_pwm; + } + } + + if (h2o.pump_up_count > 0) {h2o.pump_up_count--; h2o.pump_pwm_act = 1000;} + + if (!(sys.run)){ h2o.pump_pwm_act = 0;} + + h2o.pump_pwm_act = clamp( h2o.pump_pwm_act,0,1000,&error.t_8); + + pwm_3.write(h2o.fan_pwm_act * 0.001); +} + +void T_ALL(){ + T_1(); + T_2(); + T_3(); + T_4(); + T_5(); + T_6(); + T_7(); + T_8(); + } + +// O - Funktions +//---------------------------------------------------------------------------------------------- + + + + +void O_1() +{ + o2.rh_out_delta = ((o2.rh_out_soll) - o2.rh_out; + o2.rh_out_delta = clamp( o2.rh_out_delta,-100,100,&error.o_1); + o2.rh_pump_load = 02.rh_p * o2.rh_out_delta; + o2.rh_pump_load = clamp( o2.rh_pump_load,o2.rh_pump_min,o2.rh_pump_max,&error.o_2); +} + +void O_2() +{ + if(cap.voltage_act < cap.voltage_mid) + { + if(cap.voltage_act < cap.voltage_low) fc.current_load = cap.current_low; + else fc.current_load = cap.current_mid; + } + else fc.current_load = cap.current_high; + return 0; +} + +bool O_3() +{ + o2.lambda_min = 150; + fc.air_needed = fc.current_load * o2.lambda_min * 0.007; + return 0; +} + +bool O_4() +{ + if(o2.pump_on == false) o2.pump_load = 0; + return 0; +} + +bool O_5() +{ + if(o2.pump_override) o2.pump_load_act = o2.pump_over_load; + else o2.pump_load_act = o2.pump_load; + return 0; +} + +bool O_6() +{ + if(o2.pump_load_act < o2.pump_dual_off){o2.pump_dual = false;} + if(o2.pump_load_act > o2.pump_dual_on ){o2.pump_dual = true;} + + if (o2.pump_dual) + { + o2.pump_pwm_1 = o2.pump_load_act * 0.5; + o2.pump_pwm_2 = o2.pump_load_act * 0.5; + } + else + { + o2.pump_pwm_1 = o2.pump_load_act; + o2.pump_pwm_2 = 0; + } + return 0; +} + +void O_ALL() +{ + O_1(); + O_2(); + O_3(); + O_4(); + O_5(); + O_6(); +} + + +// M - Funktions +//---------------------------------------------------------------------------------------------- + +bool M_1() +{ + if(o2.pump_on) mosfet.pwm = 0; + mosfet.pwm = mosfet.pwm + ( ((fc.current_load - fc.current_act) * mosfet.i) / 100000); + if(sys.load_act == false) mosfet.pwm = 0; + return 0; +} + +bool M_2() +{ + sys.mos_overtemp = (mosfet.temp_act < mosfet.temp_max); + return 0; +} + +bool M_3() +{ + if(sys.mosfet && sys.run) mosfet.pwm_act = mosfet.pwm; + else mosfet.pwm_act = 0; + return 0; +} + +// S - Funktions +//---------------------------------------------------------------------------------------------- + +bool S_1() +{ + sys.run = (switches.master && switches.safety); + return 0; +} + +bool S_2() +{ + sys.fc_overtemp = (fc.temp_act > fc.temp_max); + return 0; +} + +bool S_3() +{ + sys.fc_overvoltage = (fc.voltage_act > fc.voltage_max); + return 0; +} + +bool S_4() +{ + sys.fuelcell = (sys.temp && sys.voltage); + return 0; +} + +// C - Funktions +//---------------------------------------------------------------------------------------------- + +bool C_1() +{ + sys.cap_load = (cap.voltage_act < cap.voltage_max); + return 0; +} + +bool C_2() +{ + sys.cap_down_load = (cap.voltage_act < cap.voltage_down); + return 0; +} + +bool C_3() +{ + sys.cap_voltage_reset = (cap.voltage_act > cap.voltage_max); + return 0; +} + +bool C_4() +{ + sys.cap_down_reset = (cap.voltage_act > cap.voltage_down); + return 0; +} + +bool C_5() +{ + sys.load = ((switches.drive) || (sys.cap_load && (!switches.capdown)) || (switches.capdown && sys.cap_down_load)); + return 0; +} + +bool C_6() +{ + sys.load_reset = (sys.cap_voltage_reset || (sys.cap_down_reset && switches.capdown)); + return 0; +} + +bool C_7() +{ + if(sys.load) sys.load_act = true; + if(sys.load_reset) sys.load_act = false; + return 0; +} + +bool C_8() +{ + o2.pump_on = (sys.mosfet && sys.run && sys.fuelcell && sys.load_act); + return 0; +} + + +void read_inputs() +{ + char channel = sys.count%4; + + switch (channel) + { + case 0 : switches.drive = mp2xD; + sys.h2_analog = mp2yA.read_u16() /2; + fc.voltage_act = mp1yA.read_u16() /1.638; + fc.current_act = current.read_u16()/4; + break; + + case 1 : sys.safety_V = mp2xA.read_u16() /4; + switches.safety = (sys.safety_V > 8000); + sys.current_out = mp2yA.read_u16() /5; + cap.voltage_act = mp1yA.read_u16() /1.638; + fc.current_act = current.read_u16()/4; + break; + + case 2 : switches.capdown = !mp2xD; + mosfet.temp_act = mosfet.temp_act + ((((59000-mp2yA.read_u16())/90) - mosfet.temp_act ) >> 3); + fc.voltage_act = mp1yA.read_u16() /1.638; + fc.current_act = current.read_u16()/4; + break; + + case 3 : switches.master = mp2xD; + fc.temp_act = fc.temp_act + ((((61800-mp2yA.read_u16())/90) - fc.temp_act) >> 3); + h2o.temp_out = fc.temp_act; + cap.voltage_act = mp1yA.read_u16() /1.638; + fc.current_act = current.read_u16()/4; + break; + } + + mp_A = ( (channel + 1) & 0x01); // A setzen + mp_B = (((channel + 1) >> 1) & 0x01); // B setzen + + } + +void read_i2c_RHTMP(char ad) +{ + char input[4]; + short RH = 0; + short TMP = 0; + + i2c.write(ad<<1, 0x00 , 1); //wake up + i2c.read (ad<<1, input , 4); //read out + + RH = (( 1000 * (((input[0]<<8) | (input[1] )) & 0x3FFF ))>> 14) ; //transform into 0 - 1000 as Integer represents 0.0 - 100.0 % + + TMP = (( 1650 * (((input[2]<<6) | (input[3]>>2)) & 0x3FFF ))>> 14) -400; //transform into -400 - 1250 as Integer represents -40.0 - 125.0 °C + + if (TMP > -50 && TMP < 800) + { + if (ad == I2C_IN ){o2.temp_in = TMP; o2.rh_in = RH;error.o2_in = false;}; + if (ad == I2C_OUT){o2.temp_out = TMP; o2.rh_out = RH;error.o2_out = false;}; + } + else + { + if (ad == I2C_IN ){error.o2_in = true;}; + if (ad == I2C_OUT){error.o2_out = true;}; + } +} + + +void timetable() +{ + switch (sys.count) + { + case 0: read_i2c_RHTMP(I2C_IN) ; break; + case 125: T_ALL() ; break; + case 250: read_i2c_RHTMP(I2C_OUT) ; break; + case 375: O_ALL() ; break; + case 500: read_i2c_RHTMP(I2C_IN) ; break; + case 625: T_ALL() ; break; + case 750: read_i2c_RHTMP(I2C_OUT) ; break; + case 875: O_ALL() ; break; + } + + read_inputs(); + + sys.count ++; + + if (sys.count >= 1000){sys.count=0; led_1 = !led_1;}; + +} + + + + +int main() +{ + pc.baud(115200); + i2c.frequency(400000); + + pwm_6.pulsewidth(1.0/PWM_Frequenz); //Mosfet +//pwm_5.pulsewidth(1.0/PWM_Frequenz); //H2 Purge + pwm_4.pulsewidth(1.0/PWM_Frequenz); //H2O Fan + pwm_3.pulsewidth(1.0/PWM_Frequenz); //H20 Pump + pwm_2.pulsewidth(1.0/PWM_Frequenz); //Air Pump 2 + pwm_1.pulsewidth(1.0/PWM_Frequenz); //Air Pump 2 + + + load_cfg(); + + while(1) + { + timetable(); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Jan 07 12:02:52 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file