обработка нажатия кнопки при включении питания arduino
- Войдите на сайт для отправки комментариев
Пнд, 03/09/2012 - 10:18
Здравствуйте.
Комплектация следующая: arduino nano, кнопка и Led (подключено все по стандартным схемам с примеров ардуинных).
Задача следующая (упращенная): если при включении ардуины кнопка была нажата - Led мигает с одной частотатой, если при включении ардуинки кнопка не нажата - Led мигает с совершенно другой частотой.
Но получается так что даже если при включении кнопка нажата, то ардуина обрабатывает ее как "кнопка не нажата".
код:
const int buttonPin = 2; // the number of the pushbutton pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
int ledPin = 9; // LED connected to digital pin 9
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers
int dCount;
int fadeValue = 255;
void setup() {
pinMode(buttonPin, INPUT); // nothing happens in setup
}
void loop() {
if (debounce() == 1) //если нажата
{leds(1) ;
leds(1);
leds(1);
leds(1);
}
else {leds(5); //если не нажата
leds(5);
leds(5);
leds(5);
}
}
int debounce() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonState = reading;
}
// set the LED using the state of the button:
digitalWrite(ledPin, buttonState);
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
lastButtonState = reading;
return buttonState;
}
void leds(int d) {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
delay(d*50);
digitalWrite(ledPin, HIGH);
delay(d*50);
digitalWrite(ledPin, LOW);
delay(d*50);
digitalWrite(ledPin, HIGH);
delay(d*50);
}
Подскажите как можно решить эту проблему?
С уважением,
zz-vop
Вам нужно функцию debounce() переместить из loop (17 строка) в setup, предварительно объявив глобальную переменную.
объявляете переменную:
в setup() присваиваем этой переменной состояние кнопки:
в loop() меняем 17 строку вот так:
Или при объявлении переменной сразу присвоить состояние кнопки:
Сделал, но результат такой же.
Для эксперимента я объявил boolean button = 1, потом включил с нажатой кнопкой (по идее должно было сработать), но цикл пошел по "кнопка не нажата".
Спасибо. я вообще избавился от функции debounce(), а напрямую digitalRead(buttonPin) использовал и все как надо стало.
1. debounce, в вашем случае, не имеет смысла так как вы обильно вызываете delay() внутри loop. Смысл проверять прошло ли 50 миллисекунд с прошлого нажатия если саму проверку мы делаем не чаще чем в 200 msec? Конечно прошло. Само использование delay() уже является одним из способов debounce. Два основных подхода "програмнного антидребезга возможны" - или опрашивать кнопку не слишком часто, или опрашивать "часто как только возможно", но следить за тем сколько времени прошло с прошлого нажатия.
2. При включении debounce тем более не имеет смысла. Про какой lastButtonState может идти речь если мы только включились?
Вообщем debouce у нас тут "дважды не нужен". Нужно тупой digitalRead в setup()
Далее. Зачем эти портянки-повторения вызвовов leds(...)? Любую портянку можно заменить на цикл. for(...). Но если вспомнить что loop() это уже цикл, то и этого не нужно. Достаточно, в loop(), один раз вызывать leds с нужным параметром.
И input можно не включать кнопку. По умолчанию они все на Input. Хотя чистой ошибкой это не является. Для того что-бы легче было читать код можно и явно это указать. Так что это скорее "вопрос стиля", чем "правильно/не правильно".
Далле ledPin на выход достаточно включить один раз, в setup(). И сами пины лучше объявлять через #define, а не константы
Итого: в setup посмотрели на кнопку и решили с какой частотой мигать будем, в loop - мигаем. все.
#define buttonPin 2 // the number of the pushbutton pin #define ledPin 9 // byte ledPeriod; void setup() { pinMode(ledPin, OUTPUT); ledPeriod=digitalRead(buttonPin)?50:250; // 50 если нажата, 250 если не нажата } void loop(){ digitalWrite(ledPin,!digitalRead(ledPin)); // переключаем led на противоположное состояние delay(ledPeriod); }Ну и естественно не забывает что кнопку нужно подключать в соотвесвии со скетчик. Данный скетч подразумевает что кнопка подключена от пина к питанию, а сам пин подтянут, внешним(!) резистором, к земле.
Спасибо. я вообще избавился от функции debounce(), а напрямую digitalRead(buttonPin) использовал и все как надо стало.
Не успел :) У вас вышло короче чем у меня?
а это что-то для меня новенькое.... можно поподробнее?
я так понял аналогично:
if(digitalRead(buttonPin)){ledPeriod=1;}else{ledPeriod=5;}а это что для меня новенькое.... можно поподробнее?
сокращенный синтаксис для if. Грубо говоря можно напискать такую гипотетическую функцию
ЛЮБОЙ_ТИП ifff(bool cond,ЛЮБОЙ_ТИП valueA,ЛЮБОЙ_ТИП valueB){ if(cond)return valueA; else return valueB; }И вызывать ее
так понятно что происходит? Ну а так как написать такую функцию не просто. Из-за того что трудно объяснить компилятору что такое ЛЮБОЙ_ТИП, и не хочется делать писать такую для кажого типа вроде ifffInt, ifffByte и т.п., а нужда в этом - довольно часта, то эту функцию встроили в компилятор. Добавили "синтансический сахар". Ну и придумали, что-бы отличать от обычных функций особый сопрособ вызова.
УСЛОВИЕ?ЗНАЧЕНИЕ1:ЗНАЧЕНИЕ2
Эта конструкция вернет ЗНАЧЕНИ1 если условие истинно и ЗНАЧЕНИЕ2 если нет.
я так понял аналогично:
if(digitalRead(buttonPin)){ledPeriod=1;}else{ledPeriod=5;}В данном случае - да. Но все -таки это ближе к "функции" чем к простому if. А если нам нужно два разных условия проверить? Ище и домножить, например, на разные значения по состоянию второй кнопки
Тогда как? Перебирать 4-ре варинта? Четыре if-а делать? Или два. Но прийдется водить дополнительную переменную.
P.S. Но компилятор, в любом случае, естествнно развернет это в обычные if-ы. Это просто "что-бы код легче читался".
Ладно. Перепишим так что-бы не смущать сокращенным if-ом. Но и полный if-elese я не хочу использовать. Установим значением переменной под дефолту, и будем метья его сли нопка нажата
#define buttonPin 2 // the number of the pushbutton pin #define ledPin 9 // byte ledPeriod=250; // если не нажата void setup() { pinMode(ledPin, OUTPUT); if(digitalRead(buttonPin))ledPeriod=50; // если нажата } void loop(){ digitalWrite(ledPin,!digitalRead(ledPin)); // переключаем led на противоположное состояние delay(ledPeriod); }P.S. Хотя, конечно, в споровождении такой код намного хуже. Значения "разбросанны по скетчу". При изменениях нужно два места найти и поменять их "синхронно".
[...]
Из-за того что трудно объяснить компилятору что такое ЛЮБОЙ_ТИП, и не хочется делать писать такую для кажого типа
[...]
Ну, если начальник отдела подношений не берет, то ведь есть же еще и референты ;)
Пишем определение
и готово. Можно использовать любые типы (естественно, удовлетворяющие синтаксису). Препроцессор сделает все за нас:
Спасибо. Много нового узнал.
Пишем определение
Ну я же сказал "трудно", а не "не возможно". Я же давал на примере функции, а не деректив препроцессора (так еще их объяснять нужно). Можно еще и через шаблоны сделать.
К тому же через #define у вас получилось только "присваивать переменной".
И лабуду типа
вашим дейфаном уже не напишешь. Он может только "присвоить в зависимости от условия", но не "вернуть значение".
Сейчас проверить не начем, а так заработает?
Можно еще и через шаблоны сделать.
Только через шаблоны (что-бы действительно получить функцию) нужно будет ее определение выносить в отдельный .h файл. Из-за глюков IDE который в скетче не понимает такой синтаксис C++.
Так что, лучше оставить эту функцию как "гипотетическую", просто для объяснения идеи сокращенного синтаксиса.
Кстати так же самая проблема с использованием enum или struct в качестве параметров функций. "Прямо в скетче" - не работает, а вот если вынести их определение в отдельный файл - нет проблем. И в скетче будет работать.
Сейчас проверить не начем, а так заработает?
Нет. Открывающих круглых скобок 6-ть штук, закрывающих -5ть. Не скомпилится. Где-то накосячили.
Но "как идея" - сработает. Раз "это функция", то ничто не мешает использовать саму себя в качестве аргументов.
Я же сказал "как идея" - сработает. Проверять конкретно эту строчку. Дописывать сейчас "все окружающие" (определение пинов), сидеть "жакать кнопки, ребуть плату, отписываться о результатах" - у мня нет времени.
Если хотите - напишите скетч целиком. Вместо digitalRead(buttonPin) используйтеся какие-нибудь bool переменные. Устанавливайте их. Результат - выводите в Serial.
Если проблема только "нет под руками на чем проверить" - запущу и отпощу его вывод. Но сам "рабочий скетч", который можно просто copy-past и запустил - пишите сами.
Я просто поправил.
Код:
void setup(){ bool btn1; bool btn2; bool btn3; int period=0; Serial.begin(57600); for(byte i=0;i<8;i++){ btn1=bitRead(i,0); btn2=bitRead(i,1); btn3=bitRead(i,2); period= (btn1)?12:(btn2?32:(btn3?4:0)); Serial.print("btn1=");Serial.print(btn1); Serial.print(",btn2=");Serial.print(btn2); Serial.print(",btn3=");Serial.print(btn3); Serial.print(",period=");Serial.print(period); Serial.println(); } } void loop(){ }Вывод:
Не стал создавать новую тему.
Вот код:
const int buttonPin = 2; // the number of the pushbutton pin int buttonState; // the current reading from the input pin int lastButtonState = LOW; // the previous reading from the input pin int ledPin = 9; // LED connected to digital pin 9 long lastDebounceTime = 0; // the last time the output pin was toggled long debounceDelay = 50; // the debounce time; increase if the output flickers int dCount; int fadeValue = 255; boolean button = 0; boolean Fsett = 0; boolean Dsett = 0; void setup() { pinMode(buttonPin, INPUT); // nothing happens in setup button = digitalRead(buttonPin); } void loop() { Dsett = 0; if (button == 1){ if (debounce() == 1 && Dsett == 0){ pinMode(ledPin, OUTPUT); digitalWrite(ledPin, HIGH); delay(100); dCount +=1; } else {digitalWrite(ledPin, LOW); digitalWrite(ledPin, LOW); delay(dCount*100); digitalWrite(ledPin, HIGH); delay(dCount*100); leds(1); leds(1); leds(1); leds(1); Dsett = 1; if (debounce() == 1 && Dsett == 1) { fadeValue -=5; analogWrite(ledPin, fadeValue); delay(100); } else if (Dsett == 1) {analogWrite(ledPin, fadeValue);} } } else {leds(1);} } }Я не исправлял функцию лед() она тут просто чтоб визуализировать процесс.
Как по моему мнению должен был бы исполняться код, представленный выше: при включеннии питания кнопка нажата и переменная Dsett = 0; -> переходим в условие и начинаем отсчитывать сколько горел LED. Отпускаем кнопку светодиод гаснет на время "сколько горел LED" потом загарается на такое же время. Дальше светодиод судорожно мигает и переменная Dsett становится равной 1. Потом когда я нажимаю кнопку начинается уменьшение частоты ШИМ (наглядно показывается на светодиоде). когда отпускаю - светодиод просто горит с "нужным" ШИМ.
Но на самом деле ШИМ нифига не настраивается. все зацикливается на
else {digitalWrite(ledPin, LOW); digitalWrite(ledPin, LOW); delay(dCount*100); digitalWrite(ledPin, HIGH); delay(dCount*100); leds(1); leds(1); leds(1); leds(1); Dsett = 1;Я уже испробовал и "else if" чет вообще никак. У меня ощущение, что на условие (debounce() == 1 && Dsett == 1) вообще наплевать ардуинке/компилятору. Где я накосячил? может я не понимаю логику работы else/if/else if... (я осознаю говнокодовость выше написанного).
Отдельно без наворотов ШИМ без проблем настраивается вот так вот простым удержанием кнопки и по "отпусканию" кнопки ШИМ такой как надо...
Заранее спасибо.
Сейчас нет времени вглядывать в код, что-бы точно указать строчку, но общие направление поиска должно быть таким:
1. Как я уже писал механизм debounce() и использование delay() - не совместимые вещи. Если "оно работает", то значит debounce вам совсем не нужен. И вы используете его не понимая принципа его работы. Если, все-таки, хотите debounce, что-бы было все "по взрослому" - смотрите в разделе програмирование пример "Мигаем диодом без delay()".
2. Такое впечатление, что вы забываете, что loop() это цикл. Эта функция вызывается раз-за разом бесконечно. Вам нужно смотреть ЧТО у вас происходит ПОСЛЕ того как вы включили шим. Всего на 100 милисекунд. Далее, скорее всего, loop заканчивается и начинается сначала, там попадает в какой-то вариант где вы опять вызываете leds(). Который, естественно отменяет действие шим, и останавливает скетч кучей своих delay(). В результате шим у вас имеет шанс проявить себя всего 100 милисекунд.
Поставте там delay() ощутимей, что-бы точно увидеть что "вы туда попадаете" или Serial.print сделайте. Можете вообще натыкать Serial.print-тов во все ветки и посмотрите куда ваша логика бегает в реальности, а не "как вы думаете".
Спасибо. натыкаю Serial.print'ов. посмотрю куда он там бегает. Вы правы. я все время забываю, что void loop() это бесконечный цикл.
я все время забываю, что void loop() это бесконечный цикл.
Можете написать так:
void loop(){ while(1){ ..... ВАША ЛОГИКА .... } }С точки зрение логики это будет идентично. Расплатитесь несколькими байтами памяти, зато будет "перед глазами" и точно не забудете :)
так и сделал)
так и сделал. нашел все косяки. во всем виновата невнимательность и спешка. все переписал красиво. заработало
спасибо