Индикатор длительности и количества импульсов

petrovich18
Offline
Зарегистрирован: 07.05.2017

Доброго времени суток участникам форума.
Не так давно заинтересовался МК Ардуино. С электротехникой знаком, а вот с программированием не очень.
Хочу сконструировать индикатор длительности и количества импульсов. На порты поступают импульсы, на первом порту необходимо измерять длительность импульсов за время Т(например 1 сек.) и усреднять. Далее выводить на индикатор. С второго порта необходимо считывать количество импульсов за время Т (1 сек), усреднять и выводить на дисплей.
Сложность для меня в том, что длительность импульсов и частота постоянно меняются, каким образом можно фиксировать первичные параметры импульсов, и как усреднять в непрерывном процессе?

gena
Offline
Зарегистрирован: 04.11.2012

   Изучите функции 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

petrovich18 пишет:
каким образом можно фиксировать первичные параметры импульсов

Длительность импульсов Вам измерит функция pulseIn, см. раздел http://arduino.ru/Reference .

Количество импульсво лучше всего считать прерыванием. См. attachInterrupt в том же разделе.

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

petrovich18 пишет:
как усреднять в непрерывном процессе?

Ну а как бы Вы в жизни без компьютера усредняли?

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

В любой момент, поделив первую переменную на вторую получаете среднюю длительность всех поступивших к данному моменту импульсов.

Только следите за переполнением (правильно тип выбирайте) и не забывайте об особенностях целочисленного деления.

petrovich18
Offline
Зарегистрирован: 07.05.2017

Благодарю за помощь. Про среднее значение я имел ввиду, за последнюю секунду. Частота примерно изменятся от 20 до 200 Гц. Длительность импульса от 1 до 15мс. Про сумму длительности/кол-во импульсов мысли были, но мне необходимо за отрезок времени. Импульсы идут непрерывно и имеют разброс, если их выводить на экран, то показания быдут прыгать. Чтобы не было резких скачков, хочу выводить среднее значение, т.е. для примера брать цепочку в 20 импульсов и обрабатывать их. Думаю использовать 20 переменых, которые изменяют значения с каждым импульсом(обновляются), и далее из них выводится среднее на экран.

petrovich18
Offline
Зарегистрирован: 07.05.2017

Также возник вопрос по отображению на дисплее. Есть предположение, что если выводить на экран с каждым циклом, то будет все мелькать. Думаю стоит выводить 2-5 раз в секунду.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

petrovich18 пишет:
Благодарю за помощь. Про среднее значение я имел ввиду, за последнюю секунду. Частота примерно изменятся от 20 до 200 Гц. Длительность импульса от 1 до 15мс. Про сумму длительности/кол-во импульсов мысли были, но мне необходимо за отрезок времени. Импульсы идут непрерывно и имеют разброс, если их выводить на экран, то показания быдут прыгать. Чтобы не было резких скачков, хочу выводить среднее значение, т.е. для примера брать цепочку в 20 импульсов и обрабатывать их. Думаю использовать 20 переменых, которые изменяют значения с каждым импульсом(обновляются), и далее из них выводится среднее на экран.

 А справитесь? Создаете структуру указывающую саму на себя. Создаете 3 функции: добавление новой в начало, убирание последней в конце, подсчет средней в очереди. Потом делаем кучу . И запускаем измерение с выводом на экран.

petrovich18
Offline
Зарегистрирован: 07.05.2017

Конечно хочется справиться. Цепочку вроде представляю, но вот как увязать правильно пока только изучаю.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

petrovich18 пишет:
Благодарю за помощь. Про среднее значение я имел ввиду, за последнюю секунду. Частота примерно изменятся от 20 до 200 Гц. Длительность импульса от 1 до 15мс. Про сумму длительности/кол-во импульсов мысли были, но мне необходимо за отрезок времени. Импульсы идут непрерывно и имеют разброс, если их выводить на экран, то показания быдут прыгать. Чтобы не было резких скачков, хочу выводить среднее значение, т.е. для примера брать цепочку в 20 импульсов и обрабатывать их. Думаю использовать 20 переменых, которые изменяют значения с каждым импульсом(обновляются), и далее из них выводится среднее на экран.

Блин, ну почему новички никогда не говорят что именно им нужно, а всегда просят подсказать реализацию их собвтсенных (зачастую в корне неверных) подходов?

Не нужна Вам никакая средяя за секунду. Считать её у Вас никакой памяти не хватит.

Вам нужен фильтр низких частот.

Простейшая реализация описана вот здесь - http://www.poprobot.ru/theory/low_pass_filter

Почти тоже самое, но более гибко и почти также просто делается то, что биржевики называют Exponential Moving Average (EMA). См. описание EMA здесь - https://www.metatrader5.com/ru/terminal/help/indicators/trend_indicators/ma

Наконец, есть продвинутые фильтры типа вот такого.

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

 

petrovich18
Offline
Зарегистрирован: 07.05.2017

В моей задаче используются дискретные сигналы без шумов. Пока буду решать задачу для одного порта с длительностью импульса. Частота изменяется от15 до 100 герц. Длительность верхнего фронта импулься от1 до 15 мс. Усреднение хочу использовать для плавного изменения значений и отображения на дисплее (экране). Точные значения длительности нужны будут позднее.

Скопировано:
Простое, или арифметическое, скользящее среднее рассчитывается путем суммирования цен закрытия инструмента за определенное число единичных периодов (например, за 12 часов) с последующим делением суммы на число периодов.
Примерно таким же образом я и хотел усреднять. Значения 20 последних импульсов приводить к среднму, тогда конечный результат будет изменятся плавно.

petrovich18
Offline
Зарегистрирован: 07.05.2017

В моей задаче используются дискретные сигналы без шумов. Пока буду решать задачу для одного порта с длительностью импульса. Частота изменяется от15 до 100 герц. Длительность верхнего фронта импулься от1 до 15 мс. Усреднение хочу использовать для плавного изменения значений и отображения на дисплее (экране). Точные значения длительности нужны будут позднее.

Скопировано:
Простое, или арифметическое, скользящее среднее рассчитывается путем суммирования цен закрытия инструмента за определенное число единичных периодов (например, за 12 часов) с последующим делением суммы на число периодов.
Примерно таким же образом я и хотел усреднять. Значения 20 последних импульсов приводить к среднму, тогда конечный результат будет изменятся плавно.

petrovich18
Offline
Зарегистрирован: 07.05.2017

В моей задаче используются дискретные сигналы без шумов. Пока буду решать задачу для одного порта с длительностью импульса. Частота изменяется от15 до 100 герц. Длительность верхнего фронта импулься от1 до 15 мс. Усреднение хочу использовать для плавного изменения значений и отображения на дисплее (экране). Точные значения длительности нужны будут позднее.

Скопировано:
Простое, или арифметическое, скользящее среднее рассчитывается путем суммирования цен закрытия инструмента за определенное число единичных периодов (например, за 12 часов) с последующим делением суммы на число периодов.
Примерно таким же образом я и хотел усреднять. Значения 20 последних импульсов приводить к среднму, тогда конечный результат будет изменятся плавно.

petrovich18
Offline
Зарегистрирован: 07.05.2017

В моей задаче используются дискретные сигналы без шумов. Пока буду решать задачу для одного порта с длительностью импульса. Частота изменяется от15 до 100 герц. Длительность верхнего фронта импулься от1 до 15 мс. Усреднение хочу использовать для плавного изменения значений и отображения на дисплее (экране). Точные значения длительности нужны будут позднее.

Скопировано:
Простое, или арифметическое, скользящее среднее рассчитывается путем суммирования цен закрытия инструмента за определенное число единичных периодов (например, за 12 часов) с последующим делением суммы на число периодов.
Примерно таким же образом я и хотел усреднять. Значения 20 последних импульсов приводить к среднму, тогда конечный результат будет изменятся плавно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы главной мысли не поняли. Суммирование за какой-то период предполагает запоминание значений и времени, чтобы потом выбрасывать из суммы старые значения. На это у Вас нет памяти. Поэтому я Вам предложил несколько вариантов "усреднения" БЕЗ необходимости суммирования. Что ФНЧ, что EMA не требуют суммирования и запоминания. Понимаете?

petrovich18
Offline
Зарегистрирован: 07.05.2017

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

petrovich18
Offline
Зарегистрирован: 07.05.2017

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

petrovich18
Offline
Зарегистрирован: 07.05.2017

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

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Кстати, для реализации датчика дождя тоже нужно считать число ударов капель ... чем чаще "бьют", тем полагаю, сильнее дождь. Прикинул, при сильном ливне на 1 квадратный дециметр примерно падает 30 - 40 капель в секунду. Так что, возможно, идеи для ТС пригодятся и мне

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ulis пишет:

Кстати, для реализации датчика дождя тоже нужно считать число ударов капель ... чем чаще "бьют", тем полагаю, сильнее дождь. Прикинул, при сильном ливне на 1 квадратный дециметр примерно падает 30 - 40 капель в секунду. Так что, возможно, идеи для ТС пригодятся и мне

ПОсмотрите в проектах - там есть счетчик Гейгера. Программная чать, думаю, практически идентична.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

andriano пишет:

ПОсмотрите в проектах - там есть счетчик Гейгера. Программная чать, думаю, практически идентична.

Ок, спасибо

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ulis пишет:

Прикинул, при сильном ливне на 1 квадратный дециметр примерно падает 30 - 40 капель в секунду. Так что, возможно, идеи для ТС пригодятся и мне

По моим прикидкам при самом сильном ливне (по Википедии 100 мм/ч) примерно вчетверо больше.

petrovich18
Offline
Зарегистрирован: 07.05.2017

Доброго времени суток. Наконец то добрался до компьютера и риступил к реализации программы. Пока что наваял часть для измерения длительности и усреднения. Испытания на коленке прошли успешно. ) Получился вот такой вот код. Светодиод использовался для первоночальной отладки. Сильно не ругать, первый самостоятельный скетч. Буду рад предложениям , как упростить.

#define IMPULS_PIN  5
#define LED_LAMP_PIN        7

boolean ImpulsState = LOW;        //  предыдущее состояние входа
boolean ImpulsPin   = LOW;        //  текущее состояние входа

unsigned int interval = 100;              //  ???   интервал между опросом входа, 100мкс
unsigned long currentImpMicros = 0;
unsigned long previousImpMicros = 0;          //  предыдущее время измерения импульса
unsigned long T_impuls = 0;                //  ???   Длительность импульса
long T_prom = 0;                  //  ???  промежуточная переменная 1= 100мкс

unsigned long t1 = 0;
unsigned long t2 = 0;
unsigned long t3 = 0;
unsigned long t4 = 0;
unsigned long t5 = 0;
unsigned long t6 = 0;
unsigned long t7 = 0;
unsigned long t8 = 0;
unsigned long t9 = 0;
unsigned long t10 = 0;
unsigned long t11 = 0;
unsigned long t12 = 0;
unsigned long t13 = 0;
unsigned long t14 = 0;
unsigned long t15 = 0;
unsigned long t16 = 0;
unsigned long t17 = 0;
unsigned long t18 = 0;
unsigned long t19 = 0;
unsigned long T_sred  = 0;

int second = 1;

void setup() 
{
  pinMode(IMPULS_PIN, INPUT);     // задаем режим входа для порта,
  pinMode(LED_LAMP_PIN, OUTPUT);
  
  Serial.begin(9600);
  // передаём заголовок нашей таблицы в текстовом виде, иначе
  // говоря печатаем строку (англ. print line). Символы «\t» —
  // это специальная последовательность, которая заменяется на
  // знак табуляции (англ. tab): 8-кратный выровненный пробел
  Serial.println("T_impuls\tT_sred");
}

