Начнем данную статью с определения того, что такое define. В первую очередь, по версии официальной документации C++ функция define это директива препроцессора. Препроцессор это довольно абстрактное понятие. Препроцессор-некая программа, проводящая манипуляции с кодом до процесса компиляции. Можно сказать, что препроцессор обрабатывает код, выполняет предварительные операции с файлами, после чего передает их компилятору. Он используется для компиляции программной части, написания макроса или вставки изображения. Именно директива препроцессора осуществляет подключение какой-либо библиотеки, файла или определение макроса.
Основы функции
Дословно define переводится как определить. Функция пишется в следующем виде:
#define <имя константы> <значение(то, на что меняем)>
#define <часть кода, который будет изменен> <то, на что изменяется наш код>
Функция define создает макрос(макроопределения), выполняющий замену заданных символов или строк на заданное значение. Макросы схожи с константами, их также можно использовать для задания констант. С помощью директивы #define зададим следующую константу:
#define pi 3.14
В программе языка программирования C++ это будет выглядеть так:
#define pi 3.14
void main()
{
cout << pi << end1;
}
еще один вариант реализации, только в данном случае реализовано это конкретно для ардуино:
Строка номер 5 для нас выглядит именно так, как она написана. Однако при попытке компиляции для программного компилятора она будет заменена на:
cout << 3.14 << end1;
К тому же, данную функцию можно использовать для объявления переменных:
#define BLACK 11 // присваиваем имя BLACK для пина 11
#define GREEN 12 // присваиваем имя GRN для пина 12
#define PINK 13 // присваиваем имя BLU для пина 13
void setup() {
pinMode(BLACK, OUTPUT); // используем Pin11 для вывода
pinMode(GREEN, OUTPUT); // используем Pin12 для вывода
pinMode(PINK, OUTPUT); // используем Pin13 для вывода
}
Данный код- это часть программы мигающего трехцветного светодиода. Пинам 11, 12 и 13 присвоены имена соответствующих светодиодов(их цветов), подключенных к данным пинам. При объявлении номеров пинов удобнее использовать соответствующие цвета светодиодов, для того, чтобы не запутаться в программе, поэтому в данном случае лучше использовать функцию #define. После чего программа будет просто заменять данный названия на соответствующие им номера пинов.
Отличие функции #define от констант
Константы задаются точно также, как переменные, однако перед типом данных нужно ставить const. При попытке изменить константу компилятор выдаст ошибку «assignment of read-only variable»имя переменной»»-присвоение переменной, доступной только для чтения. Приведем пример программы:
byte sound_sensor_pin = 6;
void setup() {
pinMode(sound_sensor_pin, INPUT);
int a = 5100;
int b = 9500;
int c = 22222;
const byte d = 120;
}
void loop() {
boolean val = digitalRead(sound_sensor_pin);
}
В данной программе в диапазоне функции void setup(до его закрытия }) можно использовать локальную переменную байтового типа d. Она будет доступна только в данной функции. Такой тип констант называются локальными.
void setup() {
byte sound_sensor_pin = 6;
pinMode(sound_sensor_pin, INPUT);
int a = 5100;
sound_sensor_pin*3
}
void loop() {
boolean val = digitalRead(sound_sensor_pin);
sount_sensor_pin*4;
}
При запуске данной программы вы получите ошибку “sound_sensor_pin was not declared in this scope”, поскольку константа является таковой и имеет свое уникальное значение только в void setup. Однако если задать ему локальное произвольное значение в void loop, то в конечном счете все пройдет без ошибки. В данном случае у нас будет две локальные переменные, имеющие уникальное значение, нол одинаковое имя. То есть каждая переменная с одинаковым значением доступна только там, где она задана.
Переменные, объявленные без функций доступны во всей программе. Такая переменная называется глобальной.
Использование #define в данном случае поможет избежать нагрузки на память и освободит место для хранения других переменных. Однако с ним стоит быть осторожнее, поскольку он может заменить не то, что нужно.
Упрощение кода при помощи define на Arduino IDE
К тому же, данная функция используется не только для задания постоянных переменных(констант), её функционал позволяет заменять и части кода(строки). Команды можно заменить функцией #define при помощи создания более простых команд в программе. На примере данного кода можно увидеть реализацию данного способа:
#define o(pin) pinMode(pin, INPUT) // точку не ставим, поскольку она уже есть в i
void setup() {
o(11);
o(12);
o(13);
}
Таким образом можно легко упростить код и написать его в несколько строчек. Такой способ удобен в применении при частом повторении одной и той же команды, которую написать в цикле не представляется возможным. в приведенном выше примере слово out заменялось на pinmode(pin, OUTPUT) с заданным параметром pin. Точно таким же способом можно заменять несколько команд. Например, у нас есть три светодиода, которые нужно подключить к микроконтроллеру:
#define o(pin) pinMode(pin, OUTPUT)
#define on(pin, d) digitalWrite(pin, HIGH); delay(d)
#define off(pin, d) digitalWrite(pin, LOW); delay(dl)
void setup() {
o(11);
o(12);
o(13);
}
void loop() {
on(11, 1000);
off(11, 1000);
on(12, 1000);
off(12, 1000);
on(13, 1000);
off(13, 1000);
}
Примите к сведению, что код on(11,1000), который заменяет функции, сам как таковой не носит характер функции, а функция define просто заменяет заданным кодом текст непосредственно на функцию.
Функцию следует использовать внимательно, поскольку в сложных программах существует риск создать кучу ошибок при компиляции кода, так как программа может потребовать подключения нескольких библиотек, в которых дефайн может не так понять и заменить что-то не то.
Функции команд #ifdef, #ifndef, #endif
Согласно официальной документации Arduino IDE #ifdef осуществляет поиск определения функции #define в программе, если оно встречается, то будут выполнены заданные действия. Например, если встретилось Checkbypass, то будет выведено “Yes”
#ifdef Checkbypass
Serial.println («Yes»);
#endif
Другой пример:
Если в программной части микроконтроллера встречен цвет светодиода YELLOW, то внутреннее содержание #ifndef игнорируется, в ином случае-в код добавляется define константа светодиода с цветом YELLOW.
#ifndef YELLOW // если не нашлось YELLOW, ТО
#define YELLOW 11 // ВЫВОДИМ YELLOW
#endif
Использование const или #define-что универсальнее?
Директива #define не всегда универсальна для создания констант, в таком случае советуем вам использовать const. В отличие от глобальных переменных, значение константы может быть определено только в начале программы. При использовании #define имена следует делать максимально уникальными, дабы исключить любые совпадения с командами из подключаемых библиотек, что может сломать весь функционал программы.
const int YELLOW = 11; // 11 пин-YELLOW
const int PINK = 12; // 12 пин-PINK
const int LBLUE = 13; // 13 пин- LBLUE(голубой)
void setup() {
pinMode(YELLOW, OUTPUT); // 11 пин на вывод-светодиод
pinMode(PINK, OUTPUT); // 12 пин на вывод-светодиод
pinMode(LBLUE, OUTPUT); // 13 пин на вывод-светодиод
}
По сути, использование DEFINE и CONST не имеет разницы, использование константы в данном примере аналогично дефайну-вместо PINK подставится 12. На константах правила видимости глобальных и локальных переменных аналогичен дефайну, является стандартным. К тому же, ни одна из данных функций не имеет преимущества для памяти микроконтроллера.