Инструменты пользователя

Инструменты сайта


Электронное приложение к набору «IO.KIT Электронные часы»

На этой странице ты найдёшь все нужные материалы для сборки мини-проектов набора Электронные часы из серии IO.KIT:

  • Схемы проектов в электронном виде.
  • Исходный код программ (копируй его в редактор Arduino IDE).
  • Дополнительные материалы: программные библиотеки, даташиты и т. п.

Обрати внимание

Для сборки и функционирования электронных часов тебе понадобится IO.KIT Базовый!

Проекты

Прежде чем приступать к экспериментам, нужно подготовить свой компьютер:

Драйвер чипа CH340

Установи драйвер CH340 для Windows или Linux, чтобы твой компьютер мог корректно распознать и прошить плату Iskra Nano.

№1. Индикация чисел

DisplayDigits.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3. // Создаём объект дисплея на шине SPI и пине 10
  4. QuadDisplay qd(10);
  5.  
  6. void setup() {
  7. // Инициализируем дисплей
  8. qd.begin();
  9. }
  10.  
  11. void loop() {
  12. // Выводим на дисплей целое число
  13. qd.displayInt(1234);
  14. // Ждём 1 секунду
  15. delay(1000);
  16. // Выводим на дисплей рациональное число
  17. // с заданной точностью 2 знака после запятой
  18. qd.displayFloat(3.14, 2);
  19. // Ждём 1 секунду
  20. delay(1000);
  21. // Очищаем дисплей
  22. qd.displayClear();
  23. // Ждём 1 секунду
  24. delay(1000);
  25. }

№2. Индикация символов

DisplayCharacters.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3. // Создаём объект дисплея на шине SPI и пине 10
  4. QuadDisplay qd(10);
  5.  
  6. void setup() {
  7. // Инициализируем дисплей
  8. qd.begin();
  9. // Выводим на дисплей надпись «PLAY»
  10. qd.displayDigits(QD_P, QD_L, QD_A, QD_Y);
  11. }
  12.  
  13. void loop() {
  14. }

№3. Кнопочный детектор

DisplayButton.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3.  
  4. // Подключаем библиотеку для работы с кнопками
  5. #include <TroykaButton.h>
  6.  
  7. // Создаём объект дисплея на шине SPI и пине 10
  8. QuadDisplay qd(10);
  9.  
  10. // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
  11. TroykaButton buttonS1(5);
  12. TroykaButton buttonS2(2);
  13. TroykaButton buttonS3(3);
  14. TroykaButton buttonS4(4);
  15.  
  16. void setup() {
  17. // Инициализируем дисплей
  18. qd.begin();
  19. // Инициализируем кнопки
  20. buttonS1.begin();
  21. buttonS2.begin();
  22. buttonS3.begin();
  23. buttonS4.begin();
  24. }
  25.  
  26. void loop() {
  27. // Считываем состояния с кнопок
  28. buttonS1.read();
  29. buttonS2.read();
  30. buttonS3.read();
  31. buttonS4.read();
  32. // Выводим нажатую кнопку на индикатор
  33. if (buttonS1.justPressed()) {
  34. qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_1);
  35. // Ждём 1000 мс
  36. delay(1000);
  37. } else if (buttonS2.justPressed()) {
  38. qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_2);
  39. // Ждём 1000 мс
  40. delay(1000);
  41. } else if (buttonS3.justPressed()) {
  42. qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_3);
  43. // Ждём 1000 мс
  44. delay(1000);
  45. } else if (buttonS4.justPressed()) {
  46. qd.displayDigits(QD_NONE, QD_NONE, QD_S, QD_4);
  47. // Ждём 1000 мс
  48. delay(1000);
  49. } else {
  50. // Если нажатой кнопки нет, выводим символы «----»
  51. qd.displayDigits(QD_MINUS, QD_MINUS, QD_MINUS, QD_MINUS);
  52. }
  53. }

№4. Диммер с индикацией

DisplayDimmer.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3.  
  4. // Создаём объект дисплея на шине SPI и пине 10
  5. QuadDisplay qd(10);
  6.  
  7. // Даём понятное имя пину 5 со светодиодом
  8. constexpr uint8_t LED_PIN = 5;
  9. // Даём понятное имя пину A0 с потенциометром
  10. constexpr uint8_t POT_PIN = A0;
  11.  
  12. void setup() {
  13. // Настраиваем пин со светодиодом в режим выхода
  14. pinMode(LED_PIN, OUTPUT);
  15. // Настраиваем пин с потенциометром в режим входа
  16. pinMode(POT_PIN, INPUT);
  17. // Инициализируем дисплей
  18. qd.begin();
  19. }
  20.  
  21. void loop() {
  22. // Считываем аналоговый сигнал с потенциометра
  23. int rotation = analogRead(POT_PIN);
  24. // Преобразуем диапазон значений с потенциометра [0;1023]
  25. // в диапазон значений для светодиода [0;255]
  26. int brightness = map(rotation, 0, 1023, 0, 255);
  27. // Выдаём результат на светодиод
  28. analogWrite(LED_PIN, brightness);
  29. // Преобразуем диапазон значений с потенциометра [0;1023]
  30. // в процентный диапазон значений [0;100]
  31. int percent = map(rotation, 0, 1023, 0, 100);
  32. // Выводим результат на дисплей
  33. qd.displayInt(percent);
  34. // Ждём 25 мс
  35. delay(25);
  36. }

№5. Кухонный таймер

