Hochschule München
/
H2M_2014_race
Shell Eco Fuelcell controller
Diff: main.cpp
- Revision:
- 0:adf68d4b873f
--- /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