В этой статье мы будем говорить о датчике расстояния HC-SR04, который очень популярен среди энтузиастов DIY.
Также в данной статье мы разберемся с очень простым акустическим элементом — зуммером.
Надеемся, что эта статья будет интересна разработчикам роботов и всем, кто хотел бы использовать датчик расстояния в своих проектах, пример, на фото ниже.
Однако перед этим мы рассмотрим некоторые новые приемы программирования, которые сделают наши программы еще лучше — как для Arduino, так и для человека, ответственного за создание программы, а именно для вас!
Функции без аргументов
Пока что мы поместили наш код в функции setup () {} и loop () {}. Первая была для настройки, а вторая — для бесконечного главного цикла. Например, чтобы запрограммировать (перепрошить) светодиод, подключенный к пину 13, вам нужно было написать следующую программу:
Помните, что светодиод, встроенный в Arduino, подключен к пину 13! |
1 2 3 4 5 6 7 8 9 10 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход } void loop() { digitalWrite(13, HIGH); //Включение светодиода delay(1000); //Ждем 1 секунду digitalWrite(13, LOW); //Выключение светодиода delay(1000); //Ждем 1 секунду } |
Представим себе ситуацию, что наша программа очень сложна, и мы хотим использовать перепрошивку (программирование) как подтверждение выбранных операций. Быстро выяснится, что повторное дублирование фрагмента, отвечающего за включение и выключение светодиода, требует времени у программиста. Хуже того, это также усложняет анализ всей программы.
Объявив переменную, мы можем легко ссылаться на нее много раз. Если бы мы могли записывать целые последовательности операций под простыми именами, программы были бы намного понятнее. Возможные изменения тоже были бы проще. В этом нам могут помочь функции.
При программировании на Arduino мы используем множество готовых функций, например: digitalWrite (13, HIGH);. Мы знаем, что эта запись вызывает высокое состояние (логическая 1) на выводе (пине) номер 13. Однако нам не нужно знать, как это делается. Точно так же мы можем создавать свои собственные функции. Например, рассмотрим уже упомянутую перепрошивку.
За эту операцию отвечает следующий фрагмент кода:
1 2 3 4 |
digitalWrite(13, HIGH); //Включение светодиода delay(1000); //Ждем 1 секунду digitalWrite(13, LOW); //Выключение светодиода delay(1000); //Ждем 1 секунду |
Мы можем «вытащить» его из loop () {} и сделать отдельной функцией. Как это сделать?
Сначала необходимо объявить название функции и ее тип. Мы делаем это, например: в функции loop () {} :
1 2 3 4 5 6 7 8 9 10 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход } void loop() { } void blinkedLED() { //Содержание функции } |
Как вы можете видеть перед именем функции, в этом случае blinkedLED — это тип функции. Это не более чем информация о том, возвращает ли функция какое-либо значение после своего завершения. Если да, то туда нужно ввести соответствующий тип (по типам переменных). Это может быть, например, целое число (int), символ (char), нецелое число (float) и т.д.
В этом случае есть слово void. Этот тип означает, что функция не возвращает значения. Почему мы выбрали именно этот тип? Задача функции — прошить светодиод, никакого результата (кроме видимого нашим глазом) эта операция не дает.
Если функция не дает результата, поставьте перед ней слово void! |
(Другие случаи будут обсуждаться в этой статье позже)
Скобка появляется после имени функции. А пока предположим, что в скобках ничего нет. Затем мы открываем фигурную скобку и помещаем в нее код, который должен выполняться при вызове функции. На практике:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход } void loop() { blinkedLED(); } void blinkedLED() { digitalWrite(13, HIGH); //Включение светодиода delay(500); //Ждем 0,5 секунды digitalWrite(13, LOW); //Выключение светодиода delay(500); //Ждем 0,5 секунды } |
Обратите внимание, что в loop () {} мы ввели имя нашей переменной (без префикса void). Эта операция называется вызовом функции. Загрузите программу и проверьте, работает ли она в соответствии с анимацией ниже:
Помните, что имена функций должны объяснять, что функция делает, и должны быть уникальными! Они не могут совпадать с именами переменных. |
Вернемся к ранее предполагавшейся ситуации, когда вы используете перепрошивку во многих, очень разных частях программы (для подтверждения операции). Что, если вам вдруг захотелось изменить последовательность свечения или, например, количество миганий? Вам придется изменить один и тот же фрагмент кода примерно в дюжине мест. Но если вы используете свою собственную функцию, то все, что вам нужно сделать, это изменить значение только в одном месте:
1 2 3 4 5 6 7 |
//Blink faster void blinkedLED() { digitalWrite(13, HIGH); //Включение светодиода delay(200); //Ждем 0,2 секунды digitalWrite(13, LOW); //Выключение светодиода delay(200); //Ждем 0,2 секунды } |
Домашнее задание 8.1
Напишите функцию, которая заставляет светодиод мигать (постепенное затухание и яркость). Конечно, воспользуйтесь знаниями, полученными в статье о ШИМ-сигнале.
Arduino — собственные функции с аргументами
Пришло время открыть для себя следующие секреты функции. Помните одну из наиболее часто используемых функций Arduino? Вероятно, это будет изменение состояния определенного пина, например:
1 |
digitalWrite(13, HIGH); |
В отличие от нашей функции blinkedLED (); , здесь мы вводим некоторые данные в скобках. Это может быть номер пина (вывода), состояние, которое мы хотим получить, или заполнение сигнала ШИМ. Эта информация позже используется в функциях для выполнения определенных операций.
Это аргументы, которые передаются функции. |
Обратите внимание на используемую лексику, и аргументы, и пассажи, они не использовались бессистемно. Это термины, используются всеми разработчиками! Теперь пора написать свою собственную функцию, сначала с одним аргументом.
Предположим, мы хотим отредактировать нашу функцию blinkedLED таким образом, чтобы можно было изменять скорость вспышки (мигания) при ее вызове. В нашем объявлении функции нам нужно добавить информацию о том, что она может принимать аргумент. Делаем это в заголовке функции:
1 2 3 4 5 |
//Версия ранее void blinkedLED(){ //Новая версия void blinkedLED(int time){ |
С этого момента компилятор знает, что когда он встречает вызов функции в круглых скобках, он должен ожидать число (тип int ). Это число будет передано в функцию и отобразится как время.
Это будет переменная, видимая только внутри нашей функции, т.е. это будет так называемая локальная переменная. |
На практике внутренняя часть функции будет выглядеть так:
1 2 3 4 5 6 |
void blinkedLED(int time){ digitalWrite(13, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(13, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } |
Пришло время последнего элемента, то есть вызова новой функции. Здесь, наверное, не будет ничего удивительного. Мы просто вводим число в скобках, которое будет означать время, в течение которого диод должен быть включен и выключен. Весь код выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход } void loop() { blinkedLED(50); } void blinkedLED(int time){ digitalWrite(13, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(13, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } |
Убедитесь в том, что вы точно можете влиять на частоту мигания, заменив значение в скобках. Пришло время для другого примера.
Функции с аргументом — пример 2
До сих пор непрерывное мигание светодиода было видно, потому что мы вызывали нашу функцию в цикле функции. Когда мы перемещаем вызов функции в раздел настройки, мы увидим только одну вспышку (мигание) после загрузки. Проверим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход blinkedLED(50); } void loop() { } void blinkedLED(int time){ digitalWrite(13, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(13, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } |
Это именно то, что произошло бы, если бы мы захотели использовать функцию, например, для подтверждения нажатия кнопки. Вызов blinkedLED () вызовет одно мигание.
Пришло время переписать функцию таким образом, чтобы помимо изменения времени мигания можно было также влиять на количество миганий. Во-первых, нам нужно изменить объявление функции:
1 2 3 4 5 |
//Старая версия void blinkedLED(int time){ //Новая версия void blinkedLED(int time, int howmany){ |
Мы добавили числовой аргумент, он будет отвечать за количество миганий. Этот параметр может быть другого типа, это не имеет значения. Важно, чтобы аргумент был соответствующий.
Функция может принимать множество аргументов разных типов! |
Как вы, наверное, догадались, использовать второй аргумент очень просто. У нас просто теперь есть вторая локальная переменная, howmany.
Надеюсь, вы уже знаете, какой цикл использовать, чтобы лучше контролировать количество миганий? Если нет, обратитесь к предыдущему разделу, где мы рассмотрели циклы. Однако мы предполагаем, что вы усвоили этот материал (или собираетесь восполнить недостатки) и представляем новую функцию blinkedLED:
1 2 3 4 5 6 7 8 |
void blinkedLED(int howmany, int time){ for (int i=0; i < howmany; i++) { digitalWrite(13, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(13, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } } |
Проверим весь код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход blinkedLED(100, 5); } void loop() { } void blinkedLED(int time, int howmany){ for (int i=0; i < howmany; i++) { digitalWrite(13, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(13, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } } |
Все должно работать. Теперь после запуска, светодиод должен мигнуть ровно 5 раз. Но как Arduino знает, как различать информацию в скобках, сколько времени работать и сколько повторений нужно сделать?
Что ж, правило очень простое — последовательные значения, разделенные запятыми, присваиваются следующим аргументам, описанным в объявлении функции. В приведенном выше случае, первое число всегда будет считаться временем, а второе — счетчиком повторов.
Домашнее задание 8.2
Напишите функцию, позволяющую отдельно регулировать количество миганий, время выключения светодиода и время включения светодиода.
Можно ли расширить нашу функцию? Конечно! Разве не было бы удобно, если бы, помимо объявления времени и количества повторов, можно было указать пин (вывод), к которому подключен светодиод?
Функции с аргументами — пример №3
Пин, к которому подключен светодиод, — это номер в нашей программе. Мы используем его в двух местах при объявлении данного пина (вывода) в качестве выхода и при установке высокого или низкого состояния. Значит, это число может быть еще одним аргументом нашей функции!
Сначала подключите второй диод к другому пину, например, № 8:

Мы не будем здесь больше вдаваться в подробности, сразу же представим весь пример программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход blinkedLED(100, 5, 13); blinkedLED(150, 4, 8); } void loop() { } void blinkedLED(int time, int howmany, int pin){ for (int i=0; i < howmany; i++) { digitalWrite(pin, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(pin, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } } |
Давайте проверим, работает ли? Не совсем, правда? Мигает только светодиод, подключенный к пину 13, а тот, что под номером 8, не хочет подавать признаков жизни. Почему? Что ж, мы совершили очень простую ошибку, которую легко допустить при написании таких функций. Мы нигде не предусмотрели, что другие пины (кроме 13) могут быть выходами. Проверьте раздел настройки:
1 2 3 4 5 |
void setup() { pinMode(13, OUTPUT); //Конфигурация пина 13 как выход blinkedLED(100, 5, 13); blinkedLED(150, 4, 8); } |
Мы можем исправить это относительно легко, нам просто нужно передать конфигурацию контактов нашей функции. Это выглядело бы так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void setup() { blinkedLED(100, 5, 13); blinkedLED(150, 4, 8); } void loop() { } void blinkedLED(int time, int howmany, int pin){ pinMode(pin, OUTPUT); //Конфигурация как выход for (int i=0; i < howmany; i++) { digitalWrite(pin, HIGH); //Включение светодиода delay(time); //Ждем некоторое время digitalWrite(pin, LOW); //Выключение светодиода delay(time); //Ждем некоторое время } } |
Сейчас все работает, но должны признать, что это не самое лучшее решение. Поэтому мы не рекомендуем использовать этот тип решений в более профессиональных проектах. Однако на этапе понимания ничего плохого случиться не должно, и мы можем облегчить себе жизнь с помощью такой простой функции.
Пришло время рассказать последнюю информацию, прежде чем мы перейдем к датчику расстояния.
Функции, возвращающие результат
До сих пор мы использовали только функции, которые выполняли некоторую операцию, но не должны были возвращать какой-либо результат. Задачей новой функции будет вычисление площади квадрата с заданной стороной и вернуть результат (вычисленную площадь). Сначала нужно объявить функцию, на этот раз это будет выглядеть так:
1 |
int squareField(int a) { |
Как видите, в дополнение к аргументу (стороне квадрата) перед функцией появилось целое число. Это означает, что он вернет результат, который является числом. В данном случае это, конечно же, расчетная площадь.
Внутренняя часть функции должна выглядеть так:
1 2 3 4 5 6 |
int squareField(int a) { int result = 0; result = a * a; return result; } |
Мы выделили здесь строку со словом return. После него мы помещаем значение (переменную), которое возвращается в результате этой функции. Итак, для аргумента 4 результат функции должен быть 16, потому что 4 * 4 = 16. Зачем это нужно?
Давайте посмотрим пример ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { Serial.begin(9600); } void loop() { int result = squareField(4); Serial.println(result); //Показать сообщение delay(500); } int squareField(int a) { int result = 0; result = a * a; return result; } |
Запустите пример. Результат операции должен появиться на мониторе последовательного порта, т.е. 16. Тот факт, что функция возвращает результат, означает, что после ее выполнения в том месте, где она вызывается, «результат будет заменен». В этом случае вместо squareField (4); 16 подставляется и записывается в переменную result.
Однако объявление отдельной переменной излишне. Следующая запись также будет работать правильно (но немного менее понятно):
1 2 3 4 5 6 |
//Старая версия int result = squareField(4); Serial.println(result); //Показать сообщение //Новая версия Serial.println(squareField(4)); //Показать сообщение |
Для полноты счастья, нам не хватает только того, чтобы сторона квадрата могла быть отправлена на Arduino с компьютера. Здесь мы будем использовать знания из статьи о связи через UART. Программа будет выглядеть следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
String receivedData = ""; //Пустая строка получения данных void setup() { Serial.begin(9600); } void loop() { if(Serial.available() > 0) { //Получил ли Arduino данные receivedData = Serial.readStringUntil('\n'); //Если да, то записать в полученную переменную receivedData int result = squareField(receivedData.toInt()); Serial.println(result); //Показать сообщение } } int squareField(int a) { int result = 0; result = a * a; return result; } |
Однако новинка в нашей программе — это receiveData.toInt () . Как вы, наверное, помните, все символы отправляются в виде кодов ASCII при общении через UART. Следовательно, во время наших тестов мы не могли легко отправлять числа в Arduino.
Однако это можно очень легко изменить. Достаточно добавить к прочитанной строке ().toInt () . Это преобразует число, отправленное в виде текста, в число типа int.
Операция изменения типа переменной на другой, называется проекцией. |
Домашнее задание 8.3
Напишите функции, вычисляющие площадь прямоугольника, круга и треугольника. Отправляйте результаты на ПК через UART!
Ультразвуковой датчик расстояния HC-SR04
Пришло время описать датчик расстояния. Датчик HC-SR04 состоит из передатчика и приемника ультразвука и нескольких интегральных схем. Благодаря им, основываясь на том, как отражается акустический сигнал (неслышимый для человека), мы можем довольно точно определить расстояние датчика от препятствия. Прямо как… летучие мыши:
Но вернемся к Arduino и датчику расстояния. Во-первых, давайте сосредоточимся на его четырех сигнальных контактах. Два из них используются для питания схемы (Vcc, GND), а два других (триггер и эхо) для выполнения измерений.
Триггер — это вход триггера. Когда мы дадим ему высокое состояние (как минимум на 10 микросекунд), начнется измерение расстояния. С другой стороны, по выходному эхо- сигналу мы можем прочитать измеренное расстояние. Максимальная дальность действия этой незаметной схемы заявлена производителем и составляет 4 метра.
![]() |
![]() |
Задняя часть датчика | Передняя часть датчика |
Пришло время для первого простого примера использования датчика на практике.
Измерение расстояния
Теперь будет измерять расстояния через определенные промежутки времени и отображать их на экране компьютера. Для этого необходимо собрать схему как показано на фото:
Описание контактов физически находится на датчике, но для формальности мы его представим ниже. Если смотреть сверху (как на схеме выше) и слева:
- Vcc — 5 В
- Триггер
- Эхо
- Gnd
Фото сборки мы выложили ниже. Не обращайте внимание на зеленый провод, мы забыли его отсоединить при фотографировании:

В нашем случае мы подключаем триггерный вход к контакту № 12, а эхо — к контакту № 11.
1 2 |
#define trigPin 12 #define echoPin 11 |
Вы уже более или менее знаете, как запустить измерение расстояния. Пора записать это как программу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Пин, к которому мы подключим треггер в качестве вывода pinMode(echoPin, INPUT); //и эхо, как вход } void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); //Измерение сделано } |
Обратите внимание на новую функцию delayMicroseconds (); , это не что иное, как аналог известной функции delay (); . Разница, наверное, очевидна. Новая функция ведет обратный отсчет в микросекундах. Напомню, что использованная функция задержки измеряется в миллисекундах.
Последовательность начала измерения очень проста. Вначале мы устанавливаем низкий уровень сигнала на контакте, подключенном к триггерному входу датчика. Достаточно 2 микросекунд, затем установите высокое состояние на 10 микросекунд. Датчик измеряет и возвращает результаты на вывод эхо-сигнала.
Вопрос в том, как это считать? Нужен ли мне для этого UART или другой интерфейс связи? Нет, к счастью, этот датчик очень простой, и измеренное расстояние представлено импульсом (высокое состояние) на выводе эхо-сигнала. Его длина пропорциональна расстоянию. Чем она длиннее, тем больше измеренное расстояние. Здесь пригодится новая функция, доступная в Arduino.
Измерение длительности импульса в Arduino
К счастью, в Arduino реализована очень простая функция, которая может измерять длительность импульса, подаваемого на любой вход. Его продолжительность должна составлять от 10 микросекунд до 3 минут. Измерение начинается, когда обнаруживается изменение состояния вывода.
Это очень просто:
1 2 |
int result = 0; result = pulseIn(11, HIGH); |
Функция в простейшей форме принимает только два аргумента. Номер контакта, который необходимо проверить, и измеряемый логический уровень (низкий / высокий).
Итак, чтобы измерить расстояние, мы должны выполнить следующую операцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Пин, к которому мы подключим треггер в качестве вывода pinMode(echoPin, INPUT); //и эхо, как вход } void loop() { long time; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); time = pulseIn(echoPin, HIGH); Serial.print(time); delay(500); } |
Когда вы запустите такую программу, на экране начнут появляться числа. Чем ближе к датчику находится препятствие, тем оно будет меньше. Однако они далеки от используемых нами единиц. Чтобы результаты измерения были удобочитаемыми, результат необходимо разделить на «магическое число».
Проверьте, как работает следующая программа — теперь результат должен отображаться в сантиметрах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Пин, к которому мы подключим треггер в качестве вывода pinMode(echoPin, INPUT); //и эхо, как вход } void loop() { long time, distance; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); time = pulseIn(echoPin, HIGH); distance = time / 58; Serial.print(distance); Serial.println(" cm"); delay(500); } |
Конечно, значение, на которое мы делим (58), не является «волшебным». Это результат времени, в течение которого звук распространяется на расстояние 1 см, и шаблона для расстояния, представленного производителем.
Функция, которая возвращает расстояние до датчика в см
Как видите, часть программы, позволяющая получить измерения, относительно длинна. Было бы удобней, если бы у нас была функция, которая все это делает. Не нужно ждать, представляем готовый фрагмент, в конце концов, это всего лишь копия приведенного выше кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int measureOdistance() { long time, distance; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); time = pulseIn(echoPin, HIGH); distance = time / 58; return distance; } |
Теперь в нужном месте программы достаточно вызвать функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Пин, к которому мы подключим треггер в качестве вывода pinMode(echoPin, INPUT); //и эхо, как вход } void loop() { Serial.print(measureOdistance()); Serial.println(" cm"); delay(500); } int measureOdistance() { long time, distance; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); time = pulseIn(echoPin, HIGH); distance = time / 58; return distance; } |
Так гораздо понятнее, правда?
Проверка диапазона расстояний
Пришло время для последнего объяснения в этой статье, посвященной основам Arduino. На этот раз давайте добавим в нашу схему зуммер, то есть звуковой элемент. Это выглядит так:
![]() |
![]() |
Зуммер с наклейкой сзади | Зуммер без наклейки |
Этот элемент имеет два входа, когда на один из них подается напряжение Vcc, а на другой — заземление, то зуммер начинает издавать громкий писк. Это не очень приятно, поэтому предлагаю вам оставить и не снимать наклейку (писк будет тише). Как нетрудно догадаться по надписи, эта этикетка защищает внутреннюю часть зуммера при ее промывке на производстве. В основном это делается для удаления следов припоя.
Зуммер — это полярный элемент! Обратите внимание, что одна из ножек длиннее, и на корпусе рядом с ней вы найдете значок плюса. |
Чтобы использовать зуммер, подключите его к Arduino в соответствии со схемой ниже:

Символ, который мы использовали для рисования схемы сборки, немного отличается от зуммера, поэтому вы можете дополнительно посмотреть фото нашего макета:

На этот раз мы напишем функцию, задачей которой будет проверка, находится ли объект на определенном расстоянии от датчика. В этом случае раздастся звуковой сигнал зуммера.
Функция проверки диапазона будет использовать предыдущую функцию measureOdistance () :
1 2 3 4 5 6 7 8 |
void range(int a, int b) { int howAway = measureOdistance(); if ((howAway > a) && (howAway < b)) { digitalWrite(2, HIGH); //Включаем зуммер } else { digitalWrite(2, LOW); //Отключаем зуммер, когда объект выходит за рамки } } |
Мы передаем два целых числа в качестве аргументов функции. Затем мы проверяем, больше ли измеренное расстояние, чем начальное значение нашего интервала (a), и меньше, чем максимальное значение (b) .
Кстати, вы можете видеть, что с помощью символов && мы объединяем несколько условий в одно. |
Готовая программа выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#define trigPin 12 #define echoPin 11 void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); //Пин, к которому мы подключим триггер в качестве вывода pinMode(echoPin, INPUT); //и эхо, как вход pinMode(2, OUTPUT); //Выход для зуммера } void loop() { range(10, 25); //Включить зуммер, если на расстоянии от 10 до 25 см от датчика есть препятствие delay(100); } int measureOdistance() { long time, distance; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); time = pulseIn(echoPin, HIGH); distance = time / 58; return distance; } void range(int a, int b) { int howAway = measureOdistance(); if ((howAway > a) && (howAway < b)) { digitalWrite(2, HIGH); //Включаем зуммер } else { digitalWrite(2, LOW); //Отключаем зуммер, когда объект выходит за рамки } } |
Проверьте, как программа работает на практике. На наш взгляд, она идеально подойдет для создания простой панели управления сигнализацией, которая будет следить за вашим домом!
Домашнее задание 8.4
Напишите программу, которая показывает расстояние от препятствия до датчика на светодиодной полосе. Чем ближе препятствие к датчику, тем больше светодиодов должно зажеться. Пример полосы можно собрать следующим образом:

Домашнее задание 8.5
Проверьте, как меняются показания датчика, в зависимости от материала препятствия. Вы видите разницу в отображаемом расстоянии, когда датчик нацелен, например, на твердые или мягкие объекты? Сравните такие препятствия, как стена, одеяло, лист бумаги.
Вывод
Практика показывает, что вы просто должны знать весь материал изложенный в наших статьях по основам Arduino! Эти знания предостерегут вас от серьезных ошибок в будущих проектах. Надеемся, что вам нравяться наши статьи. Если вам они действительно интересны, то напишите нам об этом в комментариях, а мы в свою очередь, обещаем добавлять в этот раздел самую важную для вас информацию.
С Уважением, МониторБанк