Цели урока:
- Познакомиться со структурой программы Arduino.
- Написать первую программу.
- Использовать последовательный порт для вывода данных.
- Познакомиться с директивой
#define. - Выполнить практическое задание в Wokwi.
Структура программы Arduino
Любая программа (скетч) для Arduino состоит из двух основных функций setup() и loop():
Функция setup()
Функция setup() выполняется один раз при запуске программы.
Она используется для настройки начальных параметров, таких как:
- Настройка пинов (входы/выходы).
- Инициализация переменных.
- Запуск Serial-порта для обмена данными с компьютером.
- Настройка других компонентов (например дисплеев, датчиков).
Пример использования setup():
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // Настройка встроенного светодиода как выхода
Serial.begin(9600); // Инициализация Serial-порта
}
Что происходит в setup():
pinMode(LED_BUILTIN, OUTPUT);- Настраивает пин 13 (встроенный светодиод) как выход.
- Это означает, что мы можем управлять этим пином (включать/выключать светодиод).
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():
digitalWrite(LED_BUILTIN, HIGH);- Включает светодиод, подавая на пин 13 высокий уровень напряжения (5 В).
delay(1000);- Приостанавливает выполнение программы на 1000 миллисекунд (1 секунду).
digitalWrite(LED_BUILTIN, LOW);- Выключает светодиод, подавая на пин 13 низкий уровень напряжения (0 В).
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:
- Читаемость: Имена констант (
LED_PIN,DELAY_TIME) делают код более понятным. - Удобство изменения: Если нужно изменить значение (например, пин светодиода или время задержки), это можно сделать в одном месте.
- Экономия памяти:
#defineне создаёт переменные, а просто заменяет текст в коде перед компиляцией.
Область видимости
Когда вы начинаете программировать, одна из самых частых проблем — это ошибки, связанные с "невидимостью" переменных в разных частях программы. Давайте разберём эту тему максимально просто, на примерах, которые поймёт даже новичок.
Область видимости — это часть программы, где переменная "живёт" и может быть использована. Если вы попытаетесь обратиться к переменной вне её области видимости, компилятор выдаст ошибку.
Основные области видимости:
- Глобальные переменные — видны везде в программе.
- Локальные переменные — видны только внутри функции, где объявлены.
Глобальные переменные
Пишутся в самом начале программы, до всех функций 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 секунду
}
Как открыть последовательный порт:
- В Arduino IDE перейдите в Tools -> Serial Monitor (или нажмите Ctrl+Shift+M).
- Убедитесь, что скорость передачи (baud rate) установлена на 9600.
- Вы увидите сообщения "Светодиод включён" и "Светодиод выключен", которые повторяются каждую секунду.
На Wokwi монитор последовательного порта появится в правой нижней части экрана.
Последовательный порт — это мощный инструмент для отладки и взаимодействия с Arduino. Вот несколько полезных функций:
- Вывод данных.
Serial.print(): Выводит данные без перевода строки.Serial.println(): Выводит данные с переводом строки.- Ввод данных.
Serial.read(): Читает один (первый) байт данных из буфера.Serial.parseInt(): Читает целое число из буфера.- Форматирование вывода.
Serial.print(1.2345, 2): выведет число с двумя знаками после точки 1.23 (цифра 2 после запятой указывает на количество знаков после точки).- Скорость передачи (baud rate).
- Пример:
- Очистка буфера.
Serial.flush(): Ожидает завершения передачи данных.
Используйте Serial.print() или Serial.println() для вывода текста, чисел или значений переменных.
int temperature = 25;
Serial.print("Температура: ");
Serial.print(temperature); // Вывод: "Температура: 25"
int humidity = 60;
Serial.println(humidity); // Вывод: "60" и переход на новую строку
Вы можете отправлять данные с компьютера на Arduino через последовательный порт.
Используйте Serial.read() или Serial.parseInt() для чтения данных.
if (Serial.available() > 0) {
char input = Serial.read(); // Чтение одного байта
Serial.print("Вы ввели: ");
Serial.println(input);
}
if (Serial.available() > 0) {
int input = Serial.parseInt(); // Чтение целого числа
Serial.print("Вы ввели число: ");
Serial.println(input);
}
Вы можете форматировать вывод с помощью функций, таких как Serial.print().
float voltage = 3.3314;
Serial.printf(voltage, 2); // Вывод: 3.33
Убедитесь, что скорость передачи последовательного порта совпадает с указанной в Serial.begin().
Serial.begin(9600); // Установка скорости 9600 бод
В настройках последовательного порта также выберите скорость 9600 (относится при работе с физическими устройствами а не для симуляции).
Иногда полезно очистить буфер перед чтением данных.
Serial.flush(); // Очистка буфера передачи
Практическое задание в Wokwi
Давайте создадим проект в Wokwi , который будет мигать встроенным светодиодом и выводить сообщение в монитор порта.
Шаги:
- Перейдите на Wokwi
- Создайте новый проект, выбрав плату Arduino UNO.
- Вставьте следующий код в редактор:
- Запустите симуляцию нажав на кнопку "Start the simulation".
- Откроется монитор последовательного порта автоматически в правой нижней части экрана.
- Наблюдайте за миганием светодиода и сообщениями в мониторе порта.
#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 секунду
}
Вот готовый проект на Wokwi с использованием монитора порта.
Что мы узнали:
- Программа Arduino состоит из
setup()иloop(). - Область видимости переменных.
- Мы можем управлять встроенным светодиодом с помощью
digitalWrite(). - Последовательный порт используется для вывода данных и отладки.
- Директива
#defineпозволяет создавать константы, делая код более читаемым и удобным для изменения. - Мы создали и протестировали проект в Wokwi
Следующий урок: Цифровые сигналы