Нужна помощь- считывание мигающего светодиода.

dinovasya
Offline
Зарегистрирован: 03.10.2013

Поставил перед собой такую задачу:

Имеется 5 светодиодов на плате.  по этим пяти светодиодам можно узнать состояние устройства.

Светодиоды могут: гореть, не гореть, мигать с частотой 2Гц, мигать с частотой 4 Гц.

Я хочу подключиться к этим 5-ти светодиодам с помощью Arduino Uno, считывать состояние всех пяти светодиодов и вывести сообщение через сериал в монитор ноута.

Всего 6 различных сочетаний горения светодиодов.

1) 1-0-0-1-(1)

2) 0-(1)-1-0-((1))

3) 0-((1))-1-0-((1))

4) (1)-0-1-0-((1))

5) ((1))-0-1-0-((1))

6) 0-0-1-0-((1))

где

0-выключенный светодиод

1-включенный светодиод

(1)-светодиод мигает с частотой 2Гц

((1))-светодиод мигает с частотой 4 Гц.

 

Для каждого из 6-ти случаев у меня есть готовое сообщение на русском языке, которое должно serial printиться.

Начинаю: подсоединяю 5 светодиодов к входам 3,4,5,6,7 на ардуине.

const int Led1= 3;

const int Led2= 4;

const int Led3= 5;

const int Led4= 6;

const int Led5= 7;

 

void setup() {

pinMode(Led1, Input);

pinMode(Led2, Input);

pinMode(Led3, Input);

pinMode(Led4, Input);

pinMode(Led5, Input);

}

 

void loop() {

if (Led1=High, Led2=Low, Led3=Low, Led4=High, Led5=Flash2);

serialprint= "срочно протрите стекло сканера. Устройство в работе."

else

if (Led1=Low, Led2=Flash2, Led3=HIgh, Led4=Low, Led5=Flash4)

serialprint= "Потрите стекло и перезапустите сканер"

 

Вот тут я и растерялся- написал пока Flash2 и Flash4, что значит мигание с частотой 2 либо 4 герца.

Как устроить циклическую проверку мигания светодиодов?

Аналоговые или цифровые входы использовать?

К шим входам надо подключать или всё равно...

 

Прошу помочь разобраться как грамотно написать такое...

 

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

dinovasya, тут возможны варианты алгоритмов. Первое, что пришло в голову - делать блоки считывания скажем по 2 секунды, с периодом например 10ms. Каждый пин опрашивается, и если его состояние меняется, то счётчик в течении 2 секунд инкременируется. Если не меняется, то считанное значение не инкременируется. Таким образом получим в конце функции переменные, в которых будут лежать либо единицы, либо нули, либо  какие-то числа. По их значению этих чисел можно определить, что это было 2гц или 4гц. 

dinovasya
Offline
Зарегистрирован: 03.10.2013

Мнекажется что надо опрашивать все светодиоды в течении скажем, менее 2 секунд, чтоб не нарваться на изменение данных во время измерения..

 

Какие функции использовать нужно?

leshak
Offline
Зарегистрирован: 29.09.2011

>Для каждого из 6-ти случаев у меня есть готовое сообщение на русском языке, которое должно serial printиться.

А вы вообще пытались что-нибудь на русском выводить? ну так, чисто перед тем как "в алгоритмы занырнуть"?

 

com
Offline
Зарегистрирован: 06.09.2013

leshak пишет:

А вы вообще пытались что-нибудь на русском выводить? ну так, чисто перед тем как "в алгоритмы занырнуть"?

тс-с-с-с.... не спугни!

com
Offline
Зарегистрирован: 06.09.2013

а по сути задачи замечания

1) комбинация диодов 4-5-6 горит всего в двух вариантах, поэтому можно вместо этих трех опрашивать только какой-нибудь один, например 4, а 5 и 6 однозначно от него зависят

2) диоды разные бывают, и на 1.5в, и на 3.4в. надо бы с уровнем сигнала определиться. взять и померить вольметром.

3) у моргания какая скважность? может, можно поставить/подобрать сглаживающий фильтр,  чтобы потом просто читать (почти)постоянный уровень сигнала? он может быть разный при 2 гц и 4 гц

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

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

Не столь важно. главное до токоограничивающего резистора подключиться. 

А зачем?, если это решается програмно 

Если зная что сигнал меняется 4 раза в секунду (4 Гц). считывать его с частотой в 4 раза ваше (из теории сигналов достаточно в 2 раза выше, но нам же надо наверняка) . т.е. 16 Гц. (1 / 16 = 0.0625 сек ) Считывать по таймеру. Каждые 8 считываний проводить анализ полученных данных . Для 5 светодиодав имеем 5 массивов данных

со следующими вариантами

1) 11111111 - диод всегда включен

2) 00000000 - диод всегда выключен

3) 11001100 - мигание 4 гц, доп варианты (10011001, 00110011, 01100110

4) 11110000- мигание 2 гц (11100001, 11000011, 10000111, 00001111 и т.д)

Далее для варианта 3 поочереди 8 раз проверяем смещеное на байт значение с  11001100. (ну или тупо сравниваем с разными комбинациями, благо из немного) Если хотябы 1 из 8 совпало то значит мигает с 4 гц. Для варианта 4 - аналогично

т.е. время определения состояния светодиода 0.0625 сек * 8 = 0.5 сек.

leshak
Offline
Зарегистрирован: 29.09.2011

А нафига так сложно? Повышать частоту измерений, быть привязанным к точности времени

Что такое частота? Это "сколько раз он поменял свое состояние" за единицу времени.

Ну вот и берем, скажем "2 сек", с запасом, определяется самой "малой частотой".

Ну и считаем сколько раз он поменял свой state за это время. больше 6-ти - значит имеем 4 гц. Больше 3-рех - значит имеем 2 гц. Меньше... ну значит либо "горит постоянно", либо "не горит". Что именно - выясняем сделав digitalRead.

Все. Никаких массивов, никаких сдвигов....

Если нам потребуется детектить 10-ть частот, а не две, то.... на не нужно будет перебирать мульен вариантов. Комбинаторный же взрыв.

 

roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

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

В моев вариате вам никто не мешает переходы считать. При 4 Гц - 2 перехода из 0 в 1 (3 или 4 смены состояний), при 2 Гц- 1 переход из 0 в 1 (1 или 2 смены состояний).  У dimax что то похожее на мое решение было, тока 10 ms не обосновано...

Я предлагал завиксировать время между измерениями, Вы предлагаете общее время измерения зафиксировать - способ выбирается кому как удобно :) 

leshak
Offline
Зарегистрирован: 29.09.2011

>Вы предлагаете общее время измерения зафиксировать 

В первую очередь я предлагаю "фиксировать количество изменений". А тупо увеличивать какой-то счетчик и потом посмотреть "сколько там натикало", всяко легче чем:
1. Хранить "историю".
2. Анализировать ее (подсчеты, сравнение с паттернами-вариантами). 

Ну и требование "к точности выдерживания таймингов" - ниже. Можно все делать "плюс/минус полметра". Ну и можно пользоватся аппаратными прерывания, для ловли изменений. Что тоже упрощает задачу.

Но вообщем, согласен - дело вкуса и предыдущего опыта (человек склонен повторять "сработавшие" приемы).
 

dinovasya
Offline
Зарегистрирован: 03.10.2013

да уж... тема-то не из легких, как мне казалось раньше..

Кстати да, на русском не получалось выводить- латинскими буквами по-русски писал.

 

А что если просто на всех 5-ти пинах ожидать сигнала, и как только один из них получит сигнал- сразу же опросить все остальные..

leshak
Offline
Зарегистрирован: 29.09.2011

>А что если просто на всех 5-ти пинах ожидать сигнала,

Гуглите "arduino pin change interrupt" (не attachInterrupt)

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

Я тут попробывал набить скетчик для одного пина по мотивам топикстартера  - однако работает :) Специально на другой дуне сделал 2 генератора, -определяются точно, только гуляет на один отсчёт. На 2-х герцах -7..8 инкрементов, на 4х герцах 15-16 инкрементов.)

#define vxod 12
unsigned long prevmillis1=0;
byte read1=255, counter1=0; 

void setup(){
Serial.begin(9600);
}
void loop(){
  if (millis()-prevmillis1 <= 2000)  {   
   if (read1==255) read1=digitalRead(vxod);//что бы отличить первую читку от последующих
     if (digitalRead(vxod) != read1){ //если считанное не равно предыдущему
      counter1=counter1+1;// инкременировать счётчик
     read1=!read1; // изменить значение прочитанного
    }
  }
  else {   
    if (counter1==0) Serial.println(read1);
      else {
        if (counter1 >= 15) Serial.println("4Hz");
          if (counter1 <= 8) Serial.println("2Hz");  
          } 
         prevmillis1=millis();
        counter1=0;//сброс счтёчика перед следующим циклом
       read1=255;
      }  
     }

 

leshak
Offline
Зарегистрирован: 29.09.2011
  if (counter1 <= 8) 

Если светик просто включится или выключится, то есть будет скажем одно изменение. То у вас получится "2Hz".

Так что, все-таки нужно и минимальное количество проверять. И если "меньше минимального", то... выводить нужно не первую читку, а "еще раз считать", что-бы вывести именно текущие состояние. (ну или инвертировать "первую читку" в зависимости от четности/не четности каунтера).

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

leshak, Вот так сделал, лучше пусть пойдёт на новый цикл. Сообщение вылезло один раз, когда надевал штырёк на выход генератора 4hz.

if (counter1 <= 8 && counter1 >=6) Serial.println("2Hz");  
              if (counter1 <6) Serial.println("abortive attempt");

 

leshak
Offline
Зарегистрирован: 29.09.2011

А зачем ему "вылазить" и оттягивать момент отчета? По условиям задачи - абсолютно шаттная ситуация.

В чем сложность сдлать?

if (counter1 <6) Serial.println(digitalRead(vxod)?"IsON":"IsOff");

leshak
Offline
Зарегистрирован: 29.09.2011
#define vxod 12

unsigned int counter1=0;

void setup(){
  Serial.begin(9600);
 
}


void loop(){
  listenInput();
  reportIfRequire();
}

// переодически отчитываемся
void reportIfRequire(){
 static unsigned long lastReported=0;
    if(millis()-lastReported>=2000){
      reportCounter(counter1); // проанализирвоали/отчитались
      counter1=0; // Обнулили счетчик
      lastReported=millis(); // запустили новый отсчет
  }
}


void reportCounter(int cnt){
    if(cnt>=7) Serial.println("4Hz"); 
      else if(cnt>3) Serial.print("2Hz");
      else { // фиг его знает, частоту обнаружить не удалось
        Serial.println(digitalRead(vxod)?"ON":"OFF"); // выводим текущие состояние пина
      }
}

void listenInput(){ // слушем пины, если поменились - увиличиваем счетчики

  static bool prevState=0;
  bool state=digitalRead(vxod); // читаем новое состояние
  if(prevState!=state){ // поменялось
    counter1++; // увеличи счетчик
  }
  
  prevState=state; // запомнили состояние
}

Честно говоря "не тестил", лениво мне "генератор собирать" :) Но общая идея, думаю понятна. Мухи (анализ) - отдельно, Увеличение счетчика (котлеты) - отдельно. Никаких "первый чтений" и т.п. Вообщем то что я словами описывал в #7 закожено.

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

Проверил. на 2 гц всегда пишет 4 гц,  когда надеваешь штырёк на +5 вольт может тоже написать 4 гц. Для скетча без отладки хороший результат :)

leshak
Offline
Зарегистрирован: 29.09.2011

>на 2 гц всегда пишет 4 гц,

