Смена частоты моргания диодом по нажатию кнопки
- Войдите на сайт для отправки комментариев
Пнд, 21/12/2015 - 12:15
Всем привет!
Купил себе стартовый набор Ардуино, чтобы играться, самому и с дочерью :) Опыта в программировании нет никакого вообще (BASIC в 7 классе не в счёт), но не гуманитарий, так что осваиваюсь. Собственно вопрос: написал программу, хочу чтобы она моргала светодиодом с частотой 10 Гц, при однократном нажатии кнопки переходила на частоту 2 Гц, по следующему нажатию выключала диод, и опять по кругу. Вот листинг:
int GREEN1 = 3; //контакт 3 для светодиода int BUTTON = 2; //контакт 2 для кнопки boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки int lmode = 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 т.к. она ничего не вычисляет { while (mode == 0) //если режим равен 0 { digitalWrite (GREEN1, HIGH); //подаём питание delay (100); //держим 100 мс digitalWrite (GREEN1, LOW); //выключаем питание delay(100); //держим 100 мс } while (mode == 1); //если режим равен 1 { digitalWrite (GREEN1, HIGH); //подаём питание delay (500); //держим 500 мс digitalWrite (GREEN1, LOW); //выключаем питание delay(500); //держим 500 мс } while (mode == 2); //если режим равен 1 { digitalWrite (GREEN1, LOW); //выключаем питание } } 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 }
По факту диод всегда моргает с частотой 10 Гц, и не реагирует на кнопку. Есть подозрение, что дело в реализации моргания с помощью delay(t) - выполнение программы прерывается, и обработки нажатия не происходит. Прав ли я?
Извините за глупый вопрос.
Попробуйте так
А также делай надо сменить на милис
Женёк, при запуске скетча Вы попадаете в цикл
while
(mode == 0)
, который будет выполняться бесконечно (выхода из него нет), то есть до следующего перезапуска скетча.vosara, cкопировал ваш код, скомпилировал и залил в плату. Диод моргает странно, два короткие вспышки (примерно по 100 мс как раз), потом пауза на полсекунды, и опять две вспышки. На кнопку не реагирует.
Araris, спасибо! То есть надо в конце каждого блока while считывать значение кнопки что ли?
вы бы вообще ушли от while
Araris и vvadim правы надо уйти от while что я и сделал заменил while на if а кнопка не работает потому что строчку № 48 нужно вынести из if что я и сделал в прилагаемом коде Хотя проблема с делай осталась и кнопку нужно держать нажатой больше одной секунды. Я специально не переписываю Ваш код а только исправил чтобы вам было легче разобраться
Delay() - долой !
Я мигание поместил бы прямо в loop(), примерно так :
vvadim, спасибо!
vosara, вы заменили внутри функции setMode(mode) все циклы while на if? Но я не понимаю, почему так работает :) Внутри конструкции if всё равно нет проверки состояния переменной mode, так же как у меня в while.
Я хочу написать функцию для моргания (чтобы вызывать её из функции setMode), вот код:
Потом я вызываю эту функцию из setMode
Но ничего не работает, диод не моргает, на кнопку не реагирует.
По поводу Вашего кода и желания. Хороший пример дал Araris просто модифицируйте его, если нужна функция возьмите код с 35 строки по 41 и вынесите отдельно.
Кстати, ваш код из предыдущего комментария не работает :( Скопировал его с форума, залил на контроллер, диод дважды моргает быстро, потом пауза на полсекунды. На кнопку не реагирует.
Код Araris тоже не работает, по крайней мере если его взять и скопировать. Он даже не компилируется, т.к. переменная mode не объявлена.
То есть в цикле while возможно только внутреннее изменение условия, а в if() - внешнее?
И есть мысли почему моя функция Blink() не работает? Вы поймите, если бы мне нужен был готовый результат, я бы пошёл в интернет и скачал готовые коды, библиотеки и т.п. Я разобраться хочу, что у меня не так.
Код Araris тоже не работает, по крайней мере если его взять и скопировать. Он даже не компилируется, т.к. переменная mode не объявлена.
Виноват-с, в строках 35, 37, 39 поменяйте mode на lmode.
Проверил в протеусе кнопка не работает по причине отсутствия подтягивающего резистора. Поставте и будет работать!!!
Всё равно не работает. Моргает 10 Гц, на кнопку не реагирует. Через некоторое время просто ровно горит.
Резистор стоит на землю, 10 кОм.
Всё-так подскажите кто знает, где у меня в функциях ошибка? Полный листинг
То есть я хочу иметь отдельную функцию debounce, которая обрабатывает нажатие кнопки, и возвращает текущее состояние. И отдельную функцию моргания, которая моргает указанным диодом с указанной частотой. Просто если я потом захочу добавить ещё 5 диодов с разной частотой моргания, то мне нужно будет всего лишь добавить 5 переменных для их контактов, 5 переменных для интервалов, и вызвать функцию Blink нужное количество раз.
P.S. Чтобы не было сомнений: вот схема соединений, для упрощения убрана монтажная плата. Схема рабочая, простейшая программа - зажечь диод при нажатой кнопке - на ней выполняется.
Сразу бросается в глаза - функция millis() возвращает unsigned long, а в скетче переменные previousTime и Time объявлены как long. С реагированием на кнопку это не связано, но лучше исправьте.
Ещё вопросы:
Что возвращает функция debounce(), если условие в 17-й строке не выполнилось ?
Для чего нужна строка 20 ?
Спасибо за замечание, но мне бы заставить программу работать, а вылизывать стиль можно и потом.
Ничего не выдаёт. А это надо в явном виде прописывать? В строке 20 мы меняем состояние переменной, хранящей состояние кнопки. То есть, если состояние кнопки изменилось, мы ждем 10 мс, ещё раз считываем его, и если оно за это время не изменилось, то мы считаем, что последнее измерение - правильное.
Сделайте временно 55-ю строку как currentButton = digitalRead(BUTTON);
Мистика какая-то! Не компилирует, на строке 01 выдаёт ошибку: 'int GREEN1' previously defined here
Перезапустил IDE, скомпилировалось. Замена на
эффекта не дала, не работает!
OK, есть ещё один способ понять, что же происходит при работе скетча.
В setup() пропишите Serial.begin(9600);
В интересующих местах выводите в монитор последовательного порта нужную информацию, например, после строки 58 вставьте Serial.print("lmode="); Serial.println(lmode);
Или, скажем, после строки 20 - Serial.print("current="); Serial.println(current);
Ну и тому подобное. Типа дебаггер.
Так, прошлое сообщение удалил, в нём смысла нет.
Рукотворный дебаггер говорит, вот что при однократном нажатии
Вот Ваш рабочий код, Сравните с тем что Вы опубликовали и проанализуйте ошибки описывать не буду.
Огромное спасибо! Всё-таки надо мне подтянуть "азы" :)
P.S. C точки зрения эффективности использования памяти, есть разница между такой записью:
и такой:
Или это одно и то же по сути?
Да но это не ошибка а оптимизация кода.
Я понимаю, что не ошибка. Даже вот так будет работать:
А в чём оптимизация? Как-то скажется на быстродействии/памяти, или это вопрос стиля?
И ещё вопрос новичка. Есть вот такой код:
Если "условие 1" ложно, будут ли выполняться второй и третий блоки if?
будут
Опять проблемы :D Добавил в функцию setMode() вот такой блок:
И в строке 67 сделал так:
И не работает, либо выключен диод, либо моргает с интервалом GREEN1_INTERVAL1. В чём может быть дело?
Не работает на чётном числе режимов. Если добавить ещё один (я добавил свечение в полнакала через ШИМ), и заменить на lmode==5, то опять работает :)
Я сделал так как Вы описали и все отлично работает
как ускорить генерацию до килогерц ?
я ставил интервал 0 и генерация слабая мне нужно больше частоту
как это сделать?
Сокращать время выполнения цикла. Теоретический предел около мегагерца. У Вас есть куда стремиться.