Главная chevron_right Уроки chevron_right Программирование chevron_right Переменные в скетчах Arduino: объявление, область видимости и типичные ошибки

Переменные в скетчах Arduino: объявление, область видимости и типичные ошибки

Что такое переменные, как их объявлять, присваивать значения и управлять областью видимости в скетчах Arduino.

Переменная — это именованное место в памяти, где хранится какое-то значение. У каждой переменной есть три обязательных атрибута: имя, значение и тип. Например, вот такая строка называется объявлением переменной:

int pin = 13;

Здесь создаётся переменная с именем pin, значением 13 и типом int. В дальнейшем вы можете обращаться к этой переменной по имени — и компилятор сам подставит её текущее значение. Например, в строке:

pinMode(pin, OUTPUT);

именно значение pin (то есть 13) будет передано функции pinMode(). В данном случае переменная технически не обязательна — этот вариант сработает точно так же:

pinMode(13, OUTPUT);

Но у переменной есть важное преимущество: реальный номер пина указывается только один раз, а используется столько раз, сколько нужно. Если позже вы решите сменить пин 13 на пин 12, достаточно исправить одно место в коде, а не искать все вхождения числа 13 по всему скетчу. Кроме того, переменные можно называть осмысленно. Например, скетч управления RGB-светодиодом мог бы содержать переменные redPin, greenPin и bluePin — сразу понятно, что к чему.

Присваивание: изменяем значение переменной

Главное отличие переменной от константы — её значение можно менять в любой момент с помощью присваивания (знак =). Например:

pin = 12;

После этой строки переменная будет хранить значение 12. Обратите внимание: тип переменной при присваивании не указывается — он задаётся один раз при объявлении и не меняется. Имя переменной навсегда связано со своим типом, меняется только значение. [1]

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

error: pin was not declared in this scope

Когда вы присваиваете значение одной переменной другой, создаётся копия значения. Изменение одной переменной никак не влияет на другую. Например, после выполнения:

int pin = 13;
int pin2 = pin;
pin = 12;

только pin получит значение 12, а pin2 по-прежнему останется равным 13.

Область видимости (scope)

В сообщении об ошибке выше встречается слово «scope» — область видимости. Это та часть программы, в которой переменная доступна. Область видимости определяется местом объявления переменной.

Глобальные переменные

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

int pin = 13;
void setup()
{
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}

Как видно, pin используется и в setup(), и в loop(). Обе функции работают с одной и той же переменной, поэтому изменение в одной функции сразу отражается в другой:

int pin = 13;
void setup()
{
pin = 12;
pinMode(pin, OUTPUT);
}
void loop()
{
digitalWrite(pin, HIGH);
}

Здесь digitalWrite(), вызванная из loop(), получит значение 12, потому что именно оно было присвоено переменной в setup().

Локальные переменные

Если переменная нужна только внутри одной функции, объявите её прямо там. Тогда её область видимости ограничится этой функцией:

void setup()
{
int pin = 13;
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
}

В этом случае переменная pin существует только внутри setup(). Если попытаться использовать её снаружи:

void loop()
{
digitalWrite(pin, LOW); // ошибка: переменная pin недоступна в этой области видимости.
}

компилятор снова скажет: error: 'pin' was not declared in this scope. Переменная объявлена в программе, но за пределами своей области видимости она просто не существует.

Почему не делать все переменные глобальными?

Может возникнуть соблазн объявлять всё глобально — зачем ограничивать доступ? Но у глобальных переменных есть серьёзный недостаток: их значение может быть изменено из любой точки программы. Чем больше скетч, тем сложнее отследить, где и когда переменная получила неожиданное значение.

Локальная переменная проще в отладке: вы точно знаете, что её значение может измениться только внутри одной конкретной функции. Это значительно сужает круг поиска, когда что-то идёт не так.

Практическое правило: используйте минимально возможную область видимости. Если переменная нужна только в одной функции — объявляйте её там. Глобальные переменные оправданы, когда данные действительно нужны нескольким функциям.

Типичные ошибки

  • Использование переменной до объявленияerror: was not declared in this scope. Решение: объявите переменную выше по коду.
  • Указание типа при повторном присваивании — например, написать int pin = 12; вместо pin = 12; внутри функции. Это создаст новую локальную переменную, а не изменит существующую.
  • Путаница с областью видимости — объявили переменную внутри if или for, а пытаетесь использовать её снаружи блока. Фигурные скобки {} всегда ограничивают область видимости.

[block scope] [size of variables]

[1] В некоторых языках, например в Python®, тип связан не с именем переменной, а с её значением — переменной можно присвоить значение любого типа. Это называется динамической типизацией. В Arduino (C++) тип фиксируется при объявлении и не меняется.