Shell Eco Fuelcell controller

Dependencies:   FastPWM mbed

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