Ардуино - одновибратор. Как создать?

День добрый, коллеги! Возникла задача по кнопке (сидящей на прерывании) на одном из пинов надо выдать одиночный импульс длиной, скажем, 100 мсек. Delay() и Millis(), как я понимаю, в прерывания не суют. Одним из выходов вижу в прерывании объявить некий флаг как “true”, а Loop’e смотреть: если он “true”, то подать на пин “HIGH”, а по прошествии времени (через Millis()) - подать “LOW“ и обнулить флаг. Правильно ли я рассуждаю? Или есть некий оператор для такого действия (увы, не нашел…). Или есть еще какой-то более изящный способ?

Заранее спасибо!

NE555

Спасибо, про это я в курсе. Не хочется насыщать девайс лишним железом. Такая (вроде бы) простая задача должна решаться программно. Мне кааца :slight_smile:

Тогда кнопка, флаг, таймер.

Специальный оператор? Смеетесь?

А то что вы описали - не “программно”? Что может быть проще, чем включить вывод на пин, выждать время и потом выключить?

В прерывании если флаг==0, то пин в 1, флаг=1, запоминаем миллис

В loop() если флаг==1 и прошло время, то пин в 0 и флаг=0

Это совет тепличника доктору))

А чё, я так и писал в первом посте. В общем, понял, моя “мысля“ получила одобрение у титанов. Так и поступим. Вообще-то доктора страсть как не любят советы. А я - люблю. Наверное, я плохой доктор, неправильный :). И еще: спасибо за запоминание миллиса В ПРЕРЫВАНИИ! Это правильно.

ты тока про дребезг не забудь

Дались вам эти прерывания ))

#include <shButton.h>      // https://github.com/VAleSh-Soft/shButton
#include <shTaskManager.h> // https://github.com/VAleSh-Soft/shTaskManager

constexpr uint8_t buttonPin = 2;
constexpr uint8_t ledPin = 13;

shTaskManager tasks(1); // создаем диспетчер задач с 1 задачей

shHandle led_pulse;      // задача по выдаче импульса на пин светодиода
shButton btn(buttonPin); // собственно кнопка

void led_pulse_task()
{
  if (!digitalRead(ledPin))
  {
    // если светодиод не горит - зажигаем его и стартуем задачу, чтобы она еще раз сработала через 100 мс
    digitalWrite(ledPin, HIGH);
    tasks.startTask(led_pulse);
  }
  else
  {
    // если светодиод уже горит - гасим его и останавливаем задачу
    digitalWrite(ledPin, LOW);
    tasks.stopTask(led_pulse);
  }
}

void setup()
{
  pinMode(ledPin, OUTPUT);

  led_pulse = tasks.addTask(100ul, led_pulse_task, false); // инициализируем задачу, длительность импульса 100 мс
}

void loop()
{
  if (btn.getButtonState() == BTN_DOWN)
  {
    // если кнопка нажата, выдаем импульс
    tasks.taskExes(led_pulse, false);
  }
}

это и есть защита от дребезга

В прерывании от кнопки запускай таймер на 100мс, пин устанавливай в HIGH. Флаг еще добавь для защиты от дребезга, как @Pyotr советует.

Через 100мс сработает прерывание от таймера - прямо в прерывнии пин устанавливай в LOW.

Таким образом у тебя будет два прерывания: одно по нажатию кнопки, второе - от таймера.

Отчего же не суют. Суют. Но, как правило, не больше одного вызова на прерывание: последовательный вызов millis() внутри прерывания с большой вероятностью вернет одинаковые значения, но тут зависит от Ардуины - на каком процессоре сделана. Например, на ESP32 - millis() работает от фонового микросекундного таймера, и можно его вызывать сколько хочешь раз в прерывании, получая корректные значения. А на какой-нибудь простенькой Ардуине millis() сам зависит от прерываний.

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

Но если задержки большие (>100мс) то в прерывании ждать плохо - вся система же стоит, ждет, когда прерывание будет обработано. Остальные прерывания не работают в это время, система в коме :). На процессорах типа ESP32 в таких случаях система будет перезагружена Interrupt Watchdog Timerом - типа, слишком долго обрабатываем прерывание.

Задержки внутри прерываний делаются “в лоб“ :

...
...
for (int i = 0; i < X; i++)
  asm volatile ("nop\r\n");

Смотришь, сколько по времени выполняется NOP (обычно - 1 такт процессора, 1/CPU_Frequency; ), подбираешь полуэкспериментально параметр X.

Ага, спасибо! Разберусь. Код в копилку!

Ардуина Мега. Попробую.

Да, в моем случае дребезг недопустим. Есть такая микруха MC14490. Поигрался с ней. Что энкодер, что кнопка - после микрухи идеальные импульсы как на дорогом генераторе. Обвеса (RC-цепочки) никакого не надо - подключается все прямо к ней.

1 лайк

Прерывания здесь лишние. Таски на любителя. Лучше что бы сам прочувствовал.

Вы сегодня в ударе, как я погляжу. Практически весь ответ - вредная для новичка бредятина.

Ж))))) ну я же написал несколько раз, что это плохо и прочее. но можно.

и с таймером, что-ли плохой совет? ну и ладно, пойду программы программировать тогда.

С водой мы еще не закончили - я там подогнал научные результаты, полученные цифровыми приборами в полевых условиях.

А у вас поди в чайнике и накипь не собирается сантиметрами?

А должна? У нас, например, вода артезианская, мягкая :wink: