Счетчик импульсов на IskraNeo (Leonardo)

Тема в разделе "Arduino & Shields", создана пользователем eleberet, 31 окт 2016.

  1. eleberet

    eleberet Нуб

    Здравствуйте товарищи!
    Есть задумка сделать некий счетчик срабатывания реле, который считает сколько было за 10 секунд этих самых срабатываний, а потом обнуляется и ждет след 10 сек и тд...
    Так вот, нарыл в сети куски кода и на их основе сделал вот это
    Однако появилась одна непонятная штука, вне зависимости от того подаю я импульсы на ногу или нет, в сериал мониторе у меня появляются цифры (в основном число 500) с интервалом в 10 сек
    Ну и сами импульсы естественно не считаются =/
    • Импульсы подаю замыкая 12ю ногу и +5V на плате
    • плата IskraNeo

    Код (C++):
    #include <MsTimer2.h>      // Либа на таймер
    volatile int colImp = 0;   // Счетчик импульсов
    volatile int T = 0;
    const int ledPin = 12;     // Подаю импульсы на 12 ножку
    void setup()
    {
      pinMode(ledPin, INPUT);
      digitalWrite(ledPin, LOW);          // Сомневаюсь что нужно HIGH или LOW
      attachInterrupt(1, D2Int, RISING);  // Прерывание по приходу импульса
        MsTimer2::set(10000, flash);       // 10000 ms  = 10 s
        MsTimer2::start();
      Serial.begin(9600);
    }
    void loop()
    {
      if (T == 1) // Если прошло 10 секунд тогда
    {
    Serial.print(colImp);
      colImp = 0; //обнуляем колличество накопленных импульсов
      T = 0;      // сбрасываем T
    }
    }
    void D2Int()
    {
         colImp++;   // увеличиваем на 1 колличество импульсов
    }
    void flash(void) //вызывается  раз в 10 секунд
    {
         T = 1; // по прошествию 10 сек
    }
     
    Последнее редактирование: 31 окт 2016
  2. rkit

    rkit Гуру

    eleberet нравится это.
  3. eleberet

    eleberet Нуб

    Добавил стягивающий резистор, "шуметь" непонятными значениями она перестала, но теперь появляются просто нули с заданным интервалом
     
  4. rkit

    rkit Гуру

    Точно все правильно подключил? Ноги разные.
     
    eleberet нравится это.
  5. eleberet

    eleberet Нуб

    Если я правильно понимаю то функция interrupt работает не со всеми ногами?
    нашел табличку
    Плата int.0 int.1 int.2 int.3 int.4
    Leonardo---3----2-----0----1------7
    и если у меня стоит attachInterrupt(1, D2Int, RISING); то надо подавать импульсы на 2ю ногу?
    может вопрос идиотский конеш)
     
  6. ostrov

    ostrov Гуру

    attachInterrupt(1, D2Int, RISING);это нога 3 (на Уно), при чем тут нога 12?
     
    eleberet нравится это.
  7. rkit

    rkit Гуру

    Лучше всего использовать digitalPinToInterrupt
     
  8. ostrov

    ostrov Гуру

    Код (C++):
    /* External Interrupt Request 0 */
    #define INT0_vect            _VECTOR(1)
    #define SIG_INTERRUPT0            _VECTOR(1)

    /* External Interrupt Request 2 */
    #define INT2_vect            _VECTOR(18)
    #define SIG_INTERRUPT2            _VECTOR(18)
     
  9. eleberet

    eleberet Нуб

    с ногой все понял, теперь подаю импульсы на нужную
    добавил антидребезг в функцию D2int
    все замечательно, считает по +1 за клик, НО клики стали пропадать
    из 10 кликов может посчитать 6 к примеру
    buttonPressTime задержку менял по разному эффекта нет
    в чем проблема быть может
    Код (C++):
    void D2Int()
    {
        static byte prevButtonState=false;      // состояние кнопки при прошлом проходе loop
        byte buttonState=!digitalRead(ledPin);  // читаем текущие состояние кнопки
        static unsigned long buttonPressTime=0;        // тут будем хранить время нажатия кнопки
        if(!prevButtonState && buttonState && (millis()-buttonPressTime>50)){ // была не нажата, стала нажата и с прошлого нажатия прошло 100ms
         Serial.println("Button Pressed");
        colImp++;    // увеличиваем на 1 колличество импульсов
         buttonPressTime=millis();    // запомнили когда у нас была нажата кнопка
      }
      prevButtonState=buttonState;
    }
     
  10. rkit

    rkit Гуру

    Какая-то куча непонятной работы в прерывании.

    Никакого предыдущего состояния тут быть не может, оно явно приравнивается к false.

    Зачем?

    И так далее.
     
  11. eleberet

    eleberet Нуб

    может есть какойто более простой и изящный способ отсечь дребезг?
    гуглил много всякого и с этим кодом хоть чтото начало отлавливать похожее на клики
    данный код взял из другой проги где оно крутилось в loop
     
  12. rkit

    rkit Гуру

    Для программирования надо понимать программу, а не просто копировать куски кода туда-сюда.
    Вот надо взять вариант с loop, продумать, понять, почему и как он работает. Потом с нуля написать вариант с прерываниями.
     
  13. ostrov

    ostrov Гуру

    Вообще то в таком виде явно оно приравнивается лишь первый раз, далее оно остается таким каким было в прошлой итерации. Ибо static.
     
  14. rkit

    rkit Гуру

    Ок, по этому пункту был не прав.
     
  15. ostrov

    ostrov Гуру

    Вообще, все эти неустойчивые переходные процессы, частным случаем которых является дребезг, я обрабатываю в виде кольцевого буфера, так мне как то проще и понятнее. На примере антидребезга кнопки достаточно сделать буфер из двух элементов:
    Код (C++):
    bool press[2] = {0, 0};
    И заполнять его так:
    Код (C++):
    press[0] = press[1];
    press[1] = digitalRead(10);
    Разумеется, между одноименными действиями должна быть некоторая пауза, создаваемая хоть банальным delay(), хоть по millis(), хоть при помощи прерываний по таймеру. Полученный таким образом "отпечаток времени" обрабатываем, например так:
    Код (C++):
    if (press[0] && !press[1]) {  // находим спад
    ... // тут реагируем на это событие
    }
    На мой взгляд, это понятнее условных last, next, old и прочего. А, самое главное, гибче! Например, в одном самодельном энкодере, представляющем из себя кольцо с прорезями и оптопару, подсчет шагов по фронту или спаду давал очень неточную картину. Проанализировав сигнал анализатором выяснилось, что в положении HIGH сигнал ровен, а в LOW в нем проскакивают иголки длиной 0.25мкс, причем довольно часто. Вот на них то счетчик и путался. Увеличили буфер до 3 элементов, и по условию (1, 1, 0) стало все замечательно работать. То есть усовершенствовали систему практически парой строк до неузнаваемости. Я всегда за прозрачные и легко модифицируемые решения.
     
    ИгорьК и eleberet нравится это.
  16. eleberet

    eleberet Нуб

    Спасибо за совет) про кольцевой буфер первый раз услышал)
    Теперь клики ловятся такой простой конструкцией
    Код (C++):

    bool press[2] = {0, 0};
    int ledPin = 10;
    int colImp;
    void setup() {
    }

    void loop() {
        press[0] = press[1];
        delay(50);
        press[1] = digitalRead(ledPin);
        if (press[0] && !press[1])
        {
          colImp++;
          Serial.println("click");
          Serial.println(colImp);
        }
    }
    И все замечательно, но когда я этот рабочий кусок добавляю к уже существующей проге (смысл которой отправить накликанное по смс) он престает считать, хотя в сериале крутится "go!" все 10 сек
    что я опять делаю не так =/
    Код (C++):
    #include <GPRS_Shield_Arduino.h>
    #include <SoftwareSerial.h>
    #include <MsTimer2.h>

    int colImp = 0;   // Счетчик импульсов
    int T = 0;           // Флаг таймера
    const int ledPin = 10;     // Подаю импульсы на 10 ножку
    bool press[2] = {0, 0};

    #define PHONE_NUMBER  "+70000000000" // номер на который будем отправлять сообщение
    GPRS gprs;
    void setup()
    {
      pinMode(ledPin, INPUT);
      digitalWrite(ledPin, HIGH);          
      MsTimer2::set(10000, flash);         // 10000 ms  = 10 s
       
     
      gprs.powerUpDown();       // включаем GPRS шилд
      Serial.begin(9600);        // открываем последовательный порт для мониторинга действий в программе
      while (!Serial) {}            // ждем открытия монитора
      while (!gprs.init())        // проверяем есть ли связь с GPRS устройством
      {

        Serial.print("Init error\r\n");
      }

    Serial.println("GPRS init success");
    Serial.println("Wait to call ");
    }


    void flash() // раз в 10 сек вызываем флаг
    {
      T = 1;
    }

    void loop()
    {
       if (gprs.ifcallNow()) // ожидаем звонка
      {
        Serial.println("Incoming call"); // выводим сообщение о входящем вызове
        delay(3000);
        gprs.callEnd();  // по истечении 3 секунд скидываем трубку
        MsTimer2::start(); // запускаем таймер который 10 сек считает импульсы
        while (T == 0)
        {
            Serial.println("go!");
            press[0] = press[1];
            delay(50);
            press[1] = digitalRead(ledPin);
            if (press[0] && !press[1])
            {
                colImp++;
                Serial.println("click");
            }
        }
        MsTimer2::stop();
     
      int toMess = colImp;
      colImp = 0;
      T = 0;
      char mess[6];
        itoa(toMess, mess, 10);       // перевод в чар для отправки по смс
        Serial.println(toMess);         // проверка в мониторе
        Serial.println("Call over. SMS Sending");
        gprs.sendSMS(PHONE_NUMBER, mess);
        Serial.println("SMS done");
       
      }
    }
    }
     
  17. eleberet

    eleberet Нуб

    И пока никто не успел ответить напишу)
    В 1м случае я при тесте забыл написать
    pinMode(ledPin, INPUT);
    digitalWrite(ledPin, HIGH);
    И почему то все заработало, закоментил в основной проге и о чудо, тож все ок
    Почему так?) я ведь даже не настраиваю пин на вход а он все равно принимает и главное адекватно считает импульсы
    Не вредно ли это для платы? Я ничего там не спалю?
     
  18. rkit

    rkit Гуру

    Пин не может быть выключен. Он всегда либо вход либо выход. Если не настроили, то уж как повезет.
     
  19. ostrov

    ostrov Гуру

    Как то немного глаз режет такое расположение delay(). А вообще, delay это неправильный костыль, я код еще не смотрел, но думаю что причина в нем. Вам бы разобраться с другими способами периодических действий, например при помощи millis(). Рассмотрите пример blink without delay и сделайте так же у себя.
     
  20. eleberet

    eleberet Нуб

    Получается всему виной была строка digitalWrite(ledPin, HIGH); почему то из за нее не работал счетчик, хотя это лишь включает подтягивающий резистор, как он может повлиять на что либо
    А почему неправильный, я точно знаю что в эти 100мс у меня ничего не придет, и ардуино больше не решает задач.
    Спасибо всем за мудрые советы)