Урок 8. Цифровая фильтрация сигналов в программах для Ардуино.

Arduino UNO R3

Узнаем о другом способе обработки сигнала кнопки для фильтрации помех и устранении дребезга контактов.

Предыдущий урок     Список уроков     Следующий урок

В уроке 6 мы рассмотрели один из способов устранения дребезга контактов кнопки и написали программу для его реализации.

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

 

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

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

А ведь такая ситуация вполне реальная.

  • Кнопка может быть подключена к контроллеру длинными проводами. Пример – кнопка на выносном пульте, расположенном на значительном расстоянии от контроллера. В этом случае в сигнале могут присутствовать импульсы электромагнитных помех.
  • Кроме кнопок, в электронных системах существует много различных компонентов с механическими контактами: реле, выключатели, датчики, конечные выключатели и т.п. Все они требуют устранения дребезга и, как правило, соединяются с контроллером длинными проводами.
  • Существует большое число компонентов, не имеющих механических контактов, но которые практически всегда устанавливаются на значительном расстоянии от контроллера. Например, оптические датчики, используемые для контроля положения механических узлов оборудования.
  • Сигналы, связи между электронными устройствами, расположенными на большом расстоянии друг от друга, также подвержены электромагнитным помехам и требуют программной обработки.

Удачный пример – охранная сигнализация.

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

И так:

  • Когда мы говорим о кнопках, мы имеем в виду любые компоненты с механическими контактами: реле, герконы, концевые выключатели и т.п. У этих элементов тоже есть дребезг контактов.
  • Любой внешний сигнал, даже не имеющий дребезга при переключении, подвержен электромагнитным помехам и должен обрабатываться программой для повышения помехозащищенности.

Во всех этих случаях следует применять цифровую фильтрацию сигналов, которая значительно повышает устойчивость к электромагнитным помехам.

 

Существуют очень сложные алгоритмы цифровой обработки сигналов. В нашем случае достаточно простого усреднения уровня сигнала. По диаграмме, показанной выше, мы легко определяем состояние сигнала. Мы просто видим, что в первой половине диаграммы средний уровень явно высокий, а во второй половине – низкий. И короткие помехи не мешают нам визуально определить состояние сигнала.

Алгоритм усреднения достаточно прост и выглядит так. Нам необходим счетчик среднего значения сигнала и константа AVERAGE_TIME  – время усреднения.

алгоритм цифровой фильтрации сигнала

  • В цикле, с определенным периодом (например, 2 мс) мы считываем состояние сигнала.
  • Если оно низкого уровня, то вычитаем из счетчика 1. Если высокого – прибавляем 1.
  • Содержимое счетчика ограничиваем снизу на уровне 0 и сверху на уровне константы, определяющей время усреднения.
  • Таким образом, счетчик содержит среднее значение уровня сигнала.
  • Когда содержимое счетчика достигает 0 принимается решение, что контакты замкнулись.
  • Когда содержимое счетчика достигает значения ограничения – константы AVERAGE_TIME,  принимается решение о том, что контакты разомкнулись.

Вот диаграммы, показывающие работу алгоритма усреднения сигнала.

Цифровая фильтрация сигнала контактов

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

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

 

Реализация алгоритма цифровой фильтрации сигнала в программе для Ардуино.

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

Назовем метод filterAvarage (фильтрация по среднему значению).

Считаем, что в классе может быть использован только один из двух методов обработки сигнала:

  • scanState()  - проверка состояния (был создан в передыдущем уроке);
  • filterAvarage() – фильтрация по среднему значению.

В таком случае нам не надо создавать новые переменные. Мы можем использовать те же признаки, те же переменные. Ограничение – можно вызывать только один из методов для каждого объекта. С точки зрения объектно-ориентированного программирования это не совсем хорошо, но помним, что ресурсы нашего контроллера ограничены. Проблем такая универсальность нам не создаст.

Добавим метод  filterAvarage() в описании класса Button.

