Функции для обработки дребезга и мигания диодом

Тема в разделе "Arduino & Shields", создана пользователем Женёк, 22 дек 2015.

  1. Женёк

    Женёк Нуб

    Всем привет!

    Я абсолютный новичок, программировал последний раз в 7 класс на BASIC, а сейчас купил Ардуино, чтобы играть с ребёнком. Хочу написать программу, которая по однократному нажатию кнопки циклично переключалась бы между режима мигания светодиода: 10 Гц - 2 Гц - выключен - 10 Гц и т.п. Мигание хочу реализовать без delay(t) с помощью отдельной функции. Написал программу, но при её заливке на плату ничего не происходит. Диод не мигает, на кнопку не реагирует.
    Код (C++):
    int GREEN1 = 3; //контакт 3 для светодиода
    int BUTTON = 2; //контакт 2 для кнопки
    boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
    boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
    int lmode = 0; //переменная для статуса светодиода
    int GREEN1_INTERVAL1 = 100; //100 мс для моргания 10 Гц
    int GREEN1_INTERVAL2 = 500; //500 мс для моргания 2 Гц
    long previousTime = 0;
    void setup()
    {
      pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
      pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
    }
    boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
    {
      boolean current = digitalRead(BUTTON); //считываем состояние кнопки
      if (last != current) //если не такое, как было
      {
        delay(10); //то ждём 10 мс
        current = digitalRead(BUTTON); //опять считываем состояние кнопки
        return current; //возвращаем состояние
      }
    }
    void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
    {
      if (mode == 0) //если режим равен 0
      {
        Blink (GREEN1, GREEN1_INTERVAL1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
      }
      if (mode == 1); //если режим равен 1
      {
        Blink (GREEN1, GREEN1_INTERVAL2);
      }
      if (mode == 2); //если режим равен 2
      {
        digitalWrite (GREEN1, LOW); //выключаем питание
      }
    }
    void Blink (long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
    {
      long Time = millis(); //записываем время работы контроллера
      if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
      {
        previousTime = Time; //перезаписываем время
        boolean LED_STATE; //вводим локальную переменную, хранящую состояние диода
        if (LED_STATE == LOW) //если диод выключен
          LED_STATE = HIGH; //то включаем его
        else //а иначе
          LED_STATE = LOW; //опять выключаем
        digitalWrite (LED_PIN, LED_STATE); //тут включаем/выключаем диод.
      }
    }
    void loop()
    {
      currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
      if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
      {
        lmode++;    //увеличиваем состояние счётчика режима на 1
      }
      lastButton = currentButton; //запоминаем последнее состояние кнопки
      if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
      lmode = 0; //то мы его обнуляем
      setMode (lmode); //и передаём значение функции setMode
    }
    Схема рабочая (см. вложение), простейшие программы на ней работают.
     
  2. Женёк

    Женёк Нуб

    По совету бывалых в setup() инициализировал COM-порт с помощью Serial.begin(9600); и добавил
    Serial.print("current=");
    Serial.println(current);
    В тело функции debounce() после строк

    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON);

    Выдача при нажатии кнопки такая:
    current=1
    current=0
    То есть кнопка меняет своё состояние при нажатии дважды.
     
  3. Sindbad

    Sindbad Гик

    10 Гц человеческий глаз будет воспринимать просто как включенный светодиод, т.к. сетчатка "помнит" изображение примерно 0,1 сек.
     
  4. Женёк

    Женёк Нуб

    Я имел в виду включить на 100 мс - выключить на 100 мс - включить на 100 мс и т.п. Такое моргание, очевидно, будет видно.
     
  5. Sindbad

    Sindbad Гик

    Такое "моргание" это выключение на 0,1 сек. Будет видно не каждому человеку и зависит от индивидуального восприятия.

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

    Апдейт. Выключение на 0,1 сек и включение на 0,1 сек. Это таки 5 Гц. Но все равно на границе восприятия.
     
    Последнее редактирование: 22 дек 2015
  6. Женёк

    Женёк Нуб

    Ну если я делаю это моргание с помощью delay(100); то глазами прекрасно всё видно.
    Вот скетч:
    Код (C++):
    int GREEN1 = 3; //контакт 3 для светодиода
    int BUTTON = 2; //контакт 2 для кнопки
    boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
    boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
    int lmode = 0; //переменная для статуса светодиода
    int GREEN1_INTERVAL1 = 100; //100 мс для моргания 10 Гц
    int GREEN1_INTERVAL2 = 500; //500 мс для моргания 2 Гц
    long previousTime = 0;
    void setup()
    {
      pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
      pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
      Serial.begin(9600);
    }
    boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
    {
      boolean current = digitalRead(BUTTON); //считываем состояние кнопки
      if (last != current) //если не такое, как было
      {
        delay(10); //то ждём 10 мс
        current = digitalRead(BUTTON); //опять считываем состояние кнопки
        Serial.print("current=");
        Serial.println(current);
        return current; //возвращаем состояние
      }
    }
    void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
    {
      if (mode == 0) //если режим равен 0
      {
        Blink (GREEN1, GREEN1_INTERVAL1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
      }
      if (mode == 1); //если режим равен 1
      {
        Blink (GREEN1, GREEN1_INTERVAL2);
      }
      if (mode == 2); //если режим равен 2
      {
        digitalWrite (GREEN1, LOW); //выключаем питание
      }
    }
    void Blink (long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
    {
      long Time = millis(); //записываем время работы контроллера
      if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
      {
        previousTime = Time; //перезаписываем время
        boolean LED_STATE; //вводим локальную переменную, хранящую состояние диода
        if (LED_STATE == LOW) //если диод выключен
        {
          LED_STATE = HIGH; //то включаем его
        }
        else //а иначе
        {
          LED_STATE = LOW; //опять выключаем
        }
        digitalWrite (LED_PIN, LED_STATE); //тут включаем/выключаем диод.
      }
    }
    void loop()
    {
      currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
      if (lastButton == HIGH && currentButton == LOW) //если кнопка нажата
      {
        lmode++;    //увеличиваем состояние счётчика режима на 1
      }
      lastButton = currentButton; //запоминаем последнее состояние кнопки
      if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
        lmode = 0; //то мы его обнуляем
      setMode (lmode); //и передаём значение функции setMode
    }
    Вот скрин после 5 нажатий. Нажатие это нажал-отпустил. Одно нажатие генерирует пару строк
    current=0
    current=1
     

    Вложения:

    • Screen5.png
      Screen5.png
      Размер файла:
      52,2 КБ
      Просмотров:
      554
  7. Sindbad

    Sindbad Гик

    Смотрите, вы вызываете Блинк так:
    Код (C++):
    Blink (GREEN1, GREEN1_INTERVAL2);
    Т.е. первый параметр - номер выхода, второй - длительность интервала
    А прототип функции выглядит так:
    Код (C++):
    void Blink (long INTERVAL, int LED_PIN)
    Т.е. первый параметр - длительность интервала, а второй - номер выхода.
     
  8. Женёк

    Женёк Нуб

    Да, точно! Спасибо!

    Правда, теперь диод едва мерцает в глубине :) И кнопка по прежнему не действует (что логично)