Как отследить наличие/отсутствие сигнала?

kost82
Offline
Зарегистрирован: 30.11.2015

Добрый день!

У меня есть такая задачка: нужно отследить наличие/отсутствие сигналов (импульсы прямоугольной формы) на входах ардуино. Импульсы берем с датчика КПП и таходатчика автомобиля. Обороты двигателя и скорость движения машины знать не обязательно - пусть этим занимается штатная панель приборов. Нужно отследить следующие события, например: скорость автомобиля нулевая (сигналов с датчика скорости нет), двигатель заглушили - через секунду включить подсветку салона. Или наоборот: двигатель работает, автомобиль поехал - включить ходовые огни.

Пока вижу два варианта:

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

2. В основном цикле программы отслеживать состояние входов. И если состояние изменяется - значит двигатель работает (или машина едет). Тут наверно надо записывать время последнего изменения и последнее состояние. Зато мы не отвлекаемся от основной программы. Единственное что меня беспокоит в этом варианте - скорей всего сигнал будет меняться за несколько циклов loop() поэтому не в каждом цикле мы будем точно знать есть обороты или нет.

Прошу у гуру подсказки как лучше реализовать этот функционал? Может я драматизирую и на прерываниях все будет прекрасно работать. Либо есть какой-то еще вариант?

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

А что, с КПП прямо мегагерцы валят, чтобы всё блокировать? Полезная нагрузка ардуины - это, по ходу дела, только лампочка. 

kost82
Offline
Зарегистрирован: 30.11.2015

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

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

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

Если сигнал один, то можно подвеситься на Overflow interrupt vector таймера #1 (328P) - тогда достаточно будет парой флагов оперировать, а остальное будет практически на железячном уровне отрабатывать.

А в 328PB уже три таймера могут захватывать сигналы.

Гриша
Offline
Зарегистрирован: 27.04.2014

для тахометра можно собрать детектор с разделительным конденсатором (ФВЧ) и опрашивать его через АЦП. обороты обычной зажигалки не ниже 600-700 для детектора достаточно. А скорость посадить на прерывание, тогда даже малые скорости можно фиксировать. 

алгоритм целиком зависит от фантазии... к примеру если АЦП< хх двигатель заглушен... если машина едет прерывание скидывает некий счетчик (таймер)... если таймер достиг некоторого значения останавливаем его что-то делаем, ставим флаг и ждем следующего прерывания для сброса флага и запуска таймера......... и еще масса вариаций - полет фантазии свободный :))))))))))))

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

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

kost82 пишет:

У меня есть такая задачка: нужно отследить наличие/отсутствие сигналов (импульсы прямоугольной формы) на входах ардуино. 

Как-то мне потребовалось быстренько написать функцию получения значения ШИМ. Если частоты в районе 400Гц то можно ее попробовать использовать. Прерывания не используются. Просто тупо много раз опрашивается пин.


// Измерение входящего сигнала ШИМа
// Возвращает значение рабочего цикла в целых процентах
// Рaботает в диапазоне 100Гц - 1МГц, при 16М тактовой.
// Может и от 50Гц, но точность немного падает
// Время измерения ~110 миллисекунд
// Если нужны более точные измерения при низкой частоте ШИМа, раскоментируйте однн из _delay_us


#define InPin 3  //Используемый пин. Работает для пинов D3-D7 (D0-D7 если не нужен сериал порт).
// Если нужны другие пины, то надо также переопределить IN_PORT и IN_PIN

uint8_t getPWMpercent()
{

#define IN_PORT PIND
#define IN_PIN  InPin
#define SAMPLES 65000
  volatile uint8_t state;
  volatile uint16_t res1 = 0;
  volatile uint16_t res0 = 0;
  pinMode(InPin, INPUT);
  for (uint16_t i = 0; i < SAMPLES; i++)
  {
    state = IN_PORT & _BV(IN_PIN);
    if (state)    res1++;
    if (!state)   res0++;
    // раскоменнтируете одну из следующую строку если надо работать на более низких частотах ШИМ
    // _delay_us(2);  //От 50 Гц. Время работы ~240 миллисекунд.
    // _delay_us(8);  //От 25 Гц. Время работы ~630 миллисекунд.
  }
  uint32_t in = uint32_t(res1) * 100 * 10 / SAMPLES  ; //результат в процентах *10;
  //округляем до целых
  uint8_t rv = in / 10;
  if ((in % 10) >= 5) ++rv;
  return rv;
}

Блин, написание комментариев заняло в 3 раза больше времени чем самого кода.