Функции Arduino
analogRead()
Функция analogRead() возвращает целочисленное значение в диапазоне от 0 до 1023, пропорциональное напряжению, поданному на аналоговый вход, номер которого мы передаем функции в качестве параметра pinA. В большинстве плат это порты 0-5. В платах Mini и Nano: 0-7, в плате Mega: 0-15.
analogWrite()
Устанавливает аналоговое значение PWM (ШИМ, Широтно-импульсная модуляция) для вывода. Используется для плавного изменения цвета у светодиода или скорости вращения мотора. Пины с поддержкой PWM обозначены на плате символом тильда (
). Для Arduino Uno выводы имеют номера 3, 5, 6, 9, 10 и 11.
Перед вызовом данной функции нет необходимости вызывать функцию pinMode().
Функция не возвращает значения и имеет два параметра.
- pin — номер вывода для отправки сигнала
- value — значение яркости от 0 (полностью выключен) до 255 (полная яркость) (значение скважности ШИМ)
Функция возвращает значение бита в указанной позиции.
Общий пример для функций с битами.
bitClear()
Функция устанавливает 0 в указанной позиции у числа.
bitRead()
Функция считывает биты с указанного числа. Возвращает значение бита (0 или 1)
- x — число, которое нас интересует
- n — какой бит нужно считать
bitSet()
Функция устанавливает бит в указанном числе в указанной позиции.
bitWrite()
Функция записывает бит в указанной позиции.
Функция находит ближайшее целое число к числу x, но не меньше чем само число x.
Функция находит косинус угла в радианах. Значение находится в интервале от -1 до 1.
delay()
Функция делает паузу в программе на указанное количество времени в миллисекундах , которое указывается в единственном параметре. Не возвращает значения.
- ms — число миллисекунд для установки паузы (unsigned long). 1000 миллисекунд = 1 сек
digitalRead()
Функция digitalRead() считывает показания с цифрового вывода. Возвращается HIGH (высокое, 1) или LOW (низкое, 0):
- pin — номер цифрового порта, на который мы отправляем сигнал
digitalWrite()
Функция digitalWrite() не возвращает значения и принимает два параметра:
- pin — номер цифрового порта, на который мы отправляем сигнал
- value — значение, которое мы отправляем на порт. Для цифровых портов значением может быть HIGH (высокое, 1) или LOW (низкое, 0)
floor()
Функция находит ближайшее целое число к числу x, но не больше чем само число x.
После выполнения setup() запускается функция loop(), которая выполняется в бесконечном цикле.
Функция loop() должна присутствовать в любой программе (скетче), даже если вам не нужно ничего выполнять в них — просто не пишите ничего между фигурными скобками.
Преобразует число из одного диапазона в другой диапазон. Т.е. значение из fromLow попадёт в toLow, значение fromHigh попадёт в toHigh, а значения между ними пропорционально попадут в новые значения другого диапазона.
Нижнее значение диапазона может быть больше или меньше верхнего значения. Функция map() в таких случаях может работать в обратном порядке. Например.
Также допускаются отрицательные числа.
Функция использует целые числа и не генерирует дробные числа. Дробные числа усекаются до целых.
- value — число для конвертации
- fromLow — нижнее значение текущего диапазона
- fromHigh — верхнее значение текущего диапазона
- toLow — нижнее значение нового диапазона
- toHigh — верхнее значение нового диапазона
Возвращается новое значение после преобразования.
Функция возвращает большее из двух чисел.
millis()
Функция без параметров возвращает число миллисекунд (unsigned long), прошедших с запуска Arduino.
Функция возвращает меньшее из двух чисел.
pinMode()
Функция pinMode() устанавливает режим для портов.
- pin — вывод, с которым мы собираемся работать
- mode — как должен работать указанный вывод: работать на выход (OUTPUT) или вход (INPUT) или INPUT_PULLUP
Функция для возведения числа в степень.
random()
Функция генерирует псевдослучайные числа.
- min — нижняя граница случайных значений
- max — верхняя граница случайных значений
Функция возвращает случайное число между min и max-1 (long)
setup()
Функция setup() выполняется один раз при запуске микроконтроллера. Обычно она используется для конфигурации портов микроконтроллера и других настроек.
Функция setup() должна присутствовать в любой программе (скетче), даже если вам не нужно ничего выполнять в них — просто не пишите ничего между фигурными скобками.
Функция находит синус угла в радианах. Значение находится в интервале от -1 до 1.
shiftOut()
В качестве третьего аргумента передаётся параметр bitOrder (порядок битов), который определяет в какой последовательности подаваемые биты будут интерпретироваться регистром — в прямом или обратном. LSBFIRST (Least Significant Bit First) — означает, что вывод в регистр начнётся с последнего бита. Например, при передаче байта 00010111 на выходах регистра окажутся значения (с 1 по 8 пины) — 00010111. MSBFIRST (Most Significant Bit First) — означает, что вывод в регистр начнётся с первого бита. При передаче байта 00010111 на выходах регистра окажутся значения в обратном порядке (с 1 по 8 пины) — 11101000.
Функция извлекает корень из числа.
Функция находит тангенс угла в радианах.
Генерирует звук заданной частоты на указанном пине. Можно указать продолжительность звука. Если продолжительность не указана, то остановить воспроизведение можно с помощью функции noTone(). Вывод можно соединить с пьезопищалкой или другим устройством, способным выводить звук.
Можно выводить только одну ноту во время исполнения.
- pin — вывод платы для воспроизведения звука
- frequency — частота звука в герцах (unsigned int)
- duration — продолжительность в миллисекундах (необязательно) — unsigned long
Функция не возвращает значения.
Serial
Класс, позволяющий общаться с компьютером.
available()
Получает число байт (символов), доступных для чтения из последовательного порта. Данные уже пришли и хранятся в специальном буфере (64 байта).
begin()
Устанавливает связь с портом для считывания данных на заданной скорости с Arduino на ваш компьютер. В IDE есть выпадающий список, в котором можно увидеть возможные варианты скоростей.
- speed — скорость бит в секунду (long)
flush()
Очищает входной буфер последовательного порта. Находящиеся в буфере данные теряются, и дальнейшие вызовы Serial.read() или Serial.available() будут иметь смысл для данных, полученных после вызова Serial.flush().
print()
Печатает данные, поступаемые с серийного порта в виде ASCII-текста без символа перевода строки. Схожа с функцией Serial.println().
- val — значение для печати
- format — формат выводимых данных. Можно использовать константы DEC (десятичная система), HEX (шестнадцатеричная), OCT (восьмеричная), BIN (бинарная)
println()
Печатает данные, поступаемые с серийного порта в виде ASCII-текста. Данные заканчиваются символом перевода строки (ASCII 13, ‘\r’) и новой строки (ASCII 10, ‘\n’). Схожа с функцией Serial.print().
- val — значение для печати
- format — формат выводимых данных. Можно использовать константы DEC (десятичная система), HEX (шестнадцатеричная), OCT (восьмеричная), BIN (бинарная)
Считывает входящие данные из последовательного порта.
Возвращает первый байт входящих данных, если они есть или -1, если данные не доступны.
write()
Записывает данные в последовательный порт. Данные посылаются как байт или последовательность байт; для отправки символьной информации следует использовать функцию print().
- val: переменная для передачи, как единственный байт
- str: строка для передачи, как последовательность байт
- buf: массив для передачи, как последовательность байт
- len: длина массива
Разное
pulseIn() — Возвращает продолжительность в микросекундах следующего импульса с напряжением HIGH на заданном контакте
noTone() — Прерывает любые серии импульсов, запущенные вызовом tone
micros() — Действует подобно millis, но возвращает число микросекунд, прошедших с момента последнего сброса платы. Значение обнуляется примерно через 70 минут
delayMicroseconds() — минимальная задержка составляет 3 мкс, максимальная — около 16 мс
attachInterrupt() — Устанавливает функцию myFunction, как обработчик положительного фронта прерывания 1 (контакт D3 в UNO)
detachInterrupt() — Запрещает обработку сигналов от прерывания 1
Типы данных, переменные
Переменная – это ячейка в оперативной памяти микроконтроллера, которая имеет своё уникальное название (а также адрес в памяти) и хранит значение соответственно своему размеру. К переменной мы можем обратиться по её имени или адресу и получить это значение, либо изменить его. Зачем это нужно? В переменной могут храниться п ромежуточные результаты вычислений, полученные “снаружи” данные (с датчиков, Интернета, интерфейсов связи) и так далее.
Измерение информации
Прежде чем перейти к переменным и их типам, нужно вспомнить школьный курс информатики, а именно – как хранятся данные в “цифровом” мире. Любая память состоит из элементарных ячеек, которые имеют всего два состояния: 0 и 1. Эта единица информации называется бит (bit). Минимальным блоком памяти, к которому можно обратиться из программы по имени или адресу, является байт (byte), который в Arduino (и в большинстве других платформ и процессоров) состоит из 8 бит, таким образом любой тип данных будет кратен 1 байту.
Максимальное количество значений, которое можно записать в один байт, составляет 2^8 = 256. В программировании счёт всегда начинается с нуля, поэтому один байт может хранить число от 0 до 255. Более подробно о двоичном представлении информации и битовых операциях мы поговорим в отдельном уроке.
Стандартные типы переменных в Arduino по своему размеру кратны степени двойки, давайте их распишем:
- 1 байт = 8 бит = 256
- 2 байта = 16 бит = 65 536
- 4 байта = 32 бита = 4 294 967 296
Типы данных
Переменные разных типов имеют разные особенности и позволяют хранить числа в разных диапазонах.
Название | Альт. название | Вес | Диапазон | Особенность |
boolean | bool | 1 байт * | 0 или 1, true или false | Логический тип |
char | – | 1 байт | -128… 127 | Символ (точнее его код) из таблицы ASCII |
– | int8_t | 1 байт | -128… 127 | Целые числа |
byte | uint8_t | 1 байт | 0… 255 | Целые числа |
int ** | int16_t , short | 2 байта | -32 768… 32 767 | Целые числа. На ESP8266/ESP32 – 4 байта! См. ниже |
unsigned int ** | uint16_t , word | 2 байта | 0… 65 535 | Целые числа. На ESP8266/ESP32 – 4 байта! См. ниже |
long | int32_t | 4 байта | -2 147 483 648… 2 147 483 647 | Целые числа |
unsigned long | uint32_t | 4 байта | 0… 4 294 967 295 | Целые числа |
float | – | 4 байта | 1.175E-38.. 3.402E+38 | Числа с плавающей точкой, точность: 6-7 знаков |
double | – | 4/8 байт | 2.225E-308.. 1.797E+308 | Для AVR то же самое, что float . На ESP и прочих 32-бит МК – 8 байт, точность – 15-16 знаков |
– | int64_t | 8 байт *** | -(2^64)/2… (2^64)/2-1 | Целые числа |
– | uint64_t | 8 байт *** | 2^64-1 | Целые числа |
- (*) – да, bool занимает 1 байт (8 бит), так как это минимальная адресуемая ячейка памяти. Есть способы запаковать логические переменные в 1 бит, о них поговорим в другом уроке.
- (**) – на ESP8266/ESP32 int и unsigned int занимает 4 байта, то есть является аналогами типов long и unsigned long !
- (***) – Компилятор также поддерживает 64 битные числа. Стандартные Arduino-библиотеки с переменными этого типа не работают, поэтому можно использовать только в своём коде.
Целочисленные типы
Переменные целочисленных типов нужны для хранения целых чисел. В своей программе рекомендуется использовать альтернативное название типов (второй столбец в таблице выше), потому что:
- Проще ориентироваться в максимальных значениях
- Легче запомнить
- Название более короткое
- Проще изменить один тип на другой
- Размер переменной задан жёстко и не зависит от платформы (например int на AVR это 2 байта, а на esp8266 – 4 байта)
Максимальные значения хранятся в константах, которые можно использовать в коде. Иногда это помогает избавиться от лишних вычислений:
- UINT8_MAX – 255
- INT8_MAX – 127
- UINT16_MAX – 65 535
- INT16_MAX – 32 767
- UINT32_MAX – 4 294 967 295
- INT32_MAX – 2 147 483 647
- UINT64_MAX – 18 446 744 073 709 551 615
- INT64_MAX – 9 223 372 036 854 775 807
Логический тип
bool – логический, он же булевый (придуман Джорджем Булем) тип данных, принимает значения 0 и 1 или false и true – ложь и правда. Используется для хранения состояний, например включено/выключено, а также для работы в условных конструкциях.
Также переменная типа bool принимает значение true , если присвоить ей любое отличное от нуля число.
Символьный тип
char – тип данных для хранения символов, символ указывается в одинарных кавычках: char var = ‘a’; . По факту это целочисленный тип данных, а переменная хранит номер (код) символа в таблице ASCII:
Отдельный символьный тип данных нужен для удобства работы, чтобы программа могла понять разницу между числом и символом, например для вывода на дисплей (чтобы вывести именно букву A, а не число 65). Из символов можно составлять строки, об этом более подробно поговорим в уроках про символьные строки и String-строки.
Дробные числа
float (англ. float – плавающий) – тип данных для чисел с плавающей точкой, т.е. десятичных дробей. Arduino поддерживает три типа ввода чисел с плавающей точкой:
Тип записи | Пример | Чему равно |
Десятичная дробь | 20.5 | 20.5 |
Научный | 2.34E5 | 2.34*10^5 или 234000 |
Инженерный | 67e-12 | 67*10^-12 или 0.000000000067 |
Выше в таблице есть пометка “точность: 6-7 знаков” – это означает, что в этом типе можно хранить числа, размер которых не больше 6-7 цифр, остальные цифры будут утеряны! Причём целой части отдаётся приоритет. Вот так это выглядит в числах (в комментарии – реальное число, которое записалось в переменную):
Другие особенности float чисел и работу с ними мы рассмотрим в уроках про математические операции и условия.
Объявление и инициализация
- Объявление переменной – резервирование ячейки памяти указанного типа на имя: тип_данных имя;
- Присваивание – задание переменной значения при помощи оператора = (равно): имя = значение;
- Инициализация переменной – объявление и присваивание начального значения: тип_данных имя = значение;
Можно объявить и инициализировать несколько переменных через запятую:
- Переменная должна быть объявлена до использования, буквально выше по коду. Иначе вы получите ошибку Not declared in this scope – переменная не объявлена.
- Нельзя объявить две и более переменных с одинаковым именем в одной области определения.
Константы
Что такое константа понятно из её названия – что-то, значение чего мы можем только прочитать и не можем изменить: при попытке изменить получим ошибку компиляции. Задать константу можно двумя способами:
Как переменную, указав перед типом данных слово const: const тип_данных имя = значение; . Пример: const byte myConst = 10; . Фактически это будет обычная переменная, но её значение нельзя поменять. Особенности:
- Занимает место в оперативной памяти МК.
- Имеет адрес в памяти, по которому к ней можно обратиться.
- Вычисления с ней не оптимизируются и чаще всего выполняются точно так же, как с обычными переменными.
- Компилятор выдаст ошибку, если имя константы совпадает с именем другой переменной в программе.
При помощи директивы #define, без знака равенства и точки с запятой в конце: #define имя значение . Пример: #define BTN_PIN 10 . Работает так: указанное имя буквально заменяется в тексте программы на указанное значение. Такая дефайн-константа:
- Не занимает места в оперативной памяти, а хранится во Flash памяти как часть кода программы.
- Не имеет адреса в оперативной памяти.
- Вычисления с такими константами оптимизируются и выполняются быстрее, так как это просто цифры.
- Если имя дефайн-константы совпадёт с именем другого “объекта” в программе или даже в библиотеке – работа может быть непредсказуемой: можно получить невнятную ошибку компиляции, либо программа может просто работать некорректно! Дефайн буквально заменяет текст в коде программы, это довольно опасная штука.
Область видимости
Переменные, константы const и другие создаваемые пользователем данные имеют такое важное понятие, как область видимости. Она бывает глобальной и локальной.
Глобальная
- Объявляется вне функций, например просто в начале программы.
- Доступна для чтения и записи в любом месте программы.
- Находится в оперативной памяти на всём протяжении работы программы, то есть не теряет своё значение.
- При объявлении имеет нулевое значение.
Локальная
- Объявляется внутри любого блока кода, заключённого в < фигурные скобки >.
- Доступна для чтения и записи только внутри своего блока кода (и во всех вложенных в него).
- Находится в оперативной памяти с момента объявления и до закрывающей фигурной скобки, то есть удаляется из памяти и её значение стирается.
- При объявлении имеет случайное значение.
Важный момент: если имя локальной переменной совпадает с одной из глобальных, то приоритет обращения отдаётся локальной переменной (в её области определения).
Статические переменные
Вспомним, как работает обычная локальная переменная: при входе в свой блок кода локальная переменная создаётся заново, а при выходе – удаляется из памяти и теряет своё значение. Если локальная переменная объявлена как static – она будет сохранять своё значение на всём протяжении работы программы, но область видимости останется локальной: взаимодействовать с переменной можно будет только внутри блока кода, где она создана (и во всех вложенных в него).
Статические переменные позволяют более красиво организовывать свой код, избавляясь от лишних глобальных переменных.
Преобразование типов
Иногда требуется преобразовать один тип данных в другой: например, функция принимает int , а вы хотите передать ей byte . В большинстве случаев компилятор сам разберётся и преобразует byte в int , но иногда вылетает ошибка в стиле “попытка передать byte туда, где ждут int“. В таком случае можно преобразовать тип данных, для этого достаточно указать нужный тип данных в скобках перед преобразуемой переменной (тип_данных)переменная , иногда можно встретить запись тип_данных(переменная) . Результат вернёт переменную с новым типом данных, сам же тип данной у переменной не изменится. Например:
И всё! val будет обрабатываться как int , а не как byte .
Видео