эмулятор ДПКВ с корректировкой
- Войдите на сайт для отправки комментариев
Вс, 17/10/2021 - 15:02
Всем привет!
Ваяю эмулятор ДПКВ с корректировкой времени задержки.
принцип работы такой: к мозгам автомобиля подключается ардуинка на ноги датчика положения коленвала.
Мозги "видят" ее как датчик.
НО! время задержки (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);
}
Полная фигня получилась, на модельке в тинкеркаде duration постоянно 0 выдает.
конечно фигня.
Во-первых, почему analogRead() если сигнал цифровой?
Во-вторых, миллис слишком груб для этого, используйте микрос
В третьих, САМОЕ ГЛАВНОЕ - пока в основном ходе у вас есть задержки через delay() - никакой подобный код работать не сможет в принципе. А у вас ваш, считай. из одних задержек и состоит
по пунктам:
1. автомобильный датчик холла - аналоговый (если я конечно не ошибаюсь).
2. принято
3. про это не понял. сам по себе приведенный кусок кода замечательно работает, или вы конкретно про замер времени?
по пунктам:
1. автомобильный датчик холла - аналоговый (если я конечно не ошибаюсь).
В любом случае сравнивать результат analogRead() с нулем - это тупиковый путь, там шумы в десятки единиц. Надо сначала померить выход датчика в замкнутом и разомкнутом состояниях и определить границы значений для каждого случая
данный кусок кода замечательно работает, но он блокирующий. Это значит, что никакой другой кусок кода, требующий точного задания или измерения времени, с этим кодом не совместим. Вам надо для начала переписать свой основной код к неблокирующему виду, например на миллис
Датчик холла имеет цифровой сигнал, либо 1 либо 0. С чего вы взяли что он аналоговый .
Вот почитайте
ок) я не настаиваю
Спасибо! прочитаю
код по ссылке #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; }код по ссылке #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); } } }создание сигнала в лупе нормально работать не будет , это я уже проходил. на 9000 об мин не успевает нормально сигнал формироваться. Я вам код дал с комментами, что именно там не понятно для пользования?
создание сигнала в лупе нормально работать не будет , это я уже проходил. на 9000 об мин не успевает нормально сигнал формироваться. Я вам код дал с комментами, что именно там не понятно для пользования?
Да в целом в нем все понятно, но для моих целей он несколько избыточен, т.к. двиг свыше 5 000 не крутится + заморочки с параметрами венца (размер зубьев и т.д.)
А как вы хотели подсунуть эбу сигнал без подбора формы сигнала (размер зубьев и количество)? Ведь эбу не понравится сигнал, если не будет соответствовать штатному. Ну если для вас заморочки три цифры ввести, то увольте.
Да в целом в нем все понятно, но для моих целей он несколько избыточен, т.к. двиг свыше 5 000 не крутится + заморочки с параметрами венца (размер зубьев и т.д.)
простите, но из этого ответа ясно, что вы ничего не поняли.
Формирование сигнала в любом случае надо делать через таймер, даже если обороты не слишком велики. В ЛУПе вы никогда не получите равномерной частоты
пока, что переписываю рабочий код на версию без 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)); } //тут остальной код }вот еще покомментил немного
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); } }Помоги немного компилятору - сделай uint16_t tooth_quantity константой - тогда tooth_quantity*2 тоже будет константой, а не постоянно вычисляться. Хотя, может, он уже и достаточно умный...
А 64 строка, как мне кажется, вообще вот так перезаписывается: if (tooth_quantity*2 - counttooth) > 3 { ... }
согласен, на коленке писал, есть место для оптимизации
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, гуд , действительно так намного лучше, теперь и количество пропущенных зубьев можно выбрать
вот еще покомментил немного
на сколько критичен тип данных: uint16_t?
я попытался прогнать вот это: http://forum.vagma.ru/index.php?app=core&module=attach§ion=attach&attach_id=3043
дробную часть отбросило
и еще вопрос: нет ли Вазовских параметров?
вазовский шкив 60 зубов и 2 пропущенных, соответственно на зуб и впадину 360/60 = 6 градусов. зуб и впадина там равны , т.е. по 3 градуса . про дроби не понял , поясните . Ну и на ВАЗе как бы индуктивный датчик, сигнал то там синус, если ещё прямоугольный основной сигнал может и съест ЭБУ , то вот где пропущенные зубья могут быть проблемы.
по ссылке выше бошевский документ, у них на впадину 3.30 и на зуб 2.70.
при тесте дробные значения срезало до целых, и вылазит предупреждение, что не равно 360 градусам.
но это я чисто для интереса попробовал. меня вазовский шкив вполне устраивает
вазовский шкив 60 зубов и 2 пропущенных, соответственно на зуб и впадину 360/60 = 6 градусов. зуб и впадина там равны , т.е. по 3 градуса . про дроби не понял , поясните . Ну и на ВАЗе как бы индуктивный датчик, сигнал то там синус, если ещё прямоугольный основной сигнал может и съест ЭБУ , то вот где пропущенные зубья могут быть проблемы.
этими 3,3 и 2.7 можно пренебречь , сделав 3.0 и 3.0 . Ардуина разрешение сигнала в 0.1 градуса уже не потянет
этими 3,3 и 2.7 можно пренебречь , сделав 3.0 и 3.0 . Ардуина разрешение сигнала в 0.1 градуса уже не потянет
Ясненько, благодарю.
Но теперь следующий вопрос: как прикрутить к этому коду корректировку времени по прохождению шторки через датчик Холла.
За один оборот шторка проходит два раза.
Сомнения по поводу того, корректно ли будет вписывать в loop отсчёт времени по millis?
И второй вопрос: можно ли прописать 500, 700 и т.д. оборотов в применённом типе данных?
Т.е. Вам надо с другого пина также имитировать сигнал датчика холла шторки трамблера? Или вы хотите считывать сигнал со шторки и считать по нему обороты? Я я не понимаю вашу фразу корректировку времени по прохождению шторки.
Конечно же через луп задержка сигнала шторки в конечном итоге задаваться не будет. И да, Обороты любые можно сделать
Чую вы хотите микропроцессорное зажигание на карбюраторный таз прикрутить. Или не, хотите инжектор прикрутить на карбюратор, не используя при этом дпкв, а обойдясь штатным трамблёр ом с датчиком холла.
Чую вы хотите микропроцессорное зажигание на карбюраторный таз прикрутить. Или не, хотите инжектор прикрутить на карбюратор, не используя при этом дпкв, а обойдясь штатным трамблёр ом с датчиком холла.
типа того
Затея так себе. Кроме просто эмуляции сигнала дпкв, этот сигнал нужно жёстко привязать к реальному положению вала. Чтобы легче понять, представьте что прорези на трамблёре только две, т. Е., Допустим, каждая прорезь должна попадать на пропуск зубьев сигнала дпкв. Начинаем измерять момент прохождения прорези, После того как зарегистрировали прорезь, начинаем подавать сигнал дпкв, обороты известны, в сигнал подаются зубчики.... 60 штук. А в реальности допустим обороты в этот момент увеличились, и уже следующая прорезь зарегистрировалась, а мы ещё не все 60 зубов передали, что прикажете делать?
Я уже не говорю про проблему того, что ориг датчик индуктивный и имеет сигнал синуса, а вы ему меандр запихнуть пытаетесь.
Пока получилось вот так:
https://youtu.be/pRWtLwKgsJc
Видео конечно красивое и увлекательное, но можно код глянуть в итоге какой получился? Вы не ответили на вопрос, который я постом выше задал, а он очень важный
Хорошего ответа на вопрос у меня нет. Разве, что надеюсь, что в моем случае это будет не очень критично, т.к. двиг больших оборотов не развивает.
ссылка на код: https://github.com/Nlegion/Arduino/blob/main/DPKV_noDelay_new_m.cpp
Будет критично 100%. В коде нет никакой привязки выдаваемого сигнала дпкв к реальному положению вала (читай вашей шторки). Момент зажигания, слышали про такой термин, дальше продолжать?
И у меня почему то по ссылке на гитхаб 404 ошибку выдаёт, нет страницы
Если делать только впрыск, без зажигания, то возможно как то и будет работать
Упрощать сложный сигнал можно (например делать из 60-2 простой сигнал с прорезями, отбрасывая лишнюю, существующую информацию), а вот наоборот - из простого сигнала, сложный никак нормально не получить, это получается придумывание информации и не соответствует реальности
Ну и мельком в видео заметил ваши добавления в код. Читайте про volatile и атомарность, иначе будет работать совсем не так, как вы ожидаете
И у меня почему то по ссылке на гитхаб 404 ошибку выдаёт, нет страницы
так удалил...
Я поэтому и сообщил, что ТС видимо не в курсе, что по ссылке ничего
MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...
код:
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); } }Пардон, забыл расшарить видимость репозитория
MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...
существует одновременный , попарно-параллельный и фазированный впрыск, из названия думаю понятно какой как работает. Исходя из вышесказанного, форсунка открывается на определённом такте только при фазированном впрыске. Наиболее вероятно это такт впуска, ну или несколько градусов до него.
NLegion, пост #35, внимательно...
MaksVV
не по теме но копать не хочется, спрошу тут, а впрыск форсунки в какой момент открывается? по идее на подходе к НМТ но всё же ...
существует одновременный , попарно-параллельный и фазированный впрыск, из названия думаю понятно какой как работает. Исходя из вышесказанного, форсунка открывается на определённом такте только при фазированном впрыске. Наиболее вероятно это такт впуска, ну или несколько градусов до него.
благодарю, почитаю, а то я только ГАЗ-51 знаю