Список команд Arduino

Arduino команди ЛОГО

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

Структура скетча

Синтаксис, структура коду

/* */

Багаторядковий коментар.

/* цей код не 
компілюється */

//

Однорядковий коментар.

// цей код
// не компілюється

 ;

Ставиться в кінці кожної дії.

void setup() {}

Функція, вміст якої виконується один раз під час запуску мікроконтролера.

void loop() {}

Функція, вміст якої виконується (або намагається виконуватися) «по колу» протягом усього часу роботи мікроконтроллеру.

#include

Директива, що дає змогу підключати до проєкту додаткові файли з кодом.

#include <Servo.h>  // подключает библиотеку Servo.h
#include "Servo.h"  // подключает библиотеку Servo.h

У чому відмінність <> і «»? Коли вказуємо назву «в лапках», компілятор спочатку шукає файл у папці зі скетчем, а потім у папці з бібліотеками. При використанні <галочок> компілятор шукає файл тільки в папці з бібліотеками.

#define

Директива, що дає команду препроцесору замінити вказану назву на вказане значення. Найчастіше таким чином оголошують константи:

#define MOTOR_PIN 10 // пін мотора 10
#define LED_PIN 3 // пін світлодіода 3

Після компіляції всі слова MOTOR_PIN, що трапляються в тексті програми, будуть замінені на цифру 10, а LED_PIN – на цифру 3. Такий спосіб зберігання констант не використовує оперативну пам’ять мікроконтролера. Також define дає змогу робити т.зв. макро функції. Наприклад Ардуїнівська функція sq (квадрат) є макро, який під час компіляції перетворюється на множення:

#define sq(x) ((x)*(x))

#if, #elif, #else, #endif

Директиви препроцесору, що дають змогу включати або виключати ділянки коду за умовою

#define TEST 1 // визначаємо TEST як 1

#if (TEST == 1) // якщо TEST 1
#define VALUE 10 // визначити VALUE як 10
#elif (TEST == 0) // TEST 0
#define VALUE 20 // визначити VALUE як 20
#else // якщо ні
#define VALUE 30 // визначити VALUE як 30
#endif // кінець умови

При помощи условной компиляции очень удобно собирать и настраивать сложные проекты с кучей настроек и библиотек, подключаемых “по условию”. Например:

#define DEBUG 1

void setup() {
#if (DEBUG == 1)
  Serial.begin(9600);
  Serial.println(«Hello!»);
#endif
}

Якщо параметру DEBUG встановити 1, то буде підключено бібліотеку Serial, якщо 0 – то ні. Таким чином отримуємо універсальний оптимізований проєкт із налагодженням.

#ifdef, #ifndef

Умовні директиви препроцесору, дають змогу вмикати або вимикати ділянки коду за умовою: ifdef – чи визначено? ifndef – чи не визначено?

#define TEST // визначаємо TEST 

#ifdef TEST // якщо TEST визначено 
#define VALUE 10 // визначити VALUE як 10 
#else // якщо закоммент. #define TEST
#define VALUE 20 // визначити VALUE як 20 
#endif // кінець умови

goto

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

for (byte r = 0; r < 255; r++) {
    for (byte g = 255; g > -1; g--) {
      for (byte b = 0; b < 255; b++) {
        if (analogRead(0) > 250) {
          // піти з порівнянь
          goto bailout;
        }
        // ще код
      }
    }
  }
bailout:
  // перенеслися сюди

return

Оператор переривання функції, він же оператор повернення значення з функції.


Умови (if, switch)

if, else if, else

Оператор порівняння та його друзі.

// при виконанні однієї дії {} необов'язкові
if (a > b) c = 10; // якщо a більше b, то c = 10
else c = 20; // якщо ні, то c = 20
// замість порівняння можна використовувати лог. змінну
boolean myFlag, myFlag2;
if (myFlag) c = 10;
// складні умови
if (myflag && myFlag2) c = 10; // якщо обидва прапори true
// при виконанні двох і більше {} обов'язкові
if (myFlag) {
  с = 10;
  b = c;
} else {
  с = 20;
  b = a;
}
byte buttonState;
if (buttonState == 1) a = 10; // якщо buttonState 1
else if (buttonState == 2) a = 20; // якщо ні, але якщо buttonState 2
else a = 30; // якщо і це не вірно, то ось

?

Скорочений запис умови: (логіка) ? правда : брехня.

int с = (a > b) ? 10 : -20; // якщо a > b, то с = 10. Якщо ні, то с = -20

boolean flag = true;
Serial.println( (flag) ? («прапор піднято») : («прапор опущено») );

switch.. case

Оператор вибору, замінює конструкцію з else if.

switch (val) {
  case 1:
    // виконати, якщо val == 1
    break;
  case 2:
    // виконати, якщо val == 2
    break;
  default:
    // виконати, якщо val ні 1 ні 2
    // default опціональний
    break;
}

Оператор break дуже важливий, дає змогу вийти з switch. Але можна використовувати так:

switch (val) {
  case 1:
  case 2:
  case 3:
  case 4:
    // виконати, якщо val == 1, 2, 3 або 4
    break;
  case 5:
    // виконати, якщо val == 5
    break;
}

Циклы (for, while)

for

Цикл – «лічильник». for (ініціалізація; умова; інкремент).

for (int i = 0; i < 10; i++) {
  a = i; // a прийме значення від 0 до 9 на кожній ітерації
  Serial.println(a); // виведення в порт
}
// для однієї дії {} не потрібні
for (int i = 0; i < 10; i++)
  Serial.println(i); // виведення в порт

Також використовується для створення замкнутих циклів, оскільки налаштування for необов’язкові. Вихід тільки через break або goto

for (;;;); // крутимося в циклі вічно

while

Цикл із передумовою.

while (a < b) {
  // виконується, поки a менше b
}

Може бути використаний для створення замкнутого циклу, вихід тільки через break або goto

while (true) {
  // крутимося в циклі вічно
}

do.. while

Цикл із постумовою.

do {
  // виконується, поки a менше b
} while (a < b);

Відрізняється від while тим, що гарантовано виконається хоча б один раз

continue

Пропускає всі дії, що залишилися в тілі циклу, і переходить до наступної ітерації

break

Виходить із циклу


Оператори

Кома ,

Кома теж є оператором, використовується в таких випадках:

  • Перерахування елементів у масивах
  • Перерахування аргументів у функціях
  • Виконання послідовності дій (зробити це І це)

Розглянемо третій випадок тут:

// оголосити a і b і дати їм значення
int a = 5, b = 10;

// присвоїти 3 до b
// додати 1 до b
// прирівняти до a
a = (b = 3, ++b); // a == 4

// оголосити i і j
// додавати i+1 і j+2
for (byte i = 0, j = 0; i < 10; i++, j += 2) {
  // тут i змінюється від 0 до 9
  // і j змінюється від 0 до 18
}

Арифметичні

Арифметичні оператори – найпростіші та найзрозуміліші з усіх

  • = присвоювання
  • % залишок від ділення
  • * множення
  • / ділення
  • + додавання
  • – віднімання

Порівняння та логіка

  • == рівність (a == b)
  • != нерівність (a != b)
  • = більше або дорівнює
  • <= менше або дорівнює
  • більше
  • < менше
  • ! логічне НЕ, заперечення. Аналог – оператор not
  • && логічне І. Аналог – оператор and
  • || логічне АБО. Аналог – оператор or

Складові оператори

  • ++ (плюс плюс) інкремент: a++ рівносильно a = a + 1
  • — (мінус мінус) декремент: a — рівносильно a = a – 1
  • += складене додавання: a += 10 рівносильно a = a + 10
  • -= складене віднімання: a -= 10 рівносильно a = a – 10
  • *= складене множення: a *= 10 рівносильно a = a * 10
  • /= складене ділення: a /= 10 рівносильно a = a / 10
  • %= додати залишок від ділення: a %= 10 рівносильно a = a + a % 10
  • &= складене бітове І: a &= b рівносильно a = a & b
  • ^= складене виключне АБО: a ^= b рівносильно a = a ^ b
  • |= складене АБО: a |= b рівносильно a = a | b

Бітові операції

  • & бітове І
  • << бітове зрушення вліво
  • >> бітове зрушення вправо
  • ^ бітове виключне АБО (аналогічний оператор – xor)
  • | бітове АБО
  • ~ бітове НЕ

Покажчики та посилання

  • & – повертає адресу даних у пам’яті (адреса першого блоку даних)
  • *- повертає значення за вказаною адресою
  • -> – оператор непрямого звернення до членів і методів (для покажчиків на структури і класи). Є коротким записом конструкції через покажчик: a->b рівносильно (*a).b

Робота з даними

Типи даних, змінні

Змінна – елементарна комірка для зберігання даних (цифр). Змінні різних типів мають різний «розмір комірки» і мають різний ліміт на розмір числа.

НазваАльтернативна назваРозмірДіапазонОсобливість
booleanbool1 байт0 або 1, true або falseЛогічна змінна. bool на Arduino також займає 1 байт, а не біт!
char1 байт-128… 127Зберігає номер символу з таблиці ASCII
int8_t1 байт-128… 127Цілі числа
byteuint8_t1 байт0… 255Цілі числа
intint16_t, short2 байти-32 768… 32 767Цілі числа
unsigned intuint16_t, word2 байти0… 65 535Цілі числа
longint32_t4 байти-2 147 483 648… 2 147 483 647Цілі числа
unsigned longuint32_t4 байти0… 4 294 967 295Цілі числа
float4 байти-3.4E+38… 3.4E+38Числа з плаваючою комою (десяткові дроби). Точність: 6-7 знаків
double4 байти-1.7E+308… 1.7E+308Для AVR те саме, що float. В інших випадках — 8 байтів
int64_t8 байтів-(2^64)/2… (2^64)/2-1Цілі числа
uint64_t8 байтів0… 2^64-1Цілі числа

Існує ще кілька спеціальних типів даних для символів.

wchar_t – 16 бітний символ

  • char16_t – 2-х байтний char
  • char32_t – 4-х байтний char

Також є таке поняття, як перевизначення типів даних (не створюючи нових типів), для цього використовується ключове слово typedef. Typedef працює таким чином: typedef <тип> <ім’я>; – створити новий тип даних <ім’я> на основі типу <тип>. Приклад:

typedef byte color;

Створює тип даних під назвою color, який буде абсолютно ідентичний типу byte (тобто приймати 0-255). Тепер із цим типом можна створювати змінні:

color R, G, B;

Створили три змінні типу color, який той самий byte, тільки в профіль. Це все!


Структури

Структура (struct) – дуже складний тип даних: сукупність різнотипних змінних, об’єднаних одним ім’ям.

struct <ярлик> {
  <тип> <ім'я змінної 1>;
  <тип> <ім'я змінної 2>;
  <тип> <ім'я змінної 3>;
};

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

<ярлик> <ім'я структури>; // оголосити одну структуру
<ярлик> <ім'я структури1>, <ім'я структури2>; // оголосити дві структури типу <ярлик>
<ярлик> <ім'я структури>[5]; // оголосити масив структур

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

struct {
  <тип> <ім'я змінної 1>;
  <тип> <ім'я змінної 2>;
  <тип> <ім'я змінної 3>;
} <ім'я структури>;
  • Звернення до члена структури відбувається ось за такою схемою: <ім’я структури>.<ім’я змінної> і дає змогу змінювати або читати значення.
  • Якщо дві структури мають однакову структуру (оголошені одним ярликом), то можна одну структуру просто прирівняти до іншої, всі змінні запишуться відповідно на свої місця.
  • Ще одним зручним варіантом є присвоювання значення ось таким чином: <ім’я структури> = ( <ярлик> ) { <значення змінної 1>, <значення змінної 2>, <значення змінної 3> };

Перечисления

Перерахування (enum – enumeration) – тип даних, що являє собою набір іменованих констант, потрібен насамперед для зручності програміста.

Оголошення перерахування чимось схоже на оголошення структури:

enum <ярлик> {<ім'я1>, <ім'я2>, <ім'я3>, <ім'я4>, <ім'я5>};

Таким чином ми оголосили ярлик. Тепер, використовуючи цей ярлик, можна оголосити саме перерахування:

<ярлик> <ім'я перерахування>;

Так само як і у структур, можна оголосити перерахування без створення ярлика (навіщо нам зайвий рядок?):

enum {<ім'я1>, <ім'я2>, <ім'я3>, <ім'я4>, <ім'я5>} <ім'я перерахування>;

Створене таким чином перерахування є змінною, яка може приймати зазначені для неї <імена>, також із цими іменами її можна порівнювати. Тепер найголовніше: імена для програми є числами, починаючи з 0 і далі по порядку збільшуючись на 1. В абстрактному прикладі вище <ім’я1> дорівнює 0, <ім’я2> дорівнює 1, <ім’я3> дорівнює 2, і так далі. Крім зазначених імен, перерахуванню можна прирівняти і число безпосередньо, але як би навіщо.

Класи

Класи в С++ – це основний і дуже потужний інструмент мови, більшість «бібліотек» є класами. Ієрархія така:

  • Клас
  • Об’єкт
  • Властивості та методи

Клас оголошується таким чином:

class /*ім'я класу*/
{
  private:
  // список властивостей і методів для використання всередині класу
  public:
  // список методів доступних іншим функціям і об'єктам програми
  protected:
  // список засобів, доступних під час успадкування
};

Масиви

Для оголошення масиву достатньо вказати квадратні дужки після імені змінної, тип даних – будь-який.

// вказуємо кількість комірок і все, далі можна з ними працювати
int myInts[6];
// вказуємо вміст комірок, компілятор сам порахує їхню кількість
int myPins[] = {2, 4, 8, 3, 6};
// вказуємо і те, і те, кількість клітинок у [ ] має збігатися з { } або бути більшою!
float Sens[3] = {0.2, 0.4, -8.5};
// зберігаємо символи
char message[6] = «hello»;
// пам'ятаємо, що порядок комірок починається з нуля!
myInts[0] = 10; // записати 10 у клітинку 0 масиву myInts

Рядки (об’єкт String)

String – дуже потужний інструмент для роботи з рядками, тобто текстовими даними. Оголосити рядок можна кількома способами:

String string0 = «Hello String»; // заповнюємо словами в лапках
String string1 = String(«lol “) + String(”kek»); // сума двох рядків
String string2 = String('a'); // рядок із символу в одинарних лапках
String string3 = String(«This is string»); // конвертуємо рядок у String
String string4 = String(string3 + « more»); // складаємо рядок string3 з текстом у лапках
String string5 = String(13); // конвертуємо з числа в String
String string6 = String(20, DEC); // конвертуємо з числа із зазначенням базису (десятковий)
String string7 = String(45, HEX); // конвертуємо з числа із зазначенням базису (16-ричний)
String string8 = String(255, BIN); // конвертуємо з числа із зазначенням базису (двійковий)
String string9 = String(5.698, 3); // з float із зазначенням кількості знаків після коми (тут 3)

// можна формувати назву зі шматочків, наприклад для роботи з файлами
#define NAME «speed»
#define TYPE «-log»
#define EXT «.txt»

// при складанні досить вказати String 1 раз для першого рядка
String filename = String(NAME) + TYPE + EXT; // filename дорівнюватиме speed-log.txt

// доступ до елемента рядка працює за таким самим механізмом, як масив
string1[0] = «a»;
// тепер замість Hello String у нас aello String

Рядки можна порівнювати, складати і віднімати, також для роботи з ними є купа функцій:

charAt()

myString.charAt(index);

Повертає елемент рядка myString під номером index. Аналог – myString[index];

setCharAt()

myString.setCharAt(index, val);

Записує в рядок myString символ val на позицію index. Аналог – myString[index] = val;

compareTo()

myString.compareTo(myString2);

  • Повертає від’ємне число, якщо myString йде перед myString2.
  • Повертає додатне число, якщо myString йде після myString2.
  • Повертає 0, якщо рядки однакові.

concat()

myString.concat(value);

Приєднує value до рядка (value може мати будь-який числовий тип даних).
Повертає true у разі успішного виконання, false при помилці.
Аналог – додавання: myString + value.

endsWith()

myString.endsWith(myString2);

Перевіряє, чи закінчується myString символами з myString2.
У разі збігу повертає true.

startsWith()

myString.startsWith(myString2);

Перевіряє, чи починається myString символами з myString2.
У разі збігу повертає true.

equals()

myString.equals(myString2);

Повертає true, якщо myString збігається з myString2.
Регістр літер має значення.

equalsIgnoreCase()

myString.equalsIgnoreCase(myString2);

Повертає true, якщо myString збігається з myString2. Регістр літер не має значення.

indexOf()

myString.indexOf(val);
myString.indexOf(val, from);

Шукає і повертає номер (позицію) значення val у рядку, шукає зліва направо, повертає номер першого символа у збігу.

val може бути char або String, тобто можна шукати в рядку інший рядок або символ.

Можна почати пошук із заданої позиції from.

Якщо val не знайдено в рядку, повертає -1.

lastIndexOf()

myString.lastIndexOf(val);
myString.lastIndexOf(val, from);

Шукає і повертає номер (позицію) значення val у рядку, шукає справа наліво, повертає номер першого символа у збігу (зліва направо).

val може бути char або String, тобто можна шукати в рядку інший рядок або символ.

Можна почати пошук із заданої позиції from.

Якщо val не знайдено в рядку, повертає -1.

length()

myString.length();

Повертає довжину рядка у кількості символів.

remove()

myString.remove(index);
myString.remove(index, count);

Видаляє з рядка символи, починаючи з index і до кінця, або до вказаної кількості count.

replace()

myString.replace(substring1, substring2);

У рядку myString замінює послідовність символів substring1 на substring2.

String myString = "babushka Misha";
myString = myString.replace("babushka", "dedushka");

System.out.println(myString); // Виведе: dedushka Misha

reserve()

myString.reserve(size);

Резервує в пам’яті кількість байтів size для роботи з рядком.

myString.trim();

Перетворює рядок у формат “C” (null-terminated string) і повертає вказівник на отриманий рядок.

myString.substring(from);
myString.substring(from, to);

Повертає частину рядка, що міститься в myString, починаючи з позиції from і до кінця, або до позиції to.

String myString = "lol kek 4eburek";
String chebur = myString.substring(8);
// рядок chebur містить "4eburek"

myString.toCharArray(buf, len);

Розподіляє рядок в масив — буфер buf (типу char[]), починаючи з початку і до довжини len.

myString.getBytes(buf, len);

Копіює вказану кількість символів len (до unsigned int) в буфер buf (типу byte[])

myString.toFloat();

Повертає вміст рядка у тип даних float

myString.toDouble();

Повертає вміст рядка у тип даних double

myString.toInt();

Цей метод перетворює рядок myString на значення типу int

String myString = "10500";
int val = myString.toInt();
// val теперь 10500

myString.toLowerCase();

Цей метод змінює рядок myString, перетворюючи всі його символи на малі літери. Наприклад, якщо було “AAAAA”, стане “aaaaa”.

myString.toUpperCase();

Цей метод змінює рядок myString, перетворюючи всі його символи на великі літери. Наприклад, якщо було “aaaaa”, стане “AAAAA”


Специфікатори змінних

