Занятие №3 Swith

Попробуем сделать кнопку-переключатель

Что хотим

Схему оставляем с прошлого занятия. Но при нажатии на кнопку диод загорается, при повторном нажатии — гаснет.

Этапы работы

  • Пробуем
  • Разочаровываемся
  • Разбираемся
  • Совершенствуем
  • Додумываем

Пробуем

В операторе digitalWrite мы можем вместо слов LOW/HIGH написать переменную, присвоив ей нужное значение. Например так:

int ledStatus = HIGH;

digitalWrite(13,ledStatus);

Еще мы можем поменять значение переменной ledStatus на противоположное:

ledStatus = !ledStatus;

Наш первый проект Blink с применением полученных знаний можно написать так:

int ledStatus = LOW;
void setup () {
pinMode(13,OUTPUT);
}
void loop () {
digitalWrite(13,ledStatus);
ledStatus = !ledStatus;
delay(1000);
}

Теперь вспомним о кнопке — когда мы её нажимаем, будем менять значение переменной ledState на противоположное:

Pin2 = digitalRead(2);
if (Pin2==HIGH) {
ledStatus=!ledStatus;
}
digitalWrite (13,ledStatus);

Полная программа выглядит так:

int ledStatus = LOW;
int Pin2 = LOW;
void setup () {
pinMode(13,OUTPUT);
pinMode(2,INPUT);
}
void loop () {
Pin2 = digitalRead(2);
if (Pin2==HIGH) {
ledStatus=!ledStatus;
}
digitalWrite (13,ledStatus);
}

Кстати, в Arduino IDE (это где Вы набираете программы) можно время от времени нажимать Ctrl+T — это придаст программе «правильный» вид, сместив вложенные операторы вправо. Так делают опытные программисты, только они это делают сами, нажимая клавишу TAB, если им необходимо сместить начало строки вправо.

Собираем, пробуем…

Странно работает. Как-то нечетко. Обратите внимание на потерю яркости диода во время нажатия на кнопку. В чем же дело?

Давайте разбираться.

Разбираемся

Попробуйте замедлить многократно свои действия, не забывая, что процессор Arduino или ChipKit работает с огромной скорость. Что же происходит с точки зрения контроллера?

Вот вы прикоснулись к кнопке, медленно-медленно нажали на неё — контакт замкнулся, в Pin2 попала логическая 1 (HIGH) и программа с радостью отработала if и переключила состояние ledState на противоположное, зажгла диод,и ринулась на следующий виток цикла loop. А палец-то Ваш всё еще жмет на кнопку. В Pin2 опять попадает единица, ledState опять поменялся (уже на LOW), доиод потух и программа ринулась на следующий виток… И так много-много раз в течение даже короткого с Вашей точки зрения нажатия. Диод очень быстро мигает и кажется, что он просто светится не на полную яркость. В дальнейшем мы это его свойство используем (правильнее говорить об особенности зрительного восприятия нашего мозга — диод практически не обладает инерционностью и действительно полностью гаснет и полностью зажигается. Но очень быстро).
Что же будет в переменной ledState при отпускании кнопки? Как повезёт — может 1 (HIGH), а может 0 (LOW). 50 на 50, как говорится.

Вот так работает написанная нами программа.

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

Совершенствуем

Для реализации идеи создадим пару переменных — oldButton и currentButton (старое и текущее состояние кнопки).

Будем считывать состояние кнопки в переменную currentButton, а значение переменной ledState менять в том случае, если текущее состояние кнопки (currentBottom) — 1, а предыдущее состояние кнопки (oldButton) — 0. Поменялось значение переменной ledState или нет, но информация о состоянии кнопки после ветвления устаревает и в переменную oldButton пишем текущее состояние: oldBotton = currentBotton.

Всё. Получилось:

int ledStatus = LOW;
int oldButton = LOW, currentButton = LOW;
void setup () {
pinMode(13,OUTPUT);
pinMode(2,INPUT);
}
void loop () {
currentButton = digitalRead(2);
if (currentButton==HIGH && oldButton == LOW) {
ledStatus=!ledStatus;
}
oldButton=currentButton;
digitalWrite (13,ledStatus);
}

Додумываем

Работает почти чисто. Почему почти? — понажимайте кнопку — изредка проходят сбои.
Дело в так называемом «дребезге контактов» — в момент нажатия кнопка с большой частотой меняет своё состояние и программа успевает включенную кнопку выключить и обратно включить. Лечится это очень просто — пусть после нажатия на кнопку программа немножко отдохнет, даст стабилизироваться кнопке: добавим delay(50) после выполнения оператора digitalRead(2);

Новая проблема — программа работает с delay’ем внутри! Тормозим, однако. Пусть задержка будет только при нажатой кнопке. Если currenButtom равно HIGH.

int ledStatus = LOW;
int oldButton = LOW, currentButton = LOW;
void setup () {
pinMode(13,OUTPUT);
pinMode(2,INPUT);
}
void loop () {
currentButton = digitalRead(2);
if (currentButton==HIGH) {delay(50);}
if (currentButton==HIGH && oldButton == LOW) {
ledStatus=!ledStatus;
}
oldButton=currentButton;
digitalWrite (13,ledStatus);
}

Теперь всё.

Конец занятия.

Успехов!

Реклама

2 комментария (+add yours?)

  1. timophey
    Дек 04, 2011 @ 18:17:13

    Так же проверку можно просто делать раз в 50 мС. Если остаток от деления числа миллисекунд с начала программы на 50 равно нулю, проверять кнопку. Узнать это количество можно с помощью функции «millis()».

    Ответить

  2. Sasa
    Янв 07, 2012 @ 22:02:20

    Саша, если применить кнопку с переключающим контактом, то можно обойтись без delay. Только нужно будет два входа. Поищи «подавление дребезга с помощью RS-триггера».

    Ответить

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: