Урок 1.4. Подсчет количества нажатий кнопки. Кликер
Базовый курс "Программирование микроконтроллеров"
Модуль 1. Введение в Arduino. Работа с цифровым и аналоговым сигналом
Сборка и проверка схемы
Сегодня мы отработаем и закрепим полученные навыки, посчитаем количество нажатий на кнопку и придумаем разнообразные применения этому действию!
Соберём схему из предыдущего урока:
Напишем код из прошлого урока, для отслеживания нажатий кнопки:
// константы используемых пинов
const int button = 2;
const int led = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
void setup()
{
pinMode(led,OUTPUT);
pinMode(button,INPUT);
Serial.begin(9600);
}
void loop()
{
// считываем состояние кнопки
state = digitalRead(button);
// если кнопканажата то включаем светодиод, в противном случае выключаем
if(state == 1)
{
digitalWrite(led,HIGH);
Serial.println("ON");
}
else
{
digitalWrite(led,LOW);
Serial.println("OFF");
}
}
Загрузим код в Ардуино и убедимся что всё прекрасно работает и светодиод загорается при нажатии на кнопку. Вспомним, что наша задача сделать такое устройство, которое будет подсчитывать количество нажатий кнопки.
Для этого создадим переменную в которую будем записывать количество нажатий и будем увеличивать её каждое нажатие, звучит просто, пробуем!
Подсчёт количества нажатий кнопки
Напишем следующий код:
// константы используемых пинов
const int button = 2;
const int led = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
// переменная для хранения количесва нажатий по кнопке
int N = 0;
void setup()
{
pinMode(led,OUTPUT);
pinMode(button,INPUT);
Serial.begin(9600);
}
void loop()
{
// считываем состояние кнопки
state = digitalRead(button);
// если кнопканажата то включаем светодиод, в противном случае выключаем
if(state == 1)
{
digitalWrite(led,HIGH);
N++; // увеличение значения переменной
Serial.println(N);
}
else
{
digitalWrite(led,LOW);
Serial.println(N);
}
}
Загрузим код в Ардуино и нажмём на кнопку. Открыв монитор порта, увидим следующую картину:
При нажатии на кнопку мы увидим, что значение переменной расчёт всё время, пока мы удерживаем толкатель кнопки во включенном положении.
Дело в том, что микроконтроллер выполняя нашу программу довольно часто обращается к порту кнопки и регистрирует что она нажата, т.е. наша программа регистрирует что кнопка нажата и удерживается, а нам необходимо что бы значение переменной N увеличивалось только тогда, когда кнопка была нажата в не зависимости от того как долго она удерживается в нажатом положении.
Наша цель, это отследить момент перехода с низкого состояния (не нажато) к высокому (нажато).
Для этого нам необходимо создать переменную, которая будет хранить предыдущее состояние кнопки и сравнивать его с текущим, и если предыдущее состояние было “не нажато” а текущее “нажато” значит произошёл клик по кнопке.
Напишем следующий код:
// константы используемых пинов
const int button = 2;
const int led = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
// переменная для хранения количества нажатий по кнопке
int N = 0;
// переменная для хранения предыдущего состояния кнопки
int last_state = 0;
void setup()
{
pinMode(led,OUTPUT);
pinMode(button,INPUT);
Serial.begin(9600);
}
void loop()
{
// считываем состояние кнопки
state = digitalRead(button);
// если кнопка сейчас нажата, а в прошлую итерацию была не нажата то включаем светодиод, в противном случае выключаем
if(state == 1 && last_state == 0)
{
digitalWrite(led,HIGH);
N++; // увеличение значения переменной
Serial.println(N);
delay(10); // задержка для светодиода
}
else
{
digitalWrite(led,LOW);
Serial.println(N);
}
//перезапись состояния кнопки для следующей итерации
last_state = state;
}
Загружаем код и проверяем, что всё прекрасно работает!
Игра "Кликер"
Сделаем игру, в которой мы будем нажимать на кнопку какое-то количество раз. Конец игры наступит тогда, когда мы достигнем определенного количества нажатий и сопровождать это всё будем световой индикацией и выводом в монитор порта.
Соберите следующую схему:
В данной схеме мы используем RGB-светодиод, его красную компоненту мы будем использовать для обозначения клика по кнопке, а синюю – как сигнал о конце игры.
Напишем следующий код:
// константы используемых пинов
const int button = 2;
const int led_red = 4;
const int led_blue = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
// переменная для хранения количества нажатий по кнопке
int N = 0;
// переменная для хранения предыдущего состояния кнопки
int last_state = 0;
void setup()
{
pinMode(led_red,OUTPUT);
pinMode(led_blue,OUTPUT);
pinMode(button,INPUT);
Serial.begin(9600);
}
void loop()
{
// считываем состояние кнопки
state = digitalRead(button);
// если кнопка сейчас нажата, а в прошлую итерацию была не нажата то включаем светодиод, в противном случае выключаем
if(state == 1 && last_state == 0)
{
digitalWrite(led_red,HIGH);
N++; // увеличение значения переменной
Serial.println(N);
delay(10); // задержка для светодиода
}
else
{
digitalWrite(led_red,LOW);
Serial.println(N);
}
//перезапись состояния кнопки для следующей итерации
last_state = state;
}
Загрузим этот код и убедимся, что подсчёт количества нажатий происходит корректно. Далее, сделаем так, что бы игра имела конец, обусловленный определенным количеством нажатий на кнопку. Для этого создадим константу для хранения нужного количества нажатий и с помощью условного оператора остановим игру.
// константы используемых пинов
const int button = 2;
const int led_red = 4;
const int led_blue = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
// переменная для хранения количества нажатий по кнопке
int N = 0;
// переменная для хранения предыдущего состояния кнопки
int last_state = 0;
// константа для хранения конечного числа нажатий
const int N_finish = 100;
void setup() {
pinMode(led_red, OUTPUT);
pinMode(led_blue, OUTPUT);
pinMode(button, INPUT);
Serial.begin(9600);
}
void loop() {
// считываем состояние кнопки
state = digitalRead(button);
// если кнопка сейчас нажата, а в прошлую итерацию была не нажата то включаем светодиод, в противном случае выключаем
if (state == 1 && last_state == 0) {
digitalWrite(led_red, HIGH);
N++; // увеличение значения переменной
Serial.println(N);
delay(10); // задержка для светодиода
} else {
digitalWrite(led_red, LOW);
Serial.println(N);
}
//перезапись состояния кнопки для следующей итерации
last_state = state;
// если текущее количество нажатий больше или равно конечному то сигнализируем об этом и перезапускаем игру
if (N >= N_finish) {
digitalWrite(led_blue, HIGH);
Serial.println("YOU WIN!");
delay(5000);
N = 0;
digitalWrite(led_blue, LOW);
}
}
Молодцы, но для интереса, добавим в нашу игру спортивный элемент – пусть помимо вывода сообщения о победе, так же будем выводить количество секунд, которые нам понадобились для достижения нужного количества кликов.
Уберем команду ожидания для мигания светодиодом и используем специальную функцию millis() – она очень простая в использовании и возвращает количество миллисекунд прошедших с момента запуска микроконтроллера.
// константы используемых пинов
const int button = 2;
const int led_red = 3;
const int led_blue = 3;
// переменная для хранения текущего состояния кнопки
int state = 0;
// переменная для хранения количества нажатий по кнопке
int N = 0;
// переменная для хранения предыдущего состояния кнопки
int last_state = 0;
// константа для хранения конечного числа нажатий
const int N_finish = 100;
// переменные для хранения времени
unsigned long t_start = 0;
unsigned long t = 0;
void setup() {
pinMode(led_red, OUTPUT);
pinMode(led_blue, OUTPUT);
pinMode(button, INPUT);
Serial.begin(9600);
t_start = millis();
}
void loop() {
// считываем состояние кнопки
state = digitalRead(button);
// если кнопка сейчас нажата, а в прошлую итерацию была не нажата то включаем светодиод, в противном случае выключаем
if (state == 1 && last_state == 0) {
digitalWrite(led_red, HIGH);
N++; // увеличение значения переменной
Serial.println(N);
} else {
digitalWrite(led_red, LOW);
Serial.println(N);
}
//перезапись состояния кнопки для следующей итерации
last_state = state;
// если текущее количество нажатий больше или равно конечному то сигнализируем об этом и перезапускаем игру
if (N >= N_finish) {
t = millis() - t_start; // расчёт времени, прошедшего с момента запуска игры
float sec = t / 1000.0;
digitalWrite(led_blue, HIGH);
Serial.println("YOU WIN! TIME = " + String(sec));
delay(5000);
N = 0;
t_start = millis();
digitalWrite(led_blue, LOW);
}
}
Поздравляем, проект завершен!