Timer.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3.  
  4. // Подключаем библиотеку для работы с кнопками
  5. #include <TroykaButton.h>
  6.  
  7. // Создаём объект дисплея на шине SPI и пине 10
  8. QuadDisplay qd(10);
  9.  
  10. // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
  11. TroykaButton buttonS1(5);
  12. TroykaButton buttonS2(2);
  13. TroykaButton buttonS3(3);
  14. TroykaButton buttonS4(4);
  15.  
  16. // Даём понятное имя пину A2 с пищалкой
  17. constexpr uint8_t BUZZER_PIN = A2;
  18. // Даём понятное имя пину A0 с потенциометром
  19. constexpr uint8_t POT_PIN = A0;
  20.  
  21. // Создаём переменную для хранения счетчика таймера
  22. int timerCount;
  23.  
  24. // Создаём переменную для работы таймера
  25. unsigned long timeLastUpdate = 0;
  26.  
  27. // Создаём перечисление состояний таймера с соответствующей переменной
  28. enum {
  29. TIMER_SETUP, // «Установка таймера»
  30. TIMER_TICK, // «Таймер тикает»
  31. TIMER_DONE // «Таймер завершен»
  32. } timerState;
  33.  
  34. void setup() {
  35. // Инициализируем дисплей
  36. qd.begin();
  37. // Инициализируем кнопки
  38. buttonS1.begin();
  39. buttonS2.begin();
  40. buttonS3.begin();
  41. buttonS4.begin();
  42. // Настраиваем пин с пищалкой в режим выхода
  43. pinMode(BUZZER_PIN, OUTPUT);
  44. // Настраиваем пин с потенциометром в режим входа
  45. pinMode(POT_PIN, INPUT);
  46. // Устанавливаем режим «Установка таймера»
  47. timerState = TIMER_SETUP;
  48. }
  49.  
  50. void loop() {
  51. // Если установлен режим «Установка таймера»
  52. if (timerState == TIMER_SETUP) {
  53. // Переходим в функцию обработки режима «Установка таймера»
  54. handleTimerSetup();
  55. }
  56. // Если установлен режим «Таймер тикает»
  57. if (timerState == TIMER_TICK) {
  58. // Переходим в функцию обработки режима «Таймер тикает»
  59. handleTimerTick();
  60. }
  61. // Если установлен режим «Таймер завершен»
  62. if (timerState == TIMER_DONE) {
  63. // Переходим в функцию обработки режима «Таймер завершен»
  64. handleTimerDone();
  65. }
  66. }
  67.  
  68. // Функция обработки режима «Установка таймера»
  69. void handleTimerSetup() {
  70. // Выводим на индикатор выводим символы «----»
  71. qd.displayDigits(QD_MINUS, QD_MINUS, QD_MINUS, QD_MINUS);
  72. // Подаём звуковой сигнал про установку таймера
  73. playMelodyTimerSetup();
  74. // Считываем состояние с кнопки S1
  75. buttonS1.read();
  76. // Пока на нажата кнопка S1
  77. while (!buttonS1.isClick()) {
  78. // Считываем показания с потенциометра
  79. timerCount = readPot(POT_PIN);
  80. // Выводим полученные показания на дисплей
  81. qd.displayInt(timerCount);
  82. // Обновляем состояние с кнопки S1
  83. buttonS1.read();
  84. }
  85. // Подаём звуковой сигнал о старте таймера
  86. playMelodyTimerBegin();
  87. // Устанавливаем режим «Таймер тикает»
  88. timerState = TIMER_TICK;
  89. }
  90.  
  91. // Функция обработки режима «Таймер тикает»
  92. void handleTimerTick() {
  93. // Передаем константе состояние таймера
  94. const auto updateDone = timer();
  95. // Если таймер обновил данные, т.е. прошла 1 секунда
  96. if (updateDone) {
  97. // Выводим счётчик таймера на дисплей
  98. qd.displayInt(timerCount);
  99. // Если счётчик дошёл до ноля
  100. if (timerCount == 0) {
  101. // Отображаем на индикаторе строку про завершения таймера
  102. qd.displayDigits(QD_NONE, QD_E, QD_n, QD_d);
  103. // Подаём звуковой сигнал на пищалку про завершения таймера
  104. playMelodyTimerEnd();
  105. // Устанавливаем режим «Таймер завершен»
  106. timerState = TIMER_DONE;
  107. }
  108. }
  109. }
  110.  
  111. // Функция обработки режима «Таймер завершен»
  112. void handleTimerDone() {
  113. do {
  114. // Считываем состояние с кнопки S1
  115. buttonS1.read();
  116. // Пока не нажата кнопка S1
  117. } while (!buttonS1.isClick());
  118. // Устанавливаем режим «Установка таймера»
  119. timerState = TIMER_SETUP;
  120. }
  121.  
  122. // Функция для отсчёта времени посекундно
  123. bool timer() {
  124. // Запоминаем текущее время
  125. long timeNow = millis();
  126. // Если прошла одна секунда
  127. if (timeNow - timeLastUpdate > 1000) {
  128. // Обновляем текущее время
  129. timeLastUpdate = timeNow;
  130. // Уменьшаем текущий счётчик на единицу
  131. timerCount--;
  132. // Да, таймер досчитал
  133. return true;
  134. }
  135. // Нет, таймер не досчитал
  136. return false;
  137. }
  138.  
  139. // Функция считывания показаний с потенциометра
  140. int readPot(int pin) {
  141. // Создаём переменную для хранения
  142. // аналогового сигнала с потенциометра в отчётах АЦП
  143. int sensorADC = 0;
  144. // Создаём переменную для хранения
  145. // преобразованных показаний с потенциометра
  146. int sensorValue = 0;
  147. // Считываем усреднённый аналоговый сигнал с потенциометра
  148. for (int i = 0; i < 16; i++) {
  149. sensorADC += analogRead(pin);
  150. delay(5);
  151. }
  152. sensorADC = sensorADC / 16;
  153. // Преобразуем диапазон значений с потенциометра [0;1023]
  154. // в диапазон значений для таймера [0;360]
  155. sensorValue = map(sensorADC, 0, 1023, 360, 0);
  156. // Возвращаем полученное значение
  157. return sensorValue;
  158. }
  159.  
  160. // Функция мелодии «Установки таймера»
  161. void playMelodyTimerSetup() {
  162. tone(BUZZER_PIN, 330, 100);
  163. delay(150);
  164. tone(BUZZER_PIN, 330, 100);
  165. delay(300);
  166. tone(BUZZER_PIN, 330, 100);
  167. delay(300);
  168. tone(BUZZER_PIN, 262, 100);
  169. delay(100);
  170. tone(BUZZER_PIN, 330, 100);
  171. delay(300);
  172. tone(BUZZER_PIN, 392, 100);
  173. delay(550);
  174. tone(BUZZER_PIN, 523, 100);
  175. delay(575);
  176. }
  177.  
  178. // Функция мелодии «Старт таймера»
  179. void playMelodyTimerBegin() {
  180. tone(BUZZER_PIN, 2000, 200);
  181. delay(300);
  182. tone(BUZZER_PIN, 3000, 200);
  183. delay(300);
  184. tone(BUZZER_PIN, 4000, 200);
  185. }
  186.  
  187. // Функция мелодии «Завершение таймера»
  188. void playMelodyTimerEnd() {
  189. for (int i = 0; i <= 5; i++) {
  190. tone(BUZZER_PIN, 1000, 200);
  191. delay(400);
  192. }
  193. }

