Функции и структурированный дашборд

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

Текстовый дашборд в консоли с несколькими аккуратно выровненными строками показаний

После урока сможешь: объявлять функцию с возвращаемым значением и без, передавать в неё параметры (включая массив), собирать читаемый текстовый дашборд из нескольких показаний. В конце — станция с аккуратным дашбордом в Serial Monitor.

Вспомни: в Python-курсе ты уже писал функции с def и return (занятие 7 первого курса) — вынес повторяющиеся расчёты под именем и вызывал много раз. Здесь та же идея, но в C++ у функции надо явно указать, ЧТО она возвращает (или void, если ничего).

Функция без возврата: void

Слово void перед именем функции значит «ничего не возвращает» — функция просто что-то делает (например, печатает строку) и не отдаёт результат вызывающему коду.

void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) {
  Serial.print(nazvanie);
  Serial.print(": ");
  Serial.print(znachenie);
  Serial.println(edinitsa);
}

void loop() {
  vyvestiPokazanie("Температура", 24.5, " C");
  vyvestiPokazanie("Влажность", 45.0, " %");
}
Температура: 24.50 C
Влажность: 45.00 %
  Вызов функции (те же три части, что в Python):

  vyvestiPokazanie("Температура", 24.5, " C")
        |                |        |      |
        |           параметр 1  параметр 2 параметр 3
        v
  тело функции выполняется с этими значениями

Функция с возвратом: указываем тип результата

Если функция должна что-то вернуть — перед именем пишут тип результата (float, int, bool) вместо void, а внутри — команду return. Массив в функцию нельзя передать «без размера» — размер массива нужно передавать вторым параметром отдельно, потому что сам массив внутри функции не хранит информацию о своей длине.

float sredneeMassiva(float arr[], int razmer) {
  float summa = 0;
  for (int i = 0; i < razmer; i = i + 1) {
    summa = summa + arr[i];
  }
  return summa / razmer;
}

void loop() {
  float pokazaniya[5] = {22.0, 23.0, 21.0, 24.0, 22.0};
  float sr = sredneeMassiva(pokazaniya, 5);
  Serial.println(sr);
}
22.40

В отличие от Python, где функции можно определять после места использования только если вызов идёт позже по файлу, в Arduino IDE порядок функций в файле не важен вообще — среда сама разбирается, что где объявлено. Пиши функции там, где удобнее читать.

Миссия: дашборд станции

Используя vyvestiPokazanie(), напечатай на каждом проходе loop() (раз в 1000 мс через millis) три строки: «Температура», «Влажность», «Давление» — со своими значениями. Значения возьми любые фиксированные или с потенциометра.

unsigned long previousMillis = 0;
const long interval = 1000;

void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) {
  Serial.print(nazvanie);
  Serial.print(": ");
  Serial.print(znachenie);
  Serial.println(edinitsa);
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    float temperatura = map(analogRead(A0), 0, 1023, -20, 60);
    vyvestiPokazanie("Температура", temperatura, " C");
    vyvestiPokazanie("Влажность", 45.0, " %");
    vyvestiPokazanie("Давление", 101.0, " кПа");
    Serial.println("----------");
  }
}

Проверь себя

Контрольный вопрос. Зачем нужны функции?

АЧтобы вынести повторяющийся код под именем и вызывать много раз, а не копировать его
БЧтобы использовать больше памяти платы
ВЧтобы программа компилировалась быстрее

Подсказка: Обратись к вступлению этого занятия — там прямо описана проблема, которую решают функции.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что означает слово void перед именем функции?

АФункция ничего не возвращает
БФункция вызывается автоматически при старте платы
ВФункция возвращает пустую строку

Подсказка: void по-английски — «пустота». Речь о результате функции.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что выведет вызов этой функции? Впиши вывод точно, как он появится.

Исходный код для этого задания:

void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) {
  Serial.print(nazvanie);
  Serial.print(": ");
  Serial.print(znachenie);
  Serial.println(edinitsa);
}

vyvestiPokazanie("Обороты", 1500.0, " об/мин");

Подсказка: Подставь параметры по порядку в тело функции: сначала nazvanie, потом двоеточие с пробелом, потом znachenie, потом edinitsa.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Функция объявлена как float sredneeMassiva(float arr[], int razmer). Что означает float перед именем функции?

АФункция вернёт дробное число
БФункция не принимает параметров
ВПервый параметр функции — дробное число

Подсказка: Тип перед именем функции — это тип ВОЗВРАЩАЕМОГО значения, а не параметра.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что вернёт вызов sredneeMassiva(arr, 4)? Впиши число.

Исходный код для этого задания:

float sredneeMassiva(float arr[], int razmer) {
  float summa = 0;
  for (int i = 0; i < razmer; i = i + 1) {
    summa = summa + arr[i];
  }
  return summa / razmer;
}

float arr[4] = {10.0, 20.0, 30.0, 40.0};

