Блокировка двигателя при повышенных оборотах

ivan163
Offline
Зарегистрирован: 07.01.2020
Добрый день! 
Имею дизельный авто. Иногда, очень редко при дистанционном запуске авто обороты мотора "взлетают" больше 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;
}

 

 

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

Можно проще, задействовать прерывание (int0 или int1)

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

Строка #35 точно на месте стоит?

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

sadman41 пишет:

Строка #35 точно на месте стоит?

тогда уж и micros() использовать, здесь жеж меньше одной миллисекунды не взять

nik182
Offline
Зарегистрирован: 04.05.2015

Функцию pulseIn использовать. В loop будет 5 строк и всё будет работать. Даже в обороты не надо пересчитывать. Проверять ширину и всё. Помнить что без импульсов на ноге возвращает 0 через таймаут. http://arduino.ru/Reference/PulseIn

 

ivan163
Offline
Зарегистрирован: 07.01.2020

Скорректировал скетч, картина абсолютно не изменилась. Так же не считает корректно обороты при повышении и не сбрасывает при оборотах =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);
  }

}

 

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

Каким образом Вы понимаете, что обороты посчитаны неправильно (в цифровом значении)?

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

Иван, опишите переменную PRM тоже как long

ВН
Offline
Зарегистрирован: 25.02.2016

ivan163 пишет:
Сигнал на схему подаю от сетевого трансформатора + согласование уровней, гальвано развязка (50 Гц.=3000 об/мин.=25 импульсов/сек). Уровень входного сигнала проверил осцилографом, меандр качественный.

показывайте свою схему, а то 50 Гц = 25 импульсов/сек)  - не катит по арифметике

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

rkit
Offline
Зарегистрирован: 23.11.2016

Вот откопал код расчета скорости по импульсам. Пришлось высчитать волшебное число 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();
        }
    }
}

 

rkit
Offline
Зарегистрирован: 23.11.2016

Сообразил, тут считается не реальная скорость, а воображаемый диапазон 0-1000, пропорциональный max_speed и min_speed. Тогда из этого кода полезна только строчка

auto delay = max(millis() - last_fall, last_delay);

которая сводит скорость к нулю в случае полной остановки и отсутствия импульсов,

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Зачем считать все миллисами/микросами и ТД ?
Аппаратный таймер включи , скажем с предделителем 64 и внешнее прерывание.
По прерыванию сбрасываешь счётчик TCNT если таймер дотикал до нужной отметки.
А если не дотикал, а прерывание пришло повторно, то тогда уже и вырубай.
15-20строк кода.
Читай про "аппаратный таймер", "внешнее прерывание".

Могу помочь на коммерческой основе, но это уже другая история.

ivan163
Offline
Зарегистрирован: 07.01.2020
Спасибо всем кто откликнулся.
ОООчень долго немог добраться до компьютера. Сделал как и советовали, подсчет оборотов через прерывание, attachInterrupt.
Все работает.
#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сек
}
Но как говорится оппетит приходит... На форуме arduino.ru, не однократно видел скетчи для автозапуска авто. И там везде ведется контроль по зарядке или давлению масла. У меня был авто, "китаец", в котором при прокрутке стартера сразу тухла лампа зарядки, а давление масла мгновенно повышалось, что абсолютно не правильно для анализа заведенного двигателя. И если вставить выше приведенный код побсчета оборотов, в другой скетч, то опрос оборотов будет через прерывание, что не допустимо для выполнения программы по авто запуску автомобиля. Ну не ставить же дополнительную плату только для подсчета оборотов (может так и проще, но без грамотней). Может есть у кого мысль как подкорректировать выше приведенный скетч в подсчету оборотов не через прерывание.
 

 

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

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

ivan163
Offline
Зарегистрирован: 07.01.2020

К примеру если я возьму разработку автозапуска двигателя автомобиля из одного из источников;

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. Программа автопрогрева будет непрерывно приостанавливаться. А хотелось бы что бы этот кусок кода не прерывал основной программы, а крутился в функции не мешающей основному коду. 

Как уйти от анализа по прерыванию, к анализу без прерываний основного кода. Может это кто то уже решал, скинте ссылку. 

ПОЖАЛУЙСТА! СПАСИБО!

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

ivan163 пишет:
А хотелось бы что бы этот кусок кода не прерывал основной программы, а крутился в функции не мешающей основному коду. 

Как уйти от анализа по прерыванию, к анализу без прерываний основного кода. Может это кто то уже решал, скинте ссылку.

так не бывает на AVR. если это будет не прерывание, то  ваш кусок кода по-любому будет крутиться в "функции" (читай цикл loop) основного кода. А значит должен как можно быстрее выполняться, чтобы не мешать оному. 

Дело в том, что как раз основной код будет тормозить ваш анализ оборотов, т.к. импульсы бегут быстро, а тот код по ссылкам писали далеко не профи и уверен, что там есть и delay- и/или блокирующие циклы.

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