Первая программа на Arduino

Урок 3: Первая программа на Arduino — "Hello, World!" с мигающим светодиодом

Цели урока:

  1. Познакомиться со структурой программы Arduino.
  2. Написать первую программу.
  3. Использовать последовательный порт для вывода данных.
  4. Познакомиться с директивой #define.
  5. Выполнить практическое задание в Wokwi.

Структура программы Arduino

Любая программа (скетч) для Arduino состоит из двух основных функций setup() и loop():

Функция setup()

Функция setup() выполняется один раз при запуске программы. Она используется для настройки начальных параметров, таких как:

  • Настройка пинов (входы/выходы).
  • Инициализация переменных.
  • Запуск Serial-порта для обмена данными с компьютером.
  • Настройка других компонентов (например дисплеев, датчиков).

Пример использования setup():

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Настройка встроенного светодиода как выхода
  Serial.begin(9600);           // Инициализация Serial-порта
}

Что происходит в setup():

  1. pinMode(LED_BUILTIN, OUTPUT);
    • Настраивает пин 13 (встроенный светодиод) как выход.
    • Это означает, что мы можем управлять этим пином (включать/выключать светодиод).
  2. Serial.begin(9600);
    • Инициализирует последовательный порт для обмена данными с компьютером.
    • Чтение состояния кнопок
    • Скорость передачи данных (baud rate) установлена на 9600 бод.

Функция loop()

Функция loop() выполняется циклически (код функции выполняется в бесконечном цикле)  после завершения setup(_). Вся основная логика программы находится здесь. Например:

  • Управление светодиодами, моторами, сервоприводами.
  • Чтение данных с датчиков.
  • Отправка данных на компьютер или другие устройства.

Пример использования loop():

void loop() {
  digitalWrite(LED_BUILTIN, HIGH); // Включить светодиод
  delay(1000);                    // Ждать 1 секунду
  digitalWrite(LED_BUILTIN, LOW);  // Выключить светодиод
  delay(1000);                    // Ждать 1 секунду
}

Что происходит в loop():

  1. digitalWrite(LED_BUILTIN, HIGH);
    • Включает светодиод, подавая на пин 13 высокий уровень напряжения (5 В).
  2. delay(1000);
    • Приостанавливает выполнение программы на 1000 миллисекунд (1 секунду).
  3. digitalWrite(LED_BUILTIN, LOW);
    • Выключает светодиод, подавая на пин 13 низкий уровень напряжения (0 В).
  4. delay(1000);
    • Снова приостанавливает выполнение программы на 1 секунду.

Цикл программы выполняется сверху вниз, когда программа доходит до последней строчки этой функции цикл начинается сначала.

Директива #define

Директива #define используется для создания макросов или констант. Она позволяет заменить определённое значение или выражение на имя, что делает код более читаемым и удобным для изменения.

Синтаксис:

#define ИМЯ ЗНАЧЕНИЕ

Пример использования #define:

#define LED_PIN 13
#define DELAY_TIME 1000

void setup() {
  pinMode(LED_PIN, OUTPUT); // Используем константу LED_PIN вместо 13
}

void loop() {
  digitalWrite(LED_PIN, HIGH); // Включить светодиод
  delay(DELAY_TIME);           // Ждать 1 секунду
  digitalWrite(LED_PIN, LOW);  // Выключить светодиод
  delay(DELAY_TIME);           // Ждать 1 секунду
}

Преимущества #define:

  1. Читаемость: Имена констант (LED_PINDELAY_TIME) делают код более понятным.
  2. Удобство изменения: Если нужно изменить значение (например, пин светодиода или время задержки), это можно сделать в одном месте.
  3. Экономия памяти: #define не создаёт переменные, а просто заменяет текст в коде перед компиляцией.

Область видимости

Когда вы начинаете программировать, одна из самых частых проблем — это ошибки, связанные с "невидимостью" переменных в разных частях программы. Давайте разберём эту тему максимально просто, на примерах, которые поймёт даже новичок.

Область видимости — это часть программы, где переменная "живёт" и может быть использована. Если вы попытаетесь обратиться к переменной вне её области видимости, компилятор выдаст ошибку.

Основные области видимости:

  1. Глобальные переменные — видны везде в программе.
  2. Локальные переменные — видны только внутри функции, где объявлены.

Глобальные переменные

Пишутся в самом начале программы, до всех функций setup() и loop().

int globalVar = 10;  // Глобальная переменная  
  
void setup() {  
  Serial.begin(9600);  
}  
  
void loop() {  
  Serial.println(globalVar);  // Можно использовать тут и в setup  
  someFunction();  
}

Плюсы:

  • Можно использовать в любом месте программы, в setup() или loop().
  • Удобны для хранения важных данных, которые нужны везде (например, настройки пинов).

Минусы:

  • Занимают память всё время работы программы, даже если не используются.
  • Если программа большая, можно случайно изменить глобальную переменную где-то в коде и получить ошибку.

Когда использовать?

  • Для конфигурации (например, номера пинов).
  • Для счётчиков, которые должны сохраняться между вызовами loop().

Локальные переменные

Пишутся внутри функций setup() или loop() и видны только в пределах функций в который объявлены.

void setup() {
  int localVar = 5;  // Локальная переменная (видна ТОЛЬКО в setup())
  Serial.begin(9600);
  Serial.println(localVar);  // Здесь работает
}

void loop() {
  // Serial.println(localVar);  // ОШИБКА! localVar не видна здесь!
  int anotherVar = 20;  // Другая локальная переменная
  Serial.println(anotherVar);  // А здесь — работает
}

Плюсы:

  • Экономят память (удаляются после выхода из функции).
  • Уменьшают риск случайно изменить переменную где-то в коде.

Минусы:

  • Нельзя использовать вне функции, где они объявлены.

Когда использовать?

  • Для временных вычислений например, внутри loop().

Первая программа: мигающий светодиод

В мире Arduino аналогом "Hello, World!" является программа, которая заставляет встроенный светодиод мигать. Встроенный светодиод подключён к пину 13 на плате Arduino Uno.

Код программы с использованием #define:

#define LED_PIN 13
#define DELAY_TIME 1000

void setup() {
  pinMode(LED_PIN, OUTPUT); // Настройка встроенного светодиода как выхода
}

void loop() {
  digitalWrite(LED_PIN, HIGH); // Включить светодиод
  delay(DELAY_TIME);           // Ждать 1 секунду
  digitalWrite(LED_PIN, LOW);  // Выключить светодиод
  delay(DELAY_TIME);           // Ждать 1 секунду
}

Объяснение кода:

  • #define LED_PIN 13: создаёт константу LED_PIN, которая заменяется на 13.
  • #define DELAY_TIME 1000: создаёт константу DELAY_TIME, которая заменяется на 1000.
  • Остальной код работает так же, как и раньше.

Вот ссылка на пример работающего проекта в симуляторе Wokwi. Нажмите на кнопку "Start the simulation" и посмотрите как будет моргать красный светодиод на плате.

Использование последовательного порта

Последовательный порт — это инструмент в Arduino IDE, который позволяет обмениваться данными между компьютером и платой Arduino. Мы можем использовать его для вывода текста, чисел или отладки.

Пример программы с выводом в последовательный порт:

#define LED_PIN 13
#define DELAY_TIME 1000

void setup() {
  pinMode(LED_PIN, OUTPUT); // Настройка встроенного светодиода как выхода
  Serial.begin(9600);       // Инициализация Serial-порта
}

void loop() {
  digitalWrite(LED_PIN, HIGH); // Включить светодиод
  Serial.println("Светодиод включён"); // Вывод сообщения
  delay(DELAY_TIME);           // Ждать 1 секунду

  digitalWrite(LED_PIN, LOW);  // Выключить светодиод
  Serial.println("Светодиод выключен"); // Вывод сообщения
  delay(DELAY_TIME);           // Ждать 1 секунду
}

Как открыть последовательный порт:

  1. В Arduino IDE перейдите в Tools -> Serial Monitor (или нажмите Ctrl+Shift+M).
  2. Убедитесь, что скорость передачи (baud rate) установлена на 9600.
  3. Вы увидите сообщения "Светодиод включён" и "Светодиод выключен", которые повторяются каждую секунду.

На Wokwi монитор последовательного порта появится в правой нижней части экрана.

Последовательный порт — это мощный инструмент для отладки и взаимодействия с Arduino. Вот несколько полезных функций:

  1. Вывод данных.
  2. Используйте Serial.print() или Serial.println() для вывода текста, чисел или значений переменных.

    • Serial.print(): Выводит данные без перевода строки.
    • int temperature = 25;
      Serial.print("Температура: ");
      Serial.print(temperature); // Вывод: "Температура: 25"
    • Serial.println(): Выводит данные с переводом строки.
    • int humidity = 60;
      Serial.println(humidity); // Вывод: "60" и переход на новую строку
  3. Ввод данных.
  4. Вы можете отправлять данные с компьютера на Arduino через последовательный порт. Используйте Serial.read() или Serial.parseInt() для чтения данных.

    • Serial.read(): Читает один (первый) байт данных из буфера.
    • if (Serial.available() > 0) {
          char input = Serial.read(); // Чтение одного байта
          Serial.print("Вы ввели: ");
          Serial.println(input);
      }
    • Serial.parseInt(): Читает целое число из буфера.
    • if (Serial.available() > 0) {
          int input = Serial.parseInt(); // Чтение целого числа
          Serial.print("Вы ввели число: ");
          Serial.println(input);
      }
  5. Форматирование вывода.
  6. Вы можете форматировать вывод с помощью функций, таких как Serial.print().

    • Serial.print(1.2345, 2): выведет число с двумя знаками после точки 1.23 (цифра 2 после запятой указывает на количество знаков после точки).
    • float voltage = 3.3314;
      Serial.printf(voltage, 2); // Вывод: 3.33
  7. Скорость передачи (baud rate).
  8. Убедитесь, что скорость передачи последовательного порта совпадает с указанной в Serial.begin().

    • Пример:
    • Serial.begin(9600); // Установка скорости 9600 бод

    В настройках последовательного порта также выберите скорость 9600 (относится при работе с физическими устройствами а не для симуляции).

  9. Очистка буфера.
  10. Иногда полезно очистить буфер перед чтением данных.

    • Serial.flush(): Ожидает завершения передачи данных.
    • Serial.flush(); // Очистка буфера передачи

Практическое задание в Wokwi

Давайте создадим проект в Wokwi , который будет мигать встроенным светодиодом и выводить сообщение в монитор порта.

Шаги:

  1. Перейдите на Wokwi
  2. Создайте новый проект, выбрав плату Arduino UNO.
  3. Вставьте следующий код в редактор:
  4. #define LED_PIN 13
    #define DELAY_TIME 1000
    
    void setup() {
        pinMode(LED_PIN, OUTPUT); // Настройка встроенного светодиода как выхода
        Serial.begin(9600);       // Инициализация Serial-порта
    }
    
    void loop() {
        digitalWrite(LED_PIN, HIGH); // Включить светодиод
        Serial.println("Светодиод включён"); // Вывод сообщения
        delay(DELAY_TIME);           // Ждать 1 секунду
    
        digitalWrite(LED_PIN, LOW);  // Выключить светодиод
        Serial.println("Светодиод выключен"); // Вывод сообщения
        delay(DELAY_TIME);           // Ждать 1 секунду
    }
  5. Запустите симуляцию нажав на кнопку "Start the simulation".
  6. Откроется монитор последовательного порта автоматически в правой нижней части экрана.
  7. Наблюдайте за миганием светодиода и сообщениями в мониторе порта.

Вот готовый проект на Wokwi с использованием монитора порта.

Что мы узнали:

  • Программа Arduino состоит из setup() и loop().
  • Область видимости переменных.
  • Мы можем управлять встроенным светодиодом с помощью digitalWrite().
  • Последовательный порт используется для вывода данных и отладки.
  • Директива #define позволяет создавать константы, делая код более читаемым и удобным для изменения.
  • Мы создали и протестировали проект в Wokwi

Следующий урок: Цифровые сигналы