void loop() 
{
  unsigned long previousMicros = 0;          //  предыдущее время измерения опроса входа
  unsigned long currentMicros = micros();  
    //проверяем не прошел ли нужный интервал, если прошел то
  if(currentMicros - previousMicros >= interval)
    {
      previousMicros = currentMicros;      // сохраняем время последнего переключения
      boolean ImpulsPin = digitalRead(IMPULS_PIN);             // присваеваем состояние входа
     
       if (ImpulsState == LOW  && ImpulsPin == HIGH )  // Выполняем проверку входа,начало импульса
          {     
             unsigned long currentImpMicros = micros();  // начало импульса
             previousImpMicros = currentImpMicros;   //  предыдущее время измерения импульса
             ImpulsState = ImpulsPin; // присваиваем новое значение
           }
       if (ImpulsState == HIGH  && ImpulsPin == LOW )  // Выполняем проверку входа,конец импульса
              {   
                  currentImpMicros = micros();
                  T_impuls = currentImpMicros - previousImpMicros;  // вычисляем длительность импульса
                  ImpulsState = ImpulsPin; // присваиваем новое значение
                   
                  T_sred  = (t1+t2+t3+t4+t5+t6+t7+t8+t9+t10+t11+t12+t13+t14+t15+t16+t17+t18+t19+T_impuls)/20000 ;  // расчет среднего знаения импульса
                  
                  t1 = t2;
                  t2 = t3;
                  t3 = t4;
                  t4 = t5;
                  t5 = t6;
                  t6 = t7;
                  t7 = t8;
                  t8 = t9;
                  t9 = t10;
                  t10 = t11;
                  t11 = t12;
                  t12 = t13;
                  t13 = t14;
                  t14 = t15;
                  t15 = t16;
                  t16 = t17;
                  t17 = t18;
                  t18 = t19;
                  t19 = T_impuls;  // присвоение скользящих значений
                  

                   Serial.println(T_impuls);
                   Serial.print("\t");
                   Serial.println(T_sred);
 
               }
               
               
      }
      boolean ImpulsPin = digitalRead(IMPULS_PIN);
      if (ImpulsPin == HIGH) {
        digitalWrite(LED_LAMP_PIN, HIGH);
        
    } else {
        digitalWrite(LED_LAMP_PIN, LOW);
        }
   digitalWrite(LED_LAMP_PIN, LOW);
   
}   // конец цикла



 

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

petrovich18 пишет:


unsigned long t1 = 0;
unsigned long t2 = 0;
unsigned long t3 = 0;
unsigned long t4 = 0;
unsigned long t5 = 0;
unsigned long t6 = 0;
unsigned long t7 = 0;
..
unsigned long t18 = 0;
unsigned long t19 = 0;

Вот так попроще:

unsigned long t[20];
for (int x = 0; x<20; x++){
 t[x] =0;}

petrovich18 пишет:

T_sred  = (t1+t2+t3+t4+t5+t6+t7+t8+t9+t10+t11+t12+t13+t14+t15+t16+t17+t18+t19+T_impuls)/20000 ;  // расчет среднего знаения импульса
                  
                  t1 = t2;
                  t2 = t3;
                  t3 = t4;
                  t4 = t5;
                  t5 = t6;
                  t6 = t7;
                  t7 = t8;
                  t8 = t9;
                  t9 = t10;
                  t10 = t11;
                  t11 = t12;
                  t12 = t13;
                  t13 = t14;
                  t14 = t15;
                  t15 = t16;
                  t16 = t17;
                  t17 = t18;
                  t18 = t19;
                  t19 = T_impuls;  // присвоение скользящих значений

А вот тут так

T_sred = t[0];
for (int x = 0; x<19; x++){
  T_sred += (t[x] = t[x+1]);}
t[19] = T_impuls;
T_sred +=T_impuls;
T_sred /=20000;

Не пойму только, почему делим на 20000, а не просто на 20

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

вместо   unsigned long previousMicros = 0; 

напиши  static unsigned long previousMicros = 0; 

иначе между вызовами loop previousMicros запоминаться не будет

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

petrovich18
Offline
Зарегистрирован: 07.05.2017

Делим на 20000 , потому что микросекунды переводим в миллисекунды.