class Button {
  public:
    void  filterAvarage(); // метод фильтрации сигнала по среднему значению
    . . . . . . . . . . . . .            // другие члены класса
};

Напишем код для нового метода.

// метод фильтрации сигнала по среднему значению
// при сигнале низкого уровня flagPress= true
// при сигнале высокого уровня flagPress= false
// при изменении состояния с высокого на низкий flagClick= true
void Button::filterAvarage() {

 if ( flagPress != digitalRead(_pin) ) {
     //  состояние кнопки осталось прежним
     if ( _buttonCount != 0 ) _buttonCount--; // счетчик подтверждений - 1 с ограничением на 0
  }
  else {
     // состояние кнопки изменилось
     _buttonCount++;   // +1 к счетчику подтверждений

     if ( _buttonCount >= _timeButton ) {
      // состояние сигнала достигло порога _timeButton
      flagPress= ! flagPress; // инверсия признака состояния
     _buttonCount= 0;  // сброс счетчика подтверждений

      if ( flagPress == true ) flagClick= true; // признак клика кнопки      
     }   
  }
}

Комментировать не буду.

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

/*  Программа sketch_8_1 урока 8
 *  К плате подключены 2 кнопки и светодиод
 *  Каждое нажатие кнопки 1 меняет состояние светодиода на плате Ардуино
 *  Каждое нажатие кнопки 2 меняет состояние светодиода на макетной плате */

#define LED_1_PIN 13     // светодиод 1 подключен к выводу 13
#define BUTTON_1_PIN 12  // кнопка 1 подключена к выводу 12
#define BUTTON_2_PIN 11  // кнопка 2 подключена к выводу 11
#define LED_2_PIN 10     // светодиод 2 подключен к выводу 10

// Описание класса обработки сигналов кнопок
class Button {
  public:
    Button(byte pin, byte timeButton);  // конструктор  
   boolean flagPress;    // признак кнопка в нажатом состоянии
    boolean flagClick;    // признак нажатия кнопки (клик)
    void  scanState();    // метод проверки состояние сигнала
    void  filterAvarage(); // метод фильтрации сигнала по среднему значению
    void setPinTime(byte pin, byte timeButton); // метод установки номера вывода и времени (числа) подтверждения
  private:
    byte  _buttonCount;    // счетчик подтверждений состояния кнопки  
    byte _timeButton;      // время подтверждения состояния кнопки
    byte _pin;             // номер вывода кнопки
};

boolean ledState1;         // переменная состояния светодиода1
boolean ledState2;         // переменная состояния светодиода2

Button button1(BUTTON_1_PIN, 15);  // создание объекта для кнопки1
Button button2(BUTTON_2_PIN, 15);  // создание объекта для кнопки2
  
void setup() {
  pinMode(LED_1_PIN, OUTPUT);           // определяем вывод светодиода1 как выход
  pinMode(LED_2_PIN, OUTPUT);           // определяем вывод светодиода2 как выход
}

// бесконечный цикл с периодом 2 мс
void loop() {

  button1.filterAvarage();  // вызов метода фильтрации по среднему сигнала кнопки 1
  button2.scanState();  // вызов метода сканирования состояния сигнала кнопки 2

 
  // блок управления светодиодом1
  if ( button1.flagClick == true ) {
    // кнопка была нажата
   button1.flagClick= false;         // сброс признака клика кнопки
    ledState1= ! ledState1;             // изменение состояние светодиода
    digitalWrite(LED_1_PIN, ledState1);  // вывод состояния светодиода1   
  }

  // блок управления светодиодом2
  if ( button2.flagClick == true ) {
    // кнопка была нажата
    button2.flagClick= false;         // сброс признака клика кнопки
    ledState2= ! ledState2;             // изменение состояние светодиода
    digitalWrite(LED_2_PIN, ledState2);  // вывод состояния светодиода2   
  }

/*
    // проверка признака кнопка нажата
    digitalWrite(LED_1_PIN, button1.flagPress);
    digitalWrite(LED_2_PIN, button2.flagPress);
*/

  delay(2);  // задержка на 2 мс
}

// метод фильтрации сигнала по среднему значению
// при сигнале низкого уровня flagPress= true
// при сигнале высокого уровня flagPress= false
// при изменении состояния с высокого на низкий flagClick= true
void Button::filterAvarage() {

 if ( flagPress != digitalRead(_pin) ) {
     //  состояние кнопки осталось прежним
     if ( _buttonCount != 0 ) _buttonCount--; // счетчик подтверждений - 1 с ограничением на 0
  }
  else {
     // состояние кнопки изменилось
     _buttonCount++;   // +1 к счетчику подтверждений

     if ( _buttonCount >= _timeButton ) {
      // состояние сигнала достигло порога _timeButton
      flagPress= ! flagPress; // инверсия признака состояния
     _buttonCount= 0;  // сброс счетчика подтверждений

      if ( flagPress == true ) flagClick= true; // признак клика кнопки      
     }   
  }
}

// метод проверки состояния кнопки
// при нажатой кнопке flagPress= true
// при отжатой кнопке flagPress= false
// при нажатии на кнопку flagClick= true
void Button::scanState() {

 if ( flagPress != digitalRead(_pin) ) {
     //  состояние кнопки осталось прежним
     _buttonCount= 0;  // сброс счетчика подтверждений
  }
  else {
     // состояние кнопки изменилось
     _buttonCount++;   // +1 к счетчику подтверждений

     if ( _buttonCount >= _timeButton ) {
      // состояние кнопки не мянялось в течение времени _timeButton
      // состояние кнопки стало устойчивым
      flagPress= ! flagPress; // инверсия признака состояния
     _buttonCount= 0;  // сброс счетчика подтверждений

      if ( flagPress == true ) flagClick= true; // признак клика кнопки      
     }   
  }
}
// метод установки номера вывода и времени подтверждения
void Button::setPinTime(byte pin, byte timeButton)  {

  _pin= pin;
  _timeButton= timeButton;
  pinMode(_pin, INPUT_PULLUP);  // определяем вывод кнопки как вход
}

// конструктор класса Button
Button::Button(byte pin, byte timeButton) {

  _pin= pin;
  _timeButton= timeButton;
  pinMode(_pin, INPUT_PULLUP);  // определяем вывод кнопки как вход
}

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

Наиболее дотошливые читатели могут проверить работу алгоритма. Для этого надо искусственно сделать время усреднения очень большим. Время усреднения будет равным 5 секунд, если Вы:

  • при создании объектов-кнопок второй параметр зададите максимальным
    Button button1(BUTTON_1_PIN, 250);  // создание объекта для кнопки 1
    Button button2(BUTTON_2_PIN, 250);  // создание объекта для кнопки 2
  • время цикла зададите 20 мс
    delay(20);  // задержка на 20 мс.

Теперь удалите блоки управления светодиодами от признаков-кликов кнопок и сделайте управление светодиодами от признаков кнопка нажата.

digitalWrite(LED_1_PIN, button1.flagPress);
digitalWrite(LED_2_PIN, button2.flagPress);

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

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

 

Мы закончили создание класса Button – кнопка. Кнопка оказалась не таким уж и простым элементом. В следующем уроке оформим этот класс библиотекой.

 

Предыдущий урок     Список уроков     Следующий урок

3

Автор публикации

не в сети 2 дня

Эдуард

279
Комментарии: 1936Публикации: 197Регистрация: 13-12-2015

