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

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

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

После урока сможешь: объявлять функцию с возвращаемым значением и без, передавать в неё параметры (включая массив), собирать читаемый текстовый дашборд из нескольких показаний. В конце — станция с аккуратным дашбордом в 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++.

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

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