Текстовая версия:

Перед вами второй урок базового курса робототехники на базе Arduino. В этом уроке мы научимся использовать цифровые входы. Внимание! В этом уроке уже используются различные конструкции языка программирования. Если вы до этого никогда не программировали, настоятельно рекомендую прочитать обучающий раздел, посвящённый языку программирования Arduino. Для этого урока нам понадобятся: светодиод, кнопка, макетная плата, резистор на 200 Ом, резистор на 10 кОм и соединительные провода.

Рис 1. Комплект для второго урока
Цифровой вход нужен для определения наличия сигнала. Для примера мы будем использовать схему с кнопкой. Переработаем схему из первого урока, что бы светодиод зажигался от нажатия кнопки. Конечно, можно собрать такую схему чисто механически:
 
Рис 2. Электротехнический вариант управления светодиода кнопкой.

Кнопка  имеет 2 пары контактов, две из них, которые смотрят друг на друга, замкнуты всегда, а две других замыкаются, когда кнопка нажата. Это хорошо видно на картинке:

Рис.3. Схема работы кнопки.
При нажатии на кнопку, светодиод будет загораться. Выход 5V на плате постоянно подает ток, что равноценно сигналу с цифрового выхода. Но наша задача не лампочкой мигать, а научиться использовать цифровые входы. Для этого нам нужно собрать схему, в которой мы будем регистрировать нажатие кнопки в программе.
Для этого соберем вот такую схему (разделим кнопку и светодиод на разные стороны макетной платы для наглядности):

Рис. 4 Логическая схема с кнопкой.
Сигнал подается через кнопку на pin11. Если кнопка нажата, то цепь замкнута и сигнал есть.
Теперь напишем программу для этого варианта:


void setup() {
  pinMode(8,OUTPUT);  // Объявляем 8 пин на выход
  pinMode(11,INPUT); // Объявляем 11 пин на вход
}
void loop() {
  if (digitalRead(11)==1) //Если на 11 пине есть сигнал
    {
       digitalWrite(8,HIGH); // То подаем сигнал на 8й пин
    }
   else // Во всех других случаях (на 11 пине нет сигнала)
    {
       digitalWrite(8,LOW); // Подаем на 8й пин 0
    }
}


После того как мы ее зальем на контроллер, видно что схема работает плохо – светодиод постоянно горит в половину яркости, а когда кнопка нажата, горит на полную. Но ведь так быть не должно? Правильно, всему виною наводки, которые заставляют pin11 думать, что сигнал есть. Если в коде заменить  11 на любой другой, к которому вообще ничего не подключено, будет заметно, что светодиод иногда помаргивает. Т.е. даже на пустом цифровом входе бывают ложные срабатывания. Но не стоит волноваться, что бы избавиться от этого неприятного эффекта, достаточно добавить в схему землю. Но что бы не терять туда ток, через большой резистор – например 10кОм:
 
Рис. 5 Схема с заземлением.
В этой схеме мы подвели землю и тем самым убрали наводки. В цифровой схеме это сделать не сложно, а вот в аналоговых датчиках борьба с шумами одна из главных проблем. Но до этого нам еще далеко.
Итак, сейчас светодиод, как и должен, загорается при нажатой кнопке, а при не нажатой не горит. Для того, что бы лучше осознать принципы работы контроллера и написания кода, переформируем задачу – при первом нажатии светодиод должен загораться, при следующем тухнуть, потом опять загораться. Длительность удерживания кнопки не должна влиять на результат.

Первое, что приходит на ум:

int svet=0; // Заводим целочисленную переменную для хранения состояния светодиода
void setup() {
  pinMode(8,OUTPUT);
  pinMode(11,INPUT);
}
void loop() {
  if (digitalRead(11)==1 && svet ==0) //Если с кнопки есть сигнал И светодиод выключен
    {
       digitalWrite(8,HIGH); //Зажигаем светодиод
       svet =1; // Записываем новое состояние
    }
   if (digitalRead(11)==1 && svet ==1) //Если с нопки есть сигнал И светодиод горит
    {
       digitalWrite(8,LOW); //Гасим светодиод
       svet =0; // Записываем новое состояние      
    }
}


Однако этот вариант работает нестабильно, лампочка то следует нашим приказам и меняет свое состояние, то нет. Это происходит по 2 причинам:
Во-первых, за секунду код пробегает по кругу много раз и каждый раз условие выполняется. Соответственно и состояние светодиода меняется много раз в секунду. На каком оно остановится, когда мы отпустим кнопку предугадать невозможно.

Во-вторых, у кнопки есть такое неприятное свойство, как дребезг. Когда контакты замыкаются, между ними успевает проскочить разряд и система воспринимает не одно нажатие на кнопку, а сразу 2-4 штуки. Для того, что бы избавиться от этого, необходимо вставлять хотя бы небольшую паузу после регистрации нажатия кнопки. Обычно хватает около 50 мс.


Для этого мы используем вот такой код (если ничего непонятно, еще раз рекомендую ознакомиться со статьей на эту тему):


int svet=0; // Заводим целочисленную переменную для хранения состояния светодиода
void setup() {
  pinMode(8,OUTPUT);
  pinMode(11,INPUT);
}
void loop() {
  if (digitalRead(11)==1 && svet ==0) //Если с кнопки есть сигнал И светодиод выключен
    {
       digitalWrite(8,HIGH); //Зажигаем светодиод
       svet =1; // Записываем новое состояние
       while (digitalRead(11)) // Ждем когда отпустят кнопку
         delay(50);
    }
   if (digitalRead(11)==1 && svet ==1) //Если с нопки есть сигнал И светодиод горит
    {
       digitalWrite(8,LOW); //Гасим светодиод
       svet =0; // Записываем новое состояние
       while (digitalRead(11)) // Ждем, когда отпустят кнопку
         delay(50);        
    }
}


Тут мы должны где-то хранить состояние светодиода и для этого заводим числовую переменную svet, в которой и храним его состояние: 0-выключен, 1-включен. Вообще говоря, такие вещи лучше хранить в переменной типа boolen, но int более универсален и позволяет обслуживать более 2х состояний. В коде программы мы проверяем, есть ли сигнал с кнопки и выключен ли светодиод: if (digitalRead(11) && svet ==0). Если условия выполняются, мы включаем светодиод, записываем его состояние в переменную и потом (важно!) в цикле while дожидаемся, пока сигнал с кнопки пропадет. Предлагаю самостоятельно убрать цикл while, оставив только задержку и посмотреть, что будет.
В качестве самостоятельной работы:
1) Возьмите 2 светодиода. Нажатия кнопки должны делать следующее: горит 1й светодиод, горит 2й светодиод, горят оба светодиода, ни один светодиод не горит.
2) Возьмите 2 кнопки и сделайте, что бы первая кнопка включала светодиод, а вторая выключала.