Ожидание внешнего сигнала. Прошу помощи.

Vadim111
Offline
Зарегистрирован: 14.01.2015

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

В целом, эта (первая часть) задачи не была очень сложной. Ожидание подтвержающего сигнала с ВУ я реализовал с помощью функции pulseIn, в параметрах которой указал пин, на который должен придти сигнал, параметр HIGH сигнала и время, в течение которого ждать сигнал. Но проблема заключается во второй части задачи: Мне необходимо чтобы в течение всего времени работы Ардуины работала другая функциональность, например, включение/выключение диода по нажатию кнопки (с использованием других пинов - не задействованных в первой части). В отдельности, вторая часть задачи тоже очень проста. Но я не могу совместить эти две задачи. Дело в том, что пока функция pulseIn ждет внешнего сигнала и выдает информацию о нем, работа программы как бы останавливается и нажатие кнопки не отрабатывает. Если убрать функцию pulseIn, то я не могу придумать алгоритм, который бы мог ожидать внешний сигнал определенное время. Если эту функцию оставить, то получается, что Ардуина кроме этой функции уже ничего не может делать.

Подскажите пожалуйста направление в котором двигаться для решения задачи.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

как это - Подтверждением включения ВУ является мигающий на нем светодиод. ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

частота, скважность мигания - для анализа нужно !

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

задачЮ попроще обрисуйте.... алгоритм-схему определите.... а то не понятно..... :(

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ВУ - недоступен ? от него - какие сигналы могут быть ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

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

 

параметры сигнала - если ВУ включилосЯ ? Частота и скважность "мигания" ВУ ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Подскажите пожалуйста направление в котором двигаться для решения задачи.

 

...в сторону аппаратных прерываний :) два градуса в минус от зюйд-зюйд-вест :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

SU-27-16 пишет:

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

 

параметры сигнала - если ВУ включилосЯ ? Частота и скважность "мигания" ВУ ?

а если не - не прийдет подтверждающий сигнал. - зацикливание ? или чё делать ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

составте алгоритм-схему....

...Пухлявый своим ШАРОМ прожёг мине мой бубен :(

...ещё и Дохтур - прописал ЧЁТА виртуально - кодить могу ( если могу ) - тока на ......... :(

Vadim111
Offline
Зарегистрирован: 14.01.2015

Спасибо всем ответившим.

Цитата:

как это - Подтверждением включения ВУ является мигающий на нем светодиод. ?

Когда ВУ выключено, диод все время потушен, когда ВУ включилось, диод начинает мигать (именно не гореть постоянно, а мигать).

Цитата:

частота, скважность мигания - для анализа нужно !

У ВУ есть несколько режимов включения. В зависимости от того, в какой режим включилось ВУ диод мигает по разному. Варианты мигания: 1сек. Горит – 1 сек. Погашен; 2сек. Горит – 2 сек. Погашен; 2 проблеска примерно по 0,5сек. – 1 сек. Погашен.

Частота мигания диода значения не имеет. Сам факт того, что раз в 5 сек (к примеру) от диода приходит хоть один сигнал говорит о том, что ВУ включилось.

Цитата:

ВУ - недоступен ? от него - какие сигналы могут быть ?

Не совсем понял вопрос. Единственный сигнал, который можно анализировать – это мигание диода. Считывание других сигналов, даже если ВУ их и выдает, боюсь, мне будет не под силу.

Цитата:

а если не - не прийдет подтверждающий сигнал. - зацикливание ? или чё делать ?

В программе (прилагаю ниже) предусмотрена переменная – сколько раз повторять включение, если ВУ не включилось.

Ниже, на всякий случай прикладываю свой скетч. Хотел бы обратить внимание, что часть программы, которая отслеживает включение ВУ работает. Проверено физически. Часть программы, которая отвечает за нажатие кнопки тоже работает – это вообще стандартный пример. Они не работают вместе. Т.е. в тот период, когда функция pulseIn ожидает внешний сигнал никакая друга функциональность не действует, т.е. происходит примерно то же, что и с функцией delay. В примере для быстроты проверки установлено время ожидания очень малое – 2с. На практике оно гораздо больше, и в этот период нужна прочая функциональность Ардуины.

//подключаем библиотеку Bounce
#include <Bounce.h>
//дефайним значения пинов с кнопкой и со светодиодом
#define DIOD 2 // Пин для входа сигнала с диода ВУ
#define BUTTON 3 // Подключенная кнопка.
#define RALAY_VKL 11 // Подключено 1 реле для включения ВУ.
#define RALAY_ZAP 12 // Подключено 2 реле для включения ВУ.
#define LED 13 // Светодиод, который должен зажигаться и гаснуть при нажатии кнопки.

Bounce bouncer = Bounce(BUTTON,5); //создаем объект класса Bounce. Указываем пин, к которому подключена кнопка, и время дребезга в мс.

int ledValue = LOW; //задаем начальное состояние светодиода "выключен"
boolean zapusk = false; // Флаг, показывающий началась ли работа по включению ВУ.
int povtorVklCounter = 0; // Счетчик повторных включений.

// НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ:

unsigned long startWork = 3; // Задаем интервал времени (с момента включения платы),
                             // когда произойдет первое вкл. реле. (в сек.)
unsigned long restartWork = 86400; // Интервал времени, через который произойдет повторение всего цикла работы.
                                   // этот период исчисляется с момента выключения.(в сек. 86400 сек. - сутки)
unsigned long workTime = 10; // Продолжительность всего цикла работы ВУ после включения.
                             // По истечении этого времени происходит выключение ВУ.(в сек.)
float firstRelayConnectTime = 0.3; // Время замыкания первого реле (в сек.)
float secondRelayConnectTime = 0.3; // Время замыкания второго реле (в сек.)
float delay_1_2_RelayTime = 0.3; // Время задержки между замыканиями первого и второго реле (в сек.)
int povtorVklNumber = 2; // Сколько раз делать повторное включение в случае несработки.
int podtvergdSignal = 2; // Время, в течение которого ожидаем подтверждение мигания светодиода с ВУ. (в сек.)

// Функция включает ВУ.
void cameraTurnOn() {
  digitalWrite(RALAY_VKL, HIGH); // Сразу включаем первое реле.
  delay(firstRelayConnectTime * 1000); // Держим включенным первое реле установленное время.
  digitalWrite(RALAY_VKL, LOW); // Отключаем первое реле.
  delay(delay_1_2_RelayTime * 1000); // Выдерживаем паузу между включениями реле.
  digitalWrite(RALAY_ZAP, HIGH); // Включаем второе реле.
  delay(secondRelayConnectTime * 1000); // Держим включенным второе реле установленное время.
  digitalWrite(RALAY_ZAP, LOW); // Отключаем второе реле.
}

// Функция отключает ВУ.
void cameraTurnOff() {
  digitalWrite(RALAY_ZAP, HIGH); // Сразу включаем 2 реле.
  delay(firstRelayConnectTime * 1000); // Держим включенным 2 реле установленное время.
  digitalWrite(RALAY_ZAP, LOW); // Отключаем 2 реле.
  delay(delay_1_2_RelayTime * 1000); // Выдерживаем паузу между включениями реле.
  digitalWrite(RALAY_VKL, HIGH); // Включаем 1 реле.
  delay(secondRelayConnectTime * 1000); // Держим включенным 1 реле установленное время.
  digitalWrite(RALAY_VKL, LOW); // Отключаем 1 реле.
}

void setup() {
  //определяем режимы работы пинов
  pinMode(BUTTON,INPUT);
  pinMode(RALAY_VKL,OUTPUT);
  pinMode(RALAY_ZAP,OUTPUT);
  pinMode(LED,OUTPUT);
}

void loop() {
  
  unsigned long currentMillis = millis(); //функция millis() возвращ. колич. милис. с момента включения платы.
  
  // ПЕРВИЧНОЕ ВКЛЮЧЕНИЕ ВУ.
  // Если истек заданный интервал времени с момента включения Ардуины и ВУ не было включено ранее...
  if (currentMillis > startWork*1000 && zapusk == false)
  {
    // Увеличиваем интервал на время работы ВУ, после чего будет выключение.
    startWork += workTime;
    // Включаем ВУ ссответствующей функцией.
    cameraTurnOn();
    // Устанавливаем флаг работы в true - работа началась.
    zapusk = true;
  }
  
  // ВЫКЛЮЧЕНИЕ ВУ ПОСЛЕ ИСТЕЧЕНИЯ СРОКА РАБОТЫ.
  // Если истек интервал времени.
  if (currentMillis > startWork*1000 && zapusk == true)
  {
    // Увеличиваем интервал на время до следующего сеанса ВУ, после чего будет выключение.
    startWork += restartWork;
    // Выключаем ВУ сответствующей функцией.
    cameraTurnOff();
    // Устанавливаем флаг работы в false - работа закончилась.
    zapusk = false;
  }
  
  // Если прошло первичное включение ВУ, то начинаем наблюдать, включилась ли ВУ на самом деле.
  if (zapusk){
    // Если в течение времени не пришел HIGH сигнал на пин DIOD, то...
    if (pulseIn(DIOD, HIGH, podtvergdSignal * 1000000) == 0)
    {
      // Если количество реальных повторных включений не превосходит количество заданных повторных включений...
      if (povtorVklCounter < povtorVklNumber) {
        cameraTurnOn(); // Повторяем включение ВУ.
        povtorVklCounter ++; // Увеличиваем счетчик повторных включений.
      }
    } else { // Если сигнал со светодиода пришел.
      povtorVklCounter = 0; // Сбрасываем счетчик повторных включений.
    }
  }
  
  
  //если сменилось состояние кнопки
  if ( bouncer.update() ) {
    //если считано значение 1
    if ( bouncer.read() == HIGH) {
     //если свет был выключен, будем его включать
     if ( ledValue == LOW ) {
       ledValue = HIGH;
     //если свет был включен, будем выключать
     } else {
       ledValue = LOW;
     }
     //записываем значение вкл/выкл на пин со светодиодом 
     digitalWrite(LED,ledValue);
    }
  }
}

 

bwn
Offline
Зарегистрирован: 25.08.2014

Аппаратное прерывание + таймер на заданный период. Прерывание сбрасывает таймер. Если не сбросило, пинаем ВУ.

Datak
Offline
Зарегистрирован: 09.10.2014












// Эту перемекнную объявить как глобальную, или как локальную статическую в функции loop( )
//
bool Started = false;

.....

// А это всё - вставить в функцию loop( ) в любом удобном месте
//
{
   static bool LedPrevious = false;
   static int  BlinkCount  = 0;

   static unsigned long StartTime = millis( );

   if( !Started )
   {
      StartTime = millis( );
   }
   else
   {
      if( digitalRead( LED ) != LedPrevious ) // состояние светодиода изменилось?
      {
         BlinkCount++;
         LedPrevious = !LedPrevious;
      }

      if( ( millis( ) - StartTime ) >= CONTROL_TIME ) // CONTROL_TIME - время ожидания старта
      {
         if( BlinkCount < BLINK_COUNT_MIN ) // BLINK_COUNT_MIN - необходимое количество миганий за время CONTROL_TIME 
         {
            Started = false;
         }

         BlinkCount = 0;
         StartTime = millis( );
      } 
   }
}

Это я примерно, только чтобы объяснить смысл. Скорее всего, есть ошибки. :)
Но после их исправления всё должно проверяться - при старте, и даже потом, в процессе работы.

Основная часть программы должна ориентироваться на значение Started. То есть, как только видит, что ( Started == false ), сразу выполняет всю процедуру запуска, и после её завершения устанавливает Started = true;

-------

UPD: Просмотрел быстренько скетч. Если я правильно понял, при включении устройства все паузы задаются обычным delay( ) ?

Тогда, боюсь, мои советы будут бесполезными. :)
Придётся эту часть тоже переписывать. Или, действительно, попробовать организовать что-то с использованием прерываний.

Jek
Offline
Зарегистрирован: 05.01.2014

Вы бы написали что за ВУ... Очень похоже на обычный GSM модуль, там то же диодик по разному мигает при подключении к сети. Но на модуле есть специальный выход, показывающий, что он включился.

Мож и на Вашем ВУ есть...

Vadim111
Offline
Зарегистрирован: 14.01.2015

Ещё раз: всем большое спасибо.

Аппаратные прерывания - это ранее неизвестная для меня сфера. Скорее всего это правильное направление для решения вопроса. Буду изучать.

ВУ - это видеосервер старой (одной их первых) модели GV-IC 01. Разные режимы - это разные варианты подключения к сети и кодировки.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Vadim111, по-моему вы собрались пойти не той тропой :) Вам не прерывания нужны, а нужно уйти от pulseIn и от пауз.  Для этого нужно придумать механизм выхода и возврата в свою функцию. Обычно для этого используют булевую или однобайтовую переменную-флаг. В ней будет всегда находится текущее состояние алгоритма.  К примеру флаг=10 -создано условие для включения В.У., флаг=11 вы включили первый тумблер и вышли в loop покурить пока считается секунда . флаг=12 вы включили второй тумблер и вышли ждать ещё секунду. флаг=20 -содалось условие для проверки включения. Для выключения флаги на 3x  А в loop стоит проверка флага. При флаге 1x возврат в функцию включения. При флаге 3x возврат в функцию отключения. Внутри функций тоже проверка флага на предмет что делать дальше.  В таком случае контроллер всегда будет свободен, прерывания не понадобятся, и в Loop  можно добавлять новые задачи. 

bwn
Offline
Зарегистрирован: 25.08.2014

Прерывания я имел в виду образно, в данном случае неважно как будет поступать информация о событии. Принцип тот, который написал Dimax. Вам нужно модифицировать 91 строку на что то типа вашей 78. Т.е задать контрольный интервал времени и проверять было ли изменение состояния DIOD. Если было - перезадаем значение интервала и проверяем дальше. Если нет переходим к пинкам ВУ. Все обработки событий лучше вынести в отдельные функции(по типу как у вас реле), а в loop проверять интервалы, флаги и принимать решения.

При той реализации  реле как у вас, основной цикл будет заблокирован на время работы этих функций.

Не очень понятна цель задания секундных интервалов в начале программы. Эти цифры будете видеть только вы, пока работаете над ее отладкой. А вот вся ненужная математика останется там навсегда и будет занимать время процессора (обработка float не самая быстрая процедура).

 

bwn
Offline
Зарегистрирован: 25.08.2014

Хотя для данной задачи, использование прерывания кажется более оправданным со стороны оптимизации кода. Он сведется к четырем строкам: В прерывании подняли флаг. В основном цикле изменили интервал, сбросили флаг или прошли мимо если сброшен. Проверять конец интервала и принимать решения нам придется при любой реализации. А вот отслеживание события уже происходит без нашего вмешательства.

Dimax, поправьте если не прав.