Макроси Arduino: повний посібник із їх освоєння з прикладами

  • Макроси в Arduino дозволяють оптимізувати код і пам'ять перед компіляцією.
  • Використання #define дозволяє створювати адаптивні функції, константи та структури.
  • Розширені макроси дозволяють об’єднувати ідентифікатори та отримувати доступ до PROGMEM.
  • Дисципліноване використання макросів покращує ефективність без шкоди для читабельності.

Ядра Arduino Zephyr OS beta-1

Arduino зробила революцію у світі електроніки завдяки легкості, з якою можна створювати функціональні прототипи та проекти. Однак для тих, хто хоче зробити крок далі у своєму програмуванні та оптимізувати ресурси, зберегти код чистим і підвищити ефективність, макроси стати ключовим інструментом.

У цій статті ми збираємося глибоко зануритися в використання макроси в Arduino: що це таке, як вони використовуються, їхні переваги та обмеження. І ми зробимо це, зібравши найбільш вичерпну та корисну інформацію з найкращих ресурсів, доступних в Інтернеті, переписану зрозумілим і сучасним способом, щоб бути дійсно практичним.

Що таке макроси в Arduino?

Макроси є директивами препроцесора у C/C++, які дозволяють замінювати текст перед компіляцією коду. Замість виконання інструкцій, як традиційна функція, макрос працює, замінюючи частини вихідного тексту, який прямий вплив на те, як генерується кінцевий двійковий код.

Препроцесор Він запускається перед фактичною компіляцією та відповідає за застосування цих замін. В Arduino це дозволяє від визначити константи, умовно включати файли або навіть створювати невеликі функції онлайн що економить час і пам'ять.

Основний приклад: таке визначення #define LED_PIN 13 призводить до автоматичної заміни всього коду LED_PIN по 13 перед складанням.

Це може здатися тривіальним, але воно пропонує a потужний спосіб написання більш гнучкого коду, який зручно підтримувати.

Переваги використання макросів

Впровадження макросів у проекти Arduino може запропонувати низку конкретних переваг:

  • Покращення читабельності коду: Завдяки повторному використанню символічних імен легше зрозуміти призначення кожного елемента.
  • Оптимізація продуктивності: Не генеруючи виклики функцій, макроси можуть виконувати операції швидше.
  • Зменште використання оперативної пам'яті: особливо корисно на дошках з обмеженими ресурсами, наприклад Arduino UNO.
  • Дозволяє умовні адаптації: Можна скомпілювати різні фрагменти коду залежно від типу використовуваної плати Arduino.

Основні макроси: використання #define

Директива #визначити Він є найбільш використовуваним. Використовується як для визначити постійні значення як для створювати введені автоматичні функції під час попередньої компіляції.

Приклад 1. Визначте шпильку

#define PINLED 13

void setup() {
  pinMode(PINLED, OUTPUT);
}

void loop() {
  digitalWrite(PINLED, HIGH);
  delay(500);
  digitalWrite(PINLED, LOW);
  delay(500);
}

Приклад 2: Макрос як вбудована функція

int itemCounter = 0;
#define COUNT_ITEM() do { itemCounter++; } while(0)

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

void loop() {
  Serial.println(itemCounter);
}

Як бачите, використання викрійки do { … } while(0) забезпечує безпечну поведінку макросу, навіть якщо він використовується в умовних структурах.

## оператор і об'єднання макросів

Оператор ## є потужним інструментом препроцесора. що дозволяє конкатенувати ідентифікатори. Це дуже корисно, коли ви хочете генерувати імена змінних динамічно.

Практичний приклад:

#define GENERAR_VARIABLE(no) \
  int var##no = no;

void setup() {
  GENERAR_VARIABLE(3); // crea int var3 = 3
}

Важливе застереження: Цей оператор не сумісний з усіма моделями плат Arduino однаково. Наприклад, він може добре працювати на Uno або Esplora, але не працювати на Mega. Крім того, ви не можете вкладати створення макросу в інші макроси безпосередньо за допомогою ##.

Макроси та збереження пам'яті

Однією з ключових переваг використання макросів в Arduino є економія оперативної пам'яті. Arduino має обмежену ємність, тому завантаження текстових рядків безпосередньо в оперативну пам’ять може стати серйозною проблемою.

Просунутий метод, щоб уникнути цього, передбачає використання FORCE_INLINE і завантажити рядки з пам'яті програми (PROGMEM):

#include <HardwareSerial.h>
#define MYSERIAL Serial
#define FORCE_INLINE __attribute__((always_inline)) inline

