эмулятор ДПКВ с корректировкой

NLegion
Offline
Зарегистрирован: 17.10.2021

Всем привет! 

Ваяю эмулятор ДПКВ с корректировкой времени задержки. 

принцип работы такой: к мозгам автомобиля подключается ардуинка на ноги датчика положения коленвала.

Мозги "видят" ее как датчик.  

НО! время задержки (delayMicroseconds) необходимо регулировать.

Решил замерять время прохождения шторки через датчик Холла. Двиг может вращаться от 600 - 5000 оборотов в минуту.

Попробовал добавить к рабочему коду что то типа: 

    int analogValue = analogRead(A2);
    start = millis();
    if (analogValue != 0)
    {duration = millis() - start;  }
    previousmillis = duration;

Полная фигня получилась, на модельке в тинкеркаде duration постоянно 0 выдает.

Прошу вспоможения в решении задачи.

Рабочий кусок кода:

int poluperiod;

void setup()
{
    pinMode(2, OUTPUT);
    pinMode(A1, INPUT);
}

void loop()
{
    int val = 70; // - 200 оборотов

    poluperiod = map(val, 0, 1023, 2500, 100);

    for (int a = 1; a <= gear - 2; a++)
    {
        digitalWrite(2, HIGH);
        delayMicroseconds(poluperiod);
        digitalWrite(2, LOW);
        delayMicroseconds(poluperiod);
    }
    delayMicroseconds(poluperiod * 4);
}

 

b707
Offline
Зарегистрирован: 26.05.2017

NLegion пишет:

Полная фигня получилась, на модельке в тинкеркаде duration постоянно 0 выдает.

конечно фигня.

Во-первых, почему analogRead() если сигнал цифровой?

Во-вторых, миллис слишком груб для этого, используйте микрос

В третьих, САМОЕ ГЛАВНОЕ - пока в основном ходе у вас есть задержки через delay() - никакой подобный код работать не сможет в принципе. А у вас ваш, считай. из одних задержек и состоит

NLegion
Offline
Зарегистрирован: 17.10.2021

по пунктам: 

1. автомобильный датчик холла - аналоговый (если я конечно не ошибаюсь).

2. принято

3. про это не понял. сам по себе приведенный кусок кода замечательно работает, или вы конкретно про замер времени?

b707
Offline
Зарегистрирован: 26.05.2017

NLegion пишет:

по пунктам: 

1. автомобильный датчик холла - аналоговый (если я конечно не ошибаюсь).

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

Цитата:
3. про это не понял. сам по себе приведенный кусок кода замечательно работает

данный кусок кода замечательно работает, но он блокирующий. Это значит, что никакой другой кусок кода, требующий точного задания или измерения времени, с этим кодом не совместим. Вам надо для начала переписать свой основной код к неблокирующему виду, например на миллис

MaksVV
Offline
Зарегистрирован: 06.08.2015

Датчик холла имеет цифровой сигнал, либо 1 либо 0. С чего вы взяли что он аналоговый  . 

MaksVV
Offline
Зарегистрирован: 06.08.2015
NLegion
Offline
Зарегистрирован: 17.10.2021

ок) я не настаиваю

NLegion
Offline
Зарегистрирован: 17.10.2021

Спасибо! прочитаю

MaksVV
Offline
Зарегистрирован: 06.08.2015

код по ссылке #5 тяжело будет для понимания. Вот упростил . (в консоли выбираем обороты, а вначале скетча количество и размер зубьев и впадин)

//--------------------------------------------
uint16_t rpm_D = 1000;    // по дефолту  1000 об/мин 

uint16_t tooth_quantity = 60;   // выбираем количество зубчиков датчика коленвала

uint16_t tooth_size  = 1; //  длина зуба    в градусах
uint16_t hole_size = 5; //  длина впадины в градусах

//сумма  зуб+впадина = 360/количество зубов (проверяем это) !!! 

bool CKPbeginLogic = 1; // логика начала сигнала колена

#define CKPpin PB0      // пин коленвала (8 пин ардуино) можно менять

//--------------------------------------------


volatile uint16_t countgrad = 1; 
volatile byte countT = 1; 
volatile byte counttooth = 1; 
volatile uint16_t rpm;     
volatile bool tooth_or_hole = 1;

void Default () 
{
 if (tooth_size+hole_size!=360/tooth_quantity) Serial.println("Неправильно выбрано количество и/или размер зубьев!!!");
rpm = rpm_D;
Serial.println ("Default settings:");
Serial.print (rpm); Serial.println (" rpm");
Serial.println();
}

void setup() {
Serial.begin(115200);
 Default () ;
  DDRB|= _BV(CKPpin);
  
 if (!CKPbeginLogic)PORTB |=_BV(CKPpin);
 
  //ниже настраиваем аппаратный таймер ардуино
  TCCR1A = 0;   
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm;  
  TIMSK1 |= (1<<OCIE1A);
}


void loop() 
{
if (Serial.available() )
          {
    static int mode = 0; 
    
    int in = Serial.read();
if (in >='0' && in <='9')       // в консоль вводим от 0 до 9, чтоб выбрать обороты(без символов конца строки)
    {
      int rpm = (in-'0')*1000;
      Serial.print (rpm); Serial.println (" rpm");
      OCR1A = 2666666UL/rpm;
    }
else if (in=='d'){Default () ; } // настройки по умолчанию
          }

}
ISR (TIMER1_COMPA_vect)

{
  
  countgrad++;
  countT++;
  if ((tooth_or_hole && countT>=tooth_size) || (!tooth_or_hole && countT>=hole_size) ) // если по градусам достигли зуба или впадины
  
  {
    tooth_or_hole = !tooth_or_hole;  // меняем состояние зуб/впадина
    countT = 0; 
    counttooth++; // увеличиваем номер текущего зуба
    if (counttooth>(tooth_quantity*2)) counttooth =1; // сбрасываем увеличение номера зуба при достижении максимума
    // ниже дергаем ногой (сигнал ДПКВ), если это не пропущенные зубья. 
    if (counttooth!=tooth_quantity*2-3&&counttooth!=tooth_quantity*2-2&&counttooth!=tooth_quantity*2-1&&counttooth!=tooth_quantity*2)PORTB ^= _BV(CKPpin);
  
  }
  if (countgrad>720) countgrad=1;

  }

 

NLegion
Offline
Зарегистрирован: 17.10.2021

MaksVV пишет:

код по ссылке #5 тяжело будет для понимания. Вот упростил . (в консоли выбираем обороты, а вначале скетча количество и размер зубьев и впадин)

 

Спасибо еще раз! вчитаюсь, но выглядит несколько сложнее чем нужно мне. 

пока, что переписываю рабочий код на версию без delay... но опять не все так как должно быть

int poluperiod;
const int ledPin = 2;
long previousMillis = 0; // храним время последнего переключения светодиода
int ledState = LOW;      // этой переменной устанавливаем состояние светодиода
int gear = 10;
long interval = 1000;

void setup()

{
    pinMode(ledPin, OUTPUT);
    pinMode(A1, INPUT);
}

void loop()

{
    unsigned long currentMillis = micros();

    for (int a = 1; a <= gear; a++)
    {

        if (currentMillis - previousMillis > interval)
        {
            previousMillis = currentMillis;
            if (a <= (gear - 2))
            {

                if (ledState == LOW)
                {
                    ledState = HIGH;
                }
                else
                {
                    ledState = LOW;
                }
            }
            else
            {
                if (ledState == HIGH)
                {
                    ledState = LOW;
                }
            }
            digitalWrite(ledPin, ledState);
        }
    }
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

создание сигнала в лупе нормально работать не будет , это я уже проходил. на 9000 об мин не успевает нормально сигнал формироваться. Я вам код дал с комментами, что именно там не понятно для пользования?

NLegion
Offline
Зарегистрирован: 17.10.2021

MaksVV пишет:

создание сигнала в лупе нормально работать не будет , это я уже проходил. на 9000 об мин не успевает нормально сигнал формироваться. Я вам код дал с комментами, что именно там не понятно для пользования?

Да в целом в нем все понятно,  но для моих целей он несколько избыточен, т.к. двиг свыше 5 000 не крутится + заморочки с параметрами венца (размер зубьев и т.д.)

MaksVV
Offline
Зарегистрирован: 06.08.2015

А как вы хотели подсунуть эбу сигнал без подбора формы сигнала (размер зубьев и количество)? Ведь эбу не понравится сигнал, если не будет соответствовать штатному. Ну если для вас заморочки три цифры ввести, то увольте.

b707
Offline
Зарегистрирован: 26.05.2017

NLegion пишет:

Да в целом в нем все понятно,  но для моих целей он несколько избыточен, т.к. двиг свыше 5 000 не крутится + заморочки с параметрами венца (размер зубьев и т.д.)

простите, но из этого ответа ясно, что вы ничего не поняли.

Формирование сигнала в любом случае надо делать через таймер, даже если обороты не слишком велики. В ЛУПе вы никогда не получите равномерной частоты

MaksVV
Offline
Зарегистрирован: 06.08.2015

NLegion пишет:

пока, что переписываю рабочий код на версию без delay... но опять не все так как должно быть

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

const byte CKPpin = 2;
uint32_t interval  = 1000; 

void setup()
{
 pinMode (CKPpin, OUTPUT);
}

void loop() 
{
 static uint32_t prev = 0; 
 if (micros()-prev > interval) 
  {
    prev = micros();
    digitalWrite (CKPpin, !digitalRead(CKPpin));
  }
//тут остальной код
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

вот еще покомментил немного 

uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

uint16_t tooth_quantity = 36; // выбираем количество зубчиков датчика коленвала

uint16_t tooth_size  = 2;     // длина зуба    в градусах
uint16_t hole_size = 8;       // длина впадины в градусах

//    зуб+впадина = 360/количество зубов (проверяем это) !!! 

bool CKPbeginLogic = 1;       // логика начала сигнала колена  (0 или 1)

#define CKPpin PB0            // пин коленвала (8 пин ардуино) можно менять


void setup() {
  Serial.begin(115200);
  if ((tooth_size+hole_size)*tooth_quantity!=360) Serial.println("Неправильно выбрано количество и/или размер зубьев!!!"); 
  Serial.print (rpm_D); Serial.println (" rpm");Serial.println();
  DDRB|= _BV(CKPpin); // пин дпкв на выход
  
  if (!CKPbeginLogic)PORTB |=_BV(CKPpin); // задаем начальный уровень сигнала дпкв
 
  //ниже настраиваем аппаратный таймер ардуино
  TCCR1A = 0;   
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm_D;  
  TIMSK1 |= (1<<OCIE1A);
}


void loop()  // луп в формировании сигнала дпкв не участвует, здесь только задаются обороты коленвала через терминал
{

  
if (Serial.available() )
          {
    byte in = Serial.read();
    if (in >='1' && in <='9')       // в консоль вводим от 1 до 9, чтоб выбрать обороты(без символов конца строки)
    {
      int rpm = (in-'0')*1000;
      Serial.print (rpm); Serial.println (" rpm");
      OCR1A = 2666666UL/rpm;
    }
         }

}

ISR (TIMER1_COMPA_vect)// обработчик таймера, сюда заходит раз в градус поворота коленвала

{
static byte countT = 0; // счетчик градусов зуба/впадины
static byte counttooth = 1; // счетчик зубов
static bool tooth_or_hole = 1; // флаг зуб/впадина

  countT++;  // прибавляем счетчик градусов зуба/впадины
  if ((tooth_or_hole && countT>=tooth_size) || (!tooth_or_hole && countT>=hole_size) ) // если по градусам достигли зуба или впадины
  {
    tooth_or_hole = !tooth_or_hole;  // меняем состояние зуб/впадина
    countT = 0;  // сбрасываем счетчик градусов зуба/впадины
    counttooth++; // увеличиваем номер текущего зуба
    if (counttooth>(tooth_quantity*2)) counttooth =1; // сбрасываем увеличение номера зуба в случае достижения максимума
    // ниже дергаем ногой (сигнал ДПКВ), если это не пропущенные зубья. 
    if (counttooth!=tooth_quantity*2-3&&counttooth!=tooth_quantity*2-2&&counttooth!=tooth_quantity*2-1&&counttooth!=tooth_quantity*2)PORTB ^= _BV(CKPpin);
  }
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Помоги немного компилятору - сделай uint16_t tooth_quantity константой - тогда tooth_quantity*2 тоже будет константой, а не постоянно вычисляться. Хотя, может, он уже и достаточно умный...

А 64 строка, как мне кажется, вообще вот так перезаписывается: if (tooth_quantity*2 - counttooth) > 3 { ... }

MaksVV
Offline
Зарегистрирован: 06.08.2015

согласен, на коленке писал, есть место для оптимизации

MaksVV
Offline
Зарегистрирован: 06.08.2015
const uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

const uint16_t tooth_quantity = 36; // выбираем количество зубчиков датчика коленвала

const uint16_t tooth_size  = 2;     // выбираем длину зуба    в градусах
const uint16_t hole_size = 8;       // выбираем длину впадины в градусах

//    зуб+впадина = 360/количество зубов (проверяем это) !!! 

const uint16_t missed_teeth = 1; // выбираем количество пропущенных зубьев

const bool CKPbeginLogic = 0;    // логика начала сигнала колена  (0 или 1)

#define CKPpin PB0               // пин коленвала (8 пин ардуино) можно менять


void setup() {
  Serial.begin(115200);
  if ((tooth_size+hole_size)*tooth_quantity!=360) Serial.println("Неправильно выбрано количество и/или размер зубьев!!!"); 
  Serial.print (rpm_D); Serial.println (" rpm");Serial.println();
  DDRB|= _BV(CKPpin); // пин дпкв на выход
  
  if (!CKPbeginLogic)PORTB |=_BV(CKPpin); // задаем начальный уровень сигнала дпкв
 
  //ниже настраиваем аппаратный таймер ардуино
  TCCR1A = 0;   
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm_D;  
  TIMSK1 |= (1<<OCIE1A);
}


void loop()  // луп в формированиим сигнала дпкв не участвует, здесь только задаются обороты коленвала через терминал
{

  
if (Serial.available() )
          {
    byte inbyte = Serial.read();
    if (inbyte >='1' && inbyte <='9')       // в консоль вводим от 1 до 9, чтоб выбрать обороты(без символов конца строки)
    {
      uint32_t rpm = (inbyte-'0')*1000;
      Serial.print (rpm); Serial.println (" rpm");
      OCR1A = 2666666UL/rpm;
    }
         }

}

ISR (TIMER1_COMPA_vect)// обрабочик таймера, сюда заходит раз в градус поворота коленвала

{
static byte countT = 0; // счетчик градусов зуба/впадины
static byte counttooth = 1; // счетчик зубов
static bool tooth_or_hole = 1; // флаг зуб/впадина

  countT++;  // прибавляем счетчик градусов зуба/впадины
  if ((tooth_or_hole && countT>=tooth_size) || (!tooth_or_hole && countT>=hole_size) ) // если по градусам достигли зуба или впадины
  {
    tooth_or_hole = !tooth_or_hole;  // меняем состояние зуб/впадина
    countT = 0;  // сбрасываем счетчик градусов зуба/впадины
    counttooth++; // увеличиваем номер текущего зуба
    if (counttooth>(tooth_quantity*2)) counttooth =1; // сбрасываем увеличение номера зуба в случае достижения максимума
    // ниже дергаем ногой (сигнал ДПКВ), если это не пропущенные зубья. 
    if ((tooth_quantity*2 - counttooth) > (missed_teeth*2-1))PORTB ^= _BV(CKPpin);
  }
}

sadman, гуд , действительно так намного лучше, теперь и количество пропущенных зубьев можно выбрать

 

NLegion
Offline
Зарегистрирован: 17.10.2021

MaksVV пишет:

вот еще покомментил немного 

uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

uint16_t tooth_quantity = 36; // выбираем количество зубчиков датчика коленвала

uint16_t tooth_size  = 2;     // длина зуба    в градусах
uint16_t hole_size = 8;       // длина впадины в градусах

на сколько критичен тип данных: uint16_t?

я попытался прогнать вот это: http://forum.vagma.ru/index.php?app=core&module=attach&section=attach&attach_id=3043

дробную часть отбросило

и еще вопрос: нет ли Вазовских параметров?

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

вазовский шкив 60 зубов и 2 пропущенных, соответственно на зуб и впадину 360/60 = 6 градусов. зуб и впадина там равны , т.е. по 3 градуса . про дроби не понял , поясните . Ну и на ВАЗе как бы индуктивный датчик, сигнал то там синус, если ещё прямоугольный основной сигнал может и съест ЭБУ , то вот где пропущенные зубья могут быть проблемы. 


uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

uint16_t tooth_quantity = 60; // выбираем количество зубчиков датчика коленвала

uint16_t tooth_size  = 3;     // длина зуба    в градусах
uint16_t hole_size = 3;       // длина впадины в градусах 


const uint16_t missed_teeth = 2; // выбираем количество пропущенных зубьев

 

NLegion
Offline
Зарегистрирован: 17.10.2021

по ссылке выше бошевский документ, у них на впадину 3.30 и на зуб 2.70.

при тесте дробные значения срезало до целых, и вылазит предупреждение, что не равно 360 градусам.

но это я чисто для интереса попробовал. меня вазовский шкив вполне устраивает

MaksVV пишет:

вазовский шкив 60 зубов и 2 пропущенных, соответственно на зуб и впадину 360/60 = 6 градусов. зуб и впадина там равны , т.е. по 3 градуса . про дроби не понял , поясните . Ну и на ВАЗе как бы индуктивный датчик, сигнал то там синус, если ещё прямоугольный основной сигнал может и съест ЭБУ , то вот где пропущенные зубья могут быть проблемы. 


uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

uint16_t tooth_quantity = 60; // выбираем количество зубчиков датчика коленвала

uint16_t tooth_size  = 3;     // длина зуба    в градусах
uint16_t hole_size = 3;       // длина впадины в градусах 


const uint16_t missed_teeth = 2; // выбираем количество пропущенных зубьев

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

этими 3,3 и 2.7 можно пренебречь , сделав 3.0 и 3.0 . Ардуина разрешение сигнала в 0.1 градуса уже не потянет

NLegion
Offline
Зарегистрирован: 17.10.2021

MaksVV пишет:

этими 3,3 и 2.7 можно пренебречь , сделав 3.0 и 3.0 . Ардуина разрешение сигнала в 0.1 градуса уже не потянет

Ясненько, благодарю. 

Но теперь следующий вопрос: как прикрутить к этому коду корректировку времени по прохождению шторки через датчик Холла. 

За один оборот шторка проходит два раза. 

Сомнения по поводу того, корректно ли будет вписывать в loop отсчёт времени по millis? 

 И второй вопрос: можно ли прописать 500, 700 и т.д. оборотов в применённом типе данных? 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Т.е. Вам надо с другого пина также имитировать сигнал датчика холла шторки трамблера? Или вы хотите считывать сигнал со шторки и считать по нему обороты? Я я не понимаю вашу фразу корректировку времени по прохождению шторки. 

Конечно же через луп задержка сигнала шторки в конечном итоге задаваться не будет. И да, Обороты любые можно сделать

MaksVV
Offline
Зарегистрирован: 06.08.2015

Чую вы хотите микропроцессорное  зажигание на карбюраторный таз прикрутить. Или не, хотите инжектор прикрутить на карбюратор,  не используя при этом дпкв, а обойдясь штатным трамблёр ом с датчиком холла. 

NLegion
Offline
Зарегистрирован: 17.10.2021

MaksVV пишет:

Чую вы хотите микропроцессорное  зажигание на карбюраторный таз прикрутить. Или не, хотите инжектор прикрутить на карбюратор,  не используя при этом дпкв, а обойдясь штатным трамблёр ом с датчиком холла. 

типа того

MaksVV
Offline
Зарегистрирован: 06.08.2015

Затея так себе. Кроме просто эмуляции сигнала дпкв, этот сигнал нужно жёстко привязать к реальному положению вала.  Чтобы легче понять, представьте что прорези на трамблёре только две, т. Е., Допустим, каждая прорезь должна попадать на пропуск зубьев сигнала дпкв. Начинаем измерять момент прохождения прорези, После того как зарегистрировали прорезь, начинаем подавать сигнал  дпкв, обороты известны, в сигнал подаются зубчики.... 60 штук. А в реальности допустим обороты в этот момент увеличились, и уже следующая прорезь зарегистрировалась, а мы ещё не все 60 зубов передали, что прикажете делать?

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

NLegion
Offline
Зарегистрирован: 17.10.2021

Пока получилось вот так: 

https://youtu.be/pRWtLwKgsJc

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

NLegion
Offline
Зарегистрирован: 17.10.2021

Хорошего ответа на вопрос у меня нет. Разве, что надеюсь, что в моем случае это будет не очень критично, т.к. двиг больших оборотов не развивает. 

ссылка на код: https://github.com/Nlegion/Arduino/blob/main/DPKV_noDelay_new_m.cpp

MaksVV
Offline
Зарегистрирован: 06.08.2015

Будет критично 100%. В коде нет никакой привязки выдаваемого  сигнала дпкв  к реальному положению вала (читай вашей шторки). Момент зажигания, слышали про такой термин, дальше продолжать? 

MaksVV
Offline
Зарегистрирован: 06.08.2015

И у меня почему то по ссылке на гитхаб 404 ошибку выдаёт, нет страницы 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Если делать только впрыск, без зажигания, то возможно как то и будет работать 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Упрощать сложный сигнал можно (например делать из 60-2 простой сигнал с прорезями, отбрасывая лишнюю, существующую информацию), а вот наоборот - из простого сигнала, сложный никак  нормально не получить, это получается придумывание информации и не соответствует реальности 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Ну и мельком в видео заметил ваши добавления в код. Читайте  про volatile и атомарность, иначе будет работать совсем не так, как вы ожидаете 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

MaksVV пишет:

И у меня почему то по ссылке на гитхаб 404 ошибку выдаёт, нет страницы 

так удалил...

MaksVV
Offline
Зарегистрирован: 06.08.2015

Я поэтому и сообщил, что ТС видимо не в курсе, что по ссылке ничего 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...

NLegion
Offline
Зарегистрирован: 17.10.2021

код: 

const uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин
const uint16_t tooth_quantity = 60; // выбираем количество зубчиков датчика коленвала
const uint16_t tooth_size = 3;      // выбираем длину зуба    в градусах
const uint16_t hole_size = 3;       // выбираем длину впадины в градусах
//    зуб+впадина = 360/количество зубов (проверяем это) !!!
const uint16_t missed_teeth = 2; // выбираем количество пропущенных зубьев
const bool CKPbeginLogic = 0;    // логика начала сигнала колена  (0 или 1)
#define CKPpin PB4               // пин коленвала (8 пин ардуино) можно менять
uint32_t T1, T2;

void setup()
{
    attachInterrupt(0, deteccion, RISING); // аппаратное прерывание по событию
    Serial.begin(115200);                  // инициализация порта вывода информации на экран
    if ((tooth_size + hole_size) * tooth_quantity != 360)
        Serial.println("Неправильно выбрано количество и/или размер зубьев!!!");
    Serial.print(rpm_D);
    Serial.println(" rpm");
    Serial.println();
    DDRB |= _BV(CKPpin); // пин дпкв на выход
    if (!CKPbeginLogic)
        PORTB |= _BV(CKPpin); // задаем начальный уровень сигнала дпкв

    //ниже настраиваем аппаратный таймер ардуино
    TCCR1A = 0;
    TCCR1B = 8;
    TCCR1B |= 1;
    OCR1A = 2666666ul / rpm_D;
    TIMSK1 |= (1 << OCIE1A);
}

void loop() // луп в формированиим сигнала дпкв не участвует, здесь только задаются обороты коленвала через терминал
{
    Serial.println(T1 * 0.000001); // вывод времени прерывания в секундах
    if (Serial.available())
    {
        byte inbyte = Serial.read();
        if (inbyte >= '1' && inbyte <= '9') // в консоль вводим от 1 до 9, чтоб выбрать обороты(без символов конца строки)
        {
            uint32_t rpm = (inbyte - '0') * 1000;
            Serial.print(rpm);
            Serial.println(" rpm");
            OCR1A = 2666666UL / rpm;
        }
    }
}

void deteccion()
{
    T1 = micros();
}

ISR(TIMER1_COMPA_vect) // обрабочик таймера, сюда заходит раз в градус поворота коленвала
{
    static byte countT = 0;                                                                 // счетчик градусов зуба/впадины
    static byte counttooth = 1;                                                             // счетчик зубов
    static bool tooth_or_hole = 1;                                                          // флаг зуб/впадина
    countT++;                                                                               // прибавляем счетчик градусов зуба/впадины
    if ((tooth_or_hole && countT >= tooth_size) || (!tooth_or_hole && countT >= hole_size)) // если по градусам достигли зуба или впадины
    {
        tooth_or_hole = !tooth_or_hole; // меняем состояние зуб/впадина
        countT = 0;                     // сбрасываем счетчик градусов зуба/впадины
        counttooth++;                   // увеличиваем номер текущего зуба
        if (counttooth > (tooth_quantity * 2))
            counttooth = 1; // сбрасываем увеличение номера зуба в случае достижения максимума
        // ниже дергаем ногой (сигнал ДПКВ), если это не пропущенные зубья.
        if ((tooth_quantity * 2 - counttooth) > (missed_teeth * 2 - 1))
            PORTB ^= _BV(CKPpin);
    }
}

 

NLegion
Offline
Зарегистрирован: 17.10.2021

Пардон, забыл расшарить видимость репозитория

MaksVV
Offline
Зарегистрирован: 06.08.2015

ua6em пишет:

MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...

существует одновременный , попарно-параллельный и фазированный впрыск, из названия думаю понятно какой как работает. Исходя из вышесказанного, форсунка открывается на определённом такте только при фазированном впрыске. Наиболее вероятно это такт впуска, ну или несколько градусов до него. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

NLegion, пост #35, внимательно...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

MaksVV пишет:

ua6em пишет:

MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...

существует одновременный , попарно-параллельный и фазированный впрыск, из названия думаю понятно какой как работает. Исходя из вышесказанного, форсунка открывается на определённом такте только при фазированном впрыске. Наиболее вероятно это такт впуска, ну или несколько градусов до него. 

благодарю, почитаю, а то я только ГАЗ-51 знаю