Shell Eco Fuelcell controller

Dependencies:   FastPWM mbed

main.cpp

Committer:
HMFK03LST1
Date:
2014-01-07
Revision:
0:adf68d4b873f

File content as of revision 0:adf68d4b873f:

#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();
    }
}