FORCE_INLINE void printFromFlash(const char *str) {
  char ch = pgm_read_byte(str);
  while (ch) {
    MYSERIAL.write(ch);
    ch = pgm_read_byte(++str);
  }
}

#define SERIAL_LOG(x) (MYSERIAL.print(x))
#define SERIAL_LOGLN(x) (MYSERIAL.println(x))

Використання цих макросів може змінити роботу проекту чи ні, особливо в програмах з дисплеями або декількома датчиками.

Макроси в поєднанні з функціями

Макроси також можуть сприяти динамічному виклику функцій на основі типу, переданого як параметр. Яскравий і досить наочний приклад:

#define FUNC_LENTA(tipo) \
  { funcion_##tipo##_lenta(); }

#define FUNC_RAPIDA(tipo) \
  { funcion_##tipo##_rapida(); }

void funcion_caminar_lenta() {
  Serial.println("Andando despacio");
}

void funcion_caminar_rapida() {
  Serial.println("Andando rápido");
}

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

void loop() {
  FUNC_RAPIDA(caminar);
}

Завдяки оператору ## і макросам ми можемо уникнути повторюваних структур і централізувати динамічну логіку..

Макроси з вихідними параметрами

Також можна використовувати макроси для інкапсуляції невеликих об’єктів або перетворень:

#define BOOL_OUT() (bool){false}
#define NUM_OUT(a,b) (float){a+b}
#define STR_OUT(msg) (String){msg}

void loop() {
  Serial.println(BOOL_OUT());
  Serial.println(NUM_OUT(1.2, 3.4));
  Serial.println(STR_OUT("Mensaje"));
}

Хороші практики та запобіжні заходи з макросами

Надмірне або необережне використання макросів може призвести до помилки, які важко усунути. Наприклад, роблячи неправильні заміни або визначаючи імена, які суперечать іменам у зовнішніх бібліотеках.

Деякі основні правила, щоб уникнути проблем:

  • Уникайте непотрібних пробілів або розривів рядків в межах макросу.
  • Не включайте коментарі у складних макросах, які використовують кілька рядків.
  • Використовуйте унікальні імена або з префіксами (наприклад, назва проекту), щоб уникнути конфліктів.
  • Замініть макроси реальними константами або функціями коли це можливо. Сучасний C++ дозволяє використовувати чистіші та безпечніші альтернативи.

З іншого боку, надмірне використання макросів може знизити чіткість коду. Метою має бути підвищення ефективності та модульності без шкоди для ремонтопридатності.

Умовні директиви та адаптивна компіляція

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

Типовий приклад:

#ifdef ARDUINO_MEGA
  #define LEDPIN 53
#else
  #define LEDPIN 13
#endif

Це також корисно для керування налагодженням або відображенням повідомлень компілятора #pragma повідомлення або навіть генерувати помилки за певних умов #помилка.

Макроси внутрішнього компілятора

Препроцесор GCC для AVR (використовується в Arduino) включає кілька спеціальні макроси, які надають інформацію про систему, дуже корисний під час розробки:

  • __LINE__: номер поточного рядка.
  • __FILE__: ім'я поточного файлу.
  • __TIME__ і __DATE__: час і дата складання.
  • __func__: назва поточної функції.

Вони дозволяють керувати версіями, структурувати журнали, а також полегшують технічне обслуговування та відстеження помилок без втручання в основний код.

Макроси пропонують потужний і гнучкий спосіб структурування проектів Arduino. Вони дозволяють визначати константи, зберегти пам'ять, адаптувати код залежно від середовища виконання та створювати повторно використовувані блоки без дублювання рядків. Звичайно, вони вимагають дисципліни, чіткості та знань, щоб уникнути незначних помилок або втрати читабельності. При правильному застосуванні вони є безцінним надбанням для розробників середнього та просунутого рівня.


Будьте першим, щоб коментувати

Залиште свій коментар

Ваша електронна адреса не буде опублікований. Обов'язкові для заповнення поля позначені *

*

*

  1. Відповідальний за дані: Мігель Анхель Гатон
  2. Призначення даних: Контроль спаму, управління коментарями.
  3. Легітимація: Ваша згода
  4. Передача даних: Дані не передаватимуться третім особам, за винятком юридичних зобов’язань.
  5. Зберігання даних: База даних, розміщена в мережі Occentus Networks (ЄС)
  6. Права: Ви можете будь-коли обмежити, відновити та видалити свою інформацію.