«Обрабатываем нажатие кнопки» средствами Arduino UNO.

Тема статьи: 
Электронные поделки и механизмы

https://youtu.be/y1GybYN6w9s

В прошлой статье мы программировали «бегущий огонёк» на разноцветных диодах, средствами платы Arduino UNO. Сейчас мы немного расширим навыки и в схему из нескольких светодиодов добавим кнопку.
Мы нашли вот такую замечательную платочку, извлечённую из какого-то старого прибора. На ней есть как раз то, что нам нужно — это три разноцветных диода и кнопка.

ArduinoKnopka01.jpg

Схема очень простая — от каждого диода и от кнопки отходят по два провода. Получается всего 8 проводов, выведенных в единый шлейф.

ArduinoKnopka02.jpg

Я обрезала шлейф и зачистила все 8 контактов. Затем припаяла разноцветные провода: 2 красных от красного диода, 2 желтых, 2 зелёных, а от кнопки белый и серый, чтобы было нагляднее.

ArduinoKnopka03.jpg

Затем, мы напечатали на 3D принтере элемент, для крепления платы Arduino и платы с диодами.

ArduinoKnopka04.jpg

Он представляет собой пластину, с несколькими выступающими пазиками как раз в тех местах, где нужно прикручивать платы. Для прикручивания использовали саморезы.

ArduinoKnopka05.jpg

Далее нужно собрать схему.

ArduinoKnopka06.jpg

У нас три диода. Каждый из анодов через резистор 220 Ом подключён к одному из цифровых контактов Arduino. К нас это 2, 3, 4.
Катоды выходят на общую шину заземления. Шина соединяется с контактом Ардуино GND (земля).
От кнопки провод анод подключен к контакту Arduino 5V. К катоду подключается провод, опрашивающий состояние на выходе кнопки, затем, мы присоединяем его к цифровому контакту Arduino (у нас 12). Далее катод через резистор на 10КОм подключается к шине заземления.

Для чего нужен резистор 10КОм? Когда кнопка включена, то на провод, опрашивающий её состояние приходит 5V и мы регистрируем включение. Когда выключена, то 5V не приходит, однако на опрашивающий провод могут повлиять различные помехи и излучения на близлежащих выводах. Под их влиянием провод может подать сигнал о наличии напряжения. Чтобы этого не происходило мы добавляем стягивающий резистор, который забирает на себя мешающее напряжение и переводит его в тепло. Провод в этом случае не регистрирует напряжение и подаёт сигнал о выключении кнопки.

Эту схему можно собрать на базе макетной платы, как делалось в предыдущей статье. Но мы решили, для удобства и компактности спаять несколько переходников для соединения между собой элементов нашей схемы.

ArduinoKnopka07.jpg

Прежде всего нам нужно, чтобы к проводам легко подсоединялись и отсоединялись резисторы. Берём такие контактные разъёмы с проводами и кассету с металлическими штырьками.

ArduinoKnopka08.jpg

К одному концу резистора припаиваем металлический штырёк, к другому разъём. Всё это закрываем термоусадкой. Получаем вот такие элементы.

ArduinoKnopka09.jpg

К ним легко присоединяются провода, для включения резисторов в цепь.

ArduinoKnopka10.jpg

Еще нам нужен элемент с двумя контактами-разъёмами на входе и одним проводом на выходе.

ArduinoKnopka11.jpg

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

ArduinoKnopka12.jpg

ArduinoKnopka13.jpg

И, наконец, по такому же типу сделанная шина заземления. Только входных контактов не два, а несколько.

ArduinoKnopka14.jpg

ArduinoKnopka15.jpg

ArduinoKnopka16.jpg

Всё, наша схема готова, теперь можно писать программы и загружать их в Arduino.

ArduinoKnopka17.jpg

Запускаем среду разработки программ под Arduino. В прошлой статье мы писали как устанавливается эта программа.
Далее создаём новый scetch.
Мы предлагаем Вашему вниманию три разные программы, написанные для нашей схемы, и задающие поведение диодов в ответ на нажатие кнопки.

Программа 1. При нажатии на кнопку зажигается следующий диод, а предыдущий — гаснет.

/*Программа для трёх светодиодов и одной кнопки. При нажатии на кнопку зажигается следующий диод, а предыдущий — гаснет.*/
//массив, содержащий номера контактов

int LEDS[3] = {2, 3, 4};
// размер массива LEDS
int sizeof_LEDS = 3;
//индекс элемента из массива LEDS, который сейчас включён
int current_led_index = 0;
/* целочисленная константа с номером контакта от кнопки, этот контакт будет опрашивать состояние кнопки*/
const int BUTTON = 12;
/* переменная, хранящяя состояние кнопки, может принимать только значения true или false */
bool but_state = false;

// инициализация всех переменных
void setup() {
/* перебираем данные массива с номерами контактов и каждому присваиваем значение: выходной контакт*/
  for(int i = 0; i < sizeof_LEDS; i++)
  {
    pinMode(LEDS[i], OUTPUT);
  }
// включаем первый диод
  digitalWrite(LEDS[current_led_index], HIGH);
// для контакта кнопки задаём значение: входной контакт
  pinMode(BUTTON, INPUT);
}

// функция, в которой циклически повторяются заданные нами действия
void loop() {
// в локальную переменную записываем текущее состояние кнопки
  bool current_but_state = digitalRead(BUTTON);

/*Cравниваем с предыдущим состоянием кнопки. Если раньше кнопка была отжата, а теперь нажата, то меняем значение переменной на true для того,
чтобы программа среагировала только на факт нажатия*/

  if( (current_but_state == true) && (but_state == false) )
  {
    but_state = true;
//выключаем текущий диод
    digitalWrite(LEDS[current_led_index], LOW);
/*в функции check_contact_param проверяем выходит ли следующий индекс за пределы размера массива*/
    current_led_index = check_contact_param(current_led_index + 1);
//включаем следующий диод
    digitalWrite(LEDS[current_led_index], HIGH);
  }
/*Если раньше кнопка была нажата, а теперь отжалась, возвращаем значение переменной в исходное, т.е. false*/
  else if( (current_but_state == false) && (but_state == true) )
  {
    but_state = false;
  }

/*задержка в 5 милисекунд нужна, чтобы избежать реакции кнопки на дребезг контактов*/
  delay(5);
}

/* функция осуществляет проверку выходит ли передаваемый параметр (индекс элемента массива LEDS) за пределы размера массива*/
int check_contact_param (int param)
{
/*в случае выхода за пределы размера массива возвращает индекс самого первого элемента*/
  if (param >= sizeof_LEDS)
    return 0;
  else
    return param;
}

Программа 2. Диоды попеременно загораются слева-направо. При нажатии на кнопку меняют направление справа-налево, и наоборот.

/*Программа для трёх диодов и одной кнопки. Диоды попеременно загораются слева-направо.
При нажатии на кнопку меняют направление справа-налево, и наоборот.*/

//массив, содержащий номера контактов
int LEDS[3] = {2, 3, 4};
// размер массива LEDS
int sizeof_LEDS = 3;
//индекс элемента из массива LEDS, который сейчас включён
int current_led_index = 0;
/* целочисленная константа с номером контакта от кнопки, этот контакт будет опрашивать состояние кнопки*/
const int BUTTON = 12;
/* переменная, хранящяя состояние кнопки, может принимать только значения true или false */
bool but_state = false;
//временной интервал, через который опрашивается состояние кнопки
int check_but_state_delay = 5;
//временной интервал, через который меняется состояние диодов
int change_diode_state_delay = 500;
//направление мигания диодов: 1 - слева-направо, -1 - справа-налево
int direct_light = 1;

// инициализация всех переменных
void setup() {
/*перебираем данные массива с номерами контактов и каждому присваиваем значение: выходной контакт*/
  for(int i = 0; i < sizeof_LEDS; i++)
  {
    pinMode(LEDS[i], OUTPUT);
  }

// включаем первый диод
  digitalWrite(LEDS[current_led_index], HIGH);

// для контакта кнопки задаём значение: входной контакт
  pinMode(BUTTON, INPUT);
}

//функция, в которой циклически повторяются заданные нами действия
void loop() {
/*локальная переменная, отсчитывающая время, через которое нужно выйти из цикла проверки состояния кнопки и выполнить переключение с одного диода, на другой*/
  int init = 0;

/*цикл, в котором вызывается функция проверки состояния кнопки через через заданный вначале временной интервал - check_but_state_delay. По прошествии заданой задержки change_diode_state_delay мы выскакиваем из цикла, чтобы переключить диоды*/
  do{
    check_button_state();
    delay(check_but_state_delay);
    init += check_but_state_delay;
  }
  while(init < change_diode_state_delay);

//выключаем текущий диод
  digitalWrite(LEDS[current_led_index], LOW);

/*в функции check_contact_param проверяем выходит ли следующий индекс за пределы размера массива*/
  current_led_index = check_contact_param(current_led_index + direct_light);

//включаем следующий диод
  digitalWrite(LEDS[current_led_index], HIGH);
}

/*Функция, проверяющая изменилось ли состояние кнопки*/
void check_button_state()
{
// в локальную переменную записываем текущее состояние кнопки
  bool current_but_state = digitalRead(BUTTON);

/*сравниваем с предыдущим состоянием кнопки. Если раньше кнопка была отжата, а теперь нажата, то меняем значение переменной на true для того, чтобы программа среагировала только на факт нажатия*/
  if( (current_but_state == true) && (but_state == false) )
  {
    but_state = true;

//меняем направление мигания диодов на противоположное
    direct_light *= -1;
  }
/*Если раньше кнопка была нажата, а теперь отжалась, возвращаем значение переменной в исходное, т.е. false*/
  else if( (current_but_state == false) && (but_state == true) )
  {
    but_state = false;
  }
}

/* функция осуществляет проверку выходит ли передаваемый параметр (индекс элемента массива LEDS) за пределы размера массива*/
int check_contact_param (int param)
{
/*в случае выхода за минимальный предел массива возвращает индекс последнего элемента*/
  if (param < 0)
    return (sizeof_LEDS - 1);
/*в случае выхода за максимальный предел массива возвращает индекс первого элемента*/
  else if (param >= sizeof_LEDS)
    return 0;
  else
    return param;
}

Программа 3. Сколько раз нажимаем на кнопку, столько диодов и загорается.

/*Программа для трёх диодов и одной кнопки. Сколько раз нажимаем на кнопку, столько диодов и загорается.*/
//массив, содержащий номера контактов
int LEDS[3] = {2, 3, 4};
// размер массива LEDS
int sizeof_LEDS = 3;
//индекс элемента из массива LEDS, который сейчас включён
int current_led_index = 0;
/* целочисленная константа с номером контакта от кнопки, этот контакт будет опрашивать состояние кнопки*/
const int BUTTON = 12;
/* переменная, хранящяя состояние кнопки, может принимать только значения true или false */
bool but_state = false;
//временной интервал, через который опрашивается состояние кнопки
int check_but_state_delay = 5;
//временной интервал, через который меняется состояние диодов
int change_diode_state_delay = 2000;

// инициализация всех переменных
void setup() {
/*перебираем данные массива с номерами контактов и каждому присваиваем значение: выходной контакт, ставим все диоды в состояние: выключено*/
  for(int i = 0; i < sizeof_LEDS; i++)
  {
    pinMode(LEDS[i], OUTPUT);
    digitalWrite(LEDS[i], LOW);
  }

// для контакта кнопки задаём значение: входной контакт
  pinMode(BUTTON, INPUT);
}

//функция, в которой циклически повторяются заданные нами действия
void loop() {
/*локальная переменная, отсчитывающая время, через которое нужно выйти из цикла проверки состояния кнопки и выполнить переключение с одного диода, на другой*/
  int init = 0;
// сколько раз было нажато на кнопку за временной интервал между переключениями диодов
  int button_click = 0;
/*цикл, в котором вызывается функция проверки состояния кнопки через через заданный вначале временной интервал - check_but_state_delay. По прошествии заданой задержки change_diode_state_delay мы выскакиваем из цикла, чтобы переключить диоды*/
  do{
    button_click += check_button_state();
    delay(check_but_state_delay);
    init += check_but_state_delay;
  } while(init < change_diode_state_delay);

/*проходимся по массиву диодов и включаем столько, сколько раз нажималась кнопка*/
  for(int i = 0; i < sizeof_LEDS; i++)
  {
    if(i < button_click)
      digitalWrite(LEDS[i], HIGH);
    else
      digitalWrite(LEDS[i], LOW);
  }
}

/*Функция, проверяющая изменилось ли состояние кнопки - если фиксируется нажатие, то возвращает 1, если нет, то возвращает 0*/
int check_button_state()
{
// в локальную переменную записываем текущее состояние кнопки
  bool current_but_state = digitalRead(BUTTON);

/*сравниваем с предыдущим состоянием кнопки. Если раньше кнопка была отжата, а теперь нажата, то меняем значение переменной на true для того, чтобы программа среагировала только на факт нажатия*/
  if( (current_but_state == true) && (but_state == false) )
  {
    but_state = true;
    return 1;
  }
/*Если раньше кнопка была нажата, а теперь отжалась, возвращаем значение переменной в исходное, т.е. false*/
  else if( (current_but_state == false) && (but_state == true) )
  {
    but_state = false;
  }
    return 0;
}

Скачать stl файл пластины для соединения двух плат и проект в blrnder3D можно по ссылке ниже:

Приложения к статье: