Каждая компьютерная система тесно связана с таким понятием как «тип данных». Это связано со спецификой информации, хранящейся в памяти контроллера.
Arduino, построенная на базе микроконтроллеров семейства ATmega, использует основные типы данных. Знание типов данных крайне важно для правильного программирования. Ниже перечислены типы данных, используемые в Arduino IDE:
Начинающие программисты, пишущие программное обеспечение для ПК, не могут полностью осознать, как важно подобрать правильный тип данных для сохранения информации. В основном это связано с тем, что использование, например, 4 байтов вместо 1 байта практически не имеет значения в системах, оснащенных несколькими Гб оперативной памяти.
В случае с Arduino быстро выясняется, что необходимо экономить оперативную память (RAM). При написании программы, объем доступной оперативной памяти быстро уменьшается, и вы должны отслеживать, насколько она эффективна используется.
Преобразования между типами данных
Часто случается, что необходимо поменять один тип данных на другой. Например, заменить символ на число или число на символ. В Arduino IDE мы имеем несколько функций, которые позволяют производить преобразование между типами данных. В следующей таблице приведены функции преобразования данных.
Диапазон переменных
Arduino IDE базируется на языке C/C++. Из него же позаимствован способ обработки переменных. При написании программы можно использовать как глобальные переменные, так и локальные переменные.
Глобальная переменная — это такая переменная, который инициализируется при запуске программы и доступна из любого места (функции) в течение всего времени действия программы.
В основном это является преимуществом, поскольку из любой функции мы получаем доступ к переменной, без необходимости передачи информации в качестве параметра вызова.
Но в некоторых случаях, к сожалению, это является недостатком. Используя готовые функции, может оказаться так, что это же имя переменной одновременно используется и для других целей и из-за этого программа может работать неправильно.
Второй тип переменной – локальная переменная. Мы определяем ее в теле функции, и она доступна только на уровне этой функции. Локальная переменная инициализируется при вызове функции и уничтожается после завершения ее работы. Использование локальных переменных снижает спрос на оперативную память, но в то же время затрудняет передачу информации между различными функциями программы.
Настоятельно рекомендуется использовать локальные переменные и функции с параметрами вызова. Глобальные переменные следует использовать в тех ситуациях, когда одна и та же переменная используется в нескольких функциях.
Следующий код иллюстрирует место и способ декларации глобальных и локальных переменных:
[slh lang=»php»]char tablica[10]; // глобальный массив доступный из любого места программыvoid setup()
{
int a; // локальная переменная «a» доступна из функции setup()
}
int x; // глобальная переменная доступна из любого места программы
void loop()
{
int a; // локальная переменная «a» доступна из функции loop()
char b; // локальная переменная «b» доступна из функции loop()
} [/slh]
Как показано в приведенном выше примере, переменные, объявленные внутри функции, являются локальными переменными, а переменные, объявленные вне тела функций, являются глобальными переменными.
Переменная «а» в функции setup () — это совершенно другая переменная, чем «а» в функции loop().
Давайте рассмотрим другой код.
Следующий код можно скомпилировать и запустить, а результат работы программы наблюдать с помощью монитора последовательного порта, доступного в Arduino IDE (функции Serial.begin и Serial.print предназначены для отправки данных через последовательный порт)
[slh lang=»php»] void setup(){
Serial.begin(9600); //инициализация последовательного порта
}
int a=10; //глобальная переменная «а» со значением 10
void loop()
{
Serial.print(a); //вывод переменной «а», 10
Serial.print(» «);
int a=1; //локальная переменная «a» со значением 1
Serial.println(a); //вывод переменной «а», 1
}[/slh]
В этом примере есть дополнительная часть — глобальная переменная и локальная переменная с тем же именем. Компилятор не возвращает ошибку. Однако, необходимо помнить о проблемах, которые могут возникнуть из приведенного выше примера.
В начале функции loop() локальная переменная еще не объявлена. Обращаясь к переменной «а», мы обращаемся к глобальной переменной, значение которой составляет 10. После объявления локальной переменной «а» внутри функции loop (), обращаемся к ней и получаем значение 1. Функция loop() вызывается в системе циклически, поэтому с помощью монитора последовательного порта, мы можем наблюдать чередование появление чисел 10 и 1.
Изменим немного код:
[slh lang=»php»] void setup(){
Serial.begin(9600); //инициализация последовательного порта
}
int a=10; //глобальная переменная «а» со значением 10
void loop()
{
Serial.print(a); //вывод переменной «а», 10
Serial.print(» «);
int a=1; //локальная переменная «a» со значением 1
a++; //увеличить значение переменной «а» на единицу
Serial.println(a); //вывод переменной «а»
}
[/slh]
Как видно на примере изменение значения переменной «а» относится к локальной переменной. Следует избегать использования локальных и глобальных переменных с одним и тем же именем, потому что это может создать потенциальные проблемы с нормальным функционированием программы.
Директивы const, static, volatile
Директивы компилятора позволяют осуществить специальную обработку некоторых элементов программного кода и заменить их при компиляции или выполнении кода.
Директива const позволяет создать переменную «только для чтения», то есть постоянную. Примеры предопределенных констант можно найти в другой статье.
Альтернативой const является define. Создатели Arduino IDE рекомендуют использовать именно const. Ниже приведены примеры для пользовательских констант:
[slh lang=»php»]const float pi=3.14; // определение константы piconst byte max=100; // максимальное значение=100
#define ledPin 13 // определение pinu13 как ledPin
[/slh]
Как видно const указывает на тип данных, а define присваивает значение без указания типа. Отсутствие точки с запятой в конце строки с define не упущение, а правильный синтаксис, заимствованный из C/C++.
Хорошей практикой является использование define для присвоения словесных обозначений для входов/выходов, а для остальных констант рекомендуется использовать директиву const.
Директива static позволяет определить способ инициализации локальных переменных. Обычно локальная переменная инициализируется во время вызова функции и уничтожается при ее завершении. Добавление директивы static приведет к тому, что с точки зрения охвата переменная останется по-прежнему локальной, но не будет уничтожена после завершения выполнения функции.
При следующем вызове функции, переменная уже не будет повторно инициализирована, а будет иметь значение, полученное при предыдущем завершении работы функции. Лучше всего проверить это на примере:
[slh lang=»php»]void setup(){
Serial.begin(9600);
}
void loop()
{
int a=1;
static int b=1;
Serial.print(a); // всегда 1
Serial.print(» «);
Serial.println(b); // 1, 2, 3…
a++;
b++;
}[/slh]
При запуске программы вы увидите, что переменная «а» каждый раз принимает начальное значение 1, а переменная «b» значение 1, 2, 3, ….
Последней важной директивой является volatile. Ее следует использовать в случае, когда значение переменной может быть изменено с помощью функции обработчика прерывания.
Понимание целесообразности использования volatile не просто. Вы должны знать, как обрабатываются прерывания. В целом обслуживание прерываний заключается в остановке выполнения основного кода программы с целью выполнения определенных инструкций с последующим возвращением к основному коду.
Если прерывания изменит значение переменной, которая используется в программе, то может оказаться так, что это изменение не будет обновлено. В этом случае на помощь приходит директива volatile, которая принудительно обновляет значение переменной после выполнения прерывания в основной программе.
[slh lang=»php»]volatile int x;…
void обработка_прерывания()
{
x++;
}[/slh]
Проще говоря, необходимо запомнить, что переменные, используемые в прерываниях, должны быть объявлены директивой volatile.