Официальный сайт компании Arduino по адресу arduino.cc
Таймеры и программный антидребезг входов.
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
16 лет занимаюсь программированием промышленной автоматики на PLC Omron, Siemens. С ардуино столкнулся месяца 2 назад. И сразу же стали бесить delay(), когда для того, чтобы правильно отработал какой-то один алгоритм, приходится тормозить весть проц и все другие аглоритмы.
Для того чтобы использовать фронты дискретных входов, нужно избавиться от дребезга контактов нужно собирать схемы с триггером Шмитта. А если таких входов штук 20???
В итоге написал библиотеку из 2-х классов Timer_P и DI.
Оттестировал. Вроде работает.
Описание:
Класс Timer_P имеет 3 публичных метода, публичные свойства отсутствуют. Timer_P() - конструктор класса, вызывается при декларации объекта класса Timer_P, аргументы отсутствуют. boolean Timer(boolean Condition, boolean Reset,int Mode, long Duration) - основной метод работы таймера Аргументы: - boolean Condition - условие запуска таймера - boolean Reset - условие принудительного сброса таймера - int Mode - режим работы таймера (0...4) см. временную диаграмму Timer_P.png - long Duration - длительность работы таймера в миллисекундах возвращает признак срабатывания таймера long GetRemains() - оставшееся время до срабатывания таймера в миллисекундах. Timer_P работает с фронтами сигналов, поэтому очень чувствителен к дребезгу входных сигналов. Для того, чтобы использовать Timer_P для входов Arduino рекомендуется "пропускать" их через класс DI. Класс DI используется для программой фильтрации дребезга контакта. Класс DI имеет 3 публичных метода, публичные свойства отсутствуют. DI(int PIN, long Duration) конструктор класса, вызывается при декларации объекта класса DI. Аргументы: - int PIN - номер пина Arduino - long Duration - длительность времени фильтрации. boolean DI_Read() - считывание фильтрованного входа, возвращает фильтрованное значени входа. void DI_Refresh() - обновление входа, связанного с объектом класса. Делать pinMode для входов используемых для DI не нужно. Они инициализируются при создании объекта класса DI. При работе со входами используется INPUT_PULLUP-режим. Значения входов нормализовываются во время обработки класса. Замкнутая кнопка - логическая 1 в DI. Пример использования классов в скетче Arduino ------------------------------------------------- #include <DI.h> //подключаем библиотеку DI - обработка дискретного входа из набора библиотек от X-Dron #include <Timer_P.h> //подключаем библиотеку Timer_P - работа с таямерами из набора библиотек от X-Dron #define Condition_PIN 2 //PIN кнопки условия работы таймера #define Reset_PIN 3 //PIN кнопки сброса таймера #define QTimer_PIN 7 //PIN светодиода работы таймера #define QReset_PIN 8 //PIN светодиода сброса таймера Timer_P Timer_Test; //создание и инициализация объекта Timer_Test класса Timer_P // Создание объектов типа "Дистретный вход" они посажены описанные выше пины. Фильтр антидребезга 30мс. DI Condition_IN(Condition_PIN, 30); DI Reset_IN(Reset_PIN, 30); void setup() { //Режимы выходов pinMode(QTimer_PIN, OUTPUT); pinMode(QReset_PIN, OUTPUT); //делать pinMode для входов не нужно. Они инициализируются при создании объекта класса DI см. DI.cpp //при работе со входами используется INPUT_PULLUP-режим. Значения входов нормализовываются во время обработки класса. //замкнутая кнопка - логическая 1. } void loop() { // Обновляем значение дискретных входов // Производится их считывание с пинов и фильтрация через внутреннюю переменную класса. Condition_IN.DI_Refresh(); Reset_IN.DI_Refresh(); //Считываем состояние фильтрованной кнопки сброса таймера и выводим его на лампочку. digitalWrite(QReset_PIN, Reset_IN.DI_Read()); //Запускаем таймер по фильтрованной кнопке запуска таймера. //Сброс выполнения таймера по фильтрованной кнопке сброса таймера. //Режим работы таймера - Mode = 1 extended pulse //Время работы таймера - 1900мс. //Результат работы таймера выводим на светодиод работы таймера digitalWrite(QTimer_PIN, Timer_Test.Timer(Condition_IN.DI_Read(), Reset_IN.DI_Read(), 1, 1900)); //Получаем значение отсрочки срабатывания таймера long T_Remains = Timer_Test.GetRemains(); } -------------------------------------------------
Библиотека находится по адресу
https://github.com/X-Dron/X-Dron_lib
Ссылка для скачивания https://github.com/X-Dron/X-Dron_lib/archive/master.zip
В примерах есть видео для разных режимов работы таймера. Временную диаграмму см. в Timer_P.png
https://raw.githubusercontent.com/X-Dron/X-Dron_lib/master/Timer_P.png
Есть в планах написать еще один класс, который будет имитировать на Arduino входы-выходы как на промышленных контроллерах. Будет:
разбиение адресного поля на отдельные разделы (дискретные входы, дискретные выходы, аналоговые входы, аналоговые выходы).
- Считывание входов в начале цикла loop.
- Вывод выходов в конце цикла loop.
- Возможность настройки антидребезга по любому входному дискретному каналу.
Для мелких контроллеров это практически не актуально, а вот для меги может пригодиться.
Когда дойдут руки - не знаю. Наиболее интересный для себя проект - это все-таки беспроводной ввод-вывод.
X-Dron, было бы любопытно узнать, в чём отличие ваших библиотек от уже существующих.
Хе. Библиотека DigitalTube с классом TM1637, например, работает с 4-х разрядным семисегментным индикатором, а класс Timer_P - создает разные импульсы. Библиотека DHT с классом DHT работает с датчиками температуры и влажности. Каков вопрос таков и ответ. Вы не указали, с какими библиотеками сравнивать, я других аналогичных не встречал. А если серьезно, то Безусловно, везде используются одни и те же принципы работы с основными базовыми наборами функций и атрибутов. Но можно всю жизнь писать на базовом уровне, а можно использовать библиотеки. Это как писать на ассемблере или на объектно-ориентированном языке. По поводу работы с кнопками есть закрепленная тема на форуме. Видел такой вариант фильтрации антидребезга
Т.е. ловим первый первый фронт нажатия, делаем паузу 10мс, снова считываем кнопку. В первых строках поста я описал, что delay() бесит. В системе регулирования паровой турбины за 10мс нужно обработать датчики положения сервоприводов, обработать регуляторы положения, выдать задания на позиционирование. А здесь 10мс фильтруем кнопку и все другое подождет. Я практически не сомневаюсь, что многие будут плеваться, т.к. если полностью отказаться от delay(), то методы программирования будут сильно отличаться. Но они гораздо ближе к тем, что используются в промышленных PLC. Простой пример. http://wiki.amperka.ru/%D0%BA%D0%BE%D0%BD%D1%81%D0%BF%D0%B5%D0%BA%D1%82-... Скетч сделан с использованием delay()
Как задание для самостоятельного решения написано: В игре есть лазейка: кнопку можно зажать до сигнала «пли!» и таким образом сразу же выиграть. Дополните программу так, чтобы так выиграть было нельзя. Начинаешь ловить фронты - ловишь дребезг. Либо используй внешнюю обвязку в виде триггера Шмитта, или делай программно. Решение на моей библиотеке выглядит так, лазейки нет.
Здесь используется обновленная библиотека, в репозитории еще вчерашняя. Обновлю через час-два. Добавился еще один конструктор класса DI и метод инициализации. Это дает возможность создавать массивы класса DI.
с помощью этой библиотеки написан скетч на подсветку с двумя датчиками, ты помогал,кстати, спасибо
сейчас что то глюкануло и не работает, не мог бы еще раз помоч?
Несколько некоректно проводить паралели с тригером Шмидта, с дребезгом эти тригеры не справляются, да они не для того и придуманы. У ардуино Шмидты кстати есть, на каждом порте с гистерезисом около 0.5В, т.е. в "1" при 2.7В, а обратно в "0" при 2.2В
16 лет занимаюсь программированием промышленной автоматики на PLC Omron, Siemens. С ардуино столкнулся месяца 2 назад. И сразу же стали бесить delay(), когда для того, чтобы правильно отработал какой-то один алгоритм, приходится тормозить весть проц и все другие аглоритмы.
Для того чтобы использовать фронты дискретных входов, нужно избавиться от дребезга контактов нужно собирать схемы с триггером Шмитта. А если таких входов штук 20???
Если вы так охрененно озабочены дребезгом, юзайте Кортекс от Nuvoton. Там на портах обработка дребезга хардварная и всё настраивается в регистрах порта при ините.
Для подавления дребезга я использую следующую конструкцию
Висит либо в цикле на конструкции
либо в прерывании таймера, если цикл работает больше 20 мс. Но это как то редко случается.
Выдаёт короткоё и длинное нажатие. Легко позволяет расширить до быстрого повтора короткого нажатия при удержании больше определённого времени - часто использую при настройке параметров. Это конечно не титановый велосипед, но меня полностью удволетворяет. Занимает мало места и времени. Не имеет задержек при подавлении дребезга. Из минусов - для каждой кнопки надо прописать свои параметры и писать строки.