Блокировка двигателя при повышенных оборотах
- Войдите на сайт для отправки комментариев
Сб, 11/01/2020 - 19:39
Добрый день!
Имею дизельный авто. Иногда, очень редко при дистанционном запуске авто обороты мотора "взлетают" больше 2000. Выключу - запущу двигатель все нормально. Для дизеля это очень много, при погреве.
Сервис сказал что необходимо менять топливную аппаратуру, стоит .....много.
Так как электронику знаю не плохо, решил собрать блокиратор двигателя. Естественно на современной базе.
Arduino занимаюсь совсем немного (начинающий), набросал небольшой скетч блокировки.
Собрал схему, но не работает. Сигнал на схему подаю от сетевого трансформатора + согласование уровней, гальвано развязка (50 Гц.=3000 об/мин.=25 импульсов/сек). Уровень входного сигнала проверил осцилографом, меандр качественный.
Скетч компилируется, но схема не работает.
В чем проблема не пойму, может кто объяснит, если не затруднит, в чем "косяк" или подсчет таким образом изначально тупик.
СПАСИБО!!!
#define Tahometr A0 // вход от тахометра
#define LED 5 // выход на блокировку мотора
unsigned long time;
unsigned int PRM = 0; // задаем счетчик оборотов
int a = 0;
void setup() {
pinMode(Tahometr, INPUT); // через резистор на 5V
pinMode(LED, OUTPUT);
}
void loop() {
if (digitalRead(Tahometr) == LOW && a == 0) // если есть сигнал тахометра LOW, запомнить время последнего оборота
{
time = millis();
}
if (digitalRead(Tahometr) == HIGH ) // если на тахометре сигнал high
{
a = 1;
}
if (digitalRead(Tahometr) == LOW && a == 1) // если есть сигнал тахометра снова LOW
{ time = millis() - time; //вычислить время оборота
PRM = 1000 / time; // вычисляем обороты, секунду делим на подсчитанное время между сигналами с тахометра
}
/*__если обороты больше 1500 об/мин =25 импульсов/сек, включаем Stop двигателя, (для эксперимента эл. сеть 50Гц = 50 импульсов/сек)__*/
if (PRM > 20) { // не правильно считает,всегда включается до значений PRM > 99, затем какоето переполнение при PRM > 100 не включается
digitalWrite(LED, HIGH);
}
/*__если обороты меньше 1500 двигатель продолжает работать__*/
if (PRM <= 20) { // не сбрасывается при пропадании импульсов
digitalWrite(LED, LOW);
}
a = 0;
}
Можно проще, задействовать прерывание (int0 или int1)
Строка #35 точно на месте стоит?
Строка #35 точно на месте стоит?
тогда уж и micros() использовать, здесь жеж меньше одной миллисекунды не взять
Функцию pulseIn использовать. В loop будет 5 строк и всё будет работать. Даже в обороты не надо пересчитывать. Проверять ширину и всё. Помнить что без импульсов на ноге возвращает 0 через таймаут. http://arduino.ru/Reference/PulseIn
Скорректировал скетч, картина абсолютно не изменилась. Так же не считает корректно обороты при повышении и не сбрасывает при оборотах =0.
int Tahometr = A0; // вход от тахометра int LED = 5; // выход на блокировку мотора unsigned long time; unsigned int PRM = 0; // задаем счетчик оборотов int a = 0; void setup() { pinMode(Tahometr, INPUT); // через резистор на 5V pinMode(LED, OUTPUT); } void loop() { if (digitalRead(Tahometr) == LOW && a == 0) // если есть сигнал тахометра LOW, запомнить время последнего оборота { time = micros(); } if (digitalRead(Tahometr) == HIGH ) a = 1; // если на тахометре сигнал high if (digitalRead(Tahometr) == LOW && a == 1) // если есть сигнал тахометра снова LOW { time = micros() - time; //вычислить время оборота PRM = 1000000 / time; // вычисляем обороты, секунду делим на подсчитанное время между сигналами с тахометра a = 0; } /*__если обороты больше 1500 об/мин =25 импульсов/сек, включаем Stop двигателя, (для эксперимента эл. сеть 50Гц = 50 импульсов/сек)__*/ if (PRM > 25) { // не правильно считает,всегда включается до значений PRM > 99, затем какоето переполнение при PRM > 100 не включается digitalWrite(LED, HIGH); } /*__если обороты меньше 1500 двигатель продолжает работать__*/ if (PRM <= 25) { // не сбрасывается при пропадании импульсов digitalWrite(LED, LOW); } }Каким образом Вы понимаете, что обороты посчитаны неправильно (в цифровом значении)?
Иван, опишите переменную PRM тоже как long
показывайте свою схему, а то 50 Гц = 25 импульсов/сек) - не катит по арифметике
и алгоритм стоило бы изменить, оценивать сколько импульсов пришло на заданный интервал, больше или меньше заданного значения.
Вот откопал код расчета скорости по импульсам. Пришлось высчитать волшебное число 618, уже не помню зачем, но работало очень четко.
#pragma once #include <Arduino.h> #include "fir.h" #include "timer.h" #include "pwm.h" ///// Настрйки считывания скорости с магнитов. // Минимальный возможный интервал между срабатываниями датчика (на максимальной скорости). constexpr uint32_t min_delay = 20; // Максимальный возможный интервал. Всё, что медленнее считаем за 0. constexpr uint32_t max_delay = 200; Fir_filter<uint16_t, 32> filter_speed; volatile uint32_t last_fall = 0; volatile uint32_t last_delay = max_delay; Timer mainLoop; Timer statsLoop; void hall_fall() { auto ms = millis(); last_delay = ms - last_fall; last_fall = ms; } void method_setup() { mainLoop.start(20); statsLoop.start(1000); } // c = 0,61803398874989484820458683436564 // для 1 / (0 + c) - c = 1 // 1 / (1 + c) - c = 0 void method_loop() { if(mainLoop.done()) { mainLoop.start(20); cli(); auto delay = max(millis() - last_fall, last_delay); sei(); auto delay1 = min(delay, max_delay) - min_delay; // Приводим гиперболу "1 / интервал" к скорости в диапазоне 0-1000 auto speed = 1000000 / (delay1 * 1000 / (max_delay - min_delay) + 618) - 618; filter_speed.write(speed); PWM::set(filter_speed.read()); if (statsLoop.done()) { statsLoop.start(1000); Serial.print("холл: "); Serial.print(delay); Serial.print(" скорость: "); Serial.print(speed); Serial.println(); } } }Сообразил, тут считается не реальная скорость, а воображаемый диапазон 0-1000, пропорциональный max_speed и min_speed. Тогда из этого кода полезна только строчка
auto delay = max(millis() - last_fall, last_delay);которая сводит скорость к нулю в случае полной остановки и отсутствия импульсов,
Зачем считать все миллисами/микросами и ТД ?
Аппаратный таймер включи , скажем с предделителем 64 и внешнее прерывание.
По прерыванию сбрасываешь счётчик TCNT если таймер дотикал до нужной отметки.
А если не дотикал, а прерывание пришло повторно, то тогда уже и вырубай.
15-20строк кода.
Читай про "аппаратный таймер", "внешнее прерывание".
Могу помочь на коммерческой основе, но это уже другая история.
#include <WDT.h> #define LED 5 //Выход счетчика #define Taho 2 //Вход сигнал тахометра volatile unsigned long microcod = 0; //Предыдущее значение таймера volatile unsigned int rpm = 0; //Обороты коленвала, об/мин volatile unsigned int rpmOFF = 0; //Обороты коленвала для отключения коротких каналов, об/мин volatile byte T_res = 0; //счетчик обнуления volatile boolean T_trig = false; //триггер void setup() { // Serial.begin(9600); // для контроля в Serial, считает или нет, можно закомментировать pinMode(LED, OUTPUT); pinMode(Taho, INPUT_PULLUP); //При включении зажигания выключить LED digitalWrite(LED, LOW); //По умолчанию LED выключено //Устанавливаем вход тахометра //digitalWrite(Taho, HIGH); //Внутренняя подтяжка attachInterrupt(0, Scan, FALLING); //Устанавливаем считывание оборотов через прерывание } void loop() { // Serial.println(rpm); // для контроля в Serial, считает или нет, можно закомментировать if (T_res != 0) { T_res--; } else { rpm = 0; }; rpmOFF = rpm + 100; // время подсчета пропусков оборотов +1--+100, чем больше, тем точнеев подсчет //Если текущие обороты больше или равны заданным, с учетом времени реакции, то включаем LED. //В противном случае выключаем LED if (rpm >= 1500) { digitalWrite(LED, HIGH); } else if (rpm < 1500) { digitalWrite(LED, LOW); } delay(50); } //Считывание оборотов void Scan() { if (!T_trig) { microcod = millis(); } else { rpm = (1000 / (millis() - microcod)) * 60 / 2; //об/мин. импульсы 2 раза на один оборот. } T_trig = !T_trig; T_res = 100; // счетчик обнуления, чем больше, тем больше время сброса LED в LOW, 1000~~15сек }с чего Вы решили, что не допустимо, в компьютере все устройства требующие безотлагательной обработки завязаны на прерывания, для этого они и придуманы, чтобы ничего не пропустить
К примеру если я возьму разработку автозапуска двигателя автомобиля из одного из источников;
http://arduino.ru/forum/proekty/avtomaticheskii-zapusk-dvigatelya-avtomo...
http://arduino.ru/forum/proekty/kotntroller-distantsionnogo-progreva-avt...
https://github.com/martinhol221/SIM800L_DTMF_control
То везде анализ заведенного двигателя берется с лампы зарядки или давления масла, что не корректно. Если я вставлю кусок кода приведенного выше, для подсчета оборотов-анализа работающего двигателя. То вовремя считывания оборотов двигателя по прерыванию, attachInterrupt. Программа автопрогрева будет непрерывно приостанавливаться. А хотелось бы что бы этот кусок кода не прерывал основной программы, а крутился в функции не мешающей основному коду.
Как уйти от анализа по прерыванию, к анализу без прерываний основного кода. Может это кто то уже решал, скинте ссылку.
ПОЖАЛУЙСТА! СПАСИБО!
Как уйти от анализа по прерыванию, к анализу без прерываний основного кода. Может это кто то уже решал, скинте ссылку.
так не бывает на AVR. если это будет не прерывание, то ваш кусок кода по-любому будет крутиться в "функции" (читай цикл loop) основного кода. А значит должен как можно быстрее выполняться, чтобы не мешать оному.
Дело в том, что как раз основной код будет тормозить ваш анализ оборотов, т.к. импульсы бегут быстро, а тот код по ссылкам писали далеко не профи и уверен, что там есть и delay- и/или блокирующие циклы.
ПС. всегда, задавая вопрос , связанный с автомобилем, пишите что за автомобиль.