Топливная карта

Yer
Offline
Зарегистрирован: 12.02.2016

Здравствуйте всем, пробую сделать блок эбу с ардуино нано.Пока вроде получается машина едит держит холостые обороты, но на больших оборотах выше 2500 и с нагрузки на двигатель уже не тянет.Смотрю сигналы которые подаются на форсунки через осцилограф на ходу в машине все норм.Дальше подключился к лямбду датчику на больших оборотах когда едишь с нагрузкой смесь сильно обедняется. Теперь начал писать код топливной картой на больших и средних оборотах но пока точно не получается.Когда большие обороты код не правильно выставляет время впрыска форсунок на средних оборотах более менее. Вот  сам код топливной картой если есть идеии для более быстрого обработки чтобы контроллер не загружать в студию 

int Cor ( volatile int correct) 
{    asm("cli");
	
	//топливная карта
	if ((oborot >= 16 )&&(otsechka == 0)&&(acp2 >= 60))
	{//***************************************
     if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 60)&&(acp2 <= 70) )//esli oboroti vishe 100 nizhe 1500 i Map bolshe >58 i nizhe 70
	{correct=5;
	return correct;
	}
	if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 70)&& (acp2 <= 80))
	{correct=10;
	return correct;
	} 
	if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}  
	if ((oborot >= 16)&& (oborot<= 25) && (acp2 >= 90) && (acp2 <= 100))
	{correct=30;
	return correct;}  
	if ((oborot >= 16) && (oborot <= 25) && (acp2 >= 100) && (acp2 <= 120))
	{correct=40;
	return correct;}
	//**************************************************
	if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 2000 i Map bolshe >58
	{correct=5;
	return correct;}
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	 if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=30;
	return correct;}
	
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=40;
	return correct;}
	//**************************************************
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 2500 i Map bolshe >58
	{correct=5;
	return correct;}
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=30;
	return correct;}
	if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 100)&&(acp2 <=120))
	{correct=40;
	return correct;}
    //************************************************************
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 3000 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=50;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=60;
	return correct;}
	//************************************************************
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 3500 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=40;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=50;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=60;
	return correct;}
	//**********************************************************
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 4000 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;
	}
	
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 80)&&(acp2 <=90))
	{correct=40;
	return correct;
	}
	
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 90)&&(acp2 <=100))
	{correct=50;
	return correct;
	}
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 100)&&(acp2 <=120))
	{correct=60;
	return correct;
	}
//***************************************************************		
	}

   else 
   {
	   correct=0;
    return correct;  
   }
 
asm("sei");
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А что return делает до восстановления SREG? Кто будет прерывания разрешать, если return сработает?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Фактически, код делает это.  И всё.  С логикой сильно не разбиралса, но смысл такой

#define AND &&

bool Between(int value, int min, int max)
{
 return (value>=min) AND (value<=max);
}

int Cor ( void) 
{   
	if (Between(oborot,16,66) AND (otsechka == 0) AND (acp2 >= 60))
 	 {
	  if (acp2 <= 70) )	       return 5;  
	  if Between(acp2,71,80))    return 10;
 	  if (Between(acp2,81,90))   return 20;
	  if (Between(acp2,91,100))  return 30;
	  if (Between(acp2,101,120)) return 40;
	};
        else return 0;
 
}

и, да, спасибо ЕвгенийП, запрет прерываний тут не то что бессмысленен, а таки и вреден. 

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

нужно иметь ввиду. При открытии дросселя, увеличивается давление во впуснкном коллекторе, т.е. возле выходного клапана форсунки и рассчитанного времени врыска уже будет не достаточно для осуществления подавания данного расчитанного количества топлива. Т.е. нужно это как то скомпенсировать. На старых автомобилях, где регуляторы давления топлива находились на топливной рампе, это делалось так. В регулятор давления топлива подходила трубка, по которой подавалась разряжение со впуска, и регулятор давления топлива, кроме своей основной функции, занимался этой компенсацией. Т.е. при открытии дросселя повышал давление топлива, грубо говоря, поддерживая всегда одинаковую разницу давлений топлива и воздуха на входе и выходе форсунки. 

На современных автомобилях регулятор давления топлива установлен в баке, а компенсанией изменения разницы давлений на концах форсунки занимается ЭБУ, с помощью изменения время впрыска. Какая у вас система? нужно это учитывать. 

Также нужно учитывать, что во время импульса открытия форсунки, не всё время импульса топливо подается. Есть две задержки -  на открытие и закрытие клапана форсунки. Так вот величина этих задержек зависит от напряжения (амплитуды) импульса, читай напряжения бортовой сети. При работе ДВС ЭБУ это учитывает, и корректирует время врыска, т.е. меньше напряжение - увеличивает немного время впрыска и наоборот. 

Также думается что при режиме Closed loop (режим, когда расчет качества топливной смеси, читай время впрыска, ведется при учете обраной связи, то есть смотрим на выхлопе, что мы там наготовили) такая простая логика работы:

- датчик показал бедную смесь - богатим её,

- датчик опять показал бедную смесь - богатим еще сильнее, и т.д.

- датчик показал богатую смесь - бедним её,

- датчик показал богатую смесь - бедним её ещё сильнее и т.д.

 

Yer
Offline
Зарегистрирован: 12.02.2016

MaksVV у меня трубка разрежение подходит к топливной рампе при большом разрежение компенсирует потерии. Загружаю полный код который у меня сейчас на двигателе работает.

/*
 * ACP_interrupt.c
 *
 * Created: 07.06.2017 11:56:00
 *  Author: asu
 */ 


#include <avr/io.h>
#include <avr/interrupt.h>
#include "eeprom_lib2.h"
#include <avr/pgmspace.h>
volatile unsigned int ACP,value,map,ob2=0;
volatile float acp2=0,oborot=0;
volatile unsigned int T,zad_t=45,zad_t2=0,zad_t3=0,ob,otsechka,top_cor=0,zad_vpris2=0,time_ob=0,vprisk_top2=0;
volatile unsigned char val,ad2=0,ad,val2,sel_chanel,pauza=0;
volatile unsigned char zapusk=0,Period=0,off,off2,raz_xx,raz_uskor,signal_xx2=0; 
#define PIN_INT0 PD2

ISR (TIMER0_COMPA_vect)
{
	 T++;//shet zadershki impulsa  
	 ob++;//shet oborota
  if (T == zad_t3)
  {PORTD &=~(1<<PD6);
  }
} 
ISR (ADC_vect)
{  
	ACP=ADCW;//znachenie MAP
	ADCSRA |=(1<<ADSC);

}
ISR (INT0_vect)
{ zapusk++;
	if(pauza ==0)
 {  PORTD |=(1<<PD6);pauza=1;
 	T=0; }
else if (pauza == 1)
{  PORTD &=~(1<<PD6); 
	pauza=0;
             }	

}


		
int main(void)
{   DDRC &=~(1<<PC1);
	DDRD &=~(1<<PD7);//vhod otsechka na XX dvigatelya
	PORTD |=(1<<PD7);
    ADCSRA |=(1<<ADEN)
	//разрешение использование АЦП
    |(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128 delim
	ADMUX |=(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0);//подключили к 5В
	//arduino A1
	ADCSRA |=(1<<ADSC);
	DDRD |=(1<<PD6);//vihod na force
	PORTD &=~(1<<PD6);
	 //настраиваем вывод на вход
    DDRD &= ~(1<<PIN_INT0);
    //включаем подтягивающий резистор
    PORTD |= (1<<PIN_INT0); 
	EICRA |=(1<<ISC01)|(1<<ISC00);//interrupt rising
	EIMSK |=(1<<INT0);//external interrupt Int0 pin2
	//********Timer0***********
	TCCR0A |= (1<<WGM01);  // Режим CTC (сброс по совпадению)
    TIMSK0 |=(1<<OCIE0A);  // Разрешить прерывание по совпадению
    OCR0A=24; //24 по достижении уходить в вектор прерывании, 24 равняется к 100 microsec  
    TCNT0=0;
    TCCR0B |=(1<<CS01)|(1<<CS00);; // CLK/64
	asm("sei");
    while(1)
    {asm("cli");  
	   vprisk_top2 = vprisk_top();
       oborot = shet_ob(); //shet oborota
	   top_cor = Cor();
	   otsechka = sw_but();//signal s otsechki
	   
    asm("sei");  
	}
}
//*****vprisk_top*****
int vprisk_top ()
{asm("cli"); 
  acp2=ACP*0.1;
  zad_t2 = (acp2/oborot)*10;

  if ((acp2 > 60) && (otsechka==0) && (oborot > 13) )//uskorenie motora
	{ 
      zad_vpris2=zad_t2+top_cor;
	}
	if (oborot < 25 && acp2 <60 )//pri otsecke motora na 1500 oborotah
	{zad_vpris2=0; 
	}
	
	if ( otsechka == 1 || acp2 < 60)  //motor XX  
	{zad_vpris2=0;
	}
	zad_t3 = zad_t+zad_vpris2;	
	 
 asm("sei"); 	
}


//**********************
int shet_ob ( )
{  asm("cli");  
   
   if (zapusk == 1 && off ==0)//start sheta oborota
	 { 
      ob=0;	off=1;off2=0;
	 }
	if (zapusk == 2 && off2 ==0)//fiksasya oborota
	{
	time_ob=ob;//sohranim znachenie oborota
	zapusk=1;off2=1;
	off=0;
	ob=0;
	ob2=(30/(time_ob*0.0001))/60;//rashet oborota v sekundu
	}
 	return ob2;
  asm("sei");
}
//*********************
//*******signal s XX *********
int sw_but( volatile int signal_xx)

{  asm("cli");
	static char butcount;
	if (!(PIND&(1<<PD7)))//esli podaetsya minus na vhod Pin7 nuzhno pottynut na plus 30 KOm
	{  
	    signal_xx=1;
	}		
	else
	{
	signal_xx =0;
	}	
	return signal_xx;
	asm("sei");
}
//********************
int Cor ( volatile int correct) 
{    asm("cli");
	
	//топливная карта
	if ((oborot >= 16 )&&(otsechka == 0)&&(acp2 >= 60))
	{//***************************************
     if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 60)&&(acp2 <= 70) )//esli oboroti vishe 100 nizhe 1500 i Map bolshe >58 i nizhe 70
	{correct=5;
	return correct;
	}
	if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 70)&& (acp2 <= 80))
	{correct=10;
	return correct;
	} 
	if ((oborot >= 16)&&(oborot <= 25) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}  
	if ((oborot >= 16)&& (oborot<= 25) && (acp2 >= 90) && (acp2 <= 100))
	{correct=30;
	return correct;}  
	if ((oborot >= 16) && (oborot <= 25) && (acp2 >= 100) && (acp2 <= 120))
	{correct=40;
	return correct;}
	//**************************************************
	if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 2000 i Map bolshe >58
	{correct=5;
	return correct;}
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	 if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=30;
	return correct;}
	
	  if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=40;
	return correct;}
	//**************************************************
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 2500 i Map bolshe >58
	{correct=5;
	return correct;}
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	 if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=30;
	return correct;}
	if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 100)&&(acp2 <=120))
	{correct=40;
	return correct;}
    //************************************************************
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 3000 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=20;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=50;
	return correct;}
	if ((oborot >= 40)&&(oborot <= 50) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=60;
	return correct;}
	//************************************************************
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 3500 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 80)&&(acp2 <= 90))
	{correct=40;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 90)&&(acp2 <= 100))
	{correct=50;
	return correct;}
	if ((oborot >= 50)&&(oborot <= 58) && (acp2 >= 100)&&(acp2 <= 120))
	{correct=60;
	return correct;}
	//**********************************************************
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 4000 i Map bolshe >58
	{correct=5;
	return correct;}
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 70)&&(acp2 <= 80))
	{correct=10;
	return correct;
	}
	
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 80)&&(acp2 <=90))
	{correct=40;
	return correct;
	}
	
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 90)&&(acp2 <=100))
	{correct=50;
	return correct;
	}
	if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 100)&&(acp2 <=120))
	{correct=60;
	return correct;
	}
//***************************************************************		
	}

   else 
   {
	   correct=0;
    return correct;  
   }
 
asm("sei");
}
//*******************************************

 

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

Yer пишет:
Когда большие обороты код не правильно выставляет время впрыска форсунок на средних оборотах более менее.

Два вопроса. 1. Что бы значть что выставляет неправильно надо знать, а как оно - правильно?

2. Даже если вы знаете "как правильно", как вы узнаете, что код выставляет неправильно? 

Нужно поподробней эти моменты описать 

anarch
Offline
Зарегистрирован: 10.09.2017

Погуглите про MegaSquirt. И за одно как работает топливный регулятор.

Будет понятно сразу, программа должна учитывать резкое открытие дроселя и моментально переобогошать смесь. И на разных режимах должен быть разный топливный состав. Здесь мы плавно переходим к теории как работает ДВС.

Не плохо еще скачать какой нибудь редактор калибровок прошивок ЭБУ. И посмотреть сколько всего учитываеться.

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

 я к тому же. Может у ТС код то всё правильно и чесно делает, просто константы в топливных картах неправильные (откуда их брали?), и машина не едет плюсом ко всему из-за того, что много ещё чего надо учитывать  в программе. 

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

я то наивный думал, что количество подаваемого топлива рассчитывается в первую очередь исходя из расхода воздуха, хотя а зачем все эти расчеты, когда можно опытным путем сделать 

correct=10, 40, 100 и т.д.

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

рассчитывается или измеряется чем либо расход воздуха в единицу времени => исходя из этого и оборотов рассчитывается цикловое наполнение воздухом => исходя из этого и стехиометрического состава рассчитывается цикловая подача топлива => исходя из этого и производительности форсунки рассчитывается время открытия форсунки

anarch
Offline
Зарегистрирован: 10.09.2017

MaksVV пишет:

рассчитывается или измеряется чем либо расход воздуха в единицу времени => исходя из оборотов рассчитывается цикловое наполнение воздухом => исходя из стехиометрического состава рассчитывается цикловая подача топлива => исходя из производительности форсунки рассчитывается время открытия форсунки

И получаем то, что машина едет как описанно выше. Это будет базовое время открытия форсы. И на это все надо накладывать корекцию: положение дроселя, напряжение АКБ и т.д.

После того как машина поедет можно будет прикручивать датчик кислорода и по нему уже исправлять смесь.

Yer
Offline
Зарегистрирован: 12.02.2016

Поставил датчик разрежение от Опел вектры, зависомости от разрежение показывает сигнал на ардуино.Делаю расчет оборотов по датчику холла который встроен на самом блоке мерса контакт TD на диагностическому разьему подключил все работает обороты вычитовает правильно. Впрыск по формуле : впрыск = Разрежение / обороты . По этой формуле задается впрыск и оно работает нормально до 2500 оборотов так как при максмальном разреженеие 101 кРа а обороты 3000 если в секунду 50 выходит , 2 мс .Вот поэтому хочу создать карту топливо с выше 1500 задавал впрыск на форсы  

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

anarch пишет:

MaksVV пишет:

рассчитывается или измеряется чем либо расход воздуха в единицу времени => исходя из оборотов рассчитывается цикловое наполнение воздухом => исходя из стехиометрического состава рассчитывается цикловая подача топлива => исходя из производительности форсунки рассчитывается время открытия форсунки

И получаем то, что машина едет как описанно выше. Это будет базовое время открытия форсы. И на это все надо накладывать корекцию: положение дроселя, напряжение АКБ и т.д.

После того как машина поедет можно будет прикручивать датчик кислорода и по нему уже исправлять смесь.

понятно что я писал про базовое. Там ещё хренова туча коэффициентов. Например Температура двигателя. Кстати расчет времени впрыска при запуске ДВС берется исходя только из температуры двигателя. 

MaksVV
Онлайн
Зарегистрирован: 06.08.2015

впрыск = Разрежение / обороты  -  крутая формула. Главное очень точная. А теперь подставьте вместо величин, единицы измерения, совпадут ли. 

anarch
Offline
Зарегистрирован: 10.09.2017

Надо использовать уровнение идеального газа. Если используем MAP датчик.

n = PV/RT

И еще раз повторюсь, посетите megasquirt. Там все это разжеванно. 

И не получиться в двух - трех строках кода сделать полноценный ЭБУ.

Yer
Offline
Зарегистрирован: 12.02.2016

Всем спасибо за отзывы разобрался с программой вроде все работает как надо теперь буду проверять на машине