44 комментария на «Урок 8. Цифровая фильтрация сигналов в программах для Ардуино.»

  1. Как подручными средствами можно специально навести помехи и проверить работоспобность метода в так сказать «реальных» условиях? Или это слишком муторно? Заранее спасибо!

    0
  2. Несколько раз пытаюсь усвоить урок Смотрю на осциллограммы и не могу понять что вы вообще делаете программным способом устраняя импульсные помехи….Если считывать цифровое значение с кнопки то оно уже будет только или 1 или 0 и других значений принимать не будет и при помехе эпюры в цифровом значении не будут отличаться от дребезга .Вот если аналоговый сигнал считывать с кнопки тогда возникает возможность выделить полезный сигнал из помехи…

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

      0
      • позвольте выражу мысли в слух.
        Если за промежуток времени появился лог 0 то кнопка нажата. , что нам собственно и нужно , а зачем нам считать лог 1? Лог 1 дадут нам представление не об уровне сигнала а его длительности…

        0
        • Вы невнимательно прочли матчасть. При длинных проводах, да ещё и не экранированных, на линии связи контроллера с кнопкой может возникнуть наведённый электрический импульс, который контроллер уловит и отработает по программе, если не применять программную (или иную) фильтрацию. Вы же не хотите чтоб Ваше устройство срабатывало 50 раз в секунду, получая наводку от осветительной сети!? А программу написать проще, чем городить огород на дополнительных электронных компонентах. В общем, это наш путь — путь наименьшего сопротивления.

          0
  3. здравствуйте. как нужно написать эту логику.

    if (кнопка нажата или отжата более 10 секунд )
    то на выходе pin 12 LOW
    else
    pin 12 HIGH

    0
  4. А вот как раз то, что я хотел от обработчика нажатий кнопки.
    Теперь прога — нраица!

    0
  5. Не слишком ли много мудрости для кнопки? Прошу извинить, но растянутость в три урока про дребезг только добавляет неразберихи. За труд, безусловно-спасибо!

    0
  6. Да, Эдуард, к обработке сигнала с кнопки Вы подошли основательно. Но мне кажется проблему надо решать в первую очередь аппаратно, в затем уже программно. Проще и правильнее поставить конденсатор параллельно кнопке для подавления дребезга, для длинной линии поднять ток в цепи кнопки или вообще опторазвязку, чтобы контроллер не пробить статикой.

    0
    • Здравствуйте!
      Совершенно не согласен. Конденсатор на кнопке — очень плохое решение. Чтобы он реально помогал надо использовать конденсатор достаточно большой емкости. Тогда снизится скорость реакции на кнопку. Конденсатор завалит фронт импульса. Это не очень хорошо для входов микроконтроллера, для чистой CMOS логики недопустимо. При отжатии кнопки напряжение на входе будет медленно нарастать и при приближении к порогу срабатывания могут проскакивать многочисленные импульсы. Т.е. будет видимость, что кнопку нажали много раз. При значительной емкости конденсатора в момент нажатия конденсатор будет разряжаться на кнопку, что нехорошо для контактов. Будет еще много неприятностей. А вход микроконтроллера статикой не пробит. На входах стоят защитные диоды.

      0
      • Здравствуйте! В какой-то степени Вы конечно правы, но я останусь при своем мнении. Небольшой конденсатор емкостью, допустим, 0,1 мкф фронты не завали и кнопку не испортит. Во входной логике гистерезис уровней заложен и нечего ей не будет. Зато наводки высокочастотные на схему снизятся. А выводить провода и кнопки за корпус устройства без какой либо защиты не хорошо ИМХО.

        0
  7. Здравствуйте. Не подскажите скетч подключения газового анализатора с отправкой по смс, или адрес не подскажите где найти можно? Кругом одни сигнализации, а пожарной и газовой нет…

    0
  8. Уберите метод void Button::setPinTime(). Он не нужен, более того он опасен. Приучайте сразу к правильному программированию, не плодите быдлокодеров.
    Если вы создадите объект
    Button b(12,15);
    у вас пин 12 настроиться как вход с пулапом.
    потом решите поменять
    b.setPinTime(9,15);
    у вас новый пин 9 настроиться как вход с пулапом. а пин 12 тоже останится входом с пулапом. Нужно старый пин деинициализировать.
    можно сделать метод, если сильно нужно.
    Button::setTime(…)

    0
  9. Здравствуйте! Отличные уроки.
    Подскажите, как это работает?
    ………………..
    if ( flagPress != digitalRead(_pin) ) {
    // состояние кнопки осталось прежним
    if ( _buttonCount != 0 ) _buttonCount—; // счетчик подтверждений — 1 с ограничением на 0
    }
    И еще вопрос. Можно ли записать код вот так?

    if(flagPress!=digitalRead(_pin)&&(_buttonCount!=0)){
    buttonCount—;
    }

    У меня просто по другому вообще не хочет работать.Ведь для выполнения buttonCount—; необходимо одновременное выполнение двух условий:
    1.Чтобы кнопка поменяла свое состояние.
    2.Чтобы кнопка поменяла до этого свое состояние хотя бы один раз?

    0
  10. Здравствуйте.

    Для чего в программе метод setPinTime? В данном примере (и в более раннем уроке) он не используется и можно выкинуть из программы (он же только объявляется в начале и в конце описывается).

    0
    • Здравствуйте!
      Метод может потребоваться, например, на случай, если необходимо в уже созданном объекте Button изменить время усреднения сигнала.

      0
  11. Здравствуйте! поясните пожалуйста,не могу разобраться.
    void Button::filterAvarage() {

    if ( flagPress != digitalRead(_pin) ) {
    // состояние кнопки осталось прежним
    if ( _buttonCount != 0 ) _buttonCount—; // счетчик подтверждений — 1 с ограничением на 0
    }
    else {
    // состояние кнопки изменилось
    _buttonCount++; // +1 к счетчику подтверждений

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

    0
    • Здравствуйте!
      В коде от счетчика отнимается 1 если состояние кнопки не изменилось. Т.е. признак flagPress не равен текущему состоянию сигнала. Не равен потому, что при нажатой кнопке состояние сигнала — низкий уровень.
      Блок-схема показывает принцип работы алгоритма усреднения. Реализация его несколько другая.

      0
  12. Здравствуйте. Почему в setup не устанавливаются начальные значения переменных ledState?
    Для надёжности нужно их установить в false.

    0
  13. Эдуард, доброго времени суток!
    Прошу пояснить такой момент:
    — в блок-схеме значение счетчика (buttonCount) либо ++, либо —, с ограничениями;
    — в методе filterAverage() он у вас и ++, и —, а еще и обнуляется при достижении верхней границы счета: _buttonCount= 0; // сброс счетчика подтверждений.
    Обнуление в методе scanState() выглядит вполне логично, но для filterAverage() мне оно не понятно.

    0
    • Здравствуйте!
      Я не помню точно, но скорее это ограничение счетчика среднего значения снизу. Иначе он при вычитании из 0 переполнится.

      0
  14. Был вопрос: как сгенерировать дребезг контактов? У меня для этого есть проверенный способ: старый, усталый, дребезжащий тумблер…
    А аппаратных методов борьбы придумано много. Например, выпускаются спец. микросхемы, реализующие усреднение на регистрах сдвига… Идеально борется с дребезгом переключатель, управляющий RS-триггером. И т.д, и т.п.

    0
  15. Подскажите, пожалуйста, Эдуард, почему после установки признака flagClick==true, в программе не обнуляется flagPress и требуется дополнительное время на декременцию счетчика countButton, затем на полный цикл проверки отжатия?

    P.s. Спасибо Вам за Вашу работу и более чем подробные уроки

    0
    • Здравствуйте!
      Признак flagPress отслеживает состояние кнопки. Он устанавливается и сбрасывается в методе scanState. Основная программа может только проверять его состояние.
      Признак flagClick в методе scanState только устанавливается. Он показывает, что было нажатие кнопки, был отрицательный фронт сигнала. После его проверки он должен быть сброшен в основной программе, чтобы выделить новое нажатие.
      Второй вопрос не очень понял. Время требуется согласно алгоритму, описанному в уроке.

      0
      • Ну как я понимаю, scanState() отслеживает нажатие кнопки длительностью 15*2 мс, если за это время меняется фронт сигнала кнопки, то счетчик _buttonCount обнуляется. filterAverage() же не действует так строго, а лишь понижает _buttoncount—. Так после обеих функций после установки признака flagClick как бы происходит обратная проверка то что кнопка была отжата только уже flagPress=true и отслеживается положительный фрон сигнала,но если во время этой проверки, когда _flagPress=true будет нажата кнопка то мы попадем в бесконечный цикл и можем удерживать кнопку сколько угодно, мы не сможем получить признак_flagClick =true, пока не выполнится проверка на отжатие. Мой вопрос был в том, будет ли ошибкой обнуление _flagPress как мы это делаем с _flagClick то есть будет ли ошибкой отсутствие проверки отжатия кнопки применительно к реальным условиям.

        0
        • Здравствуйте!
          flagPress это признак состояния кнопки, которое формируют методы filterAverage и scanState. Его нельзя обнулять. Когда состояние кнопки изменится, то изменится и он. Представьте себе, что вы считываете состояние кнопки, просто проверяя логический уровень на выводе. У вас же не возникает мысль сбрасывать состояние входа.

          0
  16. Осмелюсь предложить свой код (на мой взгляд более красивый))) для анализа состояния кнопки по Вашему методу.
    ________________________
    static char count = 0;
    if ( digitalRead(BUTTON1_PIN)== 0 ) {
    count = count+1;} //если кнопка нажата
    else {count = count-1;} //если кнопка не нажата
    count = constrain(count, 0, BUTTON1_TIME); // ограничиваем значение счётчика при переполнении
    if ( count == BUTTON1_TIME) { // если кнопка нажата
    if (press1 = false) buttonClick1 = true; //если нажали сейчас
    press1 = true; }
    if ( count == 0) press1 = false; // если кнопка не нажата
    ____________________
    Разница в обращении со счётчиком count —
    если кнопка нажата — всегда увеличиваем,
    если отжата — всегда уменьшаем.
    Такой код — без зеркальной логики — проще понять и осознать.
    Переполнился при увеличении — кнопка нажата.
    Переполнился при уменьшении — кнопка не нажата.
    (Особенность — count должен иметь возможность быть отрицательным. Поэтому char (или int))

    0
    • Здравствуйте!
      Код вполне имеет право на жизнь. Но он используется для микроконтроллеров с ограниченными ресурсами. Еще и в обработчике прерываний.
      Значит, код должен минимизироваться по времени выполнения. А вы используете функцию constrain. Вызов функции с передачей аргументов через стек довольно длительная операция. Она потребует времени больше, чем выполнение всего остального кода. Проблема усугубляется тем, что часто необходима обработка нескольких кнопок.
      Мне не в вашем коде не нравится использование функции constrain.

      0
  17. if ( _buttonCount != 0 ) _buttonCount—; // счетчик подтверждений — 1 с ограничением на 0
    Как здесь установлено ограничение buttonCount на 0? Почему оно не перейдет в область отрицательных значений и так далее?

    0
  18. В методе FilterAvarage в конце программы — if (flagpress==true) flagClick=true. А если (flagPress==false), то flagClick=false ?

    0
    • Здравствуйте!
      Признак flagClick устанавливается в методе scanState. А в основном программном цикле он проверяется, и, если установлен, то выполняются определенные действия и он сбрасывается.

      0
  19. Получилось получить нужный уровень звона контактов, чтобы корректно работала только функция из этого урока, для этого взял кнопки с графитовым напылением, как в пультах от ТВ, если нажимать под уголом, то время срабатывания теряется за звоном контактов, а вот сбор данных и усреднение работает наура

    0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".