Измерение частоты (1-10 Гц) и digitalWrite(ledPin,LOW); при частоте ниже 3 Гц

Тема в разделе "Arduino & Shields", создана пользователем urnash, 8 авг 2018.

  1. urnash

    urnash Нерд

    Добрый вечер
    Есть поверхностные знания ардуино, прошу помощи от пользователей форума
    Все делается на Arduino Leonardo

    Имеется сервер, потребление которого требуется измерять, точнее получать сигнал о его низком потреблении (если программа на сервере не работает, то потребление электричества падает)

    Собираюсь измерять следующим образом:
    На счетчике есть светодиод, который мигает с разной частотой в зависимости от потребляемого тока (примерно 4 Гц при потреблении 2кВт), предположительное напряжение диода 2 В, от него предполагаю лучше вывести 2 провода на оптрон (счетчик установлен Б/У и только для личных наблюдении), который в свою очередь будет создавать низкий уровень на входе ардуино при моргании диода.

    Нужно чтобы ардуино засекал падение потребления (частоту ниже 3 Гц для примера) тока и если это длиться более 15 минут (можно делать 3 измерения с интервалом в 5 минут и складывать полученные значения) выполнял функцию, пример digitalWrite(ledPin,LOW);
    Точность измерении не важна, нужно просто видеть разницу между потреблением в 1.5 кВт и 2 кВт
     
  2. DIYMan

    DIYMan Guest

    attachInterrupt, ну и далее простенькая работа с millis(), чтобы понять, длится ли частота 3 Гц более 15 минут или нет.
     
  3. ostrov

    ostrov Гуру

    В чем трудность конкретно?
     
  4. urnash

    urnash Нерд

    Проблема банальна, с ардуино знаком очень поверхностно, смысла изучать глубоко ради одной задачи не вижу, да и трудно это мне дается.
    Решил спросить у знатоков...
    Нужен скетч, который бы выполнил эту задачу, сам написать не могу ((
     
  5. parovoZZ

    parovoZZ Гуру

    Для таких вещей есть протокол SNMP/
    Твоя задача очень просто решается на сдвоенном NE555.
    А если хочется готовое решение, то это в "закажу проект".
     
  6. DIYMan

    DIYMan Guest

    Либо в "закажу проект", либо - самому пробовать. Я могу накидать костяк, но - проверять на корректность работы и писать комментарии - не буду, там и так всё достаточно просто. Вот, смотрите - есть от чего отталкиваться:

    Код (C++):
    volatile bool triggered = false;
    volatile uint32_t triggeredTime = 0;
    volatile uint32_t pulseWidth = 0;

    bool timerEnabled = false;
    uint32_t timerStartTime = 0;

    void interruptFunction()
    {
      if(digitalRead(2) == LOW)
      {
        triggeredTime = micros();
      }
      else
      {
        if(triggeredTime && !triggered)
        {
          pulseWidth = (micros() - triggeredTime);
          triggeredTime = 0;
          triggered = true;
        }
      }

    }

    void setup()
    {
        attachInterrupt(digitalPinToInterrupt(2),interruptFunction, CHANGE);
    }

    void loop()
    {
         if(triggered)
         {
             if(pulseWidth <= 330000)
             {
                 if(!timerEnabled)
                 {
                     timerEnabled = true;
                     timerStartTime = millis();
                 }
             }
             else
             {
                 timerEnabled = false;
             }

           
           triggered = false;
         }

        if(timerEnabled && ( (millis() - timerStartTime) >  1000*60*15))
        {
            digitalWrite(13,HIGH);
        }
     
    }
     
  7. urnash

    urnash Нерд

    Если вас не затруднит укажите пожалуйста в каком месте у кода задается частота после которой выполняется действие?
     
  8. DIYMan

    DIYMan Guest

    У вас с английским как? Словосочетание "pulse width" что-нибудь говорит?
    Код (C++):
    if(pulseWidth <= 330000)
    Это ширина импульса в микросекундах, ниже которой включается таймер, и если за время, пока таймер включён, частота не превысила минимальную - то на пине 13 появится высокий уровень. 330 000 микросекунд - это 330 миллисекунд, или примерно три раза в секунду, т.е. примерно 3 Гц.
     
  9. urnash

    urnash Нерд

    Спасибо за "костяк", подкорректировал под себя и все заработало.
    Код у меня не работал по следующей причине
    Код начинает измерять микросекунды между импульсами если видит падение
    Код (C++):
    void interruptFunction()
    {
      if(digitalRead(2) == LOW)
    Я этот участок подкорректировал на
    Код (C++):
    void interruptFunction()
    {
      if(digitalRead(2) == HIGH)
    Причина этого в том, что у меня сигнал не 50/50 (мэандр), а с 6% заполнением снизу и 94% сверху.

    Конечный вариант
    Код (C++):
    volatile bool triggered = true; //Переменная должна быть объявлена volatile, когда её значение может быть изменено за пределами того участка программы, где она объявлена
    volatile uint32_t triggeredTime = 0; //uint32_t Если в коде критично важна разрядность целочисельных типов даных.
    volatile uint32_t pulseWidth = 0; //uint32_t Если в коде критично важна разрядность целочисельных типов даных.
    bool timerEnabled = false;
    uint32_t timerStartTime = 0; //uint32_t Если в коде критично важна разрядность целочисельных типов даных.

    void interruptFunction()
    {
      if(digitalRead(2) == HIGH) //если на пине 2 высокий уровень
      {
        triggeredTime = micros(); //присваиваем triggeredTime = количество микросекунд с момента начала выполнения текущей программы
      }

      else
      {
        if(triggeredTime && !triggered) //если triggeredTime && !triggered
        {
          pulseWidth = (micros() - triggeredTime);
          triggered = true;
        }
      }

    }


    void setup()
    {
      //Serial.begin(9600); //мониторинг порта, нужен только для отладки
      pinMode(2, INPUT); // Инициализируем цифровой вход/выход в режиме входа.
      pinMode(7, OUTPUT);
      pinMode(13, OUTPUT);
      attachInterrupt(digitalPinToInterrupt(2),interruptFunction, CHANGE);  //прерывание вызывается при смене значения на порту, с LOW на HIGH и наоборот
    }


    void loop() //циклично выполняемая функция
    {
      //Serial.print("pulseWidth: "); // Для отладки
      //Serial.print(pulseWidth);
      //Serial.print(" timerEnabled: ");
      //Serial.print(timerEnabled);
      //Serial.print(" timerStartTime: ");
      //Serial.print(timerStartTime);
      //Serial.println(analogRead(13));
      delay(1000); // Частота опроса при отладке
     
      if(triggered)
        {
          if(pulseWidth >= 270000) // Примерно 270000 микросекунд для измерения частоты 3.6 Герц
            {
              if(!timerEnabled)
                {
                  timerEnabled = true;
                  timerStartTime = millis();
                }
             }
             else
             {
               timerEnabled = false;
             }

           triggered = false;
         }
       
        if(timerEnabled && ( (millis() - timerStartTime) >  300000)) //Ставим таймер 300000 (5 минут)
        {
          digitalWrite(7,HIGH);
          digitalWrite(13,HIGH);
          //Serial.print("13,HIGH ");
        }

      else
        {
          digitalWrite(7,LOW);
          digitalWrite(13,LOW);
          //Serial.print("13,LOW ");
        }
     
    }
     
  10. parovoZZ

    parovoZZ Гуру

    слушайте, господа, а где вы покупаете клавы без буквы "Е"? Киньте ссылкой.