/**Initialization of timer 0 using specified value and start, clock = 250kHz * It is assumed that this function called when all interrupts are disabled * (Инициализация таймера 0 указанным значением и запуск, clock = 250kHz. * Предполагается что вызов этой функции будет происходить при запрещенных прерываниях) * \param value value for load into timer (значение для загрузки в таймер) */ INLINE void set_timer0(uint16_t value) { TCNT0_H = _AB(value, 1); TCNT0 = ~(_AB(value, 0)); //One's complement is faster than 255 - low byte TCCR0 = _BV(CS01)|_BV(CS00); }
/**Initialize timer 0 using specified value and start it, clock = 312.5kHz * It is assumed that this function called when all interrupts are disabled * \param value Value to set timer for, 1 tick = 3.2uS */ INLINE void set_timer0(uint16_t value) { OCR0A = TCNT0 + _AB(value, 0); TCNT0_H = _AB(value, 1); SETBIT(TIMSK0, OCIE0A); SETBIT(TIFR0, OCF0A); }
/** Special function for processing falling edge, * must be called from ISR * \param tmr Timer value at the moment of falling edge */ INLINE void ProcessFallingEdge(uint16_t tmr) { //save period value if it is correct. We need to do it forst of all to have fresh stroke_period value if (CHECKBIT(flags, F_VHTPER)) { //calculate stroke period hall.stroke_period = tmr - hall.measure_start_value; WRITEBIT(flags, F_SPSIGN, tmr < hall.measure_start_value); //save sign hall.t1oc_s = hall.t1oc, hall.t1oc = 0; //save value and reset counter } SETBIT(flags, F_VHTPER); SETBIT(flags, F_STROKE); //set the stroke-synchronization event (устанавливаем событие тактовой синхронизации) hall.measure_start_value = tmr; if (!CHECKBIT(flags2, F_SHUTTER_S)) { uint16_t delay; #ifdef STROBOSCOPE hall.strobe = 1; //strobe! #endif //----------------------------------------------------- //Software PWM is very sensitive even to small delays. So, we need to allow OCF2 and TOV2 //interrupts occur during processing of this handler. #ifdef COOLINGFAN_PWM _ENABLE_INTERRUPT(); #endif //----------------------------------------------------- //start timer for counting out of advance angle (spark) delay = (((uint32_t)hall.advance_angle * hall.stroke_period) / hall.degrees_per_stroke); #ifdef COOLINGFAN_PWM _DISABLE_INTERRUPT(); #endif OCR1A = tmr + ((delay < 15) ? 15 : delay) - CALIBRATION_DELAY; //set compare channel, additionally prevent spark missing when advance angle is near to 60° TIFR1 = _BV(OCF1A); TIMSK1|= _BV(OCIE1A); //start timer for countiong out of knock window opening if (CHECKBIT(flags, F_USEKNK)) { #ifdef COOLINGFAN_PWM _ENABLE_INTERRUPT(); #endif delay = ((uint32_t)hall.knock_wnd_begin * hall.stroke_period) / hall.degrees_per_stroke; #ifdef COOLINGFAN_PWM _DISABLE_INTERRUPT(); #endif set_timer0(delay); hall.knkwnd_mode = 0; } knock_start_settings_latching();//start the process of downloading the settings into the HIP9011 (запускаем процесс загрузки настроек в HIP) adc_begin_measure(_AB(hall.stroke_period, 1) < 4);//start the process of measuring analog input values (запуск процесса измерения значений аналоговых входов) } }
/**Appends sender's buffer by 4 HEX bytes * \param i 16-bit value to be converted into hex */ static void build_i16h(uint16_t i) { #ifdef UART_BINARY append_tx_buff(_AB(i,1)); //старший байт append_tx_buff(_AB(i,0)); //младший байт #else uart.send_buf[uart.send_size++] = PGM_GET_BYTE(&hdig[_AB(i,1)/16]); //старший байт HEX числа (старший байт) uart.send_buf[uart.send_size++] = PGM_GET_BYTE(&hdig[_AB(i,1)%16]); //младший байт HEX числа (старший байт) uart.send_buf[uart.send_size++] = PGM_GET_BYTE(&hdig[_AB(i,0)/16]); //старший байт HEX числа (младший байт) uart.send_buf[uart.send_size++] = PGM_GET_BYTE(&hdig[_AB(i,0)%16]); //младший байт HEX числа (младший байт) #endif }
void process_uart_interface(struct ecudata_t* d) { uint8_t descriptor; //Following code executes at start up only if bluetooth is enabled and only 1 time if (d->param.bt_flags & _BV(BTF_USE_BT)) { if (!bt_set_baud(d, d->param.uart_divisor)) return; if (d->bt_name[0] && d->bt_pass[0]) if (!bt_set_namepass(d)) return; } if (uart_is_packet_received())//приняли новый фрейм ? { descriptor = uart_recept_packet(d); switch(descriptor) { case TEMPER_PAR: case CARBUR_PAR: case IDLREG_PAR: case ANGLES_PAR: case STARTR_PAR: case ADCCOR_PAR: case CHOKE_PAR: //если были изменены параметры то сбрасываем счетчик времени s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); break; case MISCEL_PAR: #ifdef HALL_OUTPUT ckps_set_hall_pulse(d->param.hop_start_cogs, d->param.hop_durat_cogs); #endif s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); break; case FUNSET_PAR: #ifdef REALTIME_TABLES sop_set_operation(SOP_SELECT_TABLSET); #endif //если были изменены параметры то сбрасываем счетчик времени s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); break; case OP_COMP_NC: if (_AB(d->op_actn_code, 0) == OPCODE_EEPROM_PARAM_SAVE) //приняли команду сохранения параметров { sop_set_operation(SOP_SAVE_PARAMETERS); _AB(d->op_actn_code, 0) = 0; //обработали } if (_AB(d->op_actn_code, 0) == OPCODE_CE_SAVE_ERRORS) //приняли команду чтения сохраненных кодов ошибок { sop_set_operation(SOP_READ_CE_ERRORS); _AB(d->op_actn_code, 0) = 0; //обработали } if (_AB(d->op_actn_code, 0) == OPCODE_READ_FW_SIG_INFO) //приняли команду чтения и передачи информации о прошивке { sop_set_operation(SOP_SEND_FW_SIG_INFO); _AB(d->op_actn_code, 0) = 0; //обработали } #ifdef REALTIME_TABLES if (_AB(d->op_actn_code, 0) == OPCODE_LOAD_TABLSET) //приняли команду выбора нового набора таблиц { sop_set_operation(SOP_LOAD_TABLSET); _AB(d->op_actn_code, 0) = 0; //обработали } if (_AB(d->op_actn_code, 0) == OPCODE_SAVE_TABLSET) //приняли команду сохранения набора таблиц для указанного типа топлива { sop_set_operation(SOP_SAVE_TABLSET); _AB(d->op_actn_code, 0) = 0; //обработали } #endif #ifdef DIAGNOSTICS if (_AB(d->op_actn_code, 0) == OPCODE_DIAGNOST_ENTER) //"enter diagnostic mode" command has been received { //this function will send confirmation answer and start diagnostic mode (it will has its own separate loop) diagnost_start(); _AB(d->op_actn_code, 0) = 0; //обработали } if (_AB(d->op_actn_code, 0) == OPCODE_DIAGNOST_LEAVE) //"leave diagnostic mode" command has been received { //this function will send confirmation answer and reset device diagnost_stop(); _AB(d->op_actn_code, 0) = 0; //обработали } #endif if (_AB(d->op_actn_code, 0) == OPCODE_RESET_EEPROM) //reset EEPROM command received { if (_AB(d->op_actn_code, 1) == 0xAA) //second byte must be 0xAA sop_set_operation(SOP_SEND_NC_RESET_EEPROM); _AB(d->op_actn_code, 0) = 0; //processed } break; case CE_SAVED_ERR: sop_set_operation(SOP_SAVE_CE_ERRORS); break; case CKPS_PAR: //если были изменены параметры ДПКВ, то немедленно применяем их на работающем двигателе и сбрасываем счетчик времени ckps_set_cyl_number(d->param.ckps_engine_cyl); //<--обязательно в первую очередь! ckps_set_cogs_num(d->param.ckps_cogs_num, d->param.ckps_miss_num); ckps_set_edge_type(d->param.ckps_edge_type); #ifdef SECU3T cams_vr_set_edge_type(d->param.ref_s_edge_type); //REF_S (ДНО) #endif ckps_set_cogs_btdc(d->param.ckps_cogs_btdc); ckps_set_merge_outs(d->param.merge_ign_outs); #ifndef DWELL_CONTROL ckps_set_ignition_cogs(d->param.ckps_ignit_cogs); #endif s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); #ifdef HALL_SYNC ckps_select_input(d->param.hall_flags & _BV(HSF_USECKPINP)); //select input (CKPS or PS) #endif break; case KNOCK_PAR: //аналогично для контороля детонации, обязательно после CKPS_PAR! //инициализируем процессор детонации в случае если он не использовался, а теперь поступила команда его использовать. if (!d->use_knock_channel_prev && d->param.knock_use_knock_channel) if (!knock_module_initialize()) {//чип сигнального процессора детонации неисправен - зажигаем СЕ ce_set_error(ECUERROR_KSP_CHIP_FAILED); } knock_set_band_pass(d->param.knock_bpf_frequency); //gain устанавливается в каждом рабочем цикле knock_set_int_time_constant(d->param.knock_int_time_const); ckps_set_knock_window(d->param.knock_k_wnd_begin_angle, d->param.knock_k_wnd_end_angle); ckps_use_knock_channel(d->param.knock_use_knock_channel); //запоминаем состояние флага для того чтобы потом можно было определить нужно инициализировать //процессор детонации или нет. d->use_knock_channel_prev = d->param.knock_use_knock_channel; //если были изменены параметры то сбрасываем счетчик времени s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); break; case SECUR_PAR: if (d->bt_name[0] && d->bt_pass[0]) bt_start_set_namepass(); s_timer16_set(save_param_timeout_counter, SAVE_PARAM_TIMEOUT_VALUE); break; } //мы обработали принятые данные - приемник ничем теперь не озабочен uart_notify_processed(); } //периодически передаем фреймы с данными if (s_timer_is_action(send_packet_interval_counter)) { if (!uart_is_sender_busy()) { uint8_t desc = uart_get_send_mode(); uart_send_packet(d, 0); //теперь передатчик озабочен передачей данных #ifdef DEBUG_VARIABLES if (SENSOR_DAT==desc || ADCRAW_DAT==desc || CE_ERR_CODES==desc || DIAGINP_DAT==desc) sop_set_operation(SOP_DBGVAR_SENDING); //additionally we will send packet with debug information #endif s_timer_set(send_packet_interval_counter, d->param.uart_period_t_ms); //после передачи очищаем кеш ошибок, передача битов ошибок осуществляется только в 1 из 2 пакетов if (SENSOR_DAT==desc || CE_ERR_CODES==desc) d->ecuerrors_for_transfer = 0; } } }