№6. Консольный хронометр

ClockConsole.ino
  1. // Подключаем библиотеку для работы с часами реального времени RTC
  2. #include <TroykaRTC.h>
  3.  
  4. // Создаём объект часов реального времени на шине I²C
  5. RTC clock;
  6.  
  7. void setup() {
  8. // Открываем монитор Serial-порта
  9. Serial.begin(9600);
  10. // Инициализируем часы реального времени
  11. clock.begin();
  12.  
  13. // Устанавливаем временную отметку в модуль
  14. // Выберите метод установки времени: ручной или автоматический
  15. // После установки времени в часы, закомментируйте метод clock.set
  16.  
  17. // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
  18. // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
  19. clock.set(14, 25, 45, 1, 8, 2020, SATURDAY);
  20.  
  21. // Автоматическая установка временной отметки в модуль
  22. // Время берётся из ПК при компиляции
  23. // clock.set(__TIMESTAMP__);
  24. }
  25.  
  26. void loop() {
  27. // Создаём переменные для хранения времени, даты и дня недели
  28. String timeStr;
  29. String dateStr;
  30. String weekDayStr;
  31. if (millis() % 1000 == 0) {
  32. // Если прошла одна секунда, запрашиваем данные с часов
  33. clock.read();
  34. // Получаем текущее время, дату и день недели в переменные
  35. clock.getTimeStamp(timeStr, dateStr, weekDayStr);
  36. // Выводим в консоль текущее время, дату и день недели
  37. Serial.print(timeStr);
  38. Serial.print("\t");
  39. Serial.print(dateStr);
  40. Serial.print("\t");
  41. Serial.println(weekDayStr);
  42. }
  43. }

№7. Часы

Clock.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3.  
  4. // Подключаем библиотеку для работы с кнопками
  5. #include <TroykaButton.h>
  6.  
  7. // Подключаем библиотеку для работы с часами реального времени RTC
  8. #include <TroykaRTC.h>
  9.  
  10. // Создаём объект дисплея на шине SPI и пине 10
  11. QuadDisplay qd(10);
  12.  
  13. // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
  14. TroykaButton buttonS1(5);
  15. TroykaButton buttonS2(2);
  16. TroykaButton buttonS3(3);
  17. TroykaButton buttonS4(4);
  18.  
  19. // Создаём объект часов реального времени на шине I²C
  20. RTC clock;
  21.  
  22. // Создаём переменные для хранения часов и минут
  23. uint8_t hours;
  24. uint8_t minutes;
  25.  
  26. void setup() {
  27. // Инициализируем дисплей
  28. qd.begin();
  29. // Инициализируем кнопки
  30. buttonS1.begin();
  31. buttonS2.begin();
  32. buttonS3.begin();
  33. buttonS4.begin();
  34. // Инициализируем часы реального времени
  35. clock.begin();
  36.  
  37. // Устанавливаем временную отметку в модуль
  38. // Выберите метод установки времени: ручной или автоматический
  39. // После установки времени в часы, закомментируйте метод clock.set
  40.  
  41. // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
  42. // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
  43. // clock.set(14, 25, 45, 1, 8, 2020, SATURDAY);
  44.  
  45. // Автоматическая установка временной отметки в модуль
  46. // Время берётся из ПК при компиляции
  47. clock.set(__TIMESTAMP__);
  48. }
  49.  
  50. void loop() {
  51. // Запрашиваем данные с часов
  52. clock.read();
  53. // Получаем текущие показания часов и минут в переменные
  54. hours = clock.getHour();
  55. minutes = clock.getMinute();
  56. // Выводим время на дисплей
  57. qd.displayScore(hours, minutes, true);
  58. // Обновляем время через функцию обработки кнопок
  59. updateTimeButtons();
  60. }
  61.  
  62. // Функция обновления времени через кнопки
  63. void updateTimeButtons() {
  64. // Считываем состояния с кнопок
  65. buttonS1.read();
  66. buttonS2.read();
  67. buttonS3.read();
  68. buttonS4.read();
  69. // Настраиваем время на часах с помощью кнопок
  70. if (buttonS1.isClick()) {
  71. clock.setHour(hours - 1);
  72. } else if (buttonS2.isClick()) {
  73. clock.setMinute(minutes - 1);
  74. } else if (buttonS3.isClick()) {
  75. clock.setMinute(minutes + 1);
  76. } else if (buttonS4.isClick()) {
  77. clock.setHour(hours + 1);
  78. }
  79. }

№8. Часы с будильником

ClockAlarm.ino
  1. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  2. #include <QuadDisplay2.h>
  3.  
  4. // Подключаем библиотеку для работы с кнопками
  5. #include <TroykaButton.h>
  6.  
  7. // Подключаем библиотеку для работы с часами реального времени RTC
  8. #include <TroykaRTC.h>
  9.  
  10. // Создаём объект дисплея на шине SPI и пине 10
  11. QuadDisplay qd(10);
  12.  
  13. // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
  14. TroykaButton buttonS1(5);
  15. TroykaButton buttonS2(2);
  16. TroykaButton buttonS3(3);
  17. TroykaButton buttonS4(4);
  18.  
  19. // Создаём объект часов реального времени на шине I²C
  20. RTC clock;
  21.  
  22. // Даём понятное имя пищалке на пине A2
  23. constexpr uint8_t BUZZER_PIN = A2;
  24.  
  25. // Создаём переменные для хранения часов и минут
  26. uint8_t hours;
  27. uint8_t minutes;
  28.  
  29. // Создаём константы для хранения часов и минут будильника
  30. constexpr uint8_t alarmHours = 7;
  31. constexpr uint8_t alarmMinutes = 30;
  32.  
  33. void setup() {
  34. // Инициализируем дисплей
  35. qd.begin();
  36. // Инициализируем кнопки
  37. buttonS1.begin();
  38. buttonS2.begin();
  39. buttonS3.begin();
  40. buttonS4.begin();
  41. // Инициализируем часы реального времени
  42. clock.begin();
  43. // Настраиваем пин с пищалкой в режим выхода
  44. pinMode(BUZZER_PIN, OUTPUT);
  45.  
  46. // Устанавливаем временную отметку в модуль
  47. // Выберите метод установки времени: ручной или автоматический
  48. // После установки времени в часы, закомментируйте метод clock.set
  49.  
  50. // Ручная установка временной отметки в модуль: 14:25:45 1 августа 2020 года
  51. // 14 час, 25 мин, 45 сек, 1 число, август, 2020 год, суббота
  52. // clock.set(14, 25, 45, 1, 8, 2020, SATURDAY);
  53.  
  54. // Автоматическая установка временной отметки в модуль
  55. // Время берётся из ПК при компиляции
  56. clock.set(__TIMESTAMP__);
  57. }
  58.  
  59. void loop() {
  60. // Запрашиваем данные с часов
  61. clock.read();
  62. // Получаем текущие показания часов и минут в переменные
  63. hours = clock.getHour();
  64. minutes = clock.getMinute();
  65. // Выводим время на дисплей
  66. qd.displayScore(hours, minutes, true);
  67. // Обновляем время через функцию обработки кнопок
  68. updateTimeButtons();
  69. // Обрабатываем времени будильника
  70. alarmRing();
  71. }
  72.  
  73. // Функция обновления времени через кнопки
  74. void updateTimeButtons() {
  75. // Считываем состояния с кнопок
  76. buttonS1.read();
  77. buttonS2.read();
  78. buttonS3.read();
  79. buttonS4.read();
  80. // Настраиваем время на часах с помощью кнопок
  81. if (buttonS1.isClick()) {
  82. clock.setHour(hours - 1);
  83. } else if (buttonS2.isClick()) {
  84. clock.setMinute(minutes - 1);
  85. } else if (buttonS3.isClick()) {
  86. clock.setMinute(minutes + 1);
  87. } else if (buttonS4.isClick()) {
  88. clock.setHour(hours + 1);
  89. }
  90. }
  91.  
  92. // Функция обработки времени будильника
  93. bool alarmRing() {
  94. // Если текущее время совпадает со временем будильника
  95. if (hours == alarmHours && minutes == alarmMinutes) {
  96. // Мигаем дисплеем и пищим зуммером
  97. qd.displayClear();
  98. tone(BUZZER_PIN, 1000, 200);
  99. delay(200);
  100. qd.displayScore(hours, minutes, false);
  101. delay(300);
  102. }
  103. }

№9. Плеер с выбором трека

playerMusicTrack.ino
  1. // Подключаем библиотеку для работы с мелодиями в формате RTTTL
  2. #include <anyrtttl.h>
  3.  
  4. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  5. #include <QuadDisplay2.h>
  6.  
  7. // Подключаем библиотеку для работы с кнопками
  8. #include <TroykaButton.h>
  9.  
  10. // Создаём объект дисплея на шине SPI и пине 10
  11. QuadDisplay qd(10);
  12.  
  13. // Создаём объекты кнопок на пинах: 2, 3, 4 и 5
  14. TroykaButton buttonS1(5);
  15. TroykaButton buttonS2(2);
  16. TroykaButton buttonS3(3);
  17. TroykaButton buttonS4(4);
  18.  
  19. // Даём понятное имя пину A2 с пищалкой
  20. constexpr uint8_t BUZZER_PIN = A2;
  21.  
  22. // Мелодия «Имперский марш» в формате RTTTL
  23. const char imperM[] PROGMEM = "imperMarch:d=8,o=5,b=95:"
  24. "4a4,4a4,4a4,f.4,16c,4a4,f.4,16c,"
  25. "2a4,4e,4e,4e,f.,16c,4g#4,f.4,"
  26. "16c,2a4,4a,a.4,16a4,4a,g#.,16g,"
  27. "16f#,16e,f,p,a#4,4d#,d.,16c#,16c,"
  28. "16b4,c,p,f4,4g#4,f.4,16a4,4c,"
  29. "a.4,16c,2e,4a,a.4,16a4,4a,g#.,"
  30. "16g,16f#,16e,f,p,a#4,4d#,d.,"
  31. "16c#,16c,16b4,c,p,f4,4g#4,f.4,"
  32. "16c,4a4,f.4,16c,2a4";
  33.  
  34. // Мелодия «Марио» в формате RTTTL
  35. const char marioB[] PROGMEM = "marioBroth:d=4,o=5,b=100:"
  36. "16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,"
  37. "8g,8p,8c6,16p,8g,16p,8e,16p,"
  38. "8a,8b,16a#,8a,16g.,16e6,16g6,8a6,"
  39. "16f6,8g6,8e6,16c6,16d6,8b,16p,8c6,"
  40. "16p,8g,16p,8e,16p,8a,8b,16a#,"
  41. "8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,"
  42. "16c6,16d6,8b,8p,16g6,16f#6,16f6,16d#6,"
  43. "16p,16e6,16p,16g#,16a,16c6,16p,16a,"
  44. "16c6,16d6,8p,16g6,16f#6,16f6,16d#6,16p,"
  45. "16e6,16p,16c7,16p,16c7,16c7,p,16g6,"
  46. "16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,"
  47. "16c6,16p,16a,16c6,16d6,8p,16d#6,8p,"
  48. "16d6,8p,16c6";
  49.  
  50. // Мелодия «Миссия невыполнима» в формате RTTTL
  51. const char misImp[] PROGMEM = "missionImp:d=16,o=6,b=95:"
  52. "32d,32d#,32d,32d#,32d,32d#,32d,32d#,"
  53. "32d,32d,32d#,32e,32f,32f#,32g,g,8p,"
  54. "g,8p,a#,p,c7,p,g,8p,"
  55. "g,8p,f,p,f#,p,g,8p,"
  56. "g,8p,a#,p,c7,p,g,8p,"
  57. "g,8p,f,p,f#,p,a#,g,"
  58. "2d,32p,a#,g,2c#,32p,a#,g,"
  59. "2c,a#5,8c,2p,32p,a#5,g5,2f#,"
  60. "32p,a#5,g5,2f,32p,a#5,g5,2e,"
  61. "d#,8d";
  62.  
  63. // Мелодия «Тетрис» в формате RTTTL
  64. const char tetris[] PROGMEM = "tetris:d=4,o=5,b=160:"
  65. "e6,8b,8c6,8d6,16e6,16d6,8c6,8b,"
  66. "a,8a,8c6,e6,8d6,8c6,b,8b,"
  67. "8c6,d6,e6,c6,a,2a,8p,d6,"
  68. "8f6,a6,8g6,8f6,e6,8e6,8c6,e6,"
  69. "8d6,8c6,b,8b,8c6,d6,e6,c6,"
  70. "a,a";
  71.  
  72. // Мелодия «Европа» в формате RTTTL
  73. const char europe[] PROGMEM = "Europe:d=4,o=5,b=140:"
  74. "16c#6,32b,32p,8c#.6,16p,f#,p.,32d6,32p,"
  75. "32c#6,32p,32d6,16p.,32c#6,16p.,b.,p,"
  76. "32d6,32p,32c#6,32p,d6,f#,p.,32b,"
  77. "32p,32a,32p,32b,16p.,32a,16p.,32g#,"
  78. "16p.,32b,16p.,a.,32c#6,32p,32b,32p,"
  79. "c#6,2f#,p,16p,32d6,32p,32c#6,32p,32d6,"
  80. "16p.,32c#6,16p.,b.,p,32d6,32p,32c#6,32p,"
  81. "d6,f#,p.,32b,32p,32a,32p,32b,"
  82. "16p.,32a,16p.,32g#,16p.,32b,16p.,2a,"
  83. "16p,32g#,32p,32a,32p,b.,16a,16b,"
  84. "8c#6,8b,8a,8g#,f#,d6,1c#6,8p,"
  85. "16c#6,16d6,16c#6,16b,2c#.6,16p";
  86.  
  87. // Создаём переменную для хранения номера трека
  88. uint8_t songID;
  89.  
  90. // Задаём константы минимального и максимального номеров трека
  91. constexpr uint8_t minSongID = 1;
  92. constexpr uint8_t maxSongID = 5;
  93.  
  94. // Создаём переменную для хранения паузы
  95. bool pause = false;
  96.  
  97. // Создаём перечисление состояний плеера с соответствующей переменной
  98. enum {
  99. PLAY_OFF, // «Плеер не играет»
  100. PLAY_ON, // «Плеер играет»
  101. } playState;
  102.  
  103. void setup() {
  104. // Инициализируем дисплей
  105. qd.begin();
  106. // Инициализируем кнопки
  107. buttonS1.begin();
  108. buttonS2.begin();
  109. buttonS3.begin();
  110. buttonS4.begin();
  111. // Настраиваем пин с пищалкой в режим выхода
  112. pinMode(BUZZER_PIN, OUTPUT);
  113. // Устанавливаем режим «Плеер не играет»
  114. playState = PLAY_OFF;
  115. // Устанавливаем трек №1
  116. songID = 1;
  117. }
  118.  
  119. void loop() {
  120. // Считываем состояния с кнопок
  121. readButtons();
  122. // Обновляем трек с помощью кнопок
  123. updateSongIDButtons();
  124. // Выводим выбранный трек на индикатор
  125. printDisplaySongID();
  126. // Проверяем состояние плеера
  127. switch (playState) {
  128. // Если установлен режим «Плеер не играет»
  129. case PLAY_OFF:
  130. // Переходим в функцию обработки режима «Плеер не играет»
  131. handlePlayOff();
  132. break;
  133. // Если установлен режим «Плеер играет»
  134. case PLAY_ON:
  135. // Переходим в функцию обработки режима «Плеер играет»
  136. handlePlayOn();
  137. break;
  138. }
  139. }
  140.  
  141. // Функция обработки режима «Плеер не играет»
  142. void handlePlayOff() {
  143. // Если был клик по кнопке S1
  144. if (buttonS1.isClick()) {
  145. // Выбираем трек к воспроизведению
  146. setSongID();
  147. // Устанавливаем режим «Плеер играет»
  148. playState = PLAY_ON;
  149. }
  150. }
  151.  
  152. // Функция обработки режима «Плеер играет»
  153. void handlePlayOn() {
  154. // Включаем трек
  155. playSongID();
  156. // Если был клик по кнопке S1
  157. if (buttonS1.isClick()) {
  158. // Останавливаем трек
  159. stopSongID();
  160. // Устанавливаем режим «Плеер не играет»
  161. playState = PLAY_OFF;
  162. }
  163. // Если был клик по кнопке S4
  164. if (buttonS4.isClick()) {
  165. // Ставим на паузу текущий трек
  166. pause = !pause;
  167. }
  168. }
  169.  
  170. // Функция считывания состояний с кнопок
  171. void readButtons() {
  172. buttonS1.read();
  173. buttonS2.read();
  174. buttonS3.read();
  175. buttonS4.read();
  176. }
  177.  
  178. // Функция обновления текущего трека с помощью кнопок
  179. void updateSongIDButtons() {
  180. if (buttonS3.isClick()) {
  181. songID++;
  182. }
  183. if (buttonS2.isClick()) {
  184. songID--;
  185. }
  186. // Корректируем номер трека в рамки диапазона [min;max]
  187. wrapSongID();
  188. }
  189.  
  190. // Функция корректировки номеров трека в диапазон [min;max]
  191. void wrapSongID() {
  192. if (songID > maxSongID) {
  193. songID = minSongID;
  194. }
  195. if (songID < minSongID) {
  196. songID = maxSongID;
  197. }
  198. }
  199.  
  200. // Функция вывода текущего трека на индикатор
  201. void printDisplaySongID() {
  202. if (songID == 1) {
  203. qd.displayDigits(QD_P, QD_0, QD_0, QD_1);
  204. } else if (songID == 2) {
  205. qd.displayDigits(QD_P, QD_0, QD_0, QD_2);
  206. } else if (songID == 3) {
  207. qd.displayDigits(QD_P, QD_0, QD_0, QD_3);
  208. } else if (songID == 4) {
  209. qd.displayDigits(QD_P, QD_0, QD_0, QD_4);
  210. } else if (songID == 5) {
  211. qd.displayDigits(QD_P, QD_0, QD_0, QD_5);
  212. } else {
  213. qd.displayDigits(QD_E, QD_r, QD_r, QD_NONE);
  214. }
  215. }
  216.  
  217. // Функция выбора трека
  218. void setSongID() {
  219. if (songID == 1) {
  220. anyrtttl::nonblocking::begin_P(BUZZER_PIN, imperM);
  221. } else if (songID == 2) {
  222. anyrtttl::nonblocking::begin_P(BUZZER_PIN, marioB);
  223. } else if (songID == 3) {
  224. anyrtttl::nonblocking::begin_P(BUZZER_PIN, misImp);
  225. } else if (songID == 4) {
  226. anyrtttl::nonblocking::begin_P(BUZZER_PIN, tetris);
  227. } else if (songID == 5) {
  228. anyrtttl::nonblocking::begin_P(BUZZER_PIN, europe);
  229. }
  230. }
  231.  
  232. // Функция воспроизведения трека
  233. void playSongID() {
  234. // Если не включена пауза
  235. if (pause == false) {
  236. // Продолжаем играть трек
  237. anyrtttl::nonblocking::play();
  238. }
  239. // Если трек завершился
  240. if (anyrtttl::nonblocking::done()) {
  241. // Устанавливаем режим «Плеер не играет»
  242. playState = PLAY_OFF;
  243. }
  244. }
  245.  
  246. // Функция остановки трека
  247. void stopSongID() {
  248. // Останавливаем трек
  249. anyrtttl::nonblocking::stop();
  250. }

№10. Troyka Slot-машина

SlotGame.ino
  1. // Подключаем библиотеку для работы с мелодиями в формате RTTTL
  2. #include <anyrtttl.h>
  3.  
  4. // Подключаем библиотеку для работы с четырёхразрядным дисплеем
  5. #include <QuadDisplay2.h>
  6.  
  7. // Подключаем библиотеку для работы с кнопками
  8. #include <TroykaButton.h>
  9.  
  10. // Создаём объект дисплея на шине SPI и пине 10
  11. QuadDisplay qd(10);
  12.  
  13. // Создаём объект кнопки на пине 2
  14. TroykaButton button(2);
  15.  
  16. // Даём понятное имя пину A2 с пищалкой
  17. constexpr uint8_t BUZZER_PIN = A2;
  18.  
  19. // Даём понятное имя пину 5 со светодиодом
  20. constexpr uint8_t LED_PIN = 5;
  21.  
  22. // Мелодия «Старт» в формате RTTTL
  23. const char* gameStart = "gameStart:d=4,o=5,b=100:"
  24. "16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,"
  25. "8g,8p";
  26.  
  27. // Мелодия «Игра проиграна» в формате RTTTL
  28. const char* gameOver = "gameOver:d=4,o=5,b=90:"
  29. "32c6,32c6,32c6,8p,16b,16f6,16p,16f6,"
  30. "16f.6,16e.6,16d6,16c6,16p,16e,16p,16c";
  31.  
  32. // Мелодия «Игра выиграна» в формате RTTTL
  33. const char* gameWin = "gameWin:d=4,o=5,b=180:"
  34. "8g3,8c4,8e4,8g4,8c,8e,3g,3e,"
  35. "8e3,8c4,8e#4,8A#4,8c,8e#,3a#,3e#,"
  36. "8b#3,8d4,8f4,8b#4,8d,8f,3b#,32p,"
  37. "8b#,32p,8b#,32p,8b#,1c6";
  38.  
  39. // Создаём перечисление состояний игры с соответствующей переменной
  40. enum {
  41. GAME_START, // «Начало игры»
  42. GAME_PLAY, // «Процесс игры»
  43. GAME_END, // «Конец игры»
  44. GAME_OVER, // «Игра проиграна»
  45. GAME_WIN // «Игра выиграна»
  46. } gameState;
  47.  
  48. // Создаём перечисление разрядов дисплея
  49. enum {
  50. D1 = 0, // Первый разряд
  51. D2 = 1, // Второй разряд
  52. D3 = 2, // Третий разряд
  53. D4 = 3 // Четвёртый разряд
  54. };
  55.  
  56. // Создаём переменную для хранения значения на разряде дисплея
  57. uint8_t digitCounter;
  58. // Создаём переменную для хранения значения на разряде дисплея в битовом виде
  59. uint8_t digitMaskQD;
  60. // Создаём массив для хранения значений на разрядах дисплея в битовом виде
  61. uint8_t digitMasksQD[4];
  62. // Создаём массив для хранения статуса установки значений на разрядах дисплея
  63. // true: разряд установлен, false: разряд не установлен
  64. bool digitStates[4];
  65.  
  66. // Создаём переменную для работы таймера обновления значений на разрядах дисплея
  67. long timeLastUpdateDigit = 0;
  68.  
  69. // Создаём переменную для работы таймера остановки значений на разрядах дисплея
  70. long timeLastStopDigit = 0;
  71.  
  72. // Создаём константу для хранения времени обновления значений счётчика на разрядах дисплея
  73. constexpr int timeUpdateDigit = 100;
  74. // Создаем переменную для хранения времени остановки значений счётчика на разрядах дисплея
  75. int timeStopDigit;
  76.  
  77. void setup() {
  78. // Инициализируем дисплей
  79. qd.begin();
  80. // Инициализируем кнопку
  81. button.begin();
  82. // Настраиваем пин с пищалкой в режим выхода
  83. pinMode(BUZZER_PIN, OUTPUT);
  84. // Настраиваем пин со светодиодом в режим выхода
  85. pinMode(LED_PIN, OUTPUT);
  86. // Задаём зерно генерации случайных чисел
  87. randomSeed(analogRead(A6));
  88. // Устанавливаем режим «Начало игры»
  89. gameState = GAME_START;
  90. }
  91.  
  92. void loop() {
  93. // Считываем состояние с кнопки
  94. button.read();
  95. // Выбираем действие в зависимости от текущего режима игры
  96. switch (gameState) {
  97. // Если установлен режим «Начало игры»
  98. case GAME_START: {
  99. // Переходим в функцию обработки режима «Начало игры»
  100. handleGameStart();
  101. break;
  102. }
  103. // Если установлен режим «Процесс игры»
  104. case GAME_PLAY: {
  105. // Переходим в функцию обработки режима «Процесс игры»
  106. handleGamePlay();
  107. break;
  108. }
  109. // Если установлен режим «Конец игры»
  110. case GAME_END: {
  111. // Переходим в функцию обработки режима «Конец игры»
  112. handleGameEnd();
  113. break;
  114. }
  115. // Если установлен режим «Игра проиграна»
  116. case GAME_OVER: {
  117. // Переходим в функцию обработки режима «Игры проиграна»
  118. handleGameOver();
  119. break;
  120. }
  121. // Если установлен режим «Игра выиграна»
  122. case GAME_WIN: {
  123. // Переходим в функцию обработки режима «Игры выиграна»
  124. handleGameWin();
  125. break;
  126. }
  127. }
  128. }
  129.  
  130. // Функция обработки режима «Начало игры»
  131. void handleGameStart() {
  132. // Зажигаем светодиод
  133. digitalWrite(LED_PIN, HIGH);
  134. // Выводим приветствие на дисплей
  135. qd.displayDigits(QD_P, QD_L, QD_A, QD_Y);
  136. // Играем приветственную мелодию
  137. anyrtttl::blocking::play(BUZZER_PIN, gameStart);
  138. // Ожидаем нажатие на кнопку
  139. do {
  140. // Считываем состояние с кнопки
  141. button.read();
  142. } while (!button.isClick());
  143. // Гасим светодиод
  144. digitalWrite(LED_PIN, LOW);
  145. // Сбрасываем настройки по умолчанию
  146. resetDefaults();
  147. // Генерируем случайное число
  148. timeStopDigit = timeRandom();
  149. // Устанавливаем режим «Процесс игры»
  150. gameState = GAME_PLAY;
  151. }
  152.  
  153. // Функция обработки режима «Процесс игры»
  154. void handleGamePlay() {
  155. // В режиме «Процесс игры» работают два таймера:
  156. // timerUpdateDigit(): таймер обновления значений символов,
  157. // который отвечает за время поочередного обновления цифр от 0 до 9
  158. // timerStopDigit(): таймер остановки значений символов,
  159. // который отвечает за время остановки обновления цифр от 0 до 9
  160.  
  161. // Если таймер обновления символов досчитал,
  162. // получаем последующее число от 0 до 9
  163.  
  164. // Передаем константе состояние таймера обновления символов
  165. const auto timerUpdateDone = timerUpdateDigit();
  166. // Если таймер досчитал, т.е. прошла 1 секунда
  167. if (timerUpdateDone) {
  168. // Увеличиваем цифру на один
  169. digitCounter++;
  170. // Если цифра стала более 9
  171. if (digitCounter > 9) {
  172. // Обнуляем цифру до ноля
  173. digitCounter = 0;
  174. }
  175. // Конвертируем число в QD-символов в битовом виде
  176. digitMaskQD = intToQD(digitCounter);
  177. }
  178.  
  179. // Передаем константе состояние таймера остановки значений
  180. const auto timerStopDone = timerStopDigit();
  181. // Если таймер остановки значений счётчика досчитал,
  182. // проверяем какой разряд стоит на очередь установки
  183. if (timerStopDone) {
  184. // Если очередь второго разряда
  185. if (digitStates[D2] == false) {
  186. // Фиксируем разряд статусом true: установлен
  187. digitStates[D2] = true;
  188. // Присваиваем текущий символ на счётчике в массив хранения значений результата
  189. digitMasksQD[D2] = digitMaskQD;
  190. // Генерируем случайное число
  191. timeStopDigit = timeRandom();
  192. // Если очередь третьего разряда
  193. } else if (digitStates[D3] == false) {
  194. // Фиксируем разряд статусом true: установлен
  195. digitStates[D3] = true;
  196. // Присваиваем текущий символ на счётчике в массив хранения значений результата
  197. digitMasksQD[D3] = digitMaskQD;
  198. // Генерируем случайное число
  199. timeStopDigit = timeRandom();
  200. // Если очередь четвёртого разряда
  201. } else if (digitStates[D4] == false) {
  202. // Фиксируем разряд статусом true: установлен
  203. digitStates[D4] = true;
  204. // Присваиваем текущий символ на счётчике в массив хранения значений результата
  205. digitMasksQD[D4] = digitMaskQD;
  206. }
  207. }
  208.  
  209. // Присваиваем текущий символ на счётчике всем не установленным разрядам
  210. for (int i = D2; i <= D4; i++) {
  211. if (!digitStates[i]) {
  212. digitMasksQD[i] = digitMaskQD;
  213. }
  214. }
  215.  
  216. // Если все разряды установлены
  217. if (checkDigitStates()) {
  218. // Устанавливаем режим «Конец игры»
  219. gameState = GAME_END;
  220. }
  221.  
  222. // Выводим текущие символы разрядов на дисплей
  223. printDigits();
  224. }
  225.  
  226. // Функция обработки режима «Конец игры»
  227. void handleGameEnd() {
  228. // Выводим текущие символы разрядов на дисплей
  229. printDigits();
  230. // Ждём 1000 мс для наглядности комбинации на дисплее
  231. delay(1000);
  232. // Проверяем значения разрядов на совпадения
  233. if (checkDigitsWin()) {
  234. // Устанавливаем режим «Игра выиграна»
  235. gameState = GAME_WIN;
  236. // Если вдруг совпала выигрышная комбинация,
  237. // устанавливаем читерскую инструкцию
  238. digitMasksQD[D4] = intToQD(--digitCounter);
  239. // Устанавливаем режим «Игра проиграна»
  240. gameState = GAME_OVER;
  241. } else {
  242. // Устанавливаем режим «Игра проиграна»
  243. gameState = GAME_OVER;
  244. }
  245. // Выводим текущие символы разрядов на дисплей после проверки на совпадения
  246. printDigits();
  247. // Ждём 1000 мс для наглядности комбинации на дисплее
  248. delay(1000);
  249. }
  250.  
  251. // Функция обработки режима «Игра проиграна»
  252. void handleGameOver() {
  253. // Печатаем на дисплей про проигрыш
  254. qd.displayDigits(QD_F, QD_A, QD_I, QD_L);
  255. // Играем мелодию проигрыша
  256. anyrtttl::blocking::play(BUZZER_PIN, gameOver);
  257. // Ожидаем нажатие на кнопку
  258. do {
  259. button.read();
  260. } while (!button.isClick());
  261. // Устанавливаем режим «Начало игры»
  262. gameState = GAME_START;
  263. }
  264.  
  265. // Функция обработки режима «Игра выиграна»
  266. void handleGameWin() {
  267. // Печатаем на дисплей про выигрыш
  268. qd.displayDigits(QD_C, QD_O, QD_O, QD_L);
  269. // Играем мелодию выигрыша
  270. anyrtttl::blocking::play(BUZZER_PIN, gameWin);
  271. // Ожидаем нажатие на кнопку
  272. do {
  273. button.read();
  274. } while (!button.isClick());
  275. // Устанавливаем режим «Начало игры»
  276. gameState = GAME_START;
  277. }
  278.  
  279. // Функция-таймер обновления значений счётчика на разрядах дисплея
  280. bool timerUpdateDigit() {
  281. // Запоминаем текущее время
  282. long timeNow = millis();
  283. // Если прошёл интервал времени по обновлению значений счётчика
  284. if (timeNow - timeLastUpdateDigit > timeUpdateDigit) {
  285. // Обновляем текущее время
  286. timeLastUpdateDigit = timeNow;
  287. // Да, таймер досчитал
  288. return true;
  289. }
  290. // Нет, таймер не досчитал
  291. return false;
  292. }
  293.  
  294. // Функция-таймер остановки значений счётчика на разрядах дисплея
  295. bool timerStopDigit() {
  296. // Запоминаем текущее время
  297. long timeNow = millis();
  298. // Если прошёл интервал времени по остановки значений счётчика
  299. if (timeNow - timeLastStopDigit > timeStopDigit) {
  300. timeLastStopDigit = timeNow;
  301. // Да, таймер досчитал
  302. return true;
  303. }
  304. // Нет, таймер не досчитал
  305. return false;
  306. }
  307.  
  308. // Функция конвертации целого числа int в QD-символ дисплея
  309. int intToQD(int digitInt) {
  310. // Создаём переменную для хранения QD-символа
  311. int digitQD;
  312. // Конвертируем целое число int в QD-символ дисплея
  313. switch (digitInt) {
  314. case 0: digitQD = QD_0; break;
  315. case 1: digitQD = QD_1; break;
  316. case 2: digitQD = QD_2; break;
  317. case 3: digitQD = QD_3; break;
  318. case 4: digitQD = QD_4; break;
  319. case 5: digitQD = QD_5; break;
  320. case 6: digitQD = QD_6; break;
  321. case 7: digitQD = QD_7; break;
  322. case 8: digitQD = QD_8; break;
  323. case 9: digitQD = QD_9; break;
  324. }
  325. // Возвращаем QD-символ дисплея
  326. return digitQD;
  327. }
  328.  
  329. // Функция вывода символов на дисплей
  330. void printDigits() {
  331. qd.displayDigits(QD_NONE, digitMasksQD[D2], digitMasksQD[D3], digitMasksQD[D4]);
  332. }
  333.  
  334. // Функция проверки выигрышной комбинации
  335. bool checkDigitsWin() {
  336. if (digitMasksQD[D2] == digitMasksQD[D3] && digitMasksQD[D3] == digitMasksQD[D4]) {
  337. return true;
  338. } else {
  339. return false;
  340. }
  341. }
  342.  
  343. // Функция проверки статуса установки разрядов на дисплее
  344. bool checkDigitStates() {
  345. for (int i = D2; i <= D4; i++) {
  346. if (digitStates[i] == false) {
  347. return false;
  348. }
  349. }
  350. return true;
  351. }
  352.  
  353. // Функция сброса статуса установки разрядов на дисплее
  354. void resetDigitStates() {
  355. for (int i = D2; i <= D4; i++) {
  356. digitStates[i] = false;
  357. }
  358. }
  359.  
  360. // Функция сброса настроек по умолчанию
  361. void resetDefaults() {
  362. // Засекаем текущее время для таймеров
  363. timeLastUpdateDigit = millis();
  364. timeLastStopDigit = millis();
  365. // Сбрасываем состояние разрядов
  366. resetDigitStates();
  367. // Присваиваем переменной для хранения значения разряда число 0
  368. digitCounter = 0;
  369. // Присваиваем переменной для хранения
  370. // значения разряда в символьном представление QD знак «-»
  371. digitMaskQD = QD_MINUS;
  372. }
  373.  
  374. // Функция генерации случайно числа от 1000 до 3000
  375. int timeRandom() {
  376. return random(1000, 3000);
  377. }

Ресурсы

Софт

Библиотеки