Как устранить "дребезг" на прерывании?
- Войдите на сайт для отправки комментариев
Ситуация.
Необходимо иметь контроль сетевого напряжения есть/нет.
Для этого использую развязку на оптроне. При отсутствии напряжения сети имеем высокий уровень на входе ардуинки/esp32. Однако в момент перехода из низкого в высокое имеем несколько импульсов , получается типа дребез контактов.
Второе условие - для определения состояния используем прерывание.
На просторах интернета нашел решение, но оно не устраивает , так как имеем срабатывание в момент подачи напряжения(то есть переход на низкий уровень на входе процессора)
Необходимо избавиться от срабатывания при перехода в ноль..
Вот пример скетча.
#define timeSeconds 100
// на 34 пине мониторим напряжение
const int motionSensor = 34;
volatile uint32_t debounce;
void IRAM_ATTR detectsMovement() {
Serial.println("сработало прерывание!!!");
if (millis() - debounce >= 1000 && digitalRead(motionSensor)) {
Serial.println("Вошло в иф!!!");
Serial.println(debounce);
debounce = millis();
Serial.println(debounce);
Serial.println("Падение сетевого напряжения!!!");
}
Serial.println("Мимо ифа или !!!");
}
void setup() {
// инициализируем порт
Serial.begin(115200);
// Motion Sensor устанавливаем как вход (34 пин не имеет резистора подтяжки)
pinMode(motionSensor, INPUT);
// Третий аргумент - это режим. Есть 5 разных режимов:
// LOW: для запуска прерывания всякий раз, когда вывод LOW;
// HIGH: для запуска прерывания всякий раз, когда вывод HIGH;
// CHANGE: для запуска прерывания всякий раз, когда вывод меняет значение - например, с HIGH на LOW или LOW на HIGH;
// FALLING: когда пин переходит из HIGH в LOW;
// RISING: запускается, когда пин переходит с LOW на HIGH.
attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, CHANGE);
}
void loop() {
}
Замена CHANGE на FALLING не приводит к нужному результату.
А зачем прерывание на такой медленный процесс? Тем более, что в сети бывают перерывы до нескольких периодов, например при переключении у конечного потребителя на резервную линию. Есть несколько разных алгоритмов контроля сети переменного тока 50 Гц но все они имеют время принятия решения существенно превосходящее половину периода сети - 10мс.
Что бы не было дребезга надо ставить фильтр на входе. Для сетевого напряжения герц на 100.
Из прерывания не стоит ничего выводить. Надо выставлять флаг, и по флагу вывод делать в основном цикле программы.
И что? с 2018 года не научился вставлять текст программы? Почитай в песочнице правила форума.
Это проект для запуска генератора с отслеживанием сетевого/аккумулятора/генератора.
Можно конечно мониторить в цикле и гонять процессор , но проще пробуждать и выполнять определенный код.
А так спит себе процессор и не жрет ресурсов, можно что то еще навесить на него.
Триггер шмитта
Триггер шмитта
А программно?
Триггер шмитта
А программно?
Честно говоря про сон при контроле сетевого напряжения это даже не смешно. Если б от маленького аккумулятора питание и надо как можно дольше прожить... А так выглядит как фобия какая то.
Вот такая штука используется.
Вот такая штука используется.
Что бы не было дребезга надо ставить фильтр на входе. Для сетевого напряжения герц на 100.
Из прерывания не стоит ничего выводить. Надо выставлять флаг, и по флагу вывод делать в основном цикле программы.
Естественно из прерывания буде выходить только флаг. Но на данный момент ни чего умнее как отключать прерывание на определенный интервал не придумал. Однако тогда рушаться все таймеры. Которые тоже работают на прерываниях.
А программно?
После входа в прерывание ставь задержку на время больше дребезга и ещё раз проверяй наличие напряжения. Но вот как без напряжения будет срабатывать прерывание и как определить, что прерывания не было уже давно и пора уже паниковать? Что то в программе такой случай вообще не обрабатывается.
А запретить флагами только прерывания от одного источника религия не позволяет ???
Там емкость на входе стоит.
А запретить флагами только прерывания от одного источника религия не позволяет ???
А разве так можно? Пойду читать доки.
Можно даже "Машку за ляшку" ...
После входа в прерывание ставь задержку на время больше дребезга и ещё раз проверяй наличие напряжения. Но вот как без напряжения будет срабатывать прерывание и как определить, что прерывания не было уже давно и пора уже паниковать? Что то в программе такой случай вообще не обрабатывается.
[/quote]
Спасибо за пинок в нужном направлении.
Там емкость на входе стоит.
А как же прерывания? С такой емкостью только есть нет индицировать. Или прерывания идёт только при подаче и отключении напряжения?
А как же прерывания? С такой емкостью только есть нет индицировать. Или прерывания идёт только при подаче и отключении напряжения?
[/quote]
Да это нужно для того чтобы знать есть или нет напряжения, а этот кусок программы для того, чтобы избавиться от дребезга.
При пропадании напряжения, происходит разряд конденсатора через оптрон и вот в этом моменте имеется неустойчивое положение и идет "генерация " импульсов 2-6 шт. Подключал осциллограф и регистрировал. Я даже в IF прописывал сообщения в порт, чтобы считывать их.
Я не могу понять из-за дребезга, как выловить , когда переходит в постоянный о , а когда в постоянную 1.
Далее в программе у меня идет выдержка 5 минут, и если не появляется напряжение , то происходит алгоритм запуска генератора.
Если никаких прерываний нет 5 минут и уровень HIGH запускаем генератор, не ?
Если никаких прерываний нет 5 минут и уровень HIGH запускаем генератор, не ?
Хм, а действительно, флаг срабатывания + время срабатывания, да пофиг тогда на колличество срабатываний.
спасибо.
У вас ошибка в алгоритме отслеживания.
Даже учитывая что debounce будет установлен в 0 в самом начале - у вас происходит отслеживания разницы пока прерывания не было.
Скажем так - при первом срабатывании прерывания через более чем 1 секунду от старта программы вы попадете внутрь if в функции прерывания потому, что время без прерывания будет подсчитано как дебаунс.
А вам надо понять было ли пониженное напряжение в течении какого-то времени. А на постоянно пониженное второй раз прерывание не сгенерится. Фактически вам надо отслеживать только прыжки туда сюда, а значит переменная debounce должна обновляться постоянно за пределами if конструкции.
Я бы сделал по другому, в прерывании учитывал бы время срабатывания и обновлял debounce всегда, как точку старта. А проверку сколько времени было то или иной непрерывно одинаковое (пониженное или повышенное) напряжение отслеживал бы в loop().
Для решения запускать или глушить генератор отслеживал бы какое из напряжений (низкое или нормальное) имеет постоянное состоние.
Добавлю delay() в теле прерывания использовать нельзя. Насколько мне известно - там это не сработает (так вроде в описании), ну и millis внутри прерывания работает 1 раз и всегда в следующие вызовы возвращает тоже самое время.
Насколько корректен такой код внутри функции прерывания?
Вроде работает. удаляет весь дребезг.
Интересно, как работает Serial.println, когда прерывания запрещены?
P.S.
Замечание по использованию
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile
Интересно, как работает Serial.println, когда прерывания запрещены?
P.S.
Замечание по использованию
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile
Всё неправда, кроме millis()
Всё неправда, кроме millis()
Не знаю, у меня было дело Serial.print не работал, пока перед ним sei() не поставил
Не знаю, у меня было дело Serial.print не работал, пока перед ним sei() не поставил
Вывод в порт прекрасно работает, но это для отладки. Смысл в том , что получать флаг в ифе.
Где то говорили, что case быстрее отрабатывает, но пока это еще не актуально.