  • const — константа, змінна, яку не можна змінити (інакше буде помилка). const int val = 10;
  • static — дозволяє оголосити локальну змінну всередині функції, і ця змінна не буде повторно ініціалізована при кожному виклику функції. Така собі локальна глобальна змінна.
  • volatile — вказує компілятору, що змінну не слід оптимізувати, оскільки її значення може змінюватися зовні (наприклад, апаратно або в обробнику переривання). Такий специфікатор слід використовувати для змінних, значення яких можуть змінюватися в обробниках переривань або іншими потоками.
  • extern — вказує компілятору, що ця змінна оголошена в іншому файлі програми, але ми хочемо використовувати саме її, а не створювати нову змінну з таким самим ім’ям у цьому файлі. Це дозволяє читати та змінювати змінні, створені в інших файлах (або бібліотеках).

Перетворення типів даних

Змінні різних типів даних можуть бути перетворені одна в одну — для цього достатньо вказати потрібний тип даних у дужках перед змінною, яку потрібно перетворити:
(тип_даних)змінна.
Результатом буде значення з новим типом даних, але тип самої змінної не зміниться (перетворення працює лише в межах однієї операції).

// змінна типу byte
byte val = 10;
// передаємо якійсь функції, яка очікує int
sendVal( (int)val );

Таким чином можна перетворювати звичайні змінні, вказівники та інші типи даних.

А щодо рядків — їх ми вже розглядали вище.

  • toInt()
  • toFloat()
  • toCharArray()

Інколи можна зустріти перетворення типів за допомогою оператора cast.

  • reinterpret_cast — Приведення типів без перевірки, безпосереднє вказівка компілятору. Застосовується лише в разі повної впевненості програміста у своїх діях. Не знімає const і volatile, застосовується для приведення вказівника до вказівника, вказівника до цілого і навпаки.
  • static_cast — Перетворює вирази одного статичного типу в об’єкти і значення іншого статичного типу. Підтримується перетворення числових типів, вказівників і посилань по ієрархії наслідування як вгору, так і вниз. Перетворення перевіряється на рівні компіляції, і в разі помилки приведення типів буде виведено повідомлення.
  • dynamic_cast — Використовується для динамічного приведення типів під час виконання. У разі неправильного приведення типів для посилань викликається виключна ситуація std::bad_cast, а для вказівників буде повернуто 0.
  • const_cast — найпростіше приведення типів. Знімає const і volatile, тобто константність і відмову від оптимізації компілятором змінної. Це перетворення перевіряється на рівні компіляції, і в разі помилки приведення типів буде виведено повідомлення.

Як користуватися: на прикладі попереднього прикладу

// переменная типа byte

byte val = 10;

// передаём какой-то функции, которая ожидает int

sendVal( static_cast<int>(val) );


Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *