Электронное приложение к набору «IO.KIT Электронные часы»
На этой странице ты найдёшь все нужные материалы для сборки мини-проектов набора Электронные часы из серии IO.KIT:
- Схемы проектов в электронном виде.
- Исходный код программ (копируй его в редактор Arduino IDE).
- Дополнительные материалы: программные библиотеки, даташиты и т. п.
Обрати внимание
Для сборки и функционирования электронных часов тебе понадобится IO.KIT Базовый!
Проекты
Прежде чем приступать к экспериментам, нужно подготовить свой компьютер:
- Установи среду программирования Arduino IDE и копируй туда готовый код проектов.
- Установи дополнительные библиотеки для Arduino IDE, пользуясь нашим руководством.
Драйвер чипа CH340
Установи драйвер CH340 для Windows или Linux, чтобы твой компьютер мог корректно распознать и прошить плату Iskra Nano.
№1. Индикация чисел
- DisplayDigits.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- }
- void loop() {
- // Выводим на дисплей целое число
- qd.displayInt(1234);
- // Ждём 1 секунду
- delay(1000);
- // Выводим на дисплей рациональное число
- // с заданной точностью 2 знака после запятой
- qd.displayFloat(3.14, 2);
- // Ждём 1 секунду
- delay(1000);
- // Очищаем дисплей
- qd.displayClear();
- // Ждём 1 секунду
- delay(1000);
- }
№2. Индикация символов
- DisplayCharacters.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Выводим на дисплей надпись «PLAY»
- qd.displayDigits(QD_P, QD_L, QD_A, QD_Y);
- }
- void loop() {
- }
№3. Кнопочный детектор
- DisplayButton.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
- TroykaButton buttonS1(5);
- TroykaButton buttonS2(2);
- TroykaButton buttonS3(3);
- TroykaButton buttonS4(4);
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопки
- buttonS1.begin();
- buttonS2.begin();
- buttonS3.begin();
- buttonS4.begin();
- }
- void loop() {
- // Считываем состояния с кнопок
- buttonS1.read();
- buttonS2.read();
- buttonS3.read();
- buttonS4.read();
- // Выводим нажатую кнопку на индикатор
- if (buttonS1.justPressed()) {
- qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_1);
- // Ждём 1000 мс
- delay(1000);
- } else if (buttonS2.justPressed()) {
- qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_2);
- // Ждём 1000 мс
- delay(1000);
- } else if (buttonS3.justPressed()) {
- qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_3);
- // Ждём 1000 мс
- delay(1000);
- } else if (buttonS4.justPressed()) {
- qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_4);
- // Ждём 1000 мс
- delay(1000);
- } else {
- // Если нажатой кнопки нет, выводим символы «----»
- qd.displayDigits(QD_MINUS, QD_MINUS, QD_MINUS, QD_MINUS);
- }
- }
№4. Диммер с индикацией
- DisplayDimmer.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Даём понятное имя пину 5 со светодиодом
- constexpr uint8_t LED_PIN = 5;
- // Даём понятное имя пину A0 с потенциометром
- constexpr uint8_t POT_PIN = A0;
- void setup() {
- // Настраиваем пин со светодиодом в режим выхода
- pinMode(LED_PIN, OUTPUT);
- // Настраиваем пин с потенциометром в режим входа
- pinMode(POT_PIN, INPUT);
- // Инициализируем дисплей
- qd.begin();
- }
- void loop() {
- // Считываем аналоговый сигнал с потенциометра
- int rotation = analogRead(POT_PIN);
- // Преобразуем диапазон значений с потенциометра [0;1023]
- // в диапазон значений для светодиода [0;255]
- int brightness = map(rotation, 0, 1023, 0, 255);
- // Выдаём результат на светодиод
- analogWrite(LED_PIN, brightness);
- // Преобразуем диапазон значений с потенциометра [0;1023]
- // в процентный диапазон значений [0;100]
- int percent = map(rotation, 0, 1023, 0, 100);
- // Выводим результат на дисплей
- qd.displayInt(percent);
- // Ждём 25 мс
- delay(25);
- }
№5. Кухонный таймер
- Timer.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
- TroykaButton buttonS1(5);
- TroykaButton buttonS2(2);
- TroykaButton buttonS3(3);
- TroykaButton buttonS4(4);
- // Даём понятное имя пину A2 с пищалкой
- constexpr uint8_t BUZZER_PIN = A2;
- // Даём понятное имя пину A0 с потенциометром
- constexpr uint8_t POT_PIN = A0;
- // Создаём переменную для хранения счетчика таймера
- int timerCount;
- // Создаём переменную для работы таймера
- unsigned long timeLastUpdate = 0;
- // Создаём перечисление состояний таймера с соответствующей переменной
- enum {
- TIMER_SETUP, // «Установка таймера»
- TIMER_TICK, // «Таймер тикает»
- TIMER_DONE // «Таймер завершен»
- } timerState;
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопки
- buttonS1.begin();
- buttonS2.begin();
- buttonS3.begin();
- buttonS4.begin();
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Настраиваем пин с потенциометром в режим входа
- pinMode(POT_PIN, INPUT);
- // Устанавливаем режим «Установка таймера»
- timerState = TIMER_SETUP;
- }
- void loop() {
- // Если установлен режим «Установка таймера»
- if (timerState == TIMER_SETUP) {
- // Переходим в функцию обработки режима «Установка таймера»
- handleTimerSetup();
- }
- // Если установлен режим «Таймер тикает»
- if (timerState == TIMER_TICK) {
- // Переходим в функцию обработки режима «Таймер тикает»
- handleTimerTick();
- }
- // Если установлен режим «Таймер завершен»
- if (timerState == TIMER_DONE) {
- // Переходим в функцию обработки режима «Таймер завершен»
- handleTimerDone();
- }
- }
- // Функция обработки режима «Установка таймера»
- void handleTimerSetup() {
- // Выводим на индикатор выводим символы «----»
- qd.displayDigits(QD_MINUS, QD_MINUS, QD_MINUS, QD_MINUS);
- // Подаём звуковой сигнал про установку таймера
- playMelodyTimerSetup();
- // Считываем состояние с кнопки S1
- buttonS1.read();
- // Пока на нажата кнопка S1
- while (!buttonS1.isClick()) {
- // Считываем показания с потенциометра
- timerCount = readPot(POT_PIN);
- // Выводим полученные показания на дисплей
- qd.displayInt(timerCount);
- // Обновляем состояние с кнопки S1
- buttonS1.read();
- }
- // Подаём звуковой сигнал о старте таймера
- playMelodyTimerBegin();
- // Устанавливаем режим «Таймер тикает»
- timerState = TIMER_TICK;
- }
- // Функция обработки режима «Таймер тикает»
- void handleTimerTick() {
- // Передаем константе состояние таймера
- const auto updateDone = timer();
- // Если таймер обновил данные, т.е. прошла 1 секунда
- if (updateDone) {
- // Выводим счётчик таймера на дисплей
- qd.displayInt(timerCount);
- // Если счётчик дошёл до ноля
- if (timerCount == 0) {
- // Отображаем на индикаторе строку про завершения таймера
- qd.displayDigits(QD_NONE, QD_E, QD_n, QD_d);
- // Подаём звуковой сигнал на пищалку про завершения таймера
- playMelodyTimerEnd();
- // Устанавливаем режим «Таймер завершен»
- timerState = TIMER_DONE;
- }
- }
- }
- // Функция обработки режима «Таймер завершен»
- void handleTimerDone() {
- do {
- // Считываем состояние с кнопки S1
- buttonS1.read();
- // Пока не нажата кнопка S1
- } while (!buttonS1.isClick());
- // Устанавливаем режим «Установка таймера»
- timerState = TIMER_SETUP;
- }
- // Функция для отсчёта времени посекундно
- bool timer() {
- // Запоминаем текущее время
- long timeNow = millis();
- // Если прошла одна секунда
- if (timeNow - timeLastUpdate > 1000) {
- // Обновляем текущее время
- timeLastUpdate = timeNow;
- // Уменьшаем текущий счётчик на единицу
- timerCount--;
- // Да, таймер досчитал
- return true;
- }
- // Нет, таймер не досчитал
- return false;
- }
- // Функция считывания показаний с потенциометра
- int readPot(int pin) {
- // Создаём переменную для хранения
- // аналогового сигнала с потенциометра в отчётах АЦП
- int sensorADC = 0;
- // Создаём переменную для хранения
- // преобразованных показаний с потенциометра
- int sensorValue = 0;
- // Считываем усреднённый аналоговый сигнал с потенциометра
- for (int i = 0; i < 16; i++) {
- sensorADC += analogRead(pin);
- delay(5);
- }
- sensorADC = sensorADC / 16;
- // Преобразуем диапазон значений с потенциометра [0;1023]
- // в диапазон значений для таймера [0;360]
- sensorValue = map(sensorADC, 0, 1023, 360, 0);
- // Возвращаем полученное значение
- return sensorValue;
- }
- // Функция мелодии «Установки таймера»
- void playMelodyTimerSetup() {
- tone(BUZZER_PIN, 330, 100);
- delay(150);
- tone(BUZZER_PIN, 330, 100);
- delay(300);
- tone(BUZZER_PIN, 330, 100);
- delay(300);
- tone(BUZZER_PIN, 262, 100);
- delay(100);
- tone(BUZZER_PIN, 330, 100);
- delay(300);
- tone(BUZZER_PIN, 392, 100);
- delay(550);
- tone(BUZZER_PIN, 523, 100);
- delay(575);
- }
- // Функция мелодии «Старт таймера»
- void playMelodyTimerBegin() {
- tone(BUZZER_PIN, 2000, 200);
- delay(300);
- tone(BUZZER_PIN, 3000, 200);
- delay(300);
- tone(BUZZER_PIN, 4000, 200);
- }
- // Функция мелодии «Завершение таймера»
- void playMelodyTimerEnd() {
- for (int i = 0; i <= 5; i++) {
- tone(BUZZER_PIN, 1000, 200);
- delay(400);
- }
- }
№6. Консольный хронометр
- ClockConsole.ino
- // Подключаем библиотеку для работы с часами реального времени RTC
- #include <TroykaRTC.h>
- // Создаём объект часов реального времени на шине I²C
- RTC clock;
- void setup() {
- // Открываем монитор Serial-порта
- Serial.begin(9600);
- // Инициализируем часы реального времени
- // Устанавливаем временную отметку в модуль
- // Выберите метод установки времени: ручной или автоматический
- // После установки времени в часы, закомментируйте метод clock.set
- // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
- // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
- // Автоматическая установка временной отметки в модуль
- // Время берётся из ПК при компиляции
- // clock.set(__TIMESTAMP__);
- }
- void loop() {
- // Создаём переменные для хранения времени, даты и дня недели
- String timeStr;
- String dateStr;
- String weekDayStr;
- if (millis() % 1000 == 0) {
- // Если прошла одна секунда, запрашиваем данные с часов
- // Получаем текущее время, дату и день недели в переменные
- // Выводим в консоль текущее время, дату и день недели
- Serial.print(timeStr);
- Serial.print("\t");
- Serial.print(dateStr);
- Serial.print("\t");
- Serial.println(weekDayStr);
- }
- }
№7. Часы
- Clock.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Подключаем библиотеку для работы с часами реального времени RTC
- #include <TroykaRTC.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
- TroykaButton buttonS1(5);
- TroykaButton buttonS2(2);
- TroykaButton buttonS3(3);
- TroykaButton buttonS4(4);
- // Создаём объект часов реального времени на шине I²C
- RTC clock;
- // Создаём переменные для хранения часов и минут
- uint8_t hours;
- uint8_t minutes;
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопки
- buttonS1.begin();
- buttonS2.begin();
- buttonS3.begin();
- buttonS4.begin();
- // Инициализируем часы реального времени
- // Устанавливаем временную отметку в модуль
- // Выберите метод установки времени: ручной или автоматический
- // После установки времени в часы, закомментируйте метод clock.set
- // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
- // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
- // clock.set(14, 25, 45, 1, 8, 2020, SATURDAY);
- // Автоматическая установка временной отметки в модуль
- // Время берётся из ПК при компиляции
- }
- void loop() {
- // Запрашиваем данные с часов
- // Получаем текущие показания часов и минут в переменные
- // Выводим время на дисплей
- qd.displayScore(hours, minutes, true);
- // Обновляем время через функцию обработки кнопок
- updateTimeButtons();
- }
- // Функция обновления времени через кнопки
- void updateTimeButtons() {
- // Считываем состояния с кнопок
- buttonS1.read();
- buttonS2.read();
- buttonS3.read();
- buttonS4.read();
- // Настраиваем время на часах с помощью кнопок
- if (buttonS1.isClick()) {
- } else if (buttonS2.isClick()) {
- } else if (buttonS3.isClick()) {
- } else if (buttonS4.isClick()) {
- }
- }
№8. Часы с будильником
- ClockAlarm.ino
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Подключаем библиотеку для работы с часами реального времени RTC
- #include <TroykaRTC.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
- TroykaButton buttonS1(5);
- TroykaButton buttonS2(2);
- TroykaButton buttonS3(3);
- TroykaButton buttonS4(4);
- // Создаём объект часов реального времени на шине I²C
- RTC clock;
- // Даём понятное имя пищалке на пине A2
- constexpr uint8_t BUZZER_PIN = A2;
- // Создаём переменные для хранения часов и минут
- uint8_t hours;
- uint8_t minutes;
- // Создаём константы для хранения часов и минут будильника
- constexpr uint8_t alarmHours = 7;
- constexpr uint8_t alarmMinutes = 30;
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопки
- buttonS1.begin();
- buttonS2.begin();
- buttonS3.begin();
- buttonS4.begin();
- // Инициализируем часы реального времени
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Устанавливаем временную отметку в модуль
- // Выберите метод установки времени: ручной или автоматический
- // После установки времени в часы, закомментируйте метод clock.set
- // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
- // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
- // clock.set(14, 25, 45, 1, 8, 2020, SATURDAY);
- // Автоматическая установка временной отметки в модуль
- // Время берётся из ПК при компиляции
- }
- void loop() {
- // Запрашиваем данные с часов
- // Получаем текущие показания часов и минут в переменные
- // Выводим время на дисплей
- qd.displayScore(hours, minutes, true);
- // Обновляем время через функцию обработки кнопок
- updateTimeButtons();
- // Обрабатываем времени будильника
- alarmRing();
- }
- // Функция обновления времени через кнопки
- void updateTimeButtons() {
- // Считываем состояния с кнопок
- buttonS1.read();
- buttonS2.read();
- buttonS3.read();
- buttonS4.read();
- // Настраиваем время на часах с помощью кнопок
- if (buttonS1.isClick()) {
- } else if (buttonS2.isClick()) {
- } else if (buttonS3.isClick()) {
- } else if (buttonS4.isClick()) {
- }
- }
- // Функция обработки времени будильника
- bool alarmRing() {
- // Если текущее время совпадает со временем будильника
- if (hours == alarmHours && minutes == alarmMinutes) {
- // Мигаем дисплеем и пищим зуммером
- qd.displayClear();
- tone(BUZZER_PIN, 1000, 200);
- delay(200);
- qd.displayScore(hours, minutes, false);
- delay(300);
- }
- }
№9. Плеер с выбором трека
- playerMusicTrack.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
- TroykaButton buttonS1(5);
- TroykaButton buttonS2(2);
- TroykaButton buttonS3(3);
- TroykaButton buttonS4(4);
- // Даём понятное имя пину A2 с пищалкой
- constexpr uint8_t BUZZER_PIN = A2;
- // Мелодия «Имперский марш» в формате RTTTL
- const char imperM[] PROGMEM = "imperMarch:d=8,o=5,b=95:"
- "4a4,4a4,4a4,f.4,16c,4a4,f.4,16c,"
- "2a4,4e,4e,4e,f.,16c,4g#4,f.4,"
- "16c,2a4,4a,a.4,16a4,4a,g#.,16g,"
- "16f#,16e,f,p,a#4,4d#,d.,16c#,16c,"
- "16b4,c,p,f4,4g#4,f.4,16a4,4c,"
- "a.4,16c,2e,4a,a.4,16a4,4a,g#.,"
- "16g,16f#,16e,f,p,a#4,4d#,d.,"
- "16c#,16c,16b4,c,p,f4,4g#4,f.4,"
- "16c,4a4,f.4,16c,2a4";
- // Мелодия «Марио» в формате RTTTL
- const char marioB[] PROGMEM = "marioBroth:d=4,o=5,b=100:"
- "16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,"
- "8g,8p,8c6,16p,8g,16p,8e,16p,"
- "8a,8b,16a#,8a,16g.,16e6,16g6,8a6,"
- "16f6,8g6,8e6,16c6,16d6,8b,16p,8c6,"
- "16p,8g,16p,8e,16p,8a,8b,16a#,"
- "8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,"
- "16c6,16d6,8b,8p,16g6,16f#6,16f6,16d#6,"
- "16p,16e6,16p,16g#,16a,16c6,16p,16a,"
- "16c6,16d6,8p,16g6,16f#6,16f6,16d#6,16p,"
- "16e6,16p,16c7,16p,16c7,16c7,p,16g6,"
- "16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,"
- "16c6,16p,16a,16c6,16d6,8p,16d#6,8p,"
- "16d6,8p,16c6";
- // Мелодия «Миссия невыполнима» в формате RTTTL
- const char misImp[] PROGMEM = "missionImp:d=16,o=6,b=95:"
- "32d,32d#,32d,32d#,32d,32d#,32d,32d#,"
- "32d,32d,32d#,32e,32f,32f#,32g,g,8p,"
- "g,8p,a#,p,c7,p,g,8p,"
- "g,8p,f,p,f#,p,g,8p,"
- "g,8p,a#,p,c7,p,g,8p,"
- "g,8p,f,p,f#,p,a#,g,"
- "2d,32p,a#,g,2c#,32p,a#,g,"
- "2c,a#5,8c,2p,32p,a#5,g5,2f#,"
- "32p,a#5,g5,2f,32p,a#5,g5,2e,"
- "d#,8d";
- // Мелодия «Тетрис» в формате RTTTL
- const char tetris[] PROGMEM = "tetris:d=4,o=5,b=160:"
- "e6,8b,8c6,8d6,16e6,16d6,8c6,8b,"
- "a,8a,8c6,e6,8d6,8c6,b,8b,"
- "8c6,d6,e6,c6,a,2a,8p,d6,"
- "8f6,a6,8g6,8f6,e6,8e6,8c6,e6,"
- "8d6,8c6,b,8b,8c6,d6,e6,c6,"
- "a,a";
- // Мелодия «Европа» в формате RTTTL
- const char europe[] PROGMEM = "Europe:d=4,o=5,b=140:"
- "16c#6,32b,32p,8c#.6,16p,f#,p.,32d6,32p,"
- "32c#6,32p,32d6,16p.,32c#6,16p.,b.,p,"
- "32d6,32p,32c#6,32p,d6,f#,p.,32b,"
- "32p,32a,32p,32b,16p.,32a,16p.,32g#,"
- "16p.,32b,16p.,a.,32c#6,32p,32b,32p,"
- "c#6,2f#,p,16p,32d6,32p,32c#6,32p,32d6,"
- "16p.,32c#6,16p.,b.,p,32d6,32p,32c#6,32p,"
- "d6,f#,p.,32b,32p,32a,32p,32b,"
- "16p.,32a,16p.,32g#,16p.,32b,16p.,2a,"
- "16p,32g#,32p,32a,32p,b.,16a,16b,"
- "8c#6,8b,8a,8g#,f#,d6,1c#6,8p,"
- "16c#6,16d6,16c#6,16b,2c#.6,16p";
- // Создаём переменную для хранения номера трека
- uint8_t songID;
- // Задаём константы минимального и максимального номеров трека
- constexpr uint8_t minSongID = 1;
- constexpr uint8_t maxSongID = 5;
- // Создаём переменную для хранения паузы
- bool pause = false;
- // Создаём перечисление состояний плеера с соответствующей переменной
- enum {
- PLAY_OFF, // «Плеер не играет»
- PLAY_ON, // «Плеер играет»
- } playState;
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопки
- buttonS1.begin();
- buttonS2.begin();
- buttonS3.begin();
- buttonS4.begin();
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Устанавливаем режим «Плеер не играет»
- playState = PLAY_OFF;
- // Устанавливаем трек №1
- songID = 1;
- }
- void loop() {
- // Считываем состояния с кнопок
- readButtons();
- // Обновляем трек с помощью кнопок
- updateSongIDButtons();
- // Выводим выбранный трек на индикатор
- printDisplaySongID();
- // Проверяем состояние плеера
- switch (playState) {
- // Если установлен режим «Плеер не играет»
- case PLAY_OFF:
- // Переходим в функцию обработки режима «Плеер не играет»
- handlePlayOff();
- break;
- // Если установлен режим «Плеер играет»
- case PLAY_ON:
- // Переходим в функцию обработки режима «Плеер играет»
- handlePlayOn();
- break;
- }
- }
- // Функция обработки режима «Плеер не играет»
- void handlePlayOff() {
- // Если был клик по кнопке S1
- if (buttonS1.isClick()) {
- // Выбираем трек к воспроизведению
- setSongID();
- // Устанавливаем режим «Плеер играет»
- playState = PLAY_ON;
- }
- }
- // Функция обработки режима «Плеер играет»
- void handlePlayOn() {
- // Включаем трек
- playSongID();
- // Если был клик по кнопке S1
- if (buttonS1.isClick()) {
- // Останавливаем трек
- stopSongID();
- // Устанавливаем режим «Плеер не играет»
- playState = PLAY_OFF;
- }
- // Если был клик по кнопке S4
- if (buttonS4.isClick()) {
- // Ставим на паузу текущий трек
- pause = !pause;
- }
- }
- // Функция считывания состояний с кнопок
- void readButtons() {
- buttonS1.read();
- buttonS2.read();
- buttonS3.read();
- buttonS4.read();
- }
- // Функция обновления текущего трека с помощью кнопок
- void updateSongIDButtons() {
- if (buttonS3.isClick()) {
- songID++;
- }
- if (buttonS2.isClick()) {
- songID--;
- }
- // Корректируем номер трека в рамки диапазона [min;max]
- wrapSongID();
- }
- // Функция корректировки номеров трека в диапазон [min;max]
- void wrapSongID() {
- if (songID > maxSongID) {
- songID = minSongID;
- }
- if (songID < minSongID) {
- songID = maxSongID;
- }
- }
- // Функция вывода текущего трека на индикатор
- void printDisplaySongID() {
- if (songID == 1) {
- qd.displayDigits(QD_P, QD_0, QD_0, QD_1);
- } else if (songID == 2) {
- qd.displayDigits(QD_P, QD_0, QD_0, QD_2);
- } else if (songID == 3) {
- qd.displayDigits(QD_P, QD_0, QD_0, QD_3);
- } else if (songID == 4) {
- qd.displayDigits(QD_P, QD_0, QD_0, QD_4);
- } else if (songID == 5) {
- qd.displayDigits(QD_P, QD_0, QD_0, QD_5);
- } else {
- qd.displayDigits(QD_E, QD_r, QD_r, QD_NONE);
- }
- }
- // Функция выбора трека
- void setSongID() {
- if (songID == 1) {
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, imperM);
- } else if (songID == 2) {
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, marioB);
- } else if (songID == 3) {
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, misImp);
- } else if (songID == 4) {
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, tetris);
- } else if (songID == 5) {
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, europe);
- }
- }
- // Функция воспроизведения трека
- void playSongID() {
- // Если не включена пауза
- if (pause == false) {
- // Продолжаем играть трек
- anyrtttl::nonblocking::play();
- }
- // Если трек завершился
- if (anyrtttl::nonblocking::done()) {
- // Устанавливаем режим «Плеер не играет»
- playState = PLAY_OFF;
- }
- }
- // Функция остановки трека
- void stopSongID() {
- // Останавливаем трек
- anyrtttl::nonblocking::stop();
- }
№10. Troyka Slot-машина
- SlotGame.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с четырёхразрядным дисплеем
- #include <QuadDisplay2.h>
- // Подключаем библиотеку для работы с кнопками
- #include <TroykaButton.h>
- // Создаём объект дисплея на шине SPI и пине 10
- QuadDisplay qd(10);
- // Создаём объект кнопки на пине 2
- TroykaButton button(2);
- // Даём понятное имя пину A2 с пищалкой
- constexpr uint8_t BUZZER_PIN = A2;
- // Даём понятное имя пину 5 со светодиодом
- constexpr uint8_t LED_PIN = 5;
- // Мелодия «Старт» в формате RTTTL
- const char* gameStart = "gameStart:d=4,o=5,b=100:"
- "16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,"
- "8g,8p";
- // Мелодия «Игра проиграна» в формате RTTTL
- const char* gameOver = "gameOver:d=4,o=5,b=90:"
- "32c6,32c6,32c6,8p,16b,16f6,16p,16f6,"
- "16f.6,16e.6,16d6,16c6,16p,16e,16p,16c";
- // Мелодия «Игра выиграна» в формате RTTTL
- const char* gameWin = "gameWin:d=4,o=5,b=180:"
- "8g3,8c4,8e4,8g4,8c,8e,3g,3e,"
- "8e3,8c4,8e#4,8A#4,8c,8e#,3a#,3e#,"
- "8b#3,8d4,8f4,8b#4,8d,8f,3b#,32p,"
- "8b#,32p,8b#,32p,8b#,1c6";
- // Создаём перечисление состояний игры с соответствующей переменной
- enum {
- GAME_START, // «Начало игры»
- GAME_PLAY, // «Процесс игры»
- GAME_END, // «Конец игры»
- GAME_OVER, // «Игра проиграна»
- GAME_WIN // «Игра выиграна»
- } gameState;
- // Создаём перечисление разрядов дисплея
- enum {
- D1 = 0, // Первый разряд
- D2 = 1, // Второй разряд
- D3 = 2, // Третий разряд
- D4 = 3 // Четвёртый разряд
- };
- // Создаём переменную для хранения значения на разряде дисплея
- uint8_t digitCounter;
- // Создаём переменную для хранения значения на разряде дисплея в битовом виде
- uint8_t digitMaskQD;
- // Создаём массив для хранения значений на разрядах дисплея в битовом виде
- uint8_t digitMasksQD[4];
- // Создаём массив для хранения статуса установки значений на разрядах дисплея
- // true: разряд установлен, false: разряд не установлен
- bool digitStates[4];
- // Создаём переменную для работы таймера обновления значений на разрядах дисплея
- long timeLastUpdateDigit = 0;
- // Создаём переменную для работы таймера остановки значений на разрядах дисплея
- long timeLastStopDigit = 0;
- // Создаём константу для хранения времени обновления значений счётчика на разрядах дисплея
- constexpr int timeUpdateDigit = 100;
- // Создаем переменную для хранения времени остановки значений счётчика на разрядах дисплея
- int timeStopDigit;
- void setup() {
- // Инициализируем дисплей
- qd.begin();
- // Инициализируем кнопку
- button.begin();
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Настраиваем пин со светодиодом в режим выхода
- pinMode(LED_PIN, OUTPUT);
- // Задаём зерно генерации случайных чисел
- randomSeed(analogRead(A6));
- // Устанавливаем режим «Начало игры»
- gameState = GAME_START;
- }
- void loop() {
- // Считываем состояние с кнопки
- button.read();
- // Выбираем действие в зависимости от текущего режима игры
- switch (gameState) {
- // Если установлен режим «Начало игры»
- case GAME_START: {
- // Переходим в функцию обработки режима «Начало игры»
- handleGameStart();
- break;
- }
- // Если установлен режим «Процесс игры»
- case GAME_PLAY: {
- // Переходим в функцию обработки режима «Процесс игры»
- handleGamePlay();
- break;
- }
- // Если установлен режим «Конец игры»
- case GAME_END: {
- // Переходим в функцию обработки режима «Конец игры»
- handleGameEnd();
- break;
- }
- // Если установлен режим «Игра проиграна»
- case GAME_OVER: {
- // Переходим в функцию обработки режима «Игры проиграна»
- handleGameOver();
- break;
- }
- // Если установлен режим «Игра выиграна»
- case GAME_WIN: {
- // Переходим в функцию обработки режима «Игры выиграна»
- handleGameWin();
- break;
- }
- }
- }
- // Функция обработки режима «Начало игры»
- void handleGameStart() {
- // Зажигаем светодиод
- digitalWrite(LED_PIN, HIGH);
- // Выводим приветствие на дисплей
- qd.displayDigits(QD_P, QD_L, QD_A, QD_Y);
- // Играем приветственную мелодию
- anyrtttl::blocking::play(BUZZER_PIN, gameStart);
- // Ожидаем нажатие на кнопку
- do {
- // Считываем состояние с кнопки
- button.read();
- } while (!button.isClick());
- // Гасим светодиод
- digitalWrite(LED_PIN, LOW);
- // Сбрасываем настройки по умолчанию
- resetDefaults();
- // Генерируем случайное число
- timeStopDigit = timeRandom();
- // Устанавливаем режим «Процесс игры»
- gameState = GAME_PLAY;
- }
- // Функция обработки режима «Процесс игры»
- void handleGamePlay() {
- // В режиме «Процесс игры» работают два таймера:
- // timerUpdateDigit(): таймер обновления значений символов,
- // который отвечает за время поочередного обновления цифр от 0 до 9
- // timerStopDigit(): таймер остановки значений символов,
- // который отвечает за время остановки обновления цифр от 0 до 9
- // Если таймер обновления символов досчитал,
- // получаем последующее число от 0 до 9
- // Передаем константе состояние таймера обновления символов
- const auto timerUpdateDone = timerUpdateDigit();
- // Если таймер досчитал, т.е. прошла 1 секунда
- if (timerUpdateDone) {
- // Увеличиваем цифру на один
- digitCounter++;
- // Если цифра стала более 9
- if (digitCounter > 9) {
- // Обнуляем цифру до ноля
- digitCounter = 0;
- }
- // Конвертируем число в QD-символов в битовом виде
- digitMaskQD = intToQD(digitCounter);
- }
- // Передаем константе состояние таймера остановки значений
- const auto timerStopDone = timerStopDigit();
- // Если таймер остановки значений счётчика досчитал,
- // проверяем какой разряд стоит на очередь установки
- if (timerStopDone) {
- // Если очередь второго разряда
- if (digitStates[D2] == false) {
- // Фиксируем разряд статусом true: установлен
- digitStates[D2] = true;
- // Присваиваем текущий символ на счётчике в массив хранения значений результата
- digitMasksQD[D2] = digitMaskQD;
- // Генерируем случайное число
- timeStopDigit = timeRandom();
- // Если очередь третьего разряда
- } else if (digitStates[D3] == false) {
- // Фиксируем разряд статусом true: установлен
- digitStates[D3] = true;
- // Присваиваем текущий символ на счётчике в массив хранения значений результата
- digitMasksQD[D3] = digitMaskQD;
- // Генерируем случайное число
- timeStopDigit = timeRandom();
- // Если очередь четвёртого разряда
- } else if (digitStates[D4] == false) {
- // Фиксируем разряд статусом true: установлен
- digitStates[D4] = true;
- // Присваиваем текущий символ на счётчике в массив хранения значений результата
- digitMasksQD[D4] = digitMaskQD;
- }
- }
- // Присваиваем текущий символ на счётчике всем не установленным разрядам
- for (int i = D2; i <= D4; i++) {
- if (!digitStates[i]) {
- digitMasksQD[i] = digitMaskQD;
- }
- }
- // Если все разряды установлены
- if (checkDigitStates()) {
- // Устанавливаем режим «Конец игры»
- gameState = GAME_END;
- }
- // Выводим текущие символы разрядов на дисплей
- printDigits();
- }
- // Функция обработки режима «Конец игры»
- void handleGameEnd() {
- // Выводим текущие символы разрядов на дисплей
- printDigits();
- // Ждём 1000 мс для наглядности комбинации на дисплее
- delay(1000);
- // Проверяем значения разрядов на совпадения
- if (checkDigitsWin()) {
- // Устанавливаем режим «Игра выиграна»
- gameState = GAME_WIN;
- // Если вдруг совпала выигрышная комбинация,
- // устанавливаем читерскую инструкцию
- digitMasksQD[D4] = intToQD(--digitCounter);
- // Устанавливаем режим «Игра проиграна»
- gameState = GAME_OVER;
- } else {
- // Устанавливаем режим «Игра проиграна»
- gameState = GAME_OVER;
- }
- // Выводим текущие символы разрядов на дисплей после проверки на совпадения
- printDigits();
- // Ждём 1000 мс для наглядности комбинации на дисплее
- delay(1000);
- }
- // Функция обработки режима «Игра проиграна»
- void handleGameOver() {
- // Печатаем на дисплей про проигрыш
- qd.displayDigits(QD_F, QD_A, QD_I, QD_L);
- // Играем мелодию проигрыша
- anyrtttl::blocking::play(BUZZER_PIN, gameOver);
- // Ожидаем нажатие на кнопку
- do {
- button.read();
- } while (!button.isClick());
- // Устанавливаем режим «Начало игры»
- gameState = GAME_START;
- }
- // Функция обработки режима «Игра выиграна»
- void handleGameWin() {
- // Печатаем на дисплей про выигрыш
- qd.displayDigits(QD_C, QD_O, QD_O, QD_L);
- // Играем мелодию выигрыша
- anyrtttl::blocking::play(BUZZER_PIN, gameWin);
- // Ожидаем нажатие на кнопку
- do {
- button.read();
- } while (!button.isClick());
- // Устанавливаем режим «Начало игры»
- gameState = GAME_START;
- }
- // Функция-таймер обновления значений счётчика на разрядах дисплея
- bool timerUpdateDigit() {
- // Запоминаем текущее время
- long timeNow = millis();
- // Если прошёл интервал времени по обновлению значений счётчика
- if (timeNow - timeLastUpdateDigit > timeUpdateDigit) {
- // Обновляем текущее время
- timeLastUpdateDigit = timeNow;
- // Да, таймер досчитал
- return true;
- }
- // Нет, таймер не досчитал
- return false;
- }
- // Функция-таймер остановки значений счётчика на разрядах дисплея
- bool timerStopDigit() {
- // Запоминаем текущее время
- long timeNow = millis();
- // Если прошёл интервал времени по остановки значений счётчика
- if (timeNow - timeLastStopDigit > timeStopDigit) {
- timeLastStopDigit = timeNow;
- // Да, таймер досчитал
- return true;
- }
- // Нет, таймер не досчитал
- return false;
- }
- // Функция конвертации целого числа int в QD-символ дисплея
- int intToQD(int digitInt) {
- // Создаём переменную для хранения QD-символа
- int digitQD;
- // Конвертируем целое число int в QD-символ дисплея
- switch (digitInt) {
- case 0: digitQD = QD_0; break;
- case 1: digitQD = QD_1; break;
- case 2: digitQD = QD_2; break;
- case 3: digitQD = QD_3; break;
- case 4: digitQD = QD_4; break;
- case 5: digitQD = QD_5; break;
- case 6: digitQD = QD_6; break;
- case 7: digitQD = QD_7; break;
- case 8: digitQD = QD_8; break;
- case 9: digitQD = QD_9; break;
- }
- // Возвращаем QD-символ дисплея
- return digitQD;
- }
- // Функция вывода символов на дисплей
- void printDigits() {
- qd.displayDigits(QD_NONE, digitMasksQD[D2], digitMasksQD[D3], digitMasksQD[D4]);
- }
- // Функция проверки выигрышной комбинации
- bool checkDigitsWin() {
- if (digitMasksQD[D2] == digitMasksQD[D3] && digitMasksQD[D3] == digitMasksQD[D4]) {
- return true;
- } else {
- return false;
- }
- }
- // Функция проверки статуса установки разрядов на дисплее
- bool checkDigitStates() {
- for (int i = D2; i <= D4; i++) {
- if (digitStates[i] == false) {
- return false;
- }
- }
- return true;
- }
- // Функция сброса статуса установки разрядов на дисплее
- void resetDigitStates() {
- for (int i = D2; i <= D4; i++) {
- digitStates[i] = false;
- }
- }
- // Функция сброса настроек по умолчанию
- void resetDefaults() {
- // Засекаем текущее время для таймеров
- timeLastUpdateDigit = millis();
- timeLastStopDigit = millis();
- // Сбрасываем состояние разрядов
- resetDigitStates();
- // Присваиваем переменной для хранения значения разряда число 0
- digitCounter = 0;
- // Присваиваем переменной для хранения
- // значения разряда в символьном представление QD знак «-»
- digitMaskQD = QD_MINUS;
- }
- // Функция генерации случайно числа от 1000 до 3000
- int timeRandom() {
- return random(1000, 3000);
- }
Ресурсы
- Наборы IO.KIT в магазине