Подсказка: Сложи все элементы массива и раздели на razmer (4).

Онлайн-проверка ответа появится позже

Контрольный вопрос. Почему функция sredneeMassiva принимает ВТОРОЙ параметр razmer, хотя массив arr уже передан?

АЭто просто стиль оформления, без razmer функция тоже сработает верно
Бrazmer нужен только для вывода в Serial Monitor
ВВнутри функции массив «теряет» информацию о своей длине — размер нужно передать отдельно

Подсказка: Обратись к блоку «Функция с возвратом» — там объясняется именно эта особенность массивов в функциях.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что выведется — впиши обе строки, каждую с новой строки, точно как они появятся.

Исходный код для этого задания:

void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) {
  Serial.print(nazvanie);
  Serial.print(": ");
  Serial.print(znachenie);
  Serial.println(edinitsa);
}

vyvestiPokazanie("Ток", 2.0, " А");
vyvestiPokazanie("Напряжение", 12.0, " В");

Подсказка: Подставь параметры каждого вызова по отдельности в тело функции.

Онлайн-проверка ответа появится позже

Задание. Напиши код сам. Допиши недостающую строку вместо ___, чтобы функция возвращала произведение a и b.

Исходный код для этого задания:

float umnozhit(float a, float b) {
  ___
}

Подсказка: Команда return отдаёт результат вызывающему коду — вырази произведение через *.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Задание. Напиши функцию целиком (void, 4 строки). Назови её signalTrevogi, без параметров: включает светодиод на пине 9, печатает «Тревога!», выключает светодиод. Порядок: включить, напечатать, выключить.

Исходный код для этого задания:

// напиши функцию signalTrevogi() по описанию выше

Подсказка: Функция без возврата — тип void; тело — три команды подряд: digitalWrite HIGH, Serial.println, digitalWrite LOW.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Функция объявлена как float poluchitSredneе(float arr[], int razmer), но программист забыл написать return внутри неё. Что произойдёт?

АКомпилятор выдаст предупреждение, а результат вызова функции окажется непредсказуемым мусорным значением
БПрограмма не соберётся вовсе — это синтаксическая ошибка
ВФункция автоматически вернёт 0

Подсказка: Функция ОБЕЩАЛА вернуть float (это указано в её объявлении), но не выполнила обещание.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Внутри функции объявлена переменная float summa = 0;. Можно ли обратиться к этой переменной summa из кода loop(), который вызывает эту функцию?

Исходный код для этого задания:

float sredneeMassiva(float arr[], int razmer) {
  float summa = 0;
  for (int i = 0; i < razmer; i = i + 1) {
    summa = summa + arr[i];
  }
  return summa / razmer;
}

void loop() {
  // здесь summa НЕДОСТУПНА
}
АДа, но только если функция была вызвана хотя бы один раз
БНет — summa существует только внутри тела функции, где объявлена, и исчезает после её завершения
ВДа — любая переменная функции доступна везде в файле после её объявления

Подсказка: Переменная, объявленная внутри {} функции, «живёт» только там — это называется областью видимости.

Онлайн-проверка ответа появится позже

Задание. Напиши функцию целиком (около 9 строк). float maksimumMassiva(float arr[], int razmer) — возвращает наибольший элемент массива, используя первый элемент как стартовое значение (без готовых функций max).

Исходный код для этого задания:

// напиши float maksimumMassiva(float arr[], int razmer) по описанию выше

Подсказка: Собери из уже знакомого (занятие про массивы): maksimum = arr[0], цикл с i от 1, сравнение и обновление, return в конце.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Задание. Мини-проект. Напиши функцию void vyvestiPokazanie(String nazvanie, float znachenie, String edinitsa) (как в материале занятия) и вызови её РОВНО три раза для фиксированных значений: «Температура» 24.5 « C», «Влажность» 45.0 « %», «Давление» 101.0 « кПа» — в этом порядке. Принято, если: функция объявлена с этими тремя параметрами и печатает «nazvanie: znachenie edinitsa»; вызовы идут в указанном порядке с указанными значениями; итоговый вывод — три строки дашборда.

Исходный код для этого задания:

// напиши функцию vyvestiPokazanie и три вызова по описанию выше

Подсказка: Функция — как в материале занятия (три Serial.print/println подряд); вызовы — три отдельные строки с готовыми значениями из условия, без переменных.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Что дальше

Теперь код станции читается через понятные функции, а не через повторяющиеся куски. На следующем занятии разберём, как искать и исправлять ошибки в чужом коде на C++ — тот же навык отладки, что был в Python-курсе, но применительно к новому языку.

Итог: ты объявляешь функции с возвратом и без, передаёшь параметры (включая массив с размером) и собрал читаемый дашборд. Дальше — отладка кода на C++.

← Назад  ·  ↑ В начало урока  ·  ⌂ В начало курса  ·  Вперёд →

Школа Виктора Комлева