Example #1
0
void knklogic_retard(struct ecudata_t* d, retard_state_t* p_rs)
{
 if (p_rs->delay_counter != 0)
  p_rs->delay_counter--;
 else
 {
  if (p_rs->knock_flag)
  { //detonation present
   d->knock_retard+= d->param.knock_retard_step;//retard
   p_rs->knock_flag = 0;
  }
  else
  {//detonation is absent
   d->knock_retard-= d->param.knock_advance_step;//advance
  }
  restrict_value_to(&d->knock_retard, 0, d->param.knock_max_retard);

  p_rs->delay_counter = d->param.knock_recovery_delay;
  if (0!=(p_rs->delay_counter))
    --(p_rs->delay_counter);
 }
}
Example #2
0
void knklogic_retard(struct ecudata_t* d, retard_state_t* p_rs)
{
 if (p_rs->knock_flag)
 { //detonation is present
  d->corr.knock_retard+= d->param.knock_retard_step;//retard
  p_rs->knock_flag = 0;
  p_rs->delay_counter = d->param.knock_recovery_delay; //reset delay
 }
 else
 { //detonation is absent
  if (p_rs->delay_counter == 0)
  {
   d->corr.knock_retard-= d->param.knock_advance_step;//advance
   p_rs->delay_counter = d->param.knock_recovery_delay;
  }
 }
 //restrict knock retard value
 restrict_value_to(&d->corr.knock_retard, 0, d->param.knock_max_retard);

 if (p_rs->delay_counter != 0)
  p_rs->delay_counter--;
}
Example #3
0
void choke_control(struct ecudata_t* d)
{
 switch(chks.state)
 {
  case 0:                                                     //Initialization of choke position
   if (!IOCFG_CHECK(IOP_PWRRELAY))                            //Skip initialization if power management is enabled
    initial_pos(INIT_POS_DIR, d->param.sm_steps);
   chks.state = 2;
   break;

  case 1:                                                     //system is being preparing to power-down
   initial_pos(INIT_POS_DIR, d->param.sm_steps);
   chks.state = 2;
   break;

  case 2:                                                     //wait while choke is being initialized
   if (!stpmot_is_busy())                                     //ready?
   {
    if (chks.pwdn)
     chks.state = 3;                                          //ready to power-down
    else
     chks.state = 5;                                          //normal working
    chks.smpos = 0;
   }
   break;

  case 3:                                                     //power-down
   if (pwrrelay_get_state())
   {
    chks.pwdn = 0;
    chks.state = 5;
   }
   break;

  case 5:                                                     //normal working mode
   if (d->choke_testing)
   {
    initial_pos(INIT_POS_DIR, d->param.sm_steps);
    chks.state = 6;                                           //start testing
   }
   else
   {
    int16_t tmp_pos = (((int32_t)d->param.sm_steps) * choke_closing_lookup(d)) / 200;
    int16_t rpm_cor = 0, diff;
    int16_t pos = tmp_pos + rpm_cor;
    restrict_value_to(&pos, 0, d->param.sm_steps);
    diff = pos - chks.smpos;
    if (!stpmot_is_busy() && diff != 0)
    {
     stpmot_dir(diff < 0 ? SM_DIR_CW : SM_DIR_CCW);
     stpmot_run(abs(diff));                                    //start stepper motor
     chks.smpos += diff;
    }
   }
   goto check_pwr;

  //     Testing modes
  case 6:                                                     //initialization of choke
   if (!stpmot_is_busy())                                     //ready?
   {
    stpmot_dir(SM_DIR_CCW);
    stpmot_run(d->param.sm_steps);
    chks.state = 7;
   }
   goto check_tst;

  case 7:
   if (!stpmot_is_busy())                                     //ready?
   {
    stpmot_dir(SM_DIR_CW);
    stpmot_run(d->param.sm_steps);
    chks.state = 6;
   }
   goto check_tst;

  default:
  check_tst:
   if (!d->choke_testing)
    chks.state = 1;                                           //exit choke testing mode
  check_pwr:
   if (!pwrrelay_get_state())
   {                                                          //power-down
    chks.pwdn = 1;
    chks.state = 1;
   }
   break;
 }
}
Example #4
0
//Пропорциональный регулятор для регулирования оборотов ХХ углом опережения зажигания
// Возвращает значение угла опережения в целом виде * 32.
int16_t idling_pregulator(struct ecudata_t* d, volatile s_timer8_t* io_timer)
{
int16_t error,factor,iState_error;
//зона "подхвата" регулятора при возвращени двигателя из рабочего режима в ХХ
uint16_t capture_range = 100;

 //если PXX отключен или обороты значительно выше от нормальных холостых оборотов
 // или двигатель не прогрет то выходим  с нулевой корректировкой
 if (!d->param.idl_regul || (d->sens.frequen >(d->param.idling_rpm + capture_range))
    || (d->sens.temperat < d->param.idlreg_turn_on_temp && d->param.tmp_use))
  return 0;
//вычисляем целевые обороты , по массиву Обороты vs температура
idl_coolant_rpm.output_state = idl_coolant_rpm_function(d)/16;
user_var1 = idl_coolant_rpm.output_state;

// Если обороты выше зоны РХХ , то включить задвигание РХХ
if (d->sens.frequen >(idl_coolant_rpm.output_state + capture_range)) 
{
idlregul_set_state(2,d);
}
//если PXX отключен или обороты значительно выше от нормальных холостых оборотов
// или обороты не упали ниже целевые +10 первый раз после выхода с рабочего режима , то выходим  с нулевой корректировкой
//также обнуляем сумму интегрального регулятора при первом разрешенном входе в РХХ

  if ((d->sens.frequen >(idl_coolant_rpm.output_state + 10)) && !idl_enable.output_state) 
    return 0;
  else 
  {idl_enable.output_state = 1;
   iState_error = 0;
  
  }
  if (!d->param.idl_regul || (d->sens.frequen >(idl_coolant_rpm.output_state + capture_range)))
    return 0;

//вычисляем значение ошибки, ограничиваем ошибку (если нужно), а также, если мы в зоне
//нечувствительности, то выход с 0 коррекцией.

error = idl_coolant_rpm.output_state - d->sens.frequen;

restrict_value_to(&error, -200, 100);
//Складываем ошибки для реализации интегрального регулятора
iState_error += error;
user_var2 = iState_error;
if (abs(error) <= d->param.MINEFR)
{
  // если в зоне нечувствительности , то обнуляем сумму интегрального регулятора
  iState_error = 0;
  return 0;//idl_prstate.output_state;
}
// тут работаем с механическим РХХ
if (abs(error)<= (d->param.MINEFR +20))
   idlregul_set_state(3,d);
else 
    if (error >0)
      idlregul_set_state(2,d);
        else
          idlregul_set_state(1,d);







//выбираем необходимый коэффициент регулятора, в зависимости от знака ошибки
//if (error > 0)
  factor = d->param.ifac1;
//else
 // factor = d->param.ifac2;

//изменяем значение коррекции только по таймеру idle_period_time_counter
//if (s_timer_is_action(*io_timer))
{
  //s_timer_set(*io_timer,IDLE_PERIOD_TIME_VALUE);
   
// функция реализации ПИ регулятора   
  idl_prstate.output_state = (error * factor) / 4 + (iState_error / 40)*d->param.ifac2;
  //idl_prstate.output_state = (idl_prstate.output_state * ((d->param.idling_rpm + idl_coolant_rpm.output_state)/d->sens.frequen)* factor) / 4;
//user_var3 = d->param.ifac1;
}
//ограничиваем коррекцию нижним и верхним пределами регулирования
restrict_value_to(&idl_prstate.output_state, d->param.idlreg_min_angle, d->param.idlreg_max_angle);

return idl_prstate.output_state;
}
Example #5
0
/**Main function of firmware - entry point */
MAIN()
{
 int16_t calc_adv_ang = 0; 
 uint8_t turnout_low_priority_errors_counter = 255;
 int16_t advance_angle_inhibitor_state = 0;
 retard_state_t retard_state;

 //подготовка структуры данных переменных состояния системы
 init_ecu_data(&edat);
 knklogic_init(&retard_state);

 //конфигурируем порты ввода/вывода
 ckps_init_ports();
 vent_init_ports();
 fuelecon_init_ports();
 idlecon_init_ports();
 starter_init_ports();
 ce_init_ports();
 knock_init_ports();
 jumper_init_ports();

 //если код программы испорчен - зажигаем СЕ
 if (crc16f(0, CODE_SIZE)!=PGM_GET_WORD(&fw_data.code_crc))
  ce_set_error(ECUERROR_PROGRAM_CODE_BROKEN);

 //читаем параметры
 load_eeprom_params(&edat);

#ifdef REALTIME_TABLES
 //load currently selected tables into RAM
 load_selected_tables_into_ram(&edat);
#endif

 //предварительная инициализация параметров сигнального процессора детонации
 knock_set_band_pass(edat.param.knock_bpf_frequency);
 knock_set_gain(PGM_GET_BYTE(&fw_data.exdata.attenuator_table[0]));
 knock_set_int_time_constant(edat.param.knock_int_time_const);

 if (edat.param.knock_use_knock_channel)
  if (!knock_module_initialize())
  {//чип сигнального процессора детонации неисправен - зажигаем СЕ
   ce_set_error(ECUERROR_KSP_CHIP_FAILED);
  }
 edat.use_knock_channel_prev = edat.param.knock_use_knock_channel;

 adc_init();

 //проводим несколько циклов измерения датчиков для инициализации данных
 meas_initial_measure(&edat);

 //снимаем блокировку стартера
 starter_set_blocking_state(0);

 //инициализируем UART
 uart_init(edat.param.uart_divisor);

 //инициализируем модуль ДПКВ
 ckps_init_state();
 ckps_set_cyl_number(edat.param.ckps_engine_cyl);
 ckps_set_edge_type(edat.param.ckps_edge_type);
 ckps_set_cogs_btdc(edat.param.ckps_cogs_btdc); //<--only partial initialization
#ifndef COIL_REGULATION
 ckps_set_ignition_cogs(edat.param.ckps_ignit_cogs);
#endif
 ckps_set_knock_window(edat.param.knock_k_wnd_begin_angle,edat.param.knock_k_wnd_end_angle);
 ckps_use_knock_channel(edat.param.knock_use_knock_channel);
 ckps_set_cogs_btdc(edat.param.ckps_cogs_btdc); //<--now valid initialization
 ckps_set_merge_outs(edat.param.merge_ign_outs);

 s_timer_init();
 vent_init_state();

 //разрешаем глобально прерывания
 _ENABLE_INTERRUPT();

 sop_init_operations();
 //------------------------------------------------------------------------
 while(1)
 {
  if (ckps_is_cog_changed())
   s_timer_set(engine_rotation_timeout_counter,ENGINE_ROTATION_TIMEOUT_VALUE);

  if (s_timer_is_action(engine_rotation_timeout_counter))
  { //двигатель остановился (его обороты ниже критических)
#ifdef COIL_REGULATION
   ckps_init_ports();           //чтобы IGBT не зависли в открытом состоянии
   //TODO: Сделать мягкую отсечку для избавления от нежелательной искры. Как?
#endif
   ckps_init_state_variables();
   edat.engine_mode = EM_START; //режим пуска

   if (edat.param.knock_use_knock_channel)
    knock_start_settings_latching();

   edat.curr_angle = calc_adv_ang;
   meas_update_values_buffers(&edat, 1);  //<-- update RPM only
  }

  //запускаем измерения АЦП, через равные промежутки времени. При обнаружении каждого рабочего
  //цикла этот таймер переинициализируется. Таким образом, когда частота вращения двигателя превысит
  //определенную величину, это условие выполнятся перестанет.
  if (s_timer_is_action(force_measure_timeout_counter))
  {
   if (!edat.param.knock_use_knock_channel)
   {
    _DISABLE_INTERRUPT();
    adc_begin_measure();
    _ENABLE_INTERRUPT();
   }
   else
   {
    //если сейчас происходит загрузка настроек в HIP, то нужно дождаться ее завершения.
    while(!knock_is_latching_idle());
    _DISABLE_INTERRUPT();
    //включаем режим интегрирования и ждем около 20мкс, пока интегратор начнет интегрировать (напряжение
    //на его выходе упадет до минимума). В данном случае нет ничего страшного в том, что мы держим прерывания
    //запрещенными 20-25мкс, так как это проискодит на очень маленьких оборотах.
    knock_set_integration_mode(KNOCK_INTMODE_INT);
    _DELAY_CYCLES(350);
    knock_set_integration_mode(KNOCK_INTMODE_HOLD);
    adc_begin_measure_all(); //измеряем сигнал с ДД тоже
    _ENABLE_INTERRUPT();
   }

   s_timer_set(force_measure_timeout_counter, FORCE_MEASURE_TIMEOUT_VALUE);
   meas_update_values_buffers(&edat, 0);
  }

  //----------непрерывное выполнение-----------------------------------------
  //выполнение отложенных операций
  sop_execute_operations(&edat);
  //управление фиксированием и индицированием возникающих ошибок
  ce_check_engine(&edat, &ce_control_time_counter);
  //обработка приходящих/уходящих данных последовательного порта
  process_uart_interface(&edat);
  //управление сохранением настроек
  save_param_if_need(&edat);
  //расчет мгновенной частоты вращения коленвала
  edat.sens.inst_frq = ckps_calculate_instant_freq();
  //усреднение физических величин хранящихся в кольцевых буферах
  meas_average_measured_values(&edat);
  //cчитываем дискретные входы системы и переключаем тип топлива
  meas_take_discrete_inputs(&edat);
  //управление периферией
  control_engine_units(&edat);
  //КА состояний системы (диспетчер режимов - сердце основного цикла)
  calc_adv_ang = advance_angle_state_machine(&edat);
  //добавляем к УОЗ октан-коррекцию
  calc_adv_ang+=edat.param.angle_corr;
  //ограничиваем получившийся УОЗ установленными пределами
  restrict_value_to(&calc_adv_ang, edat.param.min_angle, edat.param.max_angle);
  //Если стоит режим нулевого УОЗ, то 0
  if (edat.param.zero_adv_ang)
   calc_adv_ang = 0;

#ifdef COIL_REGULATION
  //calculate and update coil regulation time
  ckps_set_acc_time(accumulation_time(&edat));
#endif
  //Если разрешено, то делаем отсечку зажигания при превышении определенных оборотов
  if (edat.param.ign_cutoff)
   ckps_enable_ignition(edat.sens.inst_frq < edat.param.ign_cutoff_thrd);
  else
   ckps_enable_ignition(1);  
  //------------------------------------------------------------------------

  //выполняем операции которые необходимо выполнять строго для каждого рабочего цикла.
  if (ckps_is_cycle_cutover_r())
  {
   meas_update_values_buffers(&edat, 0);
   s_timer_set(force_measure_timeout_counter, FORCE_MEASURE_TIMEOUT_VALUE);

   //Ограничиваем быстрые изменения УОЗ, он не может изменится больше чем на определенную величину
   //за один рабочий цикл. В режиме пуска фильтр УОЗ отключен.
   if (EM_START == edat.engine_mode)
    edat.curr_angle = advance_angle_inhibitor_state = calc_adv_ang;
   else
    edat.curr_angle = advance_angle_inhibitor(calc_adv_ang, &advance_angle_inhibitor_state, edat.param.angle_inc_spead, edat.param.angle_dec_spead);

   //----------------------------------------------
   if (edat.param.knock_use_knock_channel)
   {
    knklogic_detect(&edat, &retard_state);
    knklogic_retard(&edat, &retard_state);
   }
   else
    edat.knock_retard = 0;
   //----------------------------------------------

   //сохраняем УОЗ для реализации в ближайшем по времени цикле зажигания
   ckps_set_advance_angle(edat.curr_angle);

   //управляем усилением аттенюатора в зависимости от оборотов
   if (edat.param.knock_use_knock_channel)
    knock_set_gain(knock_attenuator_function(&edat));

   // индицирование этих ошибок прекращаем при начале вращения двигателя
   //(при прошествии N-го количества циклов)
   if (turnout_low_priority_errors_counter == 1)
   {
    ce_clear_error(ECUERROR_EEPROM_PARAM_BROKEN);
    ce_clear_error(ECUERROR_PROGRAM_CODE_BROKEN);
   }
   if (turnout_low_priority_errors_counter > 0)
    turnout_low_priority_errors_counter--;
  }

 }//main loop
 //------------------------------------------------------------------------
}