Digitrode
цифровая электроника вычислительная техника встраиваемые системы
Как создавать и использовать методы (функции) в Arduino IDE
Сегментирование кода на функции позволяет программисту создавать модульные фрагменты кода, которые выполняют определенную задачу, а затем возвращаются в область кода, из которой функция была «вызвана». Порой, такой инструмент существенно упрощает процесс программирования.
В этом простом базовом руководстве вы узнаете, как создавать свои собственные функции, или как их еще называют, методы.
Чтобы создать метод, нам сначала нужно создать новый скетч. Поместите его в новую папку с именем, например, «Learn Functions» и переименуйте скетч, допустим, в «First Method». Метод всегда объявляется вне void loop() или void setup().Вот пример того, как это должно выглядеть:
Эта функция ничего не возвращает (void), она только выполняет ряд действий. Между фигурными скобками указано, что должна делать функция. Чтобы вызвать вашу созданную функцию, вы должны поместить на нее ссылку в «void loop()». Вы вызываете ее, помещая имя своей функции в «void loop()».
Подождите секунду, void loop() выглядит как функция! Да, вы совершенно правы, это встроенный метод. Теперь вы узнали о типе «void», и мы познакомим вас с совершенно новым типом.
Теперь, когда вы знакомы с типом «void», вы узнаете новый способ использования функций. Но не волнуйтесь! Это не так уж и сложно. В этом примере мы вычисляем значение с двумя переменными, которые уже объявлены.
Итак, перечислим, чем это отличается от void-метода: вместо void здесь int, в конце метода есть «return». Теперь возникает вопрос: что все это значит? Так, «int» означает, что метод должен возвращать целое число, подробнее о «return» позже. По сути это означает, что функция будет целым числом. «результат» является целым числом, поэтому наша функция также должна «быть» целым числом.
Оператор return – это то, что у функции должен быть конечный результат, в данном случае 357.
В последнем примере мы умножили два числа, но что, если бы у нас было много чисел, которые нужно умножить, что ж, для этого есть решение: аргументы. Аргумент помещается в фигурные скобки в имени вашего метода.
Теперь мы добавили аргументы, поэтому нашу функцию можно использовать с разными числами. В методе x и y являются аргументами, они могут быть заполнены при вызове метода.
Теперь, наверное, мы все можем согласиться с тем, что функции делают наш код более организованным, более компактным и более читаемым.
Arduino.ru
Функции
Разбиение на сегменты кода функциями позволяет создавать части кода, которые выполняют определенные задания. После выполнения происходит возврат в место, откуда была вызвана функция. Причиной создания функции является необходимость выполнять одинаковое действие несколько раз.
Для программистов, работающих с BASIC, функции в Arduino позволяют использовать подпрограммы (GOSUB в BASIC).
Разделения кода на функции имеет ряд преимуществ:
- Функции позволяют организовать программу. Очень часто помогают заранее составить концепцию программы.
- Функции кодируют одно действие в одном месте программы. Далее необходимо только отладить код функции.
- Функции сокращают шансы на появление ошибки при необходимости изменения кода.
- Функции сокращают текст скетчей и делают его компактным, т.к. некоторые секции используются много раз.
- Функции облегчают использование кода в других программах делая его модульным. В этом случае функции обладают еще одним небольшим преимуществом, делая код программы легким для чтения.
Существуют две обязательные функции в скетчах Arduino setup() и loop(). Другие функции должны создаваться за скобками этих функций. В следующем примере будет создана простая функция умножения двух чисел.
Пример
Для вызова функции умножения ей передаются параметры данных:
Созданную функцию необходимо задекларировать вне скобок любой другой функции, таким образом «myMultiplyFunction()» может стоять выше или ниже функции «loop()».
Весь скетч будет выглядеть следующим образом:
Следующая функция будет считывать данные с датчика функцией analogRead() и затем рассчитывать среднее арифметическое. Затем созданная функция будет масштабировать данные по 8 битам (0-255) и инвертировать их. // датчик подключен к выводу 0
Вызов функции осуществляется присвоением ее переменной.
Arduino — основы программирования
После ознакомления с основными элементами Arduino, а также написания программы «Hello World!» пришло время для знакомства с языком программирования.
Структура языка основана главным образом на C/C++, поэтому те, кто ранее программировал на этом языке, не будут испытывать затруднений при освоении программирования Arduino. Остальные должны освоить основную информацию о командах управления, типах данных и функциях.
Большая часть информации, содержащейся здесь, будет совместима с любым курсом C/C++, с учетом различий в типах данных, а также несколько конкретных инструкций, касающихся программирования портов ввода/вывода.
Внимание: Рекомендуется ознакомиться (хотя бы бегло) с курсом C++, а именно с системой счисления, алгоритмами, записи кода…
Основы основ
Несколько формальных вещей, то есть таких, о которых все знают, но иногда забывают…
В Arduino IDE, как в C/C++, необходимо помнить о регистрах символов. Ключевые слова, такие как if, for всегда записываются в нижнем регистре. Каждая инструкция заканчивается на «;». Точка с запятой сообщает компилятору, какую часть интерпретировать как инструкцию.
Скобки <..>используются для обозначения программных блоков. Мы используем их для ограничения тела функции (см. ниже), циклов и условных операторов.
Хорошей практикой является добавление комментариев к содержимому программы, это помогает легко понять код. Однострочные комментарии начинаются с // (двойная косая черта). Многострочные комментарии начинаются с /* и заканчиваются на */
Если мы хотим подключить в нашу программу какую-либо библиотеку, мы используем команду include. Вот примеры подключения библиотек:
[slh lang=»php»] #include // стандартная библиотека
#include «svoya_biblioteka.h» // библиотека в каталоге проекта
[/slh]
Функции в Arduino
Функция (подпрограмма) является отдельной частью программы, выполняющая некоторые операции. Функции используются для упрощения основной программы и улучшения читаемости кода. Полезно использовать функции, поскольку мы можем легко использовать их во многих своих проектах.
Стандартный курс программирования содержит информацию о функциях, которые приведем в следующих статьях. В случае с Arduino функции будут обсуждаться в начале, потому что даже простейшая программа должна иметь две специальные функции. Это уже упоминалось в предыдущих статьях, но здесь мы систематизируем эту информацию.
Объявление функции
Схема объявления функции выглядит следующим образом:
тип — это имя любого доступного типа данных на данном языке программирования. Список типов, доступных при программировании Arduino приведем в отдельной статье.
После исполнения, функция вернет значение объявленного типа. В случае, если функция не принимает никакого возвращаемого значения, то тип данных будет «void».
имя_функции позволяет ее однозначно идентифицировать. Для того чтобы вызвать (запустить) функцию, мы даем ей имя.
параметр — параметр вызова функции. Параметры не обязательны, но зачастую они бывают полезны. Если мы напишем функцию, у которой нет аргументов, мы оставляем круглые скобки пустыми.
Внутри скобок «<…>» содержится собственно тело функции или инструкция, которые мы хотим выполнить. Описание конкретных инструкций укажем в отдельной статье.
Все функции, возвращающие значение, заканчиваются оператором return, за которым следует возвращаемое значение. Только функции, объявленные нулевым указателем («void»), не содержат оператор return. Необходимо знать, что оператор return завершает выполнение функции независимо от местоположения.
Ниже приведены некоторые примеры деклараций функций.
Как вы можете видеть на примерах, объявление функции может принимать различные формы в зависимости от ваших потребностей.
Настоятельно рекомендуем вам изучить и применять функции при написании собственных программ. Со временем, у каждого программиста набирается собственная библиотека функций «на все случаи жизни», которая позволяет облегчить и ускорить процесс написания новых программ.
Теперь, когда мы знаем, как можно написать свою собственную функцию, необходимо научиться ее использовать.
Вызов функции
Все функции мы записываем в один файл/программу. Существует конечно более элегантное решение, но мы постараемся описать его в следующий раз.
Объявив функцию, мы можем использовать ее в других функциях с соответствующим именем и любыми требуемыми параметрами. Ниже приведены примеры вызова функций, которые мы привели выше:
Как вы можете видеть в примерах, вызов функции выполняется путем указания его имени и требуемого количества параметров. Важно всегда вызывать функцию в соответствии с ее объявлением.
Если функция f1() объявлена без параметров, то при ее вызове нельзя указывать никакие параметры, т.е. вызов функции f1(0) будет неверным.
Функция plus(int a, int b) требует ровно двух параметров, поэтому вызов с одним или тремя параметрами невозможно.
Вызов y=plus(1,5) приведет к выполнению функции «plus» с параметрами «1» и «5» и сохранить возвращаемое значение в переменную «y».
Функции setup() и loop().
Обладая знаниями об объявлении и вызове функций, мы можем перейти к системным функциям Arduino: setup() и loop(). Arduino IDE в обязательном порядке необходимо объявлять эти две функции.
setup () — это функция, которая вызывается автоматически при включении питания или нажатии кнопки RESET.
В соответствии с ее именем она используется для установки начальных значений переменных, деклараций входов и выходов системы, которые обычно задаются в начальных параметрах. Благодаря своей специфике эта функция не возвращает значения и не вызывается с параметрами. Правильная декларация функции setup() представлена ниже:
[slh lang=»php»] void setup ()
<
// тело функции — инициализация системы
>
[/slh]
loop () — это функция, которая вызывается в бесконечном цикле. Данная функция также не возвращает значения и не вызывается с параметрами. Ниже показано правильное объявление функции loop():
[slh lang=»php»] void loop ()
<
// тело функции — программный код
>
[/slh]
Как вы видите, объявление функции loop () идентично объявлению функции setup (). Различие состоит в выполнении этих функций микроконтроллером.
Теперь мы проанализируем следующий псевдокод:
[slh lang=»php»] void setup ()
<
on_led1 (); //включаем светодиод led1
off_led1 (); //выключаем светодиод led1
>
void loop ()
<
on_led2 (); //включаем светодиод led2
off_led2 (); //выключаем светодиод led2
>
[/slh]
В функции setup () есть две инструкции: первая включает светодиод led1, подключенный к плате (например, контакт 13), а вторая выключает светодиод led1.
Функция loop () имеет идентичные инструкции для включения и выключения светодиода led2, подключенного к плате (например, контакт 12).
В результате запуска программы светодиод led1 мигнет один раз, в то время как led2 будет загораться и гаснуть до тех пор, пока включено питание Arduino.
Нажатие кнопки RESET приведет к тому, что led1 снова мигнет один раз, а led2 снова начнет постоянно мигать.
Подведем итог:
- Функции setup () и loop () — это системные функции, которые должны быть определены в каждом проекте. Даже в ситуации, когда в одном из них мы не пропишем какой-либо код, мы все равно должны объявить эти две функции;
- Функция setup () выполняется один раз, loop() выполняется непрерывно;
- Мы создаем собственные функции в одном файле;
- Мы можем вызвать свои функции как из setup () и loop (), так и из других функций;
- Наши собственные функции можно вызывать с параметрами и возвращать значение;
- Вызов функции должен быть совершен в соответствии с ее декларацией.
Функции 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