Працюємо з 09:00 до 19:00 Пн-Пт
Київ біля ТЦ Квадрат бул.Перова

Эта статья из серии уроки Arduino. Тема этого урока: Arduino функции и как с ними бороться.

Мы узнаем для чего они нужны и научимся создавать свои функции и использовать их в скетчах.

Заходите на наш канал Youtube

Функция – это фрагмент программного кода, к которому можно обращаться из разных мест программы. Её можно представить например как печать, штамп – один раз изготавливаем и потом штампуем в разных документах, причем по ходу можно менять аргументы (в данном случае дату), и цвет чернил, которые мы передаем в тело печати. 


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


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


Но прикол в том, что в Arduino IDE программеры функции чаще используют не по каноническому назначению. Так как функции легко позволяют структурировать программу на отдельные сегменты  кода со своими индивидуальными задачами, их используют для дробления больших сложных скетчей на структурные части. Это позволяет разрабатывать легче читаемые и понимаемые программы. Так же отдельные функции легко переносить в новые скетчи для других проектов.


Общее описание функции

Описание функции в скетче в общем виде имеет следующую структуру. В ней тип возвращаемых данных, имя функции, входные аргументы, тело функции заключенное в фигурные кавычки. В теле функции знакомые операнды, а так же необязательный операнд return, который завершает выполнение инструкций функции и передает данные, заданного типа в место вызова функции. Для нас, новичков, функции отличаются типом возвращаемых данных и количеством входных аргументов.


Разновидности функций

Я чаще всего пользуюсь функциями, которые ничего не принимают как аргументы и ничего не возвращают. Тип void в типе возвращаемых данных функции сообщает компилятору, что не нужно ругаться, если функция ничего не возвратит. В такой функции можно например управлять состояниями входов-выходов, печатать что-нибудь в монитор порта, или изменять внешние переменные. В теле функции можно проводить манипуляции над глобальными переменными. Изменять из значения, использовать их в операндах. Так же можно создавать внутренние переменные, которые видны только в этой функции и при каждом её вызове создаются заново. То есть не сохраняют значение с прошлого вызова. Но с обозначением static внутренние переменные могут сохранять значения с прошлого вызова и их тоже разрешено здесь юзать. Подробнее об этом нюансе можно узнать из урока Arduino видимость переменных.

void my_function()
{  
  digitalWrite(13, LOW);  
  Serial.println(analogRead(A0));  
  a = b + 2;  
  int var1;  
  static int var2;  
  var1 = a * b;  
  var2 = var1 - 3;
}

Функция может принимать аргументы, но ничего не возвращать.

void my_function(int var1, byte var2)
{  
  digitalWrite(13, LOW);  
  Serial.println(analogRead(A0));  
  a = var1 * 4;  
  b = var2 - 3;
}

Может так же не принимать аргументы, но возвращать данные заданного типа.

int my_function()
{  
  digitalWrite(13, LOW);  
  Serial.println(analogRead(A0));  
  int var1 = a + b;  
  return var1;
}

А так же и принимать аргументы и что-то возвращать.

int my_function(int var1)
{  
  digitalWrite(13, LOW);  
  Serial.println(analogRead(A0));  
  return (var1 * 5);
}

Вызов функций

Обращаются к функциям в тексте скетча обычно такими путями:

Если функция ничего не возвращает то

void loop()
{  
  my_func();
}
void loop()
{  
  my_func(var1, var2);
}

Если возвращает то

void loop()
{  
  var1 = my_func();
}
void loop()
{  
  var1 = my_func(var2, var3);
}

Или даже можно использовать как часть логического условия

void loop()
{  
  if (my_func())  
    {  }
}
void loop()
{  
  if (my_func(var1)>10)  
    {    }
}

В теле функции оператор return завершает выполнение функции и возвращает данные. Его в одной функции можно использовать не один раз.

int my_func()
{  
  if (var1 > 100)  
  {    
    return 1;  
  }else{    
    return 0;  
  }
}

А так же с его помощью можно просто завершать выполнение функции при достижении нужного условия.

void my_function()
{  
  // код  
  return;  
  //этот код  
  //не будет выполнен
}

Что касается красивого структурирования скетча для arduino подобного контроллера, то функции позволяют привести текст функции main и главного цикла программы к минималистичному виду. При этом внутри самих функций может содержаться увесистый скетч со сложными вычислениями и обращением к различным коммуникациям. Само тело каждой функции может храниться в отдельном файле, редактироваться в отдельной вкладке программы Arduino IDE.

void setup()
{  
  my_func1();
}

void loop()
{  
  my_func2();  
  my_func3();  
  my_func4();
}

Рекомендации для лучших скетчей

Я вам советую структурировать по возможности свой скетч на такие кластеры как например: конфигурирование входов-выходов, обработка дискретных входов, обработка аналоговых входов, обработка алгоритма задачи проекта, сетевые коммуникации с внешними устройствами, обработка выходов. В следующем видео из серии Arduino уроки рассмотрим пример, как можно разложить эти задачи по отдельным функциям и оформить их отдельными файлами для удобства разработки и наладки.

void setup()
{  
  config_func();
}

void loop()
{  
  din_func();  
  ain_func();  
  run_func();  
  comm_func();  
  outs_func();
}

Выводы

А пока нам необходимо запомнить, что функция определяется в программе один раз, а вызываться может множество раз. При каждом вызове функции в неё можно передать новые значения аргументов. Функция так же может возвращать нам данные предопределённого типа, а может и ничего не возвращать – тогда мы её определяем как тип void. Спасибо за подписку, лайк и комментарий и до новых встреч.

void loop()
{  
  var1 = my_function(4, 6) + my_function(1, 7);  
  var2 = my_function(-2, 0) - 4;  
  Serial.println(my_function(0, -5)); 
}

int my_function(int a, int b)
{  
  digitalWrite(13, LOW);  
  Serial.println(analogRead(A0));  
  int var1 = a + b;  
  return var1;
}
<< Проекты << Все товары >> Статьи, уроки >>

Написать отзыв

Примечание: HTML разметка не поддерживается! Используйте обычный текст.
    Плохо           Хорошо
OLED шилд для контроллера WeMos D1 mini

OLED шилд для контроллера WeMos D1 mini

Шилд OLED под WiFi-контроллер WeMos D1 mini с диагональю 0,66" и разрешением 64x..

102.82грн.

Светодиодная лента адресная WS2812B 1м 30led

Светодиодная лента адресная WS2812B 1м 30led

Трехцветная светодиодная адресная лента на основе адресных светодиодов WS2812B 30 светодиодо..

83.16грн.

Шилд SHT30 для Wemos D1 mini

Шилд SHT30 для Wemos D1 mini

Шилд датчика температуры и влажности на основе SHT30Коммуникационный интерфейс I2CДиапазон измерения..

79.34грн.

ATtiny обзор контроллеров

ATtiny обзор контроллеров

Обозначение Память программ (FLASH) [Kбайт] Память данных [байт] Kол-во линий ввода/..

Блок питания 12В 6,5А 78Вт

Блок питания 12В 6,5А 78Вт

Блок питания 12В 6,5А 78ВтНа вход можно подавать переменное напряжение в диапазоне 100...240ВМожно к..

285.60грн.