Ну на конкретные цифры я мозг не хмурил.Скорее от ваших отталкивался. Попробуйте в первом услоивии >6, как я "прикдывал в уме", в #7

Это не учитывая что мы еще не видили кода "тесктового генератора" :)

>когда надеваешь штырёк на +5 вольт может тоже написать 4 гц. 

А вы не допускаете что  "когда одеваешь", то там в реальности и 20 kГц может быть? Требезг контактов будет почти наверняка и весьма основальный.

>Для скетча без отладки хороший результат :)

спасибо ;)

P.S. Можете просто сделать println(cnt), увидеть какие реальные показатели счетчика, тогда и думать какие границы в if записать не прийдется.

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

leshak,  да, при cnt>6 чётко показывает 2 герца! (добавлено позже: что-то я не туда посмотрел- вот после чего заработало: if(cnt>=15) Serial.println("4Hz");  else if(cnt>6) Serial.println("2Hz");

В моём скетче не было ложных считываний, у меня все глючные  ругаются "неудачная попытка" :)

А генератор у меня простейший..:

unsigned long prevmillis;
unsigned long prevmillis2;
void setup(){
  Serial.begin(9600);
  pinMode (7, OUTPUT);
}

void loop(){
 
  if (millis() - prevmillis >=250) { 
 PORTD = PORTD ^ (1<<7);
 prevmillis=millis(); 
  }
delay(10);
if (millis() - prevmillis2 >=125) { 
 PORTD = PORTD ^ (1<<4);
 prevmillis2=millis(); 
  }

}
  
  

 

leshak
Offline
Зарегистрирован: 29.09.2011

> у меня все глючные  ругаются "неудачная попытка" :)

Так почему же "неудачная"? По условиям задачи это вполне "штатная ситуация". И при ее детектировании тоже нужно сообщить "что же проиходит", а не "мы потом попробуем еще раз". 

Иначе у вас "сбивается" регулярность отчетов.

А когда пинов будет несколько.... из за одного отказываться от чтения всех? Этак можно вообще не дождаться пока все 6-ть светиков будут в PWM-мить. Или вы хотите для каждого отдельно заводить prevmillis и дублировать всю логику переодичности? Это тоже как-то "мнэээ".

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

leshak, смотрел ваш скетч ещё раз, и никак не пойму, почему у вас  не инкременируется счётчик, при чтении статического состояния HIGH ? 

void listenInput(){ // слушем пины, если поменились - увиличиваем счетчики
static bool prevState=0;
  bool state=digitalRead(vxod); // читаем новое состояние
  if(prevState!=state){ // поменялось
    counter1++; // увеличи счетчик
  }
 prevState=state; // запомнили состояние
}

Если разбирать по строчкам, то: (2) prevState=0, (3) state=1, (4) ноль не равен 1- условие сработало, (5) счётчик инкременировался, (6) prevState стал 1. При следующем вызове prevState снова 0, и снова всё повторется с инкрементацией счётчика. Что я упускаю из виду? )

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Вторая строка, слово static

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

kisoft пишет:

Вторая строка, слово static

Ясности не добавилось, мне с разжёвыванием пожалуйста :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

А погуглить? От Вас не ожидал :)

Статик переменная инициализируется один раз. Так понятней? Лень писать больше, док море, почитайте

 

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

kisoft, всё, разобрался! static я иногда использовал что-бы сохранить содержимое выходя из функции. Поэтому  совершенно не понял, для чего вы мне о нём говорите, ( ну сохраняет он, и что? пронеслось в голове :)  Не знал, что попытка повторной инициализации с присваиванием конкретного значения не меняет переменной. В голову бы не пришло. Об этом не написано в справочнике.  Оказывается всё можно делать проще, мне приходилось другими путями решать некоторые вопросы, например строчка 10 в 12 сообщении, как раз такой случай.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Я на практике часто со статиком сталкиваюсь, но чаще со статическими методами классов, а Статик переменные не люблю использовать. Но для ардуины вполне хороший метод использовать глобальные-локальные переменные, тут все проще и нет миллиона строк кода :)