ЭБУ для авто

Тема в разделе "Микроконтроллеры AVR", создана пользователем Yerabdi, 25 сен 2017.

  1. Yerabdi

    Yerabdi Нерд

    Здравствуйте всем написал код в ардуино нано, для управление м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;  }
    }
     
     
    Последнее редактирование: 15 ноя 2017
  2. Yerabdi

    Yerabdi Нерд

    [​IMG]
     

    Вложения:

  3. Yerabdi

    Yerabdi Нерд

    Сигнал берется от тахометра для подачи впрыска на форсы
     
  4. sslobodyan

    sslobodyan Гик

    А вы не замеряли время затрачиваемое в прерывании? Похоже, что оно как минимум равно 100мкс, а может и больше. Отсюда у рывки. Попробуйте при входе в прерывание поднять любую свободную ногу, а перед выходом опустить ее. И затем гляньте осциллографом либо цифроанализатором сколько времени нога будет поднята и с каким интервалом. Мне такой метод отладки здорово помогает.
    PS Задавать топливную карту через ифы очень не удобно. Лучше через N-мерный массив. Тогда ее можно хранить в епроме и настраивать без перекомпиляции кода. Да и накосячить в этой куче сравнений вероятность меньше.
     
  5. Yerabdi

    Yerabdi Нерд

    Не подскажите как можно написать топливную карту N-мерный массиве
     
  6. sslobodyan

    sslobodyan Гик

    Абсолютно просто.
    1-мерный массив. Зависимость только от одного параметра. К примеру, оборотов. Делим обороты на 100 и отнимаем 8. Полученный результат будет индексом массива [0..50], в котором храним расход топлива (или время открытия форсунки). Соответственно для 800 об\мин берем 0 элемент, для 900 - 1 элемент и т.д. до 5800.
    2-мерный массив. Зависимость от двух параметров (обороты и расход воздуха). Аналогично делением и отниманием приводим значения входных параметров к виду 0-N и 0-M, где N и М максимальное количество элементов в нашем массиве [N][M].
    3-мерный и дальше - аналогично.
    После получения расхода из нашей карты дополнительно корректируем на поправки (температура воздуха, температура ОЖ и т.д.)
     
  7. Yerabdi

    Yerabdi Нерд

    2-мерный массивом мне сложно работать так как не знаю как туда записывать и от туда считывать данные
     
  8. sslobodyan

    sslobodyan Гик

  9. Yerabdi

    Yerabdi Нерд

    большое спасибо за советы, одномерных массивы понимаю проблема двухмерных и трехмерных массивах
     
  10. sslobodyan

    sslobodyan Гик

    Примитивный пример. На значения не обращайте внимания - подставите свои нужные. Сам принцип.
    Код (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 ];
     
    Кстати, в настоящих ЭБУ таких двумерных (и одномерных) карт несколько и результирующий расход считают как сумму значений выбранных элементов из каждой карты.
     
  11. Yerabdi

    Yerabdi Нерд

    Значение определяется по вашей формуле первый столбец и пятая строка равняется = 5 правильно
     
  12. sslobodyan

    sslobodyan Гик

    900/100 - 8 = 1 -> вторая строка (счет всегда с 0)
    50 / 10 = 5 -> шестой столбец
    итого расход выбирается 55
    Кстати, в этой второй строке я не описал все 8 элементов, только 6. В настоящей карте надо не ошибиться и описать все варианты значений, а то подставится 0.
     
  13. Yerabdi

    Yerabdi Нерд

    Спасибо большое, все думал как уменьшить код топливный карты классный метод с массивами.
    Если по температуре заполнять карту нужно использовать трехмерный массив или другой метод расчета есть
     
  14. sslobodyan

    sslobodyan Гик

    я ж рассказывал о нескольких массивах. сначала выбираете значение из одного, потом прибавляете значение из второго и последующих. в массивах хранить значения со знаком - тогда поправки не только в плюс, но и в минус будут и при их суммировании выйдет нужное значение.
     
  15. Yerabdi

    Yerabdi Нерд

    Спасибо большое использовал в место ифов в топливной карте ваш массив код уменьшился в два раза
     
  16. sslobodyan

    sslobodyan Гик

    Всегда пожалуйста. Когда научитесь хранить карты в епроме и корректировать их на ходу с компа по уарту - вот тогда прочувствуете на сколько такой подход круче ваших первых проб. Не забывайте пристегиваться за рулем!
     
  17. Yerabdi

    Yerabdi Нерд

    В принципе можно хранить карты в епроме и корректировать их на ходу по уарту смесь можно смотреть через лямбда зонд
     
  18. Yerabdi

    Yerabdi Нерд

    У вас есть хотя бы ориентировочная топливная карта
     
  19. Yerabdi

    Yerabdi Нерд

    Добрый вечер, по uart передаются через терминал символьные знаки чтобы их заносить в топливную карту нужно перевести в число правильно как это возможно сделать
     
  20. sslobodyan

    sslobodyan Гик

    Самое правильное - спросить у Гугла "передача по ком-порту чисел". Первый же ответ http://pashkevich.me/article/6.html