Здравствуйте всем написал код в ардуино нано, для управление м102 мотора мерседес W124 с обьемом 2,0 литра.Там инжектор механический КЕ-ДЖетроник.ЭБУ для управление газовыми форсунками. Все работает впрыск на холостом ходу 4,5 мс, по датчику разрежение определяю нагрузку на двигателе. Чем больше разрежение впрыску добавляется до 10 мс, есть проблема если ставлю таймер с прерыванием 1 миллисекунд нормально работает.Но если таймер прерывание ставлю на 100 микросекунд впрыск становится то больше то меньше гонит. Может в коде что то не хватает или не правильно написано подскажите(частота микроконтроллера атмега328Р 16МГц) //************************* Код (C++): #include <avr/io.h> #include <avr/interrupt.h> volatile unsigned int Danie_Rx,Temp=0,shet_adc; volatile unsigned char danie_tx; volatile unsigned int ACP/*razrezhenie MAP */,ACP_2,ob2=0,T,ob,time_ob=0; volatile float acp_2=0,oborot_2=0; volatile unsigned char zad_t=45,zad_t2=0,zad_t3=0,otsechka,top_cor=0,zad_vpris2=0,vprisk_top2=0,top_cor2=0,zad_vpris4=0,zad_vpris5=0; volatile unsigned char val,ad2=0,ad,val2,sel_chanel,pauza=0,acp2,oborot,signal_xx,correct=0; volatile unsigned char zapusk=0,Period=0,period_2=0,off,off2,raz_xx,raz_uskor=0,signal_xx2=0; volatile unsigned char ch=1,zn_acp,zn_temp=0,per_adc,zn_adc,per_ch=0; #define PIN_INT0 PD2 //******timer0***** ISR (TIMER0_COMPA_vect) { T++;//shet zadershki impulsa ob++;//shet oborota } //*********ADC*********** ISR (ADC_vect) { for (int i=0;i<20;i++) {ACP=ACP+ADCW; } ACP_2=ACP/20; ADCSRA |=(1<<ADSC); return ACP_2; } int main(void) { DDRC &=~(1<<PC1);//vhod MAP datchika DDRD &=~(1<<PD7);//vhod otsechka na XX dvigatelya PORTD |=(1<<PD7); DDRD |=(1<<PD6);//vihod na force PORTD &=~(1<<PD6); DDRD |=(1<<PD4);//vihod na klapan reduktora PORTD &=~(1<<PD4); //********ACP************ ADCSRA |=(1<<ADEN) //разрешение использование АЦП |(1<<ADIE)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//8 delim ADMUX |=(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0);//подключили к 5В //arduino A1 ADCSRA |=(1<<ADSC); //настраиваем вывод на вход DDRD &= ~(1<<PIN_INT0); //включаем подтягивающий резистор PORTD |= (1<<PIN_INT0); //********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) { vprisk_top2 = vprisk_top();//rashet zadershki vpriska topliva zad_vpris4 = rashet_vprisk(); oborot = shet_ob(); //shet oborota top_cor = Cor();//toplivnaya karta otsechka = sw_but();//signal s otsechk } } //*****rashet vprisk*** int rashet_vprisk () { acp2=ACP_2*0.1; zad_t2 = (acp2/oborot)*10; if ((acp2 >= 60) && (otsechka==0))//uskorenie motora { zad_vpris2=zad_t2; if (oborot > 20 && acp2 > 60) { raz_uskor=1; top_cor2=top_cor; } if ((oborot < 20) && (raz_uskor == 1)&&(acp2 < 60))//pri otsecke motora na 1200 oborotah {zad_vpris2=0; top_cor2=0; raz_uskor=0; } } if (T == zad_t3 ) {PORTD &=~(1<<PD6);Period=1;} } //*****vprisk_top***** int vprisk_top () { asm("cli"); //*********************** static uint8_t prev_in_state = 0xFF; uint8_t in_state = PIND; // фиксируем состояние всех входов static uint8_t currBit = 4; // бит вх in2 arduino. порта if ((in_state & currBit) != currBit) { // если на канале низкий уровень if ((prev_in_state & currBit) == currBit) { // если в прошлый раз был высокий } } else if ((prev_in_state & currBit) != currBit) { // вх. импульс закончился ? // вычисляем, при каком знач.счетчика micros надо гасить соотв. выход zapusk++; if (Period==0 )//est vpris na vihode { PORTD |=(1<<PD6); T=0; } if (Period == 1)//net vpriska na vihode {Period=0; } } prev_in_state = in_state; // сохраняем текущее состояние входов //************************ asm("sei"); } //********oboroti************** int shet_ob ( ) { if (zapusk == 1 && off ==0)//start sheta oborota { ob=0; off=1;off2=0; } if (zapusk == 2 && off2 ==0)//fiksasya oborota { return ob2; } //********************* //*******signal s XX ********* int sw_but( ) { static char butcount; if (!(PIND&(1<<PD7)))//esli podaetsya minus na vhod Pin7 nuzhno pottynut na plus 30 KOm { if (butcount < 5) { butcount++; } else { signal_xx=1; } } else { if (butcount > 0) {butcount --; } else { signal_xx =0; } } return signal_xx; } //*******topliv karta************* int Cor ( ) { if ((oborot >= 20) && (oborot <= 80)&&(acp2 > 60)&&(raz_uskor == 1)) { if ((oborot >= 20) && (oborot <= 25) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 1200 i Map bolshe >58 {correct=4; return correct; } if ((oborot >= 20) && (oborot <= 25) && (acp2 >= 70)&&(acp2 <= 80)) {correct=6; return correct; } if ((oborot >= 20) && (oborot <= 25) && (acp2 >= 80)&&(acp2 <= 90)) {correct=8; return correct; } if ((oborot >= 20) && (oborot <= 25) && (acp2 >= 90)&&(acp2 <= 100)) {correct=10; return correct; } if ((oborot >= 20) && (oborot <= 25) && (acp2 >= 100)&&(acp2 <= 120)) {correct=10; return correct; } //************* if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 60)&&(acp2 <= 70))//esli oboroti vishe 1500 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=15; return correct; } if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 90)&&(acp2 <= 100)) {correct=20; return correct; } if ((oborot >= 25) && (oborot <= 33) && (acp2 >= 100)&&(acp2 <= 120)) {correct=20; return correct; } if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 60)&&(acp2<=70))//esli oboroti vishe 2000 i Map bolshe >58 {correct=10; return correct; } if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 70)&&(acp2<=80)) {correct=20; return correct; } if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 80)&&(acp2<=90)) {correct=25; } if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 90)&&(acp2<=100)) {correct=30; return correct;} if ((oborot >= 33)&&(oborot <= 40) && (acp2 >= 100)&&(acp2<=120)) {correct=30; return correct;} if ((oborot>=40)&&(oborot <= 50) && (acp2 >= 60)&&(acp2<=70))//esli oboroti vishe 2500 i Map bolshe >58 {correct=10; 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=30; return correct;} if ((oborot>=40)&&(oborot <= 50) && (acp2 >= 100)&&(acp2<=120)) {correct=30; return correct;} if ((oborot>=50)&&(oborot <= 58) && (acp2 >= 60)&&(acp2<=70))//esli oboroti vishe 3000 i Map bolshe >58 {correct=10; return correct;} if ((oborot>=50)&&(oborot <= 58) && (acp2 >= 70)&&(acp2<=80)) {correct=20; return correct;} if ((oborot>=50)&&(oborot <= 58) && (acp2 >= 80)&&(acp2<=90)) {correct=30; } if ((oborot>=50)&&(oborot <= 58) && (acp2 >= 90)&&(acp2<=100)) {correct=35; return correct;} if ((oborot>=50)&&(oborot <= 58) && (acp2 >= 100)&&(acp2<=120)) {correct=35; return correct;} if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 60)&&(acp2 <=70))//esli oboroti vishe 3500 i Map bolshe >58 {correct=1; return correct;} if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 70)&&(acp2 <=80)) {correct=20; return correct;} if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 80)&&(acp2 <=90)) {correct=30; return correct;} if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 90)&&(acp2 <=100)) {correct=37; return correct;} if ((oborot >= 58)&&(oborot <= 66) && (acp2 >= 100)&&(acp2 <=120)) {correct=37; return correct;} } else {correct=0;; return correct; } }
А вы не замеряли время затрачиваемое в прерывании? Похоже, что оно как минимум равно 100мкс, а может и больше. Отсюда у рывки. Попробуйте при входе в прерывание поднять любую свободную ногу, а перед выходом опустить ее. И затем гляньте осциллографом либо цифроанализатором сколько времени нога будет поднята и с каким интервалом. Мне такой метод отладки здорово помогает. PS Задавать топливную карту через ифы очень не удобно. Лучше через N-мерный массив. Тогда ее можно хранить в епроме и настраивать без перекомпиляции кода. Да и накосячить в этой куче сравнений вероятность меньше.
Абсолютно просто. 1-мерный массив. Зависимость только от одного параметра. К примеру, оборотов. Делим обороты на 100 и отнимаем 8. Полученный результат будет индексом массива [0..50], в котором храним расход топлива (или время открытия форсунки). Соответственно для 800 об\мин берем 0 элемент, для 900 - 1 элемент и т.д. до 5800. 2-мерный массив. Зависимость от двух параметров (обороты и расход воздуха). Аналогично делением и отниманием приводим значения входных параметров к виду 0-N и 0-M, где N и М максимальное количество элементов в нашем массиве [N][M]. 3-мерный и дальше - аналогично. После получения расхода из нашей карты дополнительно корректируем на поправки (температура воздуха, температура ОЖ и т.д.)
Примитивный пример. На значения не обращайте внимания - подставите свои нужные. Сам принцип. Код (C++): // массив 2-мерный 5 на 8 элементов (5 вариантов по первому датчику и 8 по второму) // значения - нужный расход byte map_rashod[5][8]={ {1,2,3,4,5,6,7,8}, {9,10,22,33,44,55}, {6,5,3,8,9,9,7,3}, {2,3,4,5,67,8,9,6}, {5,6,7,8,9,3,4,5} }; byte ob=900; // первый датчик ( для первого индекса массива) byte voz=50; // второй датчик (второй индекс) // получаем элемент из массива - это наш нужный расход byte rashod = map_rashod[ ob/100-8 ][ voz /10 ]; Кстати, в настоящих ЭБУ таких двумерных (и одномерных) карт несколько и результирующий расход считают как сумму значений выбранных элементов из каждой карты.
900/100 - 8 = 1 -> вторая строка (счет всегда с 0) 50 / 10 = 5 -> шестой столбец итого расход выбирается 55 Кстати, в этой второй строке я не описал все 8 элементов, только 6. В настоящей карте надо не ошибиться и описать все варианты значений, а то подставится 0.
Спасибо большое, все думал как уменьшить код топливный карты классный метод с массивами. Если по температуре заполнять карту нужно использовать трехмерный массив или другой метод расчета есть
я ж рассказывал о нескольких массивах. сначала выбираете значение из одного, потом прибавляете значение из второго и последующих. в массивах хранить значения со знаком - тогда поправки не только в плюс, но и в минус будут и при их суммировании выйдет нужное значение.
Всегда пожалуйста. Когда научитесь хранить карты в епроме и корректировать их на ходу с компа по уарту - вот тогда прочувствуете на сколько такой подход круче ваших первых проб. Не забывайте пристегиваться за рулем!
В принципе можно хранить карты в епроме и корректировать их на ходу по уарту смесь можно смотреть через лямбда зонд
Добрый вечер, по uart передаются через терминал символьные знаки чтобы их заносить в топливную карту нужно перевести в число правильно как это возможно сделать
Самое правильное - спросить у Гугла "передача по ком-порту чисел". Первый же ответ http://pashkevich.me/article/6.html