4.05.1. Лабораторная работа №4.5.1.md


Играем гимн России

Тема работы

В теории мы узнали, как функция tone() может генерировать звуки разной высоты. Теперь давайте применим эти знания для создания чего-то по-настоящему впечатляющего! В этой лабораторной работе мы напишем программу, которая научит Рудирон исполнять мелодию государственного гимна России с помощью простого пьезоизлучателя.

Цель

  • Научиться воспроизводить сложные мелодии, используя функцию tone().
  • Понять, как можно представить музыку в виде кода, используя массивы для нот и их длительностей.
  • Освоить использование директивы #define для создания именованных констант.

Оборудование и материалы

  • Отладочная плата Рудирон.
  • Макетная плата.
  • 1 пьезоизлучатель (зуммер).
  • 2 соединительных провода.
  • USB-кабель для подключения Рудирона к компьютеру.
  • Компьютер с настроенной средой Arduino IDE.

Ход работы

  1. Как записать мелодию в коде?

    Любая мелодия — это последовательность нот определённой высоты и длительности. В программировании мы можем представить её в виде двух массивов: 1. Массив нот. Хранит частоты нот в герцах (например, 392 для ноты «Соль»). 2. Массив длительностей. Хранит относительную длительность каждой ноты (например, 4 для четвертной, 8 для восьмой).

    Чтобы не запоминать частоты всех нот, мы можем определить их один раз в начале программы с помощью директивы #define. Это позволит нам использовать в коде понятные имена (NOTE_G4) вместо магических чисел (392).

  2. Сборка схемы

    Схема подключения пьезоизлучателя очень проста.

    • Вставьте пьезоизлучатель в макетную плату.
    • Один его вывод (обычно длинный или помеченный знаком «+») подключите к пину 8 Рудирона.
    • Второй вывод подключите к пину GND.

    Рис. 1. Схема подключения пьезоизлучателя

  3. Написание и загрузка кода

    • Установите перемычку PRG | RUN в положение PRG.
    • В Arduino IDE введите следующий код:

      // --- Определение частот нот ---
      // Пауза
      #define PAUSE 0
      // 1-я октава
      #define NOTE_C4  262
      #define NOTE_D4  294
      #define NOTE_E4  330
      #define NOTE_F4  349
      #define NOTE_G4  392
      #define NOTE_A4  440
      #define NOTE_B4  494
      // 2-я октава
      #define NOTE_C5  523
      #define NOTE_D5  587
      #define NOTE_E5  659
      #define NOTE_F5  698
      
      // --- Настройки ---
      const int buzzerPin = 8;
      // Темп мелодии (чем больше, тем медленнее)
      const int tempo = 1000; 
      
      // --- Гимн России ---
      int melody[] = {
        // Вступление
        NOTE_G4, 
        // 1-й куплет
        NOTE_C5, NOTE_G4, NOTE_G4, NOTE_A4, NOTE_B4, NOTE_E4, NOTE_E4, NOTE_A4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_G4, NOTE_C4, NOTE_C4,
        NOTE_D4, NOTE_D4, NOTE_E4, NOTE_E4, NOTE_F4, NOTE_F4, NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5, NOTE_D5, NOTE_D5, NOTE_G4, NOTE_G4,
        // Припев
        NOTE_C5, NOTE_B4, NOTE_A4, NOTE_B4, NOTE_E4, NOTE_E4, NOTE_A4, NOTE_G4, NOTE_F4, NOTE_G4, NOTE_C4, NOTE_C4,
        NOTE_C5, NOTE_B4, NOTE_A4, NOTE_B4, NOTE_G4,
        // 2-й куплет
        NOTE_E5, NOTE_D5, NOTE_C5, NOTE_B4, NOTE_C5, NOTE_D5, NOTE_G4, NOTE_G4,
        NOTE_C5, NOTE_B4, NOTE_A4, NOTE_B4, NOTE_E4, PAUSE, NOTE_E4, NOTE_C5, NOTE_A4, NOTE_A4, NOTE_B4, NOTE_C5, NOTE_A4, NOTE_A4, NOTE_B4, NOTE_C5,
        NOTE_D5, NOTE_C5, NOTE_F5, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_D5, NOTE_E5, NOTE_C5, NOTE_C5,
        // Припев
        NOTE_D5, NOTE_C5, NOTE_B4, NOTE_A4, NOTE_B4, NOTE_C5, NOTE_D5, NOTE_G4,
        NOTE_C5, NOTE_B4, NOTE_A4, NOTE_G4, NOTE_C4, NOTE_D5, NOTE_C5
      };
      
      // Длительности нот: 4 = четверть, 8 = восьмая, 16 = шестнадцатая
      int noteDurations[] = {
        8,
        4, 8, 16, 16, 4, 8, 8, 4, 8, 16, 16, 4, 8, 8,
        4, 16, 8, 8, 4, 16, 8, 8, 4, 8, 8, 4, 2,
        4, 8, 16, 16, 4, 8, 8, 4, 8, 8, 4, 8, 8,
        2, 4, 4, 2,
        2, 8, 8, 8, 8, 4, 8, 8, 2,
        4, 8, 16, 16, 4, 8, 8, 4, 4, 8, 16, 16, 4, 8, 16, 16,
        4, 8, 8, 2, 2, 8, 8, 8, 8, 4, 8, 8, 2,
        2, 8, 8, 8, 8, 4, 8, 8, 2,
        4, 2
      };
      
      void setup() { }
      
      void loop() {
        // Проигрываем мелодию
        for (int thisNote = 0; thisNote < sizeof(melody)/sizeof(int); thisNote++) {
        int duration = tempo / noteDurations[thisNote];
        tone(buzzerPin, melody[thisNote], duration);
      
        int pauseBetweenNotes = duration * 1.30;
        delay(pauseBetweenNotes);
        noTone(buzzerPin);
        }
        // Замолкаем навсегда после одного проигрывания
        while(true);
      }
      
    • Нажмите кнопку «Upload», чтобы загрузить код на плату.
  4. Проверка работы

    Сразу после загрузки Рудирон исполнит гимн России!

Результаты

Вы создали настоящее музыкальное устройство! Ваша программа последовательно проигрывает ноты из массива, создавая узнаваемую и сложную мелодию.

Анализ результатов

  • #define. Эта директива препроцессора позволяет нам дать числовым значениям (частотам) понятные имена.
  • Массивы melody[] и noteDurations[]. Хранят всю информацию о нашей мелодии.
  • sizeof(melody)/sizeof(int). Этот трюк позволяет автоматически рассчитать количество нот в массиве, чтобы цикл for остановился вовремя.
  • tone(pin, frequency, duration). Основная команда, которая генерирует звук нужной высоты и длительности.
  • delay(pauseBetweenNotes). Эта пауза немного длиннее самой ноты. Она создаёт крошечное молчание между звуками, делая мелодию более чёткой и выразительной.

Выводы

В этой лабораторной работе вы научились генерировать сложные звуковые последовательности с помощью функции tone() и массивов. Вы увидели, как музыка, творческий процесс, может быть описана на строгом языке программирования. Этот навык позволит вам добавлять звуковые эффекты и мелодии в любые ваши проекты.

Вопросы для самопроверки

  1. Какая команда используется для генерации звука?
  2. Что такое массив и как мы использовали его в этой работе?
  3. Зачем в коде используется директива #define?
  4. Как изменить код, чтобы мелодия играла в два раза быстрее?
  5. Что делает конструкция while(true); в конце loop()?

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