Опубликовано

Ходовая часть мобильных роботов

По материалам книги “Мобильные роботы на базе Arduino, 3-е изд.“, 3-е изд. (автор Михаил Момот) (глава 5. Ходовая часть)

Мобильные роботы на базе Arduino, 3-е изд.

Выбор двигателей

Итак, когда структура ходовой части выбрана, следует определить, какие двигатели будет использовать наш робот. На выбор: коллекторные двигатели постоянного тока с редуктором, сервопривод MG995 3600 постоянного вращения (скорость вращения задается сигналом на входе управления), шаговые двигатели. Их параметры представлены в табл. 5.1.

Таблица 5.1. Сравнительные параметры различных типов двигателей

Сравниваемые параметры Двигатель
постоянного тока с понижающим редуктором
Сервопривод MG995 3600 Шаговый
двигатель
Количество задействованных портов микроконтроллера для управления 2–3 1 2–3
Скорость реакции на поступившую команду, сек (чем больше, тем хуже) ~1/100 ~1/50 ~1/1000
Скорость вращения (с учетом понижающего редуктора), об/мин 10–240 1–60 0,1–300
Стоимость (за единицу принята стоимость двигателя постоянного тока с редуктором), сравниваются двигатели, равные по мощности 1 4 6
Минимальное количество портов управления ходовой частью для проекта колесного робота с двумя ведущими колесами 4 2 4+1
дополнительный контакт требуется для отключения всех моторов

Что мы здесь видим?

  • Коллекторные моторы с пластиковым редуктором — самые простые и самые дешевые.
  • Сервопривод MG995 3600 — наиболее экономичный по ресурсам контроллера Arduino. При его использовании хорошо регулируется скорость движения робота, если скорость колес нужно менять постоянно и держать в заданных пределах. Скорость оборота колеса, вращаемого сервоприводом, зависит только от установленного на порту управления значения сигнала, и при увеличении сопротивления (когда, например, робот движется в гору) меняется слабо, в то время как двигатель постоянного тока без обратной связи по скорости изменяет скорость своего вращения в зависимости от нагрузки.
  • Шаговый двигатель следует применять там, где нужна точность, и если это необходимо, обратитесь к книге «Мобильные роботы на базе ESP32 в среде Arduino IDE»[1], там как раз используются шаговые моторы в качестве ходовой части. Шаговым двигателем также можно держать постоянную скорость.

Все три вида двигателей применяются в ходовых частях колесных роботов, и выбор зависит от требований, предъявляемых к роботу.

Однако мы только учимся, и сверхскоростной болид нам ни к чему, скорость реакции и скорость вращения не важны, а вот низкая стоимость имеет определяющее значение на начальном этапе. Поэтому для дальнейшего рассмотрения выбираем самое распространенное решение: коллекторный мотор с пластиковым редуктором.

Драйверы двигателей

Платы Arduino, кроме специализированных, не поддерживают возможностей управления двигателями постоянного тока напрямую, и для этого нужно применять специализированные микросхемы, называемые драйверами двигателей. Наиболее распространенные из них приведены в табл. 5.2.

Таблица 5.2. Специализированные микросхемы драйверов двигателей (на платах)

Характеристики TB6612FNG
(рис. 5.6)
MX1508
(рис. 5.7)
L298N
(рис. 5.8)
Максимальный ток на канал, А 1,2 1,2 2
Количество подключаемых коллектроных моторов 2 2 2
Максимальное напряжение питания, В 13,5 10 35
Минимальное напряжение питания, В 2,5 2,5 6
Встроенная диодная защита от паразитных токов Есть Есть Есть

Все три платы драйверов подходят для управления направлением вращения и мощностью коллекторных двигателей постоянного тока. Они также могут применяться и для управления шаговыми двигателями.

Драйверы_2

Рис. 5.6. Плата драйвера TB6612FNG

Драйверы TB6612 и L298N имеют отдельные входы управления мощностью моторов (PWMA–PWMB и ENA–ENB соответственно), но если на эти входы подать высокое логическое напряжение (5 вольт), то управление драйверами TB6612, L298N и MX1508 будет осуществляться схоже по входам AIN1–AIN2 и BIN1–BIN2 — для TB6612, а также IN1–IN2 и IN3–IN4 — для L298N и MX1508. Именно такие режимы работы мы и будем использовать, чтобы наша программа вела себя одинаково и независимо от того, какой драйвер моторов вы решили использовать в своей модели.

5

Рис. 5.7. Плата драйвера MX1508

5

Рис. 5.8. Плата драйвера L298N

 

В табл. 5.3 приведены значения сигналов на входах и показана соответствующая реакция двигателя.

Таблица 5.3. Значения сигналов на входах и соответствующая реакция двигателя

IN1 (AIN1) IN2 (AIN2) Мотор A (направление вращения условное)
0 0 Отключен
0 1 Вал вращается против часовой стрелки
1 0 Вал вращается по часовой стрелке
1 1 Отключен

Таблица 5.3 (окончание)

IN3 (BIN1) IN4 (BIN2) Мотор B (направление вращения условное)
0 0 Отключен
0 1 Вал вращается против часовой стрелки
1 0 Вал вращается по часовой стрелке
1 1 Отключен

 

Сборка макета

Для закрепления материала полезно собрать несколько макетов, которые продемонстрируют работу двигателей постоянного тока вместе с драйвером L298N, можно также выполнить этот тест и на MX1508, а подключение TB6612FNG мы рассмотрим позднее.

Управляем двигателем без Arduino

Возьмем драйвер L298N (или MX1508), двигатели постоянного тока, аккумуляторы с боксом, провода, керамические конденсаторы 0,1 мкФ (маркируются числом 104) — они нужны для исключения электромагнитных наводок, которые возникают при работе двигателей и могут стать причиной сбоев в работе электроники робота, и паяльник. При пайке легко испортить поверхность стола, поэтому используйте фанеру или постелите на место работы с паяльником пару листов бумаги.

Очистим и залудим паяльником двужильный провод (или пару одножильных),
затем залудим контакты двигателя и ножки конденсатора (рис. 5.9).

2017-01-28 12-10-46

Рис. 5.9. Двигатель постоянного тока, керамический конденсатор и провода

Обмотаем ножки конденсатора вокруг залуженных кончиков проводов, как показано на рис. 5.10, — теперь ножки конденсатора хорошо держатся на проводе, и их легко можно припаять (рис. 5.11).

2017-01-28 12-13-24 2017-01-28 12-14-34 (2)
Рис. 5.10. Ножки конденсатора обмотаны
вокруг оголенных концов провода
Рис. 5.11. Пайка конденсатора

Далее припаяем кончики проводов к залуженным контактам двигателя (рис. 5.12). Если лужение контактов двигателя проходит плохо, аккуратно зачистите контакты перочинным ножом или обработайте паяльной кислотой (после паяльной кислоты нужно промыть контакты спиртом или водой).

Готовый к работе двигатель показан на рис. 5.13.

2017-01-28 12-16-20

Рис. 5.12. Припаивание проводов к контактам двигателя

5

Рис. 5.13. Двигатель с припаянными проводами и конденсатором

Картинка мотор+аккумул_bb

Рис. 5.14. Схема тестирования двигателя

Качество пайки можно проверить, присоединив двигатель к аккумуляторам (рис. 5.14), — если двигатель не работает, значит, пайка выполнена некачественно (предварительно проверьте наличие напряжения на контактах аккумуляторного бокса!).

Теперь, когда двигатели готовы, приступим к сборке схемы, изображенной на рис. 5.15. Перемычки на контактах ENA и ENB драйвера не убираем!

Картинка драйвер +мотор_стенд_bb

Рис. 5.15. Схема управления двигателями без контроллера Arduino

Двигатели подключаются к драйверу через винтовые зажимы, также подключается и аккумуляторный бокс, для контактов IN1–IN4 драйвера L298N лучше использовать провода с готовыми клеммами Dupont (см. главу 2), а для MX1508 требуется пайка.

Подключая 5 вольт к различным контактам IN1–IN4, можно проследить, как изменяется вращение двигателей M1 и M2 (используйте данные табл. 5.4).

Подсказка

Контакты IN1 и IN2 отвечают за работу двигателя М1, а IN3 и IN4 — двигателя М2.

Широтно-импульсная модуляция

Проведем наглядный эксперимент: отключим контакт IN1 мотора М1, а контакт IN2 будем руками быстро подключать к напряжению 5 вольт и отключать от него, — мотор станет вращаться с заметными рывками.

Если же делать эту операцию с высокой скоростью — такой, на которую способен контроллер, то вал мотора будет вращаться без рывков, но мощность на валу окажется меньше, чем при постоянно включенном IN2. То есть передаваемая на вал мощность зависит от частоты переподключения и длительности включения, и если время включения мало, а время отключения относительно времени включения
велико, то и выдаваемая мощность будет мала, и наоборот. Этот подход к регулированию мощности вращения двигателей постоянного тока называется широтно-импульсной модуляцией.

Мы в наших проектах будем использовать шкалу мощности от 0 до 255, где число — это относительная длительность импульса включения мотора за период (рис. 5.16). А чтобы иметь возможность изменять направление вращения, задействуем и отрицательную шкалу: –255…0…255, при этом изменяя вход драйвера, на который подается сигнал (при положительном вращении — на IN1, при отрицательном — на IN2 для мотора М1 и IN3/IN4 — для мотора М2).

рис 5_14

Рис. 5.16. Принцип работы ШИМ

Подключаем контроллер Arduino

Поскольку у нас есть три разных драйвера управления моторами, рассмотрим для них такие схемы подключения, которые позволят использовать один универсальный программный код.

Добавим к собранной схеме контроллер Arduino и научим его управлять двига-
телями. Дополнительно нам потребуется несколько проводов с клеммами Dupont.

l298nMP

Рис. 5.17. Схема управления двигателями для драйверов L298N и MX1508

На рис. 5.17 показана схема подключения драйверов L298N и MX1508, на рис. 5.18 и 5.19 — схема подключения TB6612FNG (она несколько сложнее).

Дело в том, что подключение драйвера TB6612FNG потребует немного больше соединений, т. к. нужно подать логическую единицу (5 вольт от Arduino) на контакты VCC, PWMA, PWMB и STBY, в остальном же схема схожа с подключением L298N и MX1508. Чтобы исключить на рисунках пересечение соединений и неверную их трактовку, схема подключения драйвера TB6612FNG разбита на две части: подключение силовой части (рис. 5.18) и логической части (рис. 5.19).

Удобно при этом задействовать дополнительные платы, которые упрощают реализацию соединений, — например Arduino Sensor shield V5.0 (для Arduino Uno) или NANO V3.0 Shield (для Arduino Nano).

Далее приведены примеры управления вращением двигателей при помощи программы, работающей на контроллерах Arduino UNO, Arduino Nano и Arduino Pro Mini.

23_tb6612fngPower_МП

Рис. 5.18. Схема управления двигателями для драйвера TB6612FNG (силовая часть)

23_tb6612fngCom_МП

Рис. 5.19. Схема управления двигателями для драйвера TB6612FNG (логическая часть)

Подключаем библиотеку mobrob3.zip и пишем тестовую программу

Специально для этого издания книги ее автор разработал библиотеку mobrob3.zip.
В ней, в частности, содержится модуль управления мощностью пары моторов
(см. далее).


Электронный архив

Электронный архив, включающий библиотеку mobrob3.zip, можно скачать с сервера издательства «БХВ» по ссылке https://zip.bhv.ru/9785977517034.zip или со страницы книги на сайте https://bhv.ru/ (см. приложение).


Перед использованием библиотеку mobrob3.zip нужно добавить в Arduino IDE стандартным способом: Скетч | Подключить библиотеку | Добавить .ZIP библиотеку, и выбрать с диска файл mobrob3.zip. В результате все модули и примеры из этой книги (по главам) станут доступны в Arduino IDE. Для управления моторами в библиотеку включен модуль mobrob3xmotor.h, в котором учтены некоторые особенности управления моторами для генерации ШИМ, заключающиеся в том, что в качестве левых моторов будущего робота можно использовать только контакты GPIO 2 и 3 (менять их местами можно), а для правого мотора — только 4 и 5 (их также можно менять местами, чтобы добиться вращения в нужную сторону). Подобное ограничение связано с тем, что генерация ШИМ возможна только на контактах 3 и 5 GPIO.

Логика работы тестовой программы управления двигателями (листинг 5.1) следующая.

В бесконечном цикле:

  1. Отключаем оба двигателя.
  2. Ждем 1 секунду.
  3. Подключаем двигатель 1 на полную мощность по часовой стрелке.
  4. Ждем 1 секунду.
  5. Отключаем двигатель 1.
  6. Ждем 1 секунду.
  7. Подключаем двигатель 1 на полную мощность против часовой стрелки.
  8. Ждем 1 секунду.
  9. Отключаем двигатель 1.
  10. Возвращаемся на пункт 1.

Самостоятельно измените эту программу для управления двигателем 2.

Листинг 5.1. Тестовая программа управления двигателями

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
// Контакты управления левого мотора только 2 и 3.
# define GPIO_1F 2
# define GPIO_1B 3
// Контакты управления правого мотора только 4 и 5.
# define GPIO_2F 4
# define GPIO_2B 5
 
// Подключаем библиотеку управления моторами.
#include < mobrob3xmotor.h>
void setup()
{
// Вызываем функцию инициализации моторов.
motor_setup();
}
 
// Основная программа.
void loop()
{
motors_power(0, 0); // Отключены оба.
delay(1000);
motors_power(255, 0); // Включен мотор 1 +
delay(1000);
motors_power(0, 0); // Отключены оба.
delay(1000);
motors_power(-255, 0); // Включен мотор 1 -
delay(1000);
// Проделайте те же операции для двигателя 2 самостоятельно.
// ....
}

Добавляем регулирование на основе ШИМ

Рассмотренная и подключенная в предыдущем разделе библиотека mobrob3.zip уже содержит модуль mobrob3xmotor.h, который может регулировать мощность моторов при помощи ШИМ.

Напомню, что значения ШИМ в Arduino могут изменяться от 0 до 255. На практике вал двигателя не сразу начнет вращаться — сначала (при малых значениях) двигатель станет гудеть и лишь по достижении определенного значения ШИМ начнет медленно увеличивать обороты, что связано с недостатком мощности для компенсации сил трения.

Тестовая программа управления двигателями с регуляцией на основе ШИМ

Логика работы этой тестовой программы (листинг 5.2) следующая.

В бесконечном цикле:

  1. Отключаем оба двигателя.
  2. Ждем 1 секунду.
  3. Далее в цикле через 100 миллисекунд увеличиваем мощность от 70 до 255 для обоих моторов.
  4. Далее в цикле через 100 миллисекунд уменьшаем мощность от 255 до 70 для обоих моторов.
  5. Возвращаемся к пункту 1.

Итогом работы программы будет ускоряющееся вращение двигателей в одну сторону, а затем такое же торможение и остановка.

Самостоятельно измените программу так, чтобы моторы разгонялись в разные стороны.

Листинг 5.2. Тестовая программа управления двигателями с регуляцией на основе ШИМ

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
// Зададим номера контактов управления моторами.
// Контакты управления левого мотора только 2 и 3.
# define GPIO_1F 2
# define GPIO_1B 3
// Контакты управления правого мотора только 4 и 5.
# define GPIO_2F 4
# define GPIO_2B 5
// Подключаем библиотеку управления моторами.
#include <mobrob3xmotor.h>
void setup()
{
// Вызываем функцию инициализации моторов.
motor_setup();
}
//=================================================================
// Основная программа.
void loop()
{
motors_power(0, 0);
delay(500);
for (int i = 70; i < 255; i++)
{
motors_power(i, i);
delay(100);
}
for (int i = 255; i > 70; i--)
{
motors_power(i, i);
delay(100);
}
}

Выводы

Итак, тип ходовой выбран — это колесная ходовая часть с двумя ведущими колесами. Выбран и используемый тип двигателей — это двигатель постоянного тока
с понижающим редуктором. Рассмотрен способ управления двигателями посредством специального драйвера. Определен порядок подключения и управления двигателями.

Для закрепления теоретических знаний собраны и опробованы на практике различные схемы управления двигателями постоянного тока. Следующий шаг — сборка базовой модели робота.

  1. См. https://bhv.ru/product/mobilnye-roboty-na-baze-esp32-v-srede-arduino-ide/.
Опубликовано

Воспроизведение звуковых файлов на Arduino

По материалам книги С. Монка «Мейкерство. Arduino и Raspberry Pi» (глава 15 «Звук»)

Мейкерство. Arduino и Raspberry Pi

Эксперимент: громкоговоритель без усилителя на Arduino

Для воспроизведения более или менее сложного звука понадобится какой-нибудь громкоговоритель. Громкоговорители, появившиеся почти сто лет назад, в большинстве своем работают на основе соленоида (см. разд. «Соленоиды» главы 7) — содержащаяся в них электромагнитная катушка с достаточно высокой частотой колеблет жесткий конус, создающий звуковые волны.

На громкоговорители обычно наносится маркировка в омах. И хотя этой единицей измеряется резистивное сопротивление, но применительно к громкоговорителям говорят, что это их импеданс. По своему смыслу этот термин тоже означает сопротивление, но он применяется к приборам, не являющимся резисторами в полном смысле этого слова, и имеющаяся в громкоговорителе проводная катушка (как и любая такая катушка) не работает как простой резистор. Если вы заинтересовались этой проблематикой, можете почитать статьи, посвященные индуктивности.

Обычно на громкоговорителях встречаются значения 4 или 8 ом. И если вы собираетесь подключить 8-омный громкоговоритель к выходу Arduino с напряжением 5 В, то с полным основанием можете ожидать возникновения тока, равного по силе:

I = V / R = 5 / 8 = 625 мА

То есть, тока намного большего, чем те 40 мА, которые рекомендуются для выходного контакта Arduino. Похоже, нам и здесь понадобится согласующий резистор!

Итак, в этом эксперименте мы подключим громкоговоритель к Arduino через резистор, а затем воспользуемся окном монитора порта, чтобы научить Arduino воспроизводить звук конкретной частоты.


Звуковые частоты

Частота звуковой волны в музыкальных терминах называется тоном и выражается в количестве звуковых волн, достигающих ваших ушей за одну секунду. Мне нравится представлять звуковые волны в виде ряби на пруду. Звук высокой частоты — скажем, 10 кГц (килогерц), создает 10 000 звуковых волн в секунду, а звук низкой частоты (скажем, 100 Гц) — всего 100 звуковых волн в секунду. Человек обычно слышит звуки в диапазоне от 20 Гц до 20 кГц, но верхняя граница с возрастом снижается. Звуки выше 20 кГц обычно называют ультразвуком.

У животных другие диапазоны слышимых звуков. Например, кошки могут слышать частоты вплоть до 55–79 кГц, а летучие мыши известны тем, что вообще пользуются ультразвуковой эхолокацией.

В музыке самая низкая нота «До» на обычном пианино соответствует частоте 32,7 Гц, а самая высокая — частоте 4186 Гц. Известное всем, имеющим хоть какое-то касательство к музыке, понятие октава означает удваивание частоты. Поэтому, если заставить на клавиатуре пианино зазвучать две ноты «До» смежных октав, то вторая нота будет звучать с удвоенной частотой первой ноты.


Комплектующие

Для этого эксперимента много деталей не потребуется — только громкоговоритель и резистор, хотя, если воспользоваться макетной платой и перемычками, подключения можно упростить (табл. 15.1).

Таблица 15.1. Комплектующие для работы с Arduino в эксперименте с громкоговорителем

Компонент схемы Источники
Небольшой громкоговоритель с импедансом 8 Ом Adafruit: 1891
Резистор 270 Ом 0,25 Вт Mouser: 291-270-RC
400-точечная беспаечная макетная плата Adafruit: 64
Перемычки «папа-папа» Adafruit: 758

Громкоговоритель я извлек из старого радиоприемника, и у него оказался разъем, в который можно было вставить штекерные наконечники перемычек. Вам может достаться громкоговоритель с припаянными к нему проводами, которые удастся воткнуть в разъемы Arduino, или же вам придется подпаять к этим проводам выводы, толщина которых позволит воткнуть их в гнезда монтажной платы.

Макетная схема эксперимента

Схема, собранная для проведения эксперимента на макетной плате, показана на рис. 15.1.

mkac_1501

Рис. 15.1. Схема эксперимента с громкоговорителем на Arduino в сборе

Один провод от громкоговорителя подключается к контакту GND (заземление) Arduino, а второй — к контакту D11 через резистор.

Программа для Arduino

Скетч Arduino для этого эксперимента находится в каталоге /arduino/experiments/ex_speaker (см. разд. «Код к книге» главы 2):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const int soundPin = 11;
void setup() {
pinMode(soundPin, OUTPUT);
Serial.begin(9600);
Serial.println("Введите частоту ");
}
 
void loop() {
if (Serial.available()) {
int f = Serial.parseInt();
tone(soundPin, f); //<strong> 1</strong>
delay(2000);
noTone(soundPin); //<strong> 2</strong>
}
}

Незнакомая вам часть кода может находиться внутри цикла loop():

  1. tone настраивает один из выходных контактов Arduino на воспроизведение звука с указанной частотой (в данном случае, с частотой, набранной в окне монитора порта).
  2. После двухсекундной задержки команда noTone отменяет воспроизведение звука, возвращая умиротворяющую тишину.

Загружаем и выполняем программу

Загрузите в устройство программу, а затем откройте окно монитора порта. Попробуйте ввести значение 1000 — должен услышаться не самый приятный звук умеренной громкости, но не настолько громкий, чтобы быть услышанным в шумном помещении.

Продолжите эксперимент, вводя различные частоты и наблюдая изменение звука.

В случае, если вы попытаетесь получить в этом эксперименте частоты на границах слышимости, вас, к сожалению, будет ожидать разочарование, поскольку у громкоговорителя, скорее всего, окажется свой, еще более узкий диапазон звучания, и на частотах, превышающих примерно 10 кГц, громкость звука резко пойдет на спад. Небольшие громкоговорители также обычно не способны нормально воспроизводить звуки с частотой, ниже 100 Гц.


Синусоида и меандр

Звук, излучаемый громкоговорителем при подключении его непосредственно к выходному контакту Arduino, режет слух и кажется грубым. Дело в том, что цифровой выход может находиться только во включенном и выключенном состоянии, и звуковая волна, получаемая при этом, по форме напоминает меандр.

По сравнению с более мягкой и приближенной к синусоиде звуковой волной музыкального инструмента, звуковая волна в форме меандра считается весьма ненатуральным звуком (рис. 15.2).


Звуковые волны в виде меандра и синусоиды

Рис. 15.2. Звуковые волны в виде меандра и в виде синусоиды

Усилители

Чтобы сделать генерируемый звук громче, требуется выдать на громкоговоритель больше мощности. Иными словами, сигнал нужно усилить.

В конструкции, собранной для эксперимента из разд. «Эксперимент: громкоговоритель без усилителя на Arduino», мощность звука, излучаемого громкоговорителем, можно существенно усилить, используя транзистор, как это делалось для включения и выключения реле или электродвигателя, — звук останется столь же неприятным, но станет значительно громче.

Если же требуется сгенерировать более гладкую звуковую волну — скажем, для музыки или речи, принцип включения/выключения звукового сигнала, ведущий к выдаче ужасного звучания, уже не подойдет, и придется воспользоваться настоящим усилителем звука.

Усилитель можно собрать самостоятельно, но намного проще воспользоваться уже готовым изделием или же парой колонок, которыми оснащен ваш персональный компьютер. Задействовать такие колонки, в которые усилитель уже встроен, окажется особенно заманчиво, когда дело дойдет до использования Raspberry Pi, поскольку их входной штекер можно будет просто подключить к аудиоразъему Raspberry Pi.

Такой подход мы рассмотрим позже, когда кукла Пепе (из разд. «Проект: танцующая кукла Пепе на Raspberry Pi» главы 9) станет обретать голос (см. разд. «Проект: кукла Пепе обретает голос» далее в этой главе).

Эксперимент: воспроизведение звуковых файлов на Arduino

Звуковые файлы формата WAV можно проигрывать на Arduino с помощью оборудования из разд. «Эксперимент: громкоговоритель без усилителя на Arduino» и библиотеки Arduino под названием PCM (от англ. pulse code modulation, импульсно-кодовая модуляция). Для генерирования колебаний, способных вызвать звук, в этой библиотеке используется технология, слегка похожая на технологию широтно-импульсной модуляции (ШИМ). Флэш-памяти Arduino хватает приблизительно на 4 секунды записи, а если требуется проигрывать более длинные звуковые клипы, надо добавить к Arduino кардридер SD и следовать рекомендациям, приведенным на веб-сайте Arduino по адресу: https://www.arduino.cc/en/Tutorial/SimpleAudioPlayer.

Звук мы запишем на компьютере, воспользовавшись пакетом программ Audacity, а затем запустим утилиту, предназначенную для преобразования звукового файла в набор чисел, соответствующих этому звуку, который можно будет вставить в программу для Arduino и воспроизвести.

Исходная статья с описанием такого подхода к воспроизведению звука опубликована на веб-сайте High-Low Tech (http://highlowtech.org/?p=1963). Наш эксперимент немного отличается от этого описания тем, что в нем для записи аудиоклипа используется свободно распространяемое приложение Audacity.

Оборудование и софт

В этом эксперименте используется то же самое оборудование, что и в разд. «Эксперимент: громкоговоритель без усилителя на Arduino». Но вам придется установить на компьютер следующие программы, позволяющие записывать и обрабатывать звуковые клипы:

  • приложение Audacity: audacityteam.org;
  • утилиту Audio Encoder — ссылку на версию под вашу операционную систему можно найти на веб-сайте highlowtech.org/?p=1963.

Создание звукового файла


Примечание

Если записывать свой собственный звуковой клип желания у вас нет, вы можете сразу перейти к разд. «Загружаем и выполняем программу», входящему в состав этого эксперимента, и запустить программу wav_arduino, содержащую в закодированном виде небольшое звуковой блок.


Чтобы создать звуковой файл, запустите программу Audacity, переключите режим записи в моно (Mono) и выберите частоту проекта (Project Rate) равной 8000 Гц. Эти варианты настройки выделены на рис. 15.3.

mkac_1503

Рис. 15.3. Программа Audacity: запись звукового клипа

Чтобы начать запись, щелкните на красной кнопке Record (Записать) и запишите свое сообщение. Учтите, что запись не должна быть длиннее 4 секунд. Как только запись будет сделана, в окне Audacity появится изображение звуковой волны. Можно выбрать любую «немую» область в начале или в конце записи и удалить ее, оставив только нужную часть звукового блока.

Записанный звук надо экспортировать в нужный формат. Для этого опять понадобится выполнить специальные настройки. Выберите в меню File (Файл) пункт Export (Экспорт аудио), затем в раскрывающемся меню выберите вариант Other uncompressed files (Прочие несжатые файлы), перейдите в область настроек Format options (Настройки формата) и укажите характеристики WAV (Microsoft) и Unsigned 8 bit PCM (рис. 15.4). Присвойте файлу имя и пропустите страницу, приглашающую ввести данные об исполнителе.

Только что сгенерированный файл представляет собой двоичные данные. Его нужно преобразовать в список чисел в текстовом виде, отделенных друг от друга запятыми, чтобы его можно было вставить в нашу программу. Запустите для этого утилиту Audio Encoder, загруженную с веб-сайта highlowtech.org. Она выведет на экран приглашение на выбор конвертируемого файла — выберите файл, который только что был экспортирован из Audacity.

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

Откройте программу /arduino/experiments/wav_arduino и замените всю строку, начинающуюся с последовательности 125, 119, 115, данными из буфера обмена. Это очень длинная строка, поэтому лучше всего выбрать ее, поместив курсор в начало строки, а затем, удерживая нажатой клавишу <Shift>, опустить курсор вниз и переместить его на последний символ строки. Для замены выбранного текста данными из буфера обмена, воспользуйтесь пунктом контекстного меню Insert (Вставить).

mkac_1504

Рис. 15.4. Программа Audacity: выбор параметров экспорта

Если нанести все вставленные числа на график, его форма будет напоминать ту, что вы уже видели в Audacity при записи звукового клипа.

Программа для Arduino

Перед тем как приступить к компиляции и запуску программы, нужно установить библиотеку PCM. Загрузите ZIP-архив из GitHub (https://github.com/damellis/PCM/zipball/master), распакуйте его, переименуйте папку в PCM и переместите ее в каталог своих библиотек Arduino, воспользовавшись рекомендациями, представленными во врезке «Установка библиотек Arduino» главы 12.

Программа для Arduino (если проигнорировать звуковые данные) имеет весьма скромный размер, но массив данных представлен очень длинной строкой!

1
2
3
4
5
6
7
8
9
#include &lt;PCM.h&gt;
const unsigned char sample[] PROGMEM = { //<strong> 1</strong>
125, 119, 115, 115, 112, 116, 114, 113, 124, 126, 136, 145, 139,
};
void setup() {
startPlayback(sample, sizeof(sample)); //<strong> 2</strong>
}
void loop() { //<strong> 3</strong>
}

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

  1. Данные хранятся в массиве типа char, состоящем из восьмиразрядных чисел без знака. Команда PROGMEM обеспечивает хранение данных во флэш-памяти Arduino (в ней должно быть доступно около 32 Кбайт).
  2. Проигрывание звукового сэмпла осуществляет библиотека PCM. Функции startPlayback передается массив проигрываемых данных и размер данных в байтах.
  3. Звуковой клип проигрывается однократно при каждом перезапуске Arduino, поэтому функция loop() остается пустой.

Загружаем и выполняем программу

Загрузите программу в свой Arduino, и как только загрузка завершится, звуковой клип будет воспроизведен!

Сразу же после загрузки программы в нижней части Arduino IDE появится сообщение о том, сколько флэш-памяти Arduino было задействовано, примерно следующего содержания: Binary sketch size: 11,596 bytes (of a 32,256 byte maximum) (Размер двоичной программы: 11596 байтов (из максимально возможных 32256 байтов)). Если звуковой файл окажется слишком большим, вы получите сообщение об ошибке.

Подключение Arduino к усилителю

Как ни удивительно, но только что проведенный эксперимент оказался успешным, хотя его удалось проделать с применением только лишь Arduino.

Ток звукового сигнала, поступающего от Arduino, ограничивается резистором, но напряжения 5 В, подводимого к выводному контакту Arduino, слишком много для подключения ко входу обычного усилителя звука. Поэтому, когда мы хотим подключить Arduino к звуковым колонкам с целью сделать звук громче, сначала, как ни странно, нужно уменьшить напряжение на выходе.

Для этого вполне подойдут два резистора, включенные по схеме делителя напряжения.


Делитель напряжения

Делителем напряжения называется устройство, в котором для уменьшения напряжения используются два резистора. По сравнению с напряжением, изменяющимся, скажем, пропорционально изменению звукового сигнала, делитель напряжения изменяет его в фиксированной пропорции.

Например, на рис. 15.5 показан делитель напряжения, используемый для снижения сигнала напряжением 5 В от Arduino до более подходящего в качестве входа для усилителя звука значения в 0,5 В (или около того).


Напряжение в точке соединения двух резисторов (Vout) вычисляется по формуле:

В данном случае, когда на цифровом выходе выставлен высокий уровень сигнала (high) и Vin = 5 В, то:

Vout = 5 × 1/(1+10)=0,45 В.

Делитель напряжения

Рис. 15.5. Делитель напряжения

Макетную плату из разд. «Эксперимент: громкоговоритель без усилителя на Arduino» можно приспособить под подключение к усилителю, поместив один резистор над другим, как показано на рис. 15.6, и подключив верхний резистор номиналом 10 кОм к выводу D11, а нижний вывод нижнего резистора — к выводу GND (заземление). После этого останется только выбрать способ подключения контактной линии GND и линии, на которой встретились резисторы, к усилителю.

mkac_1506

Рис. 15.6. Схема подключения Arduino ко входу усилителя звукового сигнала в сборе

Для этого можно пожертвовать входным кабелем усилителя, укоротив его наполовину и зачистив провода на конце, чтобы их можно было вставить в гнезда монтажной платы. Обычно такой кабель имеет три жилы, поскольку большинство звуковых систем рассчитано на работу со стереосигналом. То есть, в нем имеется один общий (GND) провод и два отдельных провода: для левого и правого звуковых каналов (они обычно имеют изоляцию красного и белого цвета).

Вам нужно найти только общий (GND) провод, поскольку провода для левого и правого каналов лучше соединить вместе, чтобы монофонический сигнал от Arduino был слышен в обоих колонках. Найти общий (GND) провод можно с помощью мультиметра, установленного в режим проверки наличия контакта (рис. 15.7).

mkac_1507

Рис. 15.7. Тестирование входного кабеля звукового сигнала

Прикрепите один из проводов мультиметра к самой дальней от конца штекера звукового кабеля контактной площадке. Затем по очереди прикасайтесь другим проводом мультиметра к каждому из трех проводов кабеля, пока не услышите звуковой сигнал мультиметра или не обнаружите наличие контакта по каким-либо другим признакам. Это и будет общий провод, который нужно вставить в гнездо контактной линии GND макетной платы. Два других провода нужно скрутить вместе и вставить в гнездо контактной линии материнской платы, служащей выходом, то есть, той линии, на которой соединяются два резистора.

Повторите теперь один из ранее проводившихся в этой главе экспериментов с Arduino, и получите намного более громкий и чистый звук.

Опубликовано

Прерывания и другие специальные функции

По материалам книги Джереми Блума “Изучаем Arduino: инструменты и методы технического волшебства. 2-е изд.”  (глава 13. Прерывания и другие специальные функции)

Изучаем Arduino: инструменты и методы технического волшебства. 2-е изд.

Исходный код и прочие электронные ресурсы:

Исходный код, видеоуроки и прочие электронные ресурсы для этой главы можно загрузить с веб-страницы https://www.exploringarduino.com/content2/ch13.

Исходный код для проектов этой главы можно также загрузить на вкладке Downloads веб-страницы издательства Wiley для этой книги: https://www.wiley.com/go/exploringarduino2e.

Что вы узнаете из этой главы

Все разрабатываемые нами до сих пор программы для Arduino были синхронного типа.

Это обстоятельство вызывает несколько проблем, одна из которых состоит в том, что пока исполняется функция delay(), не могут выполняться никакие другие операции. При этом плата Arduino способна решать несколько задач одновременно, поэтому при простое процессора теряются ценные процессорные циклы.

В этой главе мы рассмотрим, как использовать аппаратные и программные прерывания, чтобы придать скетчам Arduino возможность асинхронного исполнения. Прерывания обеспечивают асинхронное исполнение кода, инициируя реакцию программы на определенные события, например, истечение определенного периода времени, изменение состояния входного сигнала и т.п. Как можно судить по их названию, прерывания позволяют прервать исполнение любой исполняющейся в настоящее время задачи, выполнить какую-либо другую задачу, а затем возвратиться к продолжению исполнения прерванной задачи. Мы рассмотрим, как вызывать прерывания по запланированным событиям или по изменению состояния сигнала на входных контактах. На основе полученных знаний мы создадим систему неблокирующих аппаратных прерываний, а также разработаем программу генератора звуковых сигналов по прерываниям таймера.

Аппаратные прерывания

Аппаратные прерывания активируются изменением состояния контакта ввода-вывода. Прерывания этого типа могут быть особенно полезными в тех случаях, когда нужно изменить значение переменной состояния, не прибегая к постоянному опросу состояния выхода кнопки. В некоторых предыдущих главах при каждой итерации главного цикла loop() мы выполняли программную защиту от дребезга и проверяли состояние кнопки. Такой подход работает удовлетворительно в тех случаях, когда исполнение кода в цикле loop() не занимает много времени.

Но, предположим, что нам нужно исполнить в цикле loop() довольно длительную процедуру. Например, нам нужно медленно постепенно повышать яркость светодиода или скорость вращения электродвигателя, используя для этого цикл for() и несколько операторов задержки delay(). Если управлять цветом или скоростью повышения яркости посредством кнопки, то мы пропустим нажатия кнопки, происходящие в течение исполнения функции delay(). Обычно, человеческая реакция достаточно инерционна, что позволяет выполнить большое количество функций в цикле loop() программы Arduino, включая опрос кнопки при каждой его итерации, не пропуская нажатий кнопки. Но когда цикл loop() содержит медленно исполняющиеся компоненты, существует вероятность пропустить события внешнего ввода.

Для решения подобных проблем и предназначены прерывания. Определенные контакты платы Arduino могут вызывать внешние аппаратные прерывания. Аппаратура микроконтроллера знает состояние этих контактов и может асинхронно предоставлять их значение коду прикладной программы. Таким образом, при обнаружении внешнего аппаратного прерывания исполнение главной программы можно приостановить, чтобы выполнить соответствующую процедуру обработки прерывания. Это прерывание может произойти в любой точке исполнения программы. На рис. 13.1 показан алгоритм процесса прерывания.

Рис. 13.1. Влияние внешнего прерывания на ход исполнения главной программы

Опрос состояния и прерывания: преимущества и недостатки каждого подхода

Аппаратные прерывания можно использовать как альтернативу постоянному опросу внешнего входных контактов в цикле loop(). Нельзя сказать, что один из этих подходов лучше другого, поскольку каждый из них обладает своими достоинствами и недостатками. При разработке системы необходимо рассмотреть все доступные варианты и выбрать из них тот, который лучше всего подходит для данного приложения. В этом разделе рассматриваются основные различия между опросом входных контактов и использованием прерываний, чтобы вы могли сами решить, какой из этих методов лучше всего подходит для вашего конкретного приложения.

Программная реализация

Замечательные качества языка программирования Arduino делают программную реализацию внешних прерываний очень прямолинейной задачей. Тем не менее, метод опроса для определения состояния входных контактов Arduino все же легче, поскольку требует только вызова функции digitalRead(). Поэтому, если нет особой необходимости в аппаратных прерываниях, не используйте их вместо опроса, поскольку для обеспечения прерываний нужен чуть больший объем кода.

Аппаратная реализация

С точки зрения аппаратной реализации для большинства цифровых контактов нет разницы между опросом контакта в цикле и прерыванием, т. к. в обоих случаях просто считывается состояние входа. Но в случае прерываний, активируемых перепадом уровней сигнала, аппаратную составляющую необходимо должным образом модифицировать. Как рассматривалось в главе 2, при нажатии многих кнопок (которые часто используются для активирования входа) их контакты испытывают дребезг. Это представляет серьезную проблему, поскольку дребезг будет много раз активировать процедуру обработки прерывания, тогда как мы хотим вызвать ее только один раз. Еще хуже то, что здесь не подойдет созданная нами ранее программная функция защиты от дребезга, поскольку в процедуре обработки прерывания недопустима функция delay(). Поэтому если для входного сигнала с дребезгом требуется аппаратное прерывание, то сначала нужно аппаратно устранить дребезг. Но в случае входного сигнала свободного от дребезга (например, с поворотного кодера или с другой микросхемы) аппаратное прерывание не будет отличаться от опроса.

Многозадачность

Одна из основных причин для использования прерывания — возможность получения псевдо-многозадачности. Плата Arduino не способна поддерживать настоящую многозадачность, поскольку она оснащена только одним главным микроконтроллером, которым может исполнять только одну команду за раз. Но одну задачу можно кратковременно прерывать для перехода к другой, возвращаясь после нее к первой, и благодаря очень высокой скорости исполнения команд создается видимость одновременного выполнения этих задач, что и называется псевдо-многозадачностью. Например, используя прерывания, можно в процессе уменьшения яркости светодиода реагировать на нажатие кнопки, сигнал с которой управляет скоростью изменения яркости. При методе опроса получить значение состояния контакта внешнего входа можно только тогда, когда процесс исполнения кода в цикле loop() дойдет до функции digitalRead(). Это означает, что наличие в программе каких-либо медленных функций может создать трудности с эффективным мониторингом состояния входного сигнала.

Точность сбора данных

Для некоторых задач высокоскоростного сбора данных прерывания являются абсолютно необходимыми. Предположим, что мы считываем состояние выходного сигнала поворотного кодера, установленного на электродвигателе постоянного тока и выдающего импульс при повороте вала двигателя на определенный угол. Этот сигнал можно подавать на плату Arduino для создания системы обратной связи, способной отслеживать положение вала двигателя, а не только скорость его вращения. Это позволит нам динамически регулировать скорость, в зависимости от нагрузки или следить за величиной поворота вала электродвигателя.

Но при этом нам необходимо не пропустить ни одного импульса от кодера. Эти импульсы довольно короткие (намного короче, чем импульсы, создаваемые нажатием кнопки), и если отслеживать их методом опроса в цикле loop(), то некоторые из них можно пропустить. Если поворотный кодер выдает только один импульс за полный поворот вала, то пропустив один такой импульс, программа будет считать, что двигатель вращается вдвое медленнее, чем в действительности. Таким образом, чтобы обеспечить захват важных событий, подобных рассмотренному, без аппаратных прерываний не обойтись. Но в случае сигналов с медленно изменяющимся состоянием (например, выходной сигнал кнопки) метод опроса может оказаться достаточным.

Возможности аппаратных прерываний Arduino

Для большинства плат Arduino сигналы прерываний можно подавать только на определенные контакты. Информацию, какие именно контакты вашей платы Arduino доступны для подачи на них сигналов прерываний, можно найти в документации по прерываниям на веб-сайте Arduino (blum.fyi/arduino-attach-interrupt).

Настройка контакта платы Arduino для работы в режиме источника аппаратных прерываний осуществляется с помощью функции attachInterrupt(). В первом аргументе функции указывается ID-номер прерывания, который не обязательно такой же самый, как и номер контакта. Определить, какой ID-номер прерывания можно присвоить конкретному контакту платы Arduino, можно с помощью функции digitalPinToInterrupt(). Для этого данной функции нужно просто передать номер цифрового контакта платы, и она сама определит соответствующий ID-номер прерывания в зависимости от версии платы Arduino, для которой компилируются скетч. Например, если мы хотим присвоить сигнал прерывания с кнопки контакту 2 платы Arduino Uno (или эквивалентной плате-клону с микроконтроллером ATmega328P), то в качестве первого аргумента функции attachInterrupt() нужно указать функцию digitalPinToInterrupt(2). Непосредственное указание одной функции в качестве аргумента другой функции вполне приемлемо[1], и, кроме того, делает код более аккуратным.

При возникновении аппаратного прерывания вызывается процедура его обработки. Данная функция указывается во втором аргументе функции attachInterrupt(). Например, менять значение булевой переменной на обратное при каждом прерывании можно с помощью следующей функции, которая передается функции attachInterrupt() во втором аргументе:

1
2
3
4
void toggleLed()
{
var = !var;
}

При вызове этой функции значение булевой переменной меняется на противоположное текущему значению, после чего продолжается исполнение команды главной программы, следующей команде, после исполнения которой произошло прерывание.

В последнем, третьем, аргументе функции attachInterrupt() указывается режим запуска прерывания. Прерывания Arduino могут запускаться низким уровнем сигнала (LOW) на контакте прерывания, изменением уровня сигнала (CHANGE), положительным перепадом уровня сигнала (RISING) или отрицательным перепадом уровня сигнала (FALLING). Некоторые платы Arduino также поддерживают запуск прерываний наличием сигнала высокого уровня (HIGH) на контакте прерывания. Наиболее часто используются режимы запуска CHANGE, RISING, and FALLING, поскольку они обеспечивают одноразовый запуск прерывания при изменении состояния внешнего входного сигнала, например, при смене уровня сигнала кнопки с низкого (LOW) на высокий (HIGH). Смена уровня сигнала с низкого (LOW) на высокий (HIGH) является положительным (RISING) перепадом, а с высокого (HIGH) на низкий (LOW) — отрицательным (FALLING). Режимы запуска LOW и HIGH менее распространены, поскольку в таких случаях прерывание будет запускаться постоянно, пока сохраняется данный уровень сигнала, блокируя исполнение остального кода программы.

Объединив все эти возможности, можно, например, при каждом нажатии кнопки, подключенной к контакту 2 платы Arduino Uno (т. е. изменении уровня ее выходного сигнала с низкого на высокий), вызывать рассмотренную ранее функцию toggleLED(). Для этого в секцию setup() нужно вставить следующую строку кода:

1
attachInterrupt(digitalPinToInterrupt(2), toggleLED, RISING);

Схема запуска прерывания кнопкой, оснащенной аппаратной защитой от дребезга

Чтобы закрепить наши новые знания, мы создадим схему с RGB-светодиодом и кнопкой с аппаратной защитой от дребезга. Яркость выбранного цветового элемента RGB-светодиода циклически постепенно увеличивается до максимальной, а затем уменьшается до минимальной, используя для этого функцию delay(). При нажатии кнопки элемент RGB-светодиода с регулируемой таким образом яркостью меняется на другой.

Схема аппаратной защиты от дребезга

Как рассматривалось в главе 2, в большинстве случаев при нажатии кнопки ее контакты не смыкаются мгновенно, а вибрируют в течение некоторого времени, замыкаясь и размыкаясь, пока не успокоятся в замкнутом положении. Этот эффект называется дребезгом контактов. Это обстоятельство представляет серьезную проблему при вводе сигнала с кнопки для запуска аппаратного прерывания, поскольку кажущееся одноразовое нажатие кнопки, по сути, является многоразовым, в результате чего прерывание будет запускаться несколько раз. К счастью эффект дребезга контактов можно устранить из конечного сигнала аппаратным способом, получив чистый сигнал для подачи на микроконтроллер.

Сначала рассмотрим обычный сигнал, получаемый при нажатии кнопки, оснащенной повышающим резистором. Функция повышающего резистора заключается в установлении на контакте ввода-вывода входного сигнала высокого уровня при разомкнутой кнопке. При нажатии кнопки происходит подключение контакта ввода-вывода на землю, т. е. установка на этом контакте сигнала низкого уровня. При необходимости этот сигнал низкого уровня можно инвертировать далее в схеме. На рис. 13.2 показана осциллограмма выходного сигнала кнопки в момент ее нажатия. Как можно видеть, уровень выходного сигнала кнопки не становится моментально низким, а скачет вверх и вниз, пока не установится в низком состоянии.

Рис. 13.2. Дребезг выходного сигнала нажатой кнопки

Если использовать сигнал, изображенный на рис. 13.2, для запуска прерывания, то прерывание будет запущено не один раз, как ожидалось бы, а столько раз, сколько насчитывается отрицательных перепадов сигнала в процессе перехода его уровня от стабильно высокого к стабильно низкому. Но эту проблему можно решить с помощью резистивно-емкостной цепочки или RC-цепи.

Такую цепочку можно создать, подключив выход кнопки к входному контакту микроконтроллера через резистор, а входной контакт микроконтроллера на землю — через конденсатор. При отпущенной кнопке конденсатор заряжается до напряжения питания (+5 В) через повышающий резистор и добавленный резистор RC-цепи. Конденсатор можно рассматривать, как накопитель электроэнергии, заряжающийся от шины положительного питания. Пока кнопка отпущена, этот накопитель заполняется. А при нажатии кнопки, т. е. при замыкании ее контактов, конденсатор начинает разряжаться на землю через резистор RC-цепи и замкнутые контакты кнопки.

Разряд конденсатора происходит не моментально, а занимает некоторый период времени, в течение которого на входном контакте микроконтроллера напряжение сохраняется на уровне близком к 5 В. Конденсатор перезаряжается при каждом отпускании кнопки, т. е. при размыкании ее контактов. Длительность времени разряда конденсатора превышает период дребезга контактов кнопки, в результате чего к моменту полного разряда конденсатора контакты кнопки успокоятся в стабильном замкнутом состоянии. В результате уровень сигнала на входном контакте микроконтроллера изменяется с высокого к низкому только один раз. Продолжительность периодов заряда и разряда конденсатора, и соответственно, длительность защиты от дребезга, определяется номиналами резистора и конденсатора Рассмотренная схема защиты от дребезга контактов показана на рис. 13.3.

Рис. 13.3. Схема защиты от дребезга с RC-цепочкой (Рисунок создан в программе EAGLE)

Подключенный последовательно кнопке резистор R2 в схеме на рис. 13.3 предотвращает почти моментальный разряд конденсатора. В результате выходной сигнал при разряде конденсатора выглядит так, как показано на осциллограмме на рис. 13.4.

Рис. 13.4. Устранение последствий дребезга контактов с помощью RC-цепочки

Таким образом, на вход контакта прерывания Arduino будет подаваться сигнал с плавным переходом от высокого уровня к низкому. Но для запуска прерывания требуется перепад, который определяется, когда переход с низкого уровня к высокому или наоборот происходит с определенной скоростью.

Большинство современных микроконтроллеров обладают встроенной способностью работать с медленными положительными или отрицательными перепадами цифровых сигналов. Например, в справочном листке для микроконтроллера ATmega приводятся разные пороговые значения для низкого и высокого уровней входного сигнала. При переходе входного сигнала с высокого уровня на низкий, его напряжение должно опуститься ниже 0,2U+, чтобы уровень определился, как низкий. А при переходе входного сигнала с низкого уровня на высокий, его напряжение должно подняться выше ниже 0,7U+, чтобы уровень определился, как высокий. Здесь U+ обозначает напряжение питания микроконтроллера (5 В в моем случае). Этот промежуток обеспечивает устойчивость сигнала в процессе перехода и называется гистерезисом.

Прерывания платформы Arduino могут запускаться таким медленным перепадом уровня входного сигнала. Но желательно разобраться, каким именно образом реализуется эта возможность. Для этого мы создадим схему на триггере Шмитта, чтобы она работала независимо от Arduino. Триггер Шмитта представляет собой схему, которая может создавать резкий перепад выходного сигнала, когда входной сигнал превышает определенное пороговое значение. Полученный таким образом сигнал можно подавать на входной контакт платы Arduino. Для нашего эксперимента мы возьмем микросхему 74AHCT14 триггера Шмитта. Хотя данная микросхема содержит шесть элементов триггера Шмитта, нам понадобится только один из них. Многие производители выпускают логические микросхемы, которые функционально идентичны серии 7400. На рис. 13.5 показана цоколевка шестиэлементной микросхемы инвертирующих триггеров Шмитта производства компании STMicroelectronics.

Рис. 13.5. Цоколевка шестиэлементной микросхемы инвертирующих триггеров Шмитта (Источник: © STMicroelectronics. Репродукция с разрешения)

Мы пропустим выходной сигнал нашей схемы защиты от дребезга через один из таких триггеров Шмитта, прежде чем подавать его на входной контакт прерывания платы Arduino. Принципиальная схема такого устройства изображена на рис. 13.6.

Рис. 13.6. Схема аппаратной защиты от дребезга с обработкой выходного сигнала инвертирующим триггером Шмитта (Рисунок создан в программе EAGLE)

Поскольку это инвертирующий триггер, уровень его выходного сигнала будет противоположен уровню входного сигнала. Это означает, что при нажатой кнопке выходной сигнал будет иметь высокий логический уровень, а при отпущенной — низкий. Поэтому, при написании кода на следующем шаге, для определения события нажатия кнопки нам нужно будет распознать положительный перепад входного сигнала. Окончательно форма выходного сигнала изображена на рис. 13.7, как видим, сигнал чистый, без дребезга.

 

 

Рис. 13.7. Сигнал на выходе схемы подавления дребезга с инвертирующим триггером Шмитта

Такой сигнал вполне подходит для формирования аппаратного прерывания.

Монтаж схемы устранения дребезга

Теперь у нас есть достаточно знаний, чтобы собрать схему устранения дребезга кнопки. Для последующих экспериментов по тестированию аппаратной защиты от дребезга и кода обработки прерываний нам нужно будет собрать схему с RGB-светодиодом и кнопкой. Монтажная схема показана на рис. 13.8.

Рис. 13.8. Монтажная схема аппаратной защиты от дребезга (Рисунок создан в программе Fritzing)

Разработка программы

Следующая задача — создать простую программу для тестирования как нашей схемы защиты от дребезга, так и возможностей аппаратных прерываний платформы Arduino. Самым очевидным и полезным применением аппаратных прерываний с платформой Arduino будет получение возможности мониторинга состояния входных сигналов даже при выполнении операций заданной длительности, в которых используется функция delay(). Такая возможность может потребоваться во многих ситуациях, но мы рассмотрим одну из наиболее простых: постепенное изменение яркости светодиода методом широтно-импульсной модуляции посредством функции analogWrite(). В этом скетче яркость одного из элементов RGB-светодиода будет циклически повышаться до максимального значения 255, а затем понижаться до минимального значения 0. При нажатии кнопки будет меняться элемент RGB-светодиода с регулируемой таким образом яркостью. Решить эту задачу методом опроса невозможно, поскольку мы могли бы проверять состояние кнопки только по завершению цикла, в результате чего большинство нажатий кнопки были бы наверняка пропущены.

Но прежде чем приступать к рассмотрению программы для реализации этой задачи, нам нужно разобраться с понятием волатильных (временных) переменных. В частности, переменные, значения которых будут меняться при исполнении процедуры обработки прерывания, должны объявляться как волатильные: volatile. Это необходимо для правильной обработки этих переменных компилятором. Объявление переменной волатильной выполняется добавлением ключевого слова volatile в начале объявления:

volatile int selectedLED = 9;

Чтобы плата Arduino ожидала сигнала прерывания на соответствующем контакте, для этого контакта в разделе setup() нужно посредством функции attachInterrupt() задать режим отслеживания прерываний. В аргументах этой функции указывается ID-номер прерывания в виде функции digitalPinToInterrupt(), функция обработки прерывания, а также режим запуска прерывания (RISING, FALLING и т.п.). В нашей программе кнопка подключена к контакту 2 платы Arduino, которому функция digitalPinToInterrupt() присваивает ID-номер прерывания 0. При запросе прерывания вызывается функция swap(), а сам запуск осуществляется положительным перепадом сигнала прерывания. В результате, функция attachInterrupt() будет иметь такой вид:

attachInterrupt(digitalPinToInterrupt(2), swap, RISING);

Далее нужно создать функцию swap() и добавить ее в программу, полный код которой приведен в листинге 13.1. Это все, что нам необходимо сделать в отношении программной части. Подключив прерывание и создав функцию для его обработки, в остальной части основной программы можно выполнять любые требуемые операции. При запуске прерывания исполнение основной программы приостанавливается и исполняется функция обработки прерывания, по завершению которой возобновляется исполнение основной в точке, в которой оно было прервано. Поскольку прерывания останавливают ход основной программы, функции их обработки следует делать очень короткими и не использовать в них никаких пауз. В действительности, функция delay() даже не будет работать в функции обработки прерывания. Выяснив все это, теперь мы можем написать следующую программу, которая циклически повышает и понижает яркость одного из трех элементов RGB-светодиода и при нажатии кнопки переключается на другой, продолжая с ним делать то же самое.

Листинг 13.1. Программа hw_multitask.ino для демонстрации аппаратных прерываний

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Управление прерыванием, используя кнопку с аппаратной защитой
// от дребезга
// Контакты Arduino для считывания сигнала с кнопок
const int BTN = 2; // Сигнал кнопки после устранения дребезга
// подаем на контакт 2
const int RED = 11; // Подключаем катод красного светодиода
// к контакту 11
const int GREEN = 10; // Подключаем катод зеленого светодиода
// к контакту 10
const int BLUE = 9; // Подключаем катод синего светодиода
// к контакту 9
// Волатильные переменные могут модифицироваться
// функцией обработки прерывания
volatile int selectedLED = RED;
 
void setup()
{
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
// Начинаем исполнение с выключенным RGB-светодиодом
// Сигнал управления инвертирован, поскольку мы управляем катодом
digitalWrite(RED, HIGH);
digitalWrite(BLUE, HIGH);
digitalWrite(GREEN, HIGH);
// Поскольку сигнал на контакте инвертирован,
// ожидаем положительный перепад
attachInterrupt(digitalPinToInterrupt(BTN), swap, RISING);
}
 
void swap()
{
// Выключаем текущий составляющий светодиод. Высокий уровень (HIGH)
// выключает светодиод, поскольку это светодиод с общим анодом
digitalWrite(selectedLED, HIGH);
// Затем включаем другой составляющий светодиод
if (selectedLED == GREEN)
selectedLED = RED;
else if (selectedLED == RED)
selectedLED = BLUE;
else if (selectedLED == BLUE)
selectedLED = GREEN;
}
 
void loop()
{
// Постепенно повышаем яркость светодиода
// Сигнал управления инвертирован, поскольку мы управляем катодом
for (int i=255; i&gt;=0; i--)
{
analogWrite(selectedLED, i);
delay(10);
}
// Постепенно понижаем яркость светодиода
// Сигнал управления инвертирован, поскольку мы управляем катодом
for (int i=0; i&lt;=255; i++)
{
analogWrite(selectedLED, i);
delay(10);
}
delay(1000);
}

При исполнении этой программы, включается один из составляющих светодиодов RGB-светодиода, и яркость его начинает циклически постепенно повышаться и понижаться. При каждом нажатии кнопки, текущий составляющий светодиод выключается и включается другой, с такой же самой яркостью, которая была у предыдущего при его выключении, и которая далее начинает изменяться так же, как и у предыдущего.


Примечание

  1. На веб-странице для этой главы (https://www.exploringarduino.com/content2/ch13) можно просмотреть видеоклип, демонстрирующий эту схему и скетч для нее в действии.
  2. А в данном случае даже рекомендуется. См. документацию по функции attachInterrupt() на веб-сайте Arduino https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/.
Опубликовано

Создание собственных библиотек

По материалам книги “Arduino. Большая книга рецептов“, 3-е изд. (авторы Джепсон Брайан, Марголис Майкл, Уэлдин Николас Роберт) (глава 16. Использование, модифицирование и создание библиотек)

Arduino. Большая книга рецептов, 3-издание

ЗАДАЧА

Требуется создать свою библиотеку. Библиотеки предоставляют удобный способ использования одного и того же кода во многих скетчах, а также дают другим разработчикам возможность использовать ваш код.

РЕШЕНИЕ

Библиотека представляет собой набор методов и переменных, объединенных в формате, предоставляющем пользователю стандартный способ доступа к этим функциям и переменным.

Большинство библиотек Arduino создаются в виде класса. Те из вас, кто знаком с языком С++ или Java, должны знать, что такое класс. Однако библиотеки можно также создавать и без использования классов, и здесь мы увидим, как это сделать.

Итак, давайте модифицируем скетч решения из разд. 7.1, чтобы включить функцию BlinkLED() в библиотеку.

Схема подключения светодиодов приводится на рис. 7.2, а описание ее работы — в разд. 7.1. Создаваемая нами библиотека будет содержать функцию blinkLED() из этого решения. В листинге 16.5 приводится код скетча blinkLibTest, с помощью которого будет выполняться тестирование созданной библиотеки.

Листинг 16.5. Скетч для тестирования созданной библиотеки

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
* Скетч blinkLibTest
*/
 
#include "blinkLED.h"
const int firstLedPin = 3; // Контакты для подключения светодиодов
const int secondLedPin = 5;
const int thirdLedPin = 6;
 
void setup(){
pinMode(firstLedPin, OUTPUT); // Задаем выходной режим работы для
// контактов светодиодов
pinMode(secondLedPin, OUTPUT);
pinMode(thirdLedPin, OUTPUT);
}
 
void loop(){
// Мигаем каждым светодиодом один раз в 1,000 мс (1 секунду)
blinkLED(firstLedPin, 1000);
blinkLED(secondLedPin, 1000);
blinkLED(thirdLedPin, 1000);
}

Функцию blinkLED() нужно удалить из скетча решения, приведенного в разд. 7.1, и поместить в отдельный файл с названием blinkLED.cpp, как показано в листинге 16.6 (файлы *.cpp рассматриваются более подробно далее — в разд. «Обсуждение работы решения и возможных проблем» этого раздела).

Листинг 16.6. Код библиотеки blinkLED

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* blinkLED.cpp
* Простая библиотека для мигания светодиодом с периодом в миллисекундах
*/
#include "Arduino.h" // Для версий среды Arduino IDE более ранних,
// чем версия 1.0, используйте файл Wprogram.h
#include "blinkLED.h"
// Мигаем светодиодом на этом контакте в течение duration миллисекунд
void blinkLED(int pin, int duration)
{
digitalWrite(pin, HIGH); // Включаем светодиод
delay(duration);
digitalWrite(pin, LOW); // Выключаем светодиод
delay(duration);
}
Большинство библиотек разрабатывается программистами, которые используют для этого свою среду разработки, но их с таким же успехом можно создавать и в любом обычном текстовом редакторе типа Блокнот.

А теперь создайте заголовочный файл blinkLED.h и скопируйте в него следующий код:

1
2
3
4
5
6
/*
* blinkLED.h
* Заголовочный файл для библиотеки BlinkLED
*/
#include "Arduino.h"
void blinkLED(int pin, int duration); // Прототип функции

Обсуждение работы решения и возможных проблем

Наша библиотека будет называться blinkLED и храниться в папке libraries (см. разд. 16.2). Создайте в этой папке вложенную папку blinkLED и переместите в нее файлы blinkLED.h и blinkLED.cpp. Затем создайте в папке blinkLED вложенную папку examples, а в ней — вложенную папку blinkLibTest. Создайте из скетча для тестирования библиотеки (см. листинг 16.5) файл с именем blinkLibTest.ino и поместите его в папку blinkLibTest. Путь к этому файлу должен выглядеть так: examples/blinkLibTest/ blinkLibTest.ino.

В результате мы переместили функцию blinkLED() скетча решения из разд. 7.1 в файл библиотеки blinkLED.cpp (расширением cpp обозначаются файлы с исходным кодом, созданным на языке С++, — С plus plus).

Используемые в документации библиотек Arduino термины функция и метод обозначают блоки кода — такие как blinkLED(). Термин метод служит для обозначения функциональных блоков классов. Оба термина обозначают именованные функциональные блоки, доступ к которым предоставляется посредством библиотек.

Файл blinkLED.cpp содержит исходный код функции blinkLED(), который идентичен коду этой функции в скетче из листинга 7.1, за исключением следующих двух строк в начале кода:

1
2
#include "Arduino.h" // Подключение заголовочного файла Arduino.h
#include "blinkLED.h"

Оператор #include “Arduino.h” требуется для библиотек, использующих любые функции или константы языка Arduino. При отсутствии этого оператора компилятор будет выдавать сообщения об ошибке для всех функций, используемых в скетче.

 

Заголовочный файл Arduino.h был добавлен в версии 1.0 среды Arduino IDE, заменив заголовочный файл WProgram.h, используемый в более ранних версиях среды. При работе с такими более ранними версиями среды Arduino IDE можно использовать следующую конструкцию, чтобы подключать правильный заголовочный файл:

1
2
3
4
5
#if ARDUINO &gt;= 100
#include "Arduino.h // для версий 1.0 и более поздних
#else
#include "WProgram.h" // для более ранних версий
#endif

Следующая строка кода: #include “blinkLED.h” — содержит определение функции (которое также называется прототипом функции) для нашей библиотеки. Компилятор Arduino автоматически создает прототипы для всех функций в скетче при его компилировании, но не создает прототипов для функций, содержащихся в библиотеках, поэтому при создании библиотеки необходимо самому создать заголовочный файл, содержащий эти прототипы. При подключении библиотеки к скетчу в него добавляется именно этот заголовочный файл (см. разд. 16.1).

Каждая библиотека должна иметь файл, в котором объявляются названия предо- ставляемых функций. Такой файл называется заголовочным (header file) или включаемым (include file), а его название имеет формат НазваниеБиблиотеки.h. В рассматриваемом примере заголовочный файл называется blinkLED.h и размещается в той же папке, что и файл blinkLED.cpp.

Содержимое заголовочного файла для нашей библиотеки очень простое — объявление одной функции:

1
void blinkLED(int pin, int duration); // Прототип функции

Это объявление почти такое же, как и объявление этой функции в файле blinkLED.cpp:

1
void blinkLED(int pin, int duration)

Однако разница между этими двумя объявлениями функции хотя и тонкая, но критическая. Объявление прототипа функции в заголовочном файле завершается точкой с запятой. Это сообщает компилятору, что это просто объявление формата для функции, но не ее кода. А отсутствие завершающей точки с запятой в объявлении функции в файле исходного кода blinkLED.cpp сообщает компилятору, что это собственно исходный код функции.

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

Более подробную информацию по использованию заголовочных файлов и файлов *.cpp для создания модулей кода можно получить, прочитав какую-либо хорошую книгу по языку C++ (в разд. «Дополнительная информация» этого раздела рекомендуется несколько таких весьма популярных книг).

Разместив файлы blinkLED.cpp, blinkLED.h и blinkLibTest.ino в соответствующие вложенные папки в папке libraries, закройте среду разработки Arduino IDE, а затем снова запустите ее. Структура задействованных папок и файлов должна выглядеть следующим образом:

libraries/

└── blinkLED/

├── blinkLED.cpp

├── blinkLED.h

└── examples/

└── blinkLibTest/

└── blinkLibTest.ino

Среда Arduino IDE обновляет список доступных библиотек только при ее запуске. Чтобы установленная вручную библиотека отобразилась в этом списке, необходимо закрыть, а затем снова запустить среду Arduino IDE. И хотя среду Arduino IDE нужно перезапустить при исходном добавлении библиотеки в папку libraries, впоследствии — после модифицирования библиотеки — перезапуск не требуется.

Выполнив команду меню Файл | Примеры (Примеры из пользовательских библиотек) | blinkLED | blinkLibTest, откройте в окне Arduino IDE тестовый скетч blinkLibTest. Загрузите этот скетч в свою плату Arduino, и подключенные к ней светодиоды должны начать мигать так же, как и при исполнении скетча решения из разд. 7.1.

Добавить новую функциональность в существующую библиотеку не составляет никаких проблем. Предположим, например, что вы хотите добавить в нее несколько постоянных, наиболее часто используемых значений задержки, чтобы пользователи библиотеки могли применять описательные названия констант вместо значений в миллисекундах.

Эта задача решается добавлением в заголовочный файл библиотеки трех строк кода со значениями констант, которые обычно размещаются непосредственно перед кодом объявления прототипа функции:

1
2
3
4
5
// Константы для периода мигания светодиодов
const int BLINK_SHORT = 250;
const int BLINK_MEDIUM = 500;
const int BLINK_LONG = 1000;
void blinkLED(int pin, int duration); // Прототип функции

Затем надо модифицировать код в функции loop() скетча примера, как показано в листинге 16.7. Загрузив модифицированный скетч в плату, мы увидим, что каждый светодиод мигает с другой частотой.

Листинг 16.7. Модифицированный код функции loop() для мигания светодиодами с разной частотой

1
2
3
4
5
void loop(){
blinkLED(firstLedPin, <strong>BLINK_SHORT</strong>);
blinkLED(secondLedPin, <strong>BLINK_MEDIUM</strong>);
blinkLED(thirdLedPin, <strong>BLINK_LONG</strong>);
}

Также легко добавляются в библиотеку и новые функции. В листинге 16.8 приводится код главного цикла loop(), который мигает каждым светодиодом заданное для него количество раз.

Листинг 16.8. Код цикла loop() для мигания каждым светодиодом в течение заданного для него периода

1
2
3
4
5
void loop(){
blinkLED(firstLedPin, BLINK_SHORT, 5); // <strong>Мигает 5 раз</strong>
blinkLED(secondLedPin, BLINK_MEDIUM, 3); // <strong>Мигает 3 раза</strong>
blinkLED(thirdLedPin, BLINK_LONG); // <strong>Мигает один раз</strong>
}

Чтобы добавить эту функцию в библиотеку, в файл blinkLED.h нужно добавить ее прототип, как показано в листинге 16.9.

Листинг 16.9. Добавление прототипа новой функции в заголовочный файл

1
2
3
4
5
6
7
8
9
10
11
12
/*
* blinkLED.h
* Заголовочный файл для библиотеки blinkLED
*/
#include "Arduino.h"
// Константы для периода мигания светодиодов
const int BLINK_SHORT = 250;
const int BLINK_MEDIUM = 500;
const int BLINK_LONG = 1000;
void blinkLED(int pin, int duration);
<strong>// Определение новой функции для мигания заданного количества раз</strong>
<strong>void blinkLED(int pin, int duration, int repeats);</strong>

А в файл blinkLED.cpp добавляем исходный код функции, как показано в листинге 16.10.

Листинг 16.10. Исходный код функции мигания светодиодами заданное количество раз

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
* blinkLED.cpp
* Простая библиотека для мигания светодиодом с периодом в миллисекундах
*/
#include "Arduino.h"
#include "blinkLED.h"
// Мигаем светодиодом на этом контакте в течение duration миллисекунд
 
void blinkLED(int pin, int duration)
{
digitalWrite(pin, HIGH); // Включаем светодиод
delay(duration);
digitalWrite(pin, LOW); // Выключаем светодиод
delay(duration);
}
/* Функция для повторения мигания */
void blinkLED(int pin, int duration, int repeats)
{
while(repeats)
{
blinkLED(pin, duration);
repeats = repeats -1;
};
}

Для созданной библиотеки можно добавить возможность выделения цветом ключевых слов при просмотре исходного кода скетча в окне редактора скетчей среды IDE. Для этого нужно создать специальный файл keywords.txt. Это обычный текстовый файл, который содержит список ключевых слов и их типов: каждый тип ключевого слова выделяется другим цветом. Ключевые слова и типы разделяются табуляцией, а не просто пробелом. В листинге 16.11 приводится пример файла keywords.txt, в котором задается выделение цветом констант периода мигания светодиода.

Листинг 16.11. Файл keywords.txt для библиотеки blinkLED

1
2
3
4
5
6
7
8
9
10
11
#######################################
# Methods and Functions (KEYWORD2)
#######################################
blinkLED KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
 
BLINK_SHORT LITERAL1
BLINK_MEDIUM LITERAL1
BLINK_LONG LITERAL1

Сохраните его в папке blinkLED и перезапустите среду Arduino IDE. Если теперь открыть файл скетча blinkLibTest.ino в среде Arduino IDE, то константы BLINK_SHORT, BLINK_MEDIUM и BLINK_LONG будут выделяться цветом.

Дополнительная информация

Дополнительные примеры создания библиотек рассматриваются в разд. 16.5.

Дополнительная информация по созданию библиотек для Arduino приводится в справочном документе «Writing a Library for Arduino» (https://oreil.ly/vLNvx).

Рекомендуем также следующие книги по программированию на C++:

  • «Practical C++ Programming» («Практическое программирование на языке C++»), автор Steve Oualline, издательство O’Reilly;
  • «C++ Primer Plus» («Язык программирования С++»), автор Stephen Prata, издательство Sams;
  • «C++ Primer» («Учебник C++ для начинающих»), авторы Stanley B. Lippman, Josee Lajoie и Barbara E. Moo, издательство Addison-Wesley Professional.
Опубликовано

Управление направлением и скоростью вращения щеточного электродвигателя с помощью датчиков

По материалам книги “Arduino. Большая книга рецептов“, 3-е изд. (авторы Джепсон Брайан, Марголис Майкл, Уэлдин Николас Роберт) (глава 8. Управление
электродвигателями)

Arduino. Большая книга рецептов, 3-издание

ЗАДАЧА

Требуется управлять направлением и скоростью вращения щеточного электродвигателя, используя сигнал обратной связи с датчиков. Например, организовать управление скоростью и направлением электродвигателей с помощью двух фотодатчиков таким образом, чтобы шасси робота двигалось по направлению к источнику света.

РЕШЕНИЕ

Двигатели для этого решения подключаются так же, как показано на рис. 8.10, но к схеме добавлены два фоторезистора (или фототранзистора — подробную информацию по фототранзисторам см. в разд. 1.6), как показано в схеме на рис. 8.12. Конденсаторы номиналом 0,1 мкФ на электродвигателях должны быть керамическими.

C:\Users\acer\Documents\#Electronics\Магазин электроники\фрагменты из книг\2788. Arduino Cookbook. Recipes to Begin, Expand, and Enhance\verstka\pic\08\8.12.png

Рис. 8.12. Управление двумя щеточными электродвигателями с помощью датчиков

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

Листинг 8.12. Управление двумя электродвигателями с помощью фотодатчиков

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* Скетч Brushed_H_Bridge_Direction
* Управляет электродвигателями на основании сигналов фотодатчиков,
* направляя шасси робота к источнику света
*/
 
int leftPins[] = {5,7,4}; // Один контакт для ШИМ (скорость),
// два контакта для направления левого двигателя
int rightPins[] = {6,3,2}; // То же, для правого двигателя
const int MIN_PWM = 64; // Это значение может быть в диапазоне от 0 до MAX_PWM
const int MAX_PWM = 128; // Это значение может быть в диапазоне от 50 до 255
const int leftSensorPin = A0; // Контакты для подключения фотодатчиков
const int rightSensorPin = A1;
 
int sensorThreshold = 0; // Пороговый уровень освещенности на датчике
// для вращения электродвигателя
void setup()
{
 
for(int i=1; i &lt; 3; i++)
{
pinMode(leftPins[i], OUTPUT);
pinMode(rightPins[i], OUTPUT);
}
}
 
void loop()
{
int leftVal = analogRead(leftSensorPin);
int rightVal = analogRead(rightSensorPin);
if(sensorThreshold == 0) // Датчики откалиброваны?
{
// Если нет, калибруем до уровня освещенности несколько выше
// среднего уровня освещенности окружающей среды
sensorThreshold = ((leftVal + rightVal) / 2) + 100 ;
}
if( leftVal &gt; sensorThreshold || rightVal &gt; sensorThreshold)
{
// Если уровень освещенности достаточно высокий
// для движения вперед
setSpeed(rightPins, map(rightVal,0,1023, MIN_PWM, MAX_PWM));
setSpeed(leftPins, map(leftVal ,0,1023, MIN_PWM, MAX_PWM));
}
}
 
void setSpeed(int pins[], int speed )
{
if(speed &lt; 0)
{
digitalWrite(pins[1],HIGH);
digitalWrite(pins[2],LOW);
speed = -speed;
}
else
{
digitalWrite(pins[1],LOW);
digitalWrite(pins[2],HIGH);
}
analogWrite(pins[0], speed);
}

Обсуждение работы решения и возможных проблем

Скетч управляет скоростью вращения двух электродвигателей, реагируя на уровень освещенности, определяемый двумя фотодатчиками. Фотодатчики установлены таким образом, что повышение уровня освещенности на одной стороне шасси
повышает скорость вращения электродвигателя на другой стороне шасси. В результате шасси будет поворачиваться по направлению к более высокому уровню освещенности. При одинаковом уровне освещенности с обеих сторон шасси будет двигаться вперед по прямой линии. При слишком низком уровне освещенности шасси останавливается.

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

Сигнал с фотодатчиков подается на аналоговые контакты A0 и A1 платы Arduino,
с которых он считывается функцией analogRead() (эта функция подробно рассматривается в разд. 6.3). В начале исполнения скетча измеряется уровень фоновой освещенности, и это пороговое значение используется для определения минимального уровня освещенности, необходимого, чтобы начинать движение шасси. К измеренному пороговому уровню освещенности добавляется запас величиной в 100 еди­ниц, чтобы небольшие изменения уровня фоновой освещенности не вызывали движения. Значение уровня освещенности, возвращенное функцией analogRead(), преобразовывается с помощью функции map() в значение ШИМ. Константе MIN_PWM следует задать приблизительное значение ШИМ, при котором шасси должно начинать движение (слишком низкие значения не дадут достаточного крутящего момента. Точное значение надо будет определить экспериментальным путем). А константе MAX_PWM нужно задать значение (до 255), определяющее максимальную скорость шасси.

Скорость вращения электродвигателей управляется функцией setSpeed(). Для управления направлением вращения каждого электродвигателя используются два контакта платы Arduino и еще один контакт — для управления скоростью вращения. Номера этих контактов хранятся в массивах leftPins и rightPins для левого и правого двигателей соответственно. В первом элементе массива хранится номер контакта для управления скоростью вращения, а в двух других — для управления направлением.

В любом из решений, в котором используется микросхема H-моста L293, вместо нее можно альтернативно применить микросхему TB6612FNG. На рис. 8.13 показано подключение к плате Arduino микросхемы H-моста TB6612 (установленной на адаптерной плате артикул 713 компании Pololu).

C:\Users\acer\Documents\#Electronics\Магазин электроники\фрагменты из книг\2788. Arduino Cookbook. Recipes to Begin, Expand, and Enhance\verstka\pic\08\8.13.png

Рис. 8.13. Подключение адаптерной платы микросхемы H-моста TB6612 производства компании Pololu

Количество контактов платы Arduino, задействованных для управления схемой, можно уменьшить, добавив в схему дополнительный компонент для управления контактами направления H-моста. Такой компонент представляет собой транзистор или логический элемент для инвертирования логического уровня, подаваемого на другой ввод H-моста, позволяя использовать только один контакт платы Arduino для управления направлением вращения электродвигателя. Соответствующую принципиальную схему можно найти на веб-сайте Arduino, но также существуют и готовые решения — например, шилд H-моста Arduino Motor Shield (артикул 7630049200371, https://store.arduino.cc/arduino-motor-shield-rev3) или шилд Ardumoto компании SparkFun (артикул DEV-09213). Оба эти шилда используют микросхему L298, которая является более мощной альтернативой микросхеме L293. Эти шилды вставляются в гнездовые разъемы платы Arduino и требует только подключения к электродвигателю и его источнику питания.

В листинге 8.13 приводится скетч для управления электродвигателями с помощью шилда Arduino Motor Shield (контакты A0 и A1 платы Arduino задействованы для измерения тока, поэтому для управления в скетче используются контакты A2 и A3).

Листинг 8.13. Управление электродвигателями с помощью шилда Arduino Motor Shield

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
39
40
41
42
43
44
45
46
47
48
49
50
/*
* Скетч Brushed_H_Bridge_Direction sketch for motor shield
* Управляет электродвигателями на основании сигналов фотодатчиков,
* направляя шасси робота к источнику света
*/
int leftPins[] = {3,12}; // Один контакт для ШИМ-сигнала (скорость),
// один — для направления
int rightPins[] = {11,13};
const int MIN_PWM = 64; // Это значение может быть в диапазоне
// от 0 до MAX_PWM
const int MAX_PWM = 128; // Это значение может быть в диапазоне от 50 до 255
const int leftSensorPin = A2; // Аналоговые контакты для подключения фотодатчиков
const int rightSensorPin = A3;
int sensorThreshold = 0; // Пороговый уровень освещенности на датчике
// для вращения электродвигателя
void setup()
{
pinMode(leftPins[1], OUTPUT);
pinMode(rightPins[1], OUTPUT);
}
 
void loop(){
int leftVal = analogRead(leftSensorPin);
int rightVal = analogRead(rightSensorPin);
if(sensorThreshold == 0) // Датчики откалиброваны?
{
// Если нет, калибруем до уровня освещенности несколько выше
// среднего уровня освещенности окружающей среды
sensorThreshold = ((leftVal + rightVal) / 2) + 100 ;
}
if( leftVal &gt; sensorThreshold || rightVal &gt; sensorThreshold)
{
// Если уровень освещенности достаточно высокий для движения вперед
setSpeed(rightPins, map(rightVal,0,1023, MIN_PWM, MAX_PWM));
setSpeed(leftPins, map(leftVal, 0,1023, MIN_PWM, MAX_PWM));
}
}
void setSpeed(int pins[], int speed )
{
if(speed &lt; 0)
{
digitalWrite(pins[1], HIGH);
speed = -speed;
}
else
{
digitalWrite(pins[1], LOW);
}
analogWrite(pins[0], speed);
}

Функция loop() здесь идентична этой функции скетча из листинге 8.12. Функция setSpeed() скетча содержит меньший объем кода, чем ее предыдущая версия, поскольку аппаратное обеспечение шилда позволяет использовать только один контакт платы Arduino для управления направлением вращения электродвигателя.
В шилде Ardumoto используются другие контакты, поэтому для работы с ним код скетча нужно откорректировать следующим образом:

1
2
3
int leftPins[] = {3, 2}; // Один контакт для ШИМ-сигнала (скорость),
// один — для направления
int rightPins[] = {11, 4};

В листинге 8.14 приводится код скетча, реализующий эту же функциональность на основе шилда Adafruit Motor Shield V2 (https://oreil.ly/kFygk), подключение которого показано на рис. 8.14. В скетче используется библиотека Adafruit_MotorShield, которая устанавливается стандартным способом с помощью Менеджера библиотек.

Шилд Adafruit Motor Shield V2 поддерживает подключение четырех электродвигателей, но в скетче из листинге 8.14 предусмотрено, что два электродвигателя подключены к разъемам шилда 3 и 4.

Листинг 8.14. Управление электродвигателями с помощью шилда Adafruit Motor Shield V2

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
* Скетч Brushed_H_Bridge_Direction sketch for Adafruit Motor shield
* Управляет электродвигателями на основании сигналов фотодатчиков,
* направляя шасси робота к источнику света
*/
#include &lt;Wire.h&gt;
#include &lt;Adafruit_MotorShield.h&gt; // Подключаем библиотеку Adafruit_MotorShield
// Создаем экземпляр объекта шилда
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *leftMotor = AFMS.getMotor(1);
Adafruit_DCMotor *rightMotor = AFMS.getMotor(2);
const int MIN_PWM = 64; // Это значение может быть в диапазоне от 0 до MAX_PWM
const int MAX_PWM = 128; // Это значение может быть в диапазоне от 50 до 255
const int leftSensorPin = A0; // Аналоговые контакты для подключения фотодатчиков
const int rightSensorPin = A1;
int sensorThreshold = 0; // Пороговый уровень освещенности на датчике
// для вращения электродвигателя
void setup()
{
AFMS.begin(); // Инициализируем экземпляр шилда частотой
// по умолчанию 1,6 КГц
}
 
void loop()
{
int leftVal = analogRead(leftSensorPin);
int rightVal = analogRead(rightSensorPin);
if(sensorThreshold == 0) // Датчики откалиброваны?
{
// Если нет, калибруем до уровня освещенности несколько выше
// среднего уровня освещенности окружающей среды
sensorThreshold = ((leftVal + rightVal) / 2) + 100 ;
}
if( leftVal &gt; sensorThreshold || rightVal &gt; sensorThreshold)
{
// Если уровень освещенности достаточно высокий для движения вперед
setSpeed(rightMotor, map(rightVal,0,1023, MIN_PWM, MAX_PWM));
setSpeed(leftMotor, map(leftVal ,0,1023, MIN_PWM, MAX_PWM));
}
}
void setSpeed(Adafruit_DCMotor *motor, int speed )
{
if(speed &lt; 0)
{
motor-&gt;run(BACKWARD);
speed = -speed;
}
else
{
motor-&gt;run(FORWARD);
}
motor-&gt;setSpeed(speed);
}

C:\Users\acer\Documents\#Electronics\Магазин электроники\фрагменты из книг\2788. Arduino Cookbook. Recipes to Begin, Expand, and Enhance\verstka\pic\08\8.14.png

Рис. 8.14. Подключение шилда Adafruit Motor Shield V2

В случае использования иного шилда, чем только что рассмотренные, надо будет уточнить по его справочному листку, что значения в скетче совпадают с контактами, используемыми для сигналов управления скоростью (ШИМ) и направления.

Дополнительная информация

Подробная информация по адаптерной плате компании Pololu для H-моста TB6612FNG приводится в справочном листке на нее (https://oreil.ly/bD_83).

Дополнительная информация по шилду Ardumoto компании SparkFun приводится на его веб-странице (https://oreil.ly/XZTCY).

Дополнительная информация по шилду Arduino Motor Shield приводится на его веб-странице (https://oreil.ly/2gKoX).

Дополнительная информация по шилду Adafruit Motor Shield V2 приводится на его веб-странице (https://oreil.ly/T19_o).

Опубликовано

Подключение к Интернету с помощью платы расширения Arduino Ethernet shield

По материалам книги В. Петина “Проекты с использованием контроллера Arduino. 4-е изд.” (глава 13. Arduino и Интернет вещей)

Проекты с использованием контроллера Arduino. 4-е изд.

Самый распространенный метод обеспечить доступ платы Arduino к сети Интернет — использование платы Ethernet shield (рис. 13.1). Ethernet shield — это плата расширения, которая устанавливается на плату Arduino сверху. Она дает ей возможность выступать в роли сетевого устройства и общаться по проводной сети с аналогичными устройствами, с обычными компьютерами, принтерами, сервисами в Интернете и прочими сетевыми ресурсами. Последняя версия платы Ethernet Shield Rev3 полностью совместима с Arduino Mega2560.

Плата Ethernet shield основана на микросхеме Wiznet W5100, которая поддерживает как TCP-, так и UDP-протоколы. Одновременно открытыми могут быть до четырех подключений.

Плата обладает стандартным Ethernet-портом для подключения к сети с помощью патч-корда витой пары и набором контактов для подключения к Arduino. Для общения между собой Ethernet shield и Arduino задействуют контакты 4-й и с 10-го по 13-й, поэтому их использование в других целях в присутствии платы расширения невозможно.

Для программирования сетевого взаимодействия подключается библиотека Ethernet из стандартного дистрибутива. При использовании этой библиотеки необходимо указывать MAC-адрес платы (уникальный идентификатор любого сетевого устройства). В более новых версиях Ethernet-шилда MAC-адрес можно увидеть на наклейке на плате. Если такой наклейки нет, то просто введите любую похожую комбинацию, — главное, чтобы в вашей сети не было устройств с совпадающими MAC-адресами.
На плате размещен слот для карты памяти формата microSD, которая может быть использована для хранения ресурсов, раздаваемых по сети. Для взаимодействия с такой картой следует подключить, например, библиотеку sdfatlib.
Для отправки данных в облачные сервисы в примерах этого раздела мы воспользуемся веб-клиентом на основе платы Arduino c установленной на нее платой расширения Ethernet shield.

ris_04_04

Рис. 13.1. Плата Ethernet shield Rev3

13.1.1. Получение IP-адреса по DHCP

Соединим Ethernet shield с платой Arduino и создадим простой пример получения ими IP-адреса по DHCP. Соединяется Ethernet shield с платой Arduino так же просто, как и любой другой шилд, — просто состыкуйте их вместе. Cледует учесть, что установка других шилдов поверх Ethernet shield весьма затруднительна. Это связано с большими размерами имеющегося на плате Ethernet shield разъема RJ-45, служащего для подключения сетевого кабеля, поэтому, если вы хотите использовать совместно с Arduino еще и другие шилды, лучше их размещать между Arduino и Ethernet shield.

Итак, подключим плату Arduino к USB-порту компьютера, а Ethernet shield подсоединим c помощью сетевого кабеля к маршрутизатору, имеющему выход в Интернет (рис. 13.2).

Скетч, обеспечивающий получение IP-адреса по DHCP, представлен в листинге 13.1, а пример назначения статического IP-адреса — в листинге 13.2.

ris_04_05

Рис. 13.2. Подключение к плате Arduino платы расширения Ethernet shield Rev3

Листинг 13.1

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
// Получение IP-адреса по DHCP
// MAC-адрес Ethernet shield (можно увидеть на наклейке на плате) или
// произвольный уникальный в сети
 
#include &lt;Ethernet.h&gt;
#include &lt;SPI.h&gt;
byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02};
void setup() {
 
// Open serial communications and wait for port to open:
 
Serial.begin(9600);
}
 
// запуск Ethernet-соединения
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
for (;;)
;
}
 
// печать в последовательный порт полученного по DHCP адреса
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte &lt; 4; thisByte++) {
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
}
 
void loop() {;}

Электронный архив

Полный вариант рассмотренного скетча находится в папке examples\13\_13_01 сопровождающего книгу электронного архива (см. приложение 2).


Листинг 13.2

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
// Получение статического IP-адреса
// MAC-адрес Ethernet shield (можно увидеть на наклейке на плате) или
// произвольный уникальный в сети
 
#include &lt;Ethernet.h&gt;
#include &lt;SPI.h&gt;
byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02};
 
// IP-адрес, назначаемый Ethernet shield:
byte ip[] = { 192, 168, 0, 111 };
// IP-адрес dns сервера:
byte sdns[] = { 192, 168, 1, 1 };
// адрес шлюза:
byte gateway[] = { 192, 168, 0, 1 };
// маска:
byte subnet[] = { 255, 255, 255, 0 };
 
void setup() {
Serial.begin(9600);
// запуск Ethernet-соединения
Ethernet.begin(mac, ip, sdns, gateway, subnet);
delay(1000);
Serial.println(Ethernet.localIP());
}
 
void loop() {;}

Электронный архив
Полный вариант рассмотренного скетча находится в папке examples\13\_13_02 сопровождающего книгу электронного архива (см. приложение 2).


Опубликовано

Термостатический охладитель напитков на модуле Пельтье

Раздел гл. 12 книги “Мейкерство. Arduino и Raspberry Pi” (автор Саймон Монк)

В этом проекте мы добавим термостатическое регулирование к проекту из разд. «Проект: охладитель напитков» главы 11, чтобы напитки могли более точно охлаждаться до нужной температуры (рис. 12.17). В главе 14 проект получит свое дальнейшее развитие — к нему будет добавлен дисплей, показывающий заданную и фактическую температуры.

Термостатический охладитель напитков в сбореРис. 12.17. Термостатический охладитель напитков в сборе

Как уже было сказано, этот проект реализуется с использованием Arduino, но учитывая, что вы уже научились использовать Raspberry Pi совместно с микросхемой DS18B20, у вас не должно возникнуть проблем и по изменению проекта под работу с Raspberry Pi.

Оборудование

Этот проект основывается на проекте из разд. «Проект: охладитель напитков» главы 11, но с добавлением в рабочий цикл платы Arduino и датчика температуры DS18B20, поэтому, если вы еще не проработали тот проект, следуйте инструкциям по его реализации, имеющимся в главе 11.

Комплектующие

В этом проекте для работы с Arduino понадобятся следующие комплектующие (табл. 12.2).

Таблица 12.2. Комплектующие для работы с Arduino в проекте по управлению термостатическим охладителем напитков

Обозначение Компонент схемы Источники
R1 Резистор 4,7 кОм Mouser: 291-4.7k-RC
R2 Резистор 1 кОм Mouser: 291-1k-RC
R3 Резистор 270 Ом Mouser: 291-270-RC
R4 Подстроечный резистор на 10 кОм Adafruit: 356

Sparkfun: COM-09806

Герметичный температурный датчик DS18B20 Adafruit: 381

eBay

Q1 МОП-транзистор FQP30N06L Mouser: 512-FQP30N06L
LED1 Зеленый светодиод Adafruit: 298

Sparkfun: COM-09650

Термоэлектрическое охлаждающее устройство на элементах Пельтье с двумя вентиляторами и с током потребления не более 4 А eBay
Переходник с круглым гнездом и винтовыми зажимами Adafruit: 368
Источник питания (12 В 5 A) Adafruit: 352
Двунаправленная клеммная колодка Магазин строительных или электротоваров
Большая емкость из-под молока или сока Б/у

Герметичный температурный датчик DS18B20 содержит точно такую же микросхему, что использовалась в экспериментах из разд. «Эксперимент: насколько хорош терморегулятор, основанный на включении и выключении?» и из разд. «Эксперимент: термостатический ПИД-регулятор», за исключением того, что он поставляется в удобной водонепроницаемой капсуле с длинными проводами, которые могут быть подключены непосредственно к макетной плате.

Если потребуется задействовать более мощный элемент Пельтье, чем тот, что указан в табл. 12.2, следует воспользоваться более мощным блоком питания, чтобы его максимально допустимый ток наверняка превышал ток, потребляемый элементом. Предусмотрите, как минимум, превышение в половину ампера для вентиляторов и еще в половину ампера на всякий случай.

Схема проекта

Принципиальная схема этого проекта показана на рис. 12.18. В левой части схемы показан подстроечный резистор R4, который также называют потенциометром (см. далее врезку «Потенциометры»). Подвижный контакт потенциометра подключен к контакту A0, представляющему собой аналоговый вход Arduino (см. разд. «Аналоговые входы» главы 2). Положением ручки потенциометра на контакте A0 устанавливается напряжение, которое замеряется Arduino, а затем используется для установки нужной температуры охладителя.

Потенциометры

Компонент под названием потенциометр должен быть вам известен по регуляторам громкости радиоприемника или усилителя. У него есть ручка, вращающаяся почти на полный оборот.

Область на рис. 12.18 вокруг R4, показывает, как потенциометр используется в качестве устройства ввода данных в Arduino: верхний контакт потенциометра подключен к линии 5 В, а нижний — к заземлению, при этом на среднем контакте потенциометра напряжение в зависимости от положения ручки будет изменяться в диапазоне от 0 до 5 В.

Правая часть схемы на рис. 12.18 очень похожа на схему эксперимента из разд. «Эксперимент: насколько хорош терморегулятор, основанный на включении и выключении?», за исключением того, что вместо маломощного транзистора MPSA14 используется мощный МОП-транзистор FQP30N06L. Этот транзистор способен коммутировать подводимый к охладителю ток силой 4 А и более, при этом степень его нагрева позволяет обойтись без радиатора.

Принципиальная схема термостатического охладителяРис. 12.18. Принципиальная схема термостатического охладителя

Сборка проекта

Предполагая, что вы уже реализовали проект из разд. «Проект: охладитель напитков» главы 11, для реализации этого проекта нужно выполнить лишь следующие дополнительные действия.

Шаг 1. Добавление температурного датчика

Физическая конструкция охладителя остается точно такой же, что и в проекте из разд. «Проект: охладитель напитков» главы 11, но теперь к ней добавляется температурный датчик, который следует разместить на дне контейнера — под ставящиеся на него охлаждаемые стаканы или бутылки (рис. 12.19). В данном случае я просто прикрепил датчик ко дну контейнера клейкой лентой, но лучше его все же основательно приклеить.

Добавление температурного датчикаРис. 12.19. Добавление температурного датчика

Шаг 2. Сборка схемы на макетной плате

На рис. 12.20 показана собранная на макетной плате схема, используемая для проекта, а также показаны соединения различных деталей проекта.

Схема проекта, собранная на макетной платеРис. 12.20. Схема проекта, собранная на макетной плате

Расположите компоненты на макетной плате, убедившись в правильном подключении МОП-транзистора и светодиода. Температурный датчик имеет в своем кабеле четыре провода. Провода с красной и черной изоляцией подключаются соответственно к общей линии питания (VCC) и к заземлению (GND), а провод с желтой изоляцией является цифровым выходом зонда. Четвертый провод никуда подключать не нужно.

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

Шаг 3. Подключение охладителя

У охладителя имеются три пары проводов: две — для вентиляторов, и одна — для самого элемента Пельтье. Чтобы упростить подключение охладителя, используется двунаправленная клеммная колодка, позволяющая подключить охладитель к макетной плате всего двумя проводами (рис. 12.21).

Подключение охладителяРис. 12.21. Подключение охладителя

Шаг 4. Подключение блока питания

Переходник с круглым гнездом и винтовыми зажимами, конечно, может быть подключен к макетной плате перемычками «папа-папа». С этим вариантом можно согласиться в случае использования высококачественных проводов-перемычек относительно большого поперечного сечения, однако многие соединительные провода содержат слишком тонкие проводники, которые могут сильно нагреваться от проходящего по ним тока силой в несколько ампер. Само по себе это не создает проблем до тех пор, пока эти провода не станут сильно греться, вместо того, чтобы быть просто теплыми. Но это означает, что из 12 В на элемент Пельтье станет попадать не все напряжение, и на то, чтобы войти в рабочий режим, охладителю потребуется больше времени.

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

Программа для Arduino

Использование ПИД-регулятора для охладителя напитков можно посчитать излишеством. Но вопрос в данном случае упирается только в программу, поэтому на использование «крутого» алгоритма поддержки напитков в охлажденном состоянии дополнительных затрат не предвидится.

Программа этого проекта во многом похожа на ту, что использовалась в экспериментах из разд. «Эксперимент: насколько хорош терморегулятор, основанный на включении и выключении?» и из разд. «Эксперимент: термостатический ПИД-регулятор», включая весь код для создания интерфейса с температурным датчиком DS18B20, поэтому, чтобы разобраться в этом коде, следует вернуться к описанию упомянутых экспериментов:

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include &lt;OneWire.h&gt;
#include &lt;DallasTemperature.h&gt;
#include &lt;PID_v1.h&gt;
const double minTemp = 0.0; //<strong> 1</strong>
const double maxTemp = 20.0;
const float tempOKMargin = 0.5;
double kp = 1500; //<strong> 2</strong>
double ki = 50.0;
double kd = 0.0;
const int tempPin = 2;
const int coolPin = 9;
const int ledPin = 10; //<strong> 3</strong>
const int potPin = A0;
const long period = 1000; // &gt;750
OneWire oneWire(tempPin);
DallasTemperature sensors(&amp;oneWire);
double setTemp = 0.0;
double measuredTemp = 0.0;
double outputPower = 0.0;
long lastSampleTime = 0;
PID myPID(&amp;measuredTemp, &amp;outputPower,
&amp;setTemp, kp, ki, kd, REVERSE); //<strong> 4</strong>
 
void setup() {
pinMode(coolPin, OUTPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
sensors.begin();
myPID.SetSampleTime(1000);
myPID.SetMode(AUTOMATIC);
}
 
void loop() { //<strong> 5</strong>
long now = millis();
if (now &gt; lastSampleTime + period) {
checkTemperature();
lastSampleTime = now;
}
setTemp = readSetTempFromPot(); //<strong> 6</strong>
}
 
void checkTemperature() { //<strong> 7</strong>
measuredTemp = readTemp();
Serial.print(measuredTemp);
Serial.print(", ");
Serial.print(setTemp);
Serial.print(", ");
Serial.println(outputPower);
myPID.Compute();
analogWrite(coolPin, outputPower);
float error = setTemp - measuredTemp; //<strong> 8</strong>
if (abs(error) &lt; tempOKMargin) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
}
double readSetTempFromPot() { //<strong> 9</strong>
int raw = analogRead(potPin);
double temp = map(raw, 0, 1023, minTemp, maxTemp);
return temp;
}
double readTemp() {
sensors.requestTemperatures();
return sensors.getTempCByIndex(0);
}

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

  1. Диапазон температур, задаваемых с помощью потенциометра, устанавливается двумя константами: minTemp и maxTemp. Переменная tempOKMargin определяет значение выше или ниже заданной температуры, которое может иметь фактическая температура до того, как погаснет зеленый светодиод.
  2. Для kp установлено довольно высокое значение, чтобы включение и выключение охладителя происходило более четко. Сделано это в основном с тем, чтобы избавиться от унылого звучания моторов вентиляторов, когда они питаются в режиме низкого уровня выходной мощности. Вместо этого вентиляторы можно запитать отдельно, чтобы они постоянно работали, и заниматься только регулировкой мощности на элементе Пельтье.
  3. Определение дополнительных контактов для светодиода и потенциометра.
  4. ПИД-регулятор инициализируется в режиме REVERSE, а не DIRECT (как ранее), поскольку добавление выходной мощности будет снижать, а не повышать температуру.
  5. В основном цикле проверяется истечение секундного интервала, после чего для включения и выключения охладителя по мере надобности вызывается функция checkTemperature.
  6. При каждом прохождении цикла (которое должно осуществляться несколько раз в секунду), для установки значения переменной setTemp на основании позиции ручки потенциометра вызывается функция readSetTempFromPot.
  7. Функция checkTemperature производит измерение температуры, считывает полученные данные, а затем производит обновление ПИД-контроллера. Эта функция также записывает прочитанные данные в окно монитора порта, позволяя настроить охладитель или отследить его работу. Arduino не нуждается в подключении через порт USB, поскольку получает электропитание через свой контакт Vin, но если его подключить через порт USB, выводимые данные можно будет увидеть на экране в окне монитора порта.
  8. Остальная часть этой функции включает светодиод, если измеренная температура находится в пределах допустимого отклонения от заданной температуры, определяемого с помощью константы tempOKMargin. Функция abs (абсолютное значение) удаляет знак минуса перед числом.
  9. Код превращения позиции потенциометра в значение между minTemp и maxTemp. Необработанное аналоговое считывание (значения в диапазоне от 0 до 1023) производится в переменную raw. Затем для преобразования считанного значения в желаемый диапазон температур вызывается функция map (см. далее врезку «Функция map, используемая в Arduino»).

Функция map, используемая в Arduino

При управлении какими-либо устройствами с помощью Arduino или Raspberry Pi часто возникает проблема преобразования числа, имеющего один диапазон значений, в число в каком-нибудь другом диапазоне значений.

Например, на аналоговом входе Arduino установлен диапазон значений от 0 до 1023, и если нужно отобразить этот диапазон на температуру, например, между 0 и 20, можно просто разделить число на 51,15 (то есть, на 1023 / 20). Тогда 1023 превратится в 1023 / 51,15 = 20.

Задача усложняется, если оба диапазона начинаются не с нуля. И тут может пригодиться имеющаяся в Arduino функция map. Как далее показано, она получает пять параметров, которые преобразуют число в диапазоне от 0 до 1023 в число в диапазоне от 20 до 40:

map(value, 0, 1023, 20, 40);

Первый параметр представлен здесь значением, которое нужно преобразовать, второй и третий параметры задают диапазон имеющегося значения, а четвертый и пятый — диапазон, в котором нужно получить соответствующее значение (в данном случае, это диапазон от 20 до 40).

В языке Python отсутствует встроенная функция диапазона, но ее довольно просто создать, а затем использовать в своей программе. Она должна выглядеть примерно так:

1
2
3
4
5
6
7
8
def map(value, from_low, from_high,
to_low, to_high):
from_range = from_high -
from_low
to_range = to_high - to_low
scale_factor = from_range / to_range
return to_low + (value /
scale_factor)

Затем эту функцию на языке Python можно будет вызвать с такими же параметрами, что и у ее двойника в Arduino. Например:

map(510, 0, 1023, 20, 40)

В результате будет возвращено значение 30, которое является средним значением для диапазона от 20 до 40, точно так же, как и значение 510, которое расположено примерно посредине между значениями в диапазоне от 0 до 1023.

Опубликовано

Охладитель напитков на элементе Пельтье

Глава из книги “Мейкерство. Arduino и Raspberry Pi” (автор Саймон Монк)

Элементы Пельтье

Элементы Пельтье (рис. 11.5) обладают очень полезным свойством — когда через них пропускается ток, одна сторона элемента становится более горячей, а другая — более холодной.

Чтобы это произошло, пропускаемый ток должен иметь солидную величину (обычно от 2 до 6 А при 12 В), т. е. для использования элемента Пельтье вам понадобится достаточно мощный блок питания. Такие элементы можно часто обнаружить в переносных холодильниках и в охладителях напитков. Элементы Пельтье в ряде случаев предпочтительнее обычных холодильников, поскольку у них нет движущихся частей, которые могут сломаться.

mkac_1105

Рис. 11.5. Элемент Пельтье

Как работают элементы Пельтье?

Когда электрический ток протекает через переход между двумя различными проводящими материалами, то материал с одной стороны перехода становится несколько горячее, а с другой — несколько холоднее. Это явление назвали эффектом Пельтье в честь французского физика Жана Пельтье, открывшего его в 1894 году. Явление это известно также как термоэлектрический эффект.

Термоэлектрический эффект относительно мал, и чтобы сделать его нам полезным, — например, для охлаждения напитков, его нужно многократно усилить. Это достигается за счет размещения групп переходов друг за другом — тогда при прохождении тока каждый переход вносит свой вклад в общий эффект. Обычные недорогие элементы Пельтье имеют, как правило, около 12 переходов (рис. 11.6). По обеим сторонам элемента Пельтье расположен базовый материал, образующий основу для блока групп переходов.

Устройство элемента Пельтье

Рис. 11.6. Устройство элемента Пельтье

Материалы, образующие стыки (переходы) элемента Пельтье, — это полупроводники двух типов, аналогичные тем, что используются при производстве транзисторов и микросхем, но оптимизированные для термоэлектрического эффекта. Они известны как полупроводники N-типа и P-типа — от слов Negative (отрицательный) и Positive (положительный).

Элементы Пельтье имеют еще одну очень интересную особенность — их можно использовать не только для охлаждения. Если нагреть одну сторону элемента Пельтье больше, чем другую, то элемент будет генерировать небольшое количество электроэнергии.

Особенности практического применения

Основная проблема элементов Пельтье состоит в том, что горячая и холодная его стороны находятся в тесном контакте, вследствие чего горячая сторона очень быстро нагревает холодную. Чтобы уменьшить этот неприятный эффект, нужно снимать тепло с холодной стороны как можно скорее.

Решением такой проблемы может может служить применение теплоотводящего радиатора (рис. 11.7). Такой радиатор представляет собой алюминиевую пластину с ребрами, увеличивающими площадь охлаждаемой поверхности, что способствует лучшему отводу тепла. Холодная сторона элемента сконструирована в виде блока, вдающегося внутрь теплоотводящего радиатора.

Простой радиатор сам по себе не столь эффективен, как тот же радиатор, но с вентилятором. Вентилятор уносит от пластин радиатора нагретый за счет конвекции воздух и заменяет его новой порцией холодного воздуха. На практике некоторые устройства имеют вентиляторы с обеих сторон элемента Пельтье, что позволяет повысить эффективность его работы (рис. 11.8).

mkac_1107

Рис. 11.7. Элемент Пельтье на теплоотводящем радиаторе

mkac_1108

Рис. 11.8. Охлаждение элемента Пельтье двумя вентиляторами

Проект: охладитель напитков

В этом проекте не используется ни Raspberry Pi, ни Arduino. Проект просто демонстрирует, как нужно подключать элемент Пельтье, и как можно самому собрать простой охладитель напитков (рис. 11.9). Этот базовый проект мы дополним в главе 12, добавив в него контроль за температурой и термостабилизацию. Затем, в главе 14, в него будет добавлен OLED-дисплей для отображения температуры.

mkac_1109

Рис. 11.9. Охладитель напитков в сборе

Комплектующие

В этом проекте нам понадобятся следующие комплектующие (табл. 11.3).

Таблица 11.3. Комплектующие для работы с проектом охладителя напитков

Компонент схемы Источники
Элемент Пельтье с двумя охлаждающими вентиляторами (ток 4 А или меньше) eBay
Переходник с круглым гнездом и винтовыми зажимами Adafruit: 368
Источник питания (12 В 5 A) Adafruit: 352
Большая емкость из-под молока или сока Б/у
Освежающий напиток

Если потребуется задействовать более мощный элемент Пельтье, чем тот, что указан в табл. 11.3, следует воспользоваться более мощным блоком питания, чтобы его максимально допустимый ток наверняка превышал ток, потребляемый элементом. Предусмотрите, как минимум, превышение в половину ампера для вентиляторов и еще в половину ампера на всякий случай.

Конструкция

Рассмотрев провода, идущие к блоку охлаждения, можно выделить три пары проводов: одна пара идет к элементу Пельтье, и по паре проводов — к каждому из вентиляторов. Им всем требуется 12 В от источника питания, и самый простой способ подключения состоит в использовании винтового зажима на разъеме, идущем к блоку питания. Проще говоря, все три красных провода от охлаждающего устройства нужно зафиксировать в винтовой клемме с маркировкой (+), а все три черных провода — в винтовой клемме с маркировкой (–), как показано на рис. 11.10.

mkac_1110

Рис. 11.10. Подключение проводов в проекте охладителя напитков

Крышку пластикового контейнера, предназначенного для охлаждения емкости с напитком, нужно отрезать, а в его боковой стенке вырезать квадратное отверстие с таким расчетом, чтобы охлаждающая часть элемента Пельтье в этом отверстии плотно держалась (рис. 11.11). Контейнер должен быть достаточно большим, чтобы в нем можно было разместить для охлаждения любимый стакан или бутылочку.

mkac_1111

Рис. 11.11. Подготовка пластикового контейнера

Если на охлаждающей стороне элемента Пельтье имеются отверстия под винты для крепления, то под них нужно проделать отверстия также и в контейнере, — с помощью винтов элемент можно будет закрепить на контейнере надежнее. При правильно вырезанном отверстии дно контейнера и основание элемента Пельтье окажутся на одном уровне, и в собранном виде у контейнера не будет причин опрокидываться.

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

Использование охладителя

Когда вся конструкция будет собрана, подключите блок питания, — оба вентилятора должны начать вращаться, и если опустить в контейнер руку, то сразу же можно будет почувствовать холодный воздух, идущий от меньшего вентилятора.

Как показали расчеты, проведенные при попытке вскипятить воду, изменение температуры даже относительно небольшого количества воды занимает много времени. И хотя наш охладитель способен охладить и теплый напиток, гораздо лучше до использования сохранять напиток прохладным, чем дожидаться, пока до нужной температуры охладится теплый напиток.

Этот проект также несколько неэкономичен, на сохранять прохладным небольшого количества напитка расходует 50 Вт электрической энергии. В главе 12 мы сделаем наш проект несколько эффективней, добавив в него режим термостатирования.

Заключение

В этой главе мы узнали, что быстрый нагрев и охлаждение требуют довольно высокой мощности, и что схемы с использованием транзисторов и реле могут успешно использоваться для управления как нагревателями, так и элементами Пельтье.

В следующей главе мы рассмотрим способы точного регулирования температуры и узнаем, как можно улучшить охладитель напитков, используя терморегулятор.

Опубликовано

Модуль реле в системе автополива

По материалам руководства к набору “Умный дом на базе Arduino. Большой набор + КНИГА

Реле позволяет электрическому сигналу или импульсу включать (или выключать) электрический ток. Для управления реле используется низкое напряжение или слабый ток, чтобы с его помощью управлять высоким напряжением и/или сильным током.

В электромеханическом реле ток протекает через катушку, которая действует как электромагнит, замыкающий (или размыкающий) контакты силовой части реле. Кроме электромеханических существуют и твердотельные реле использующие твердотельную электронику (без катушки и механических движущихся частей).

Внешний вид, назначение контактов

Для удобства управления и подключения к Arduino реле устанавливаются на платы, где, кроме самого реле, расположены контакты для подключения нагрузки и другие элементы (рис. M3.1). На одной плате могут размещаться несколько реле.

3-03-1-relay

Рис. M3.1. Назначение контактов одноканальных модулей реле

Основные характеристики

Наименование Значение
Рабочее напряжение, В 5
Потребляемый ток при переключении контактов, мА 5
Потребляемый ток в состоянии ожидания, мА 10 ÷ 13
Рабочая частота, МГц 13,56
Размеры (L×W×H), мм 50×26×18,5
Максимальная нагрузка AC 250 В/10 A
DC 30 В/10 A

 


Предупреждение

Модуль реле, входящий в набор, рассчитан на коммутирование небольших нагрузок. Вы можете подключать к нему бытовые приборы с рабочим напряжением 220 В, но нагрузка не должна превышать 3-х ампер (мощность до 660 Вт).
Имейте в виду, что мощность утюга составляет 1000÷1500 Вт, и поэтому такое реле не годится для создания устройства для включения/выключения утюга. Cуществуют специальные модули реле, рассчитанные на большие мощности.


Схема подключения

3-03-2-relay

Рис. M3.2. Схема подключения реле

Программный код

Тестовая программа для включения и выключения лампочки через каждые 2 секунды приведена в листинге M3.1.

Листинг M3.1. Включение лампочки с помощью реле

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define relayPin 2 //номер пина для управления реле
 
void setup() {
 
pinMode(relayPin, OUTPUT); //настройка пина реле на выход
 
}
 
void loop() {
 
digitalWrite(relayPin, HIGH);// замыкаем реле
 
delay(3000); // ждем 3 секунды
 
digitalWrite(relayPin, LOW); // размыкаем реле
 
delay(3000); // ждем 3 секунды
 
}

«Умный горшок»

С помощь модуля реле можно создать систему автоматического полива растений в цветочном горшке. Для этого, кроме модуля реле, мы задействуем микронасос, помещенный в банку с водой, и датчик влажности почвы (рис. M3.3). Как только влажность почвы опускается ниже заданных значений, Arduino включает микронасос и выключает его, когда почва становится снова достаточно влажной.

Систему можно усложнить, добавив датчик глубины, чтобы сигнализировать об окончании воды в банке и недопустить сгорания микронасоса.

Схема подключения

3-03-3-relay

Рис. M3.3. Система автоматического полива цветочного горшка

Программный код

Листинг M3.2. Система автоматического полива цветочного горшка

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//определения
 
// пин аналогового выхода датчика уровня воды
 
#define pinWaterLevel A0
 
//пин аналогового выхода датчик влажности почвы
 
#define pinSoilMoisture A1
 
//пин реле для управление насосом
 
#define pinRelayPump 12
 
 
 
//константы
 
const int delayPumpBefore=2; //время полива (в секундах)
 
const int delayPumpAfter=30; //время после полива, чтобы
 
//земля пропиталась (в секундах)
 
const int minMoisture=600; //минимальный порог влажности почвы
 
 
 
// переменные
 
int aLevel = 0; // значение датчика уровня воды
 
int aMoisture = 0; // состояние датчика влажности почвы
 
int levels[3]={600,500,400}; //массив значений уровней воды
 
 
 
//установки
 
void setup() {
 
//объявляем пин реле для включения насоса как выход:
 
pinMode(pinRelayPump, OUTPUT);
 
//объявляем пины датчиков глубины и влажности почвы как входы:
 
pinMode(pinWaterLevel, INPUT);
 
pinMode(pinSoilMoisture, INPUT);
 
Serial.begin(9600);
 
}
 
 
 
void loop() {
 
// считываем значение датчика уровня воды
 
aLevel=analogRead(pinWaterLevel);
 
// считываем состояния датчика влажности почвы
 
aMoisture = analogRead (pinSoilMoisture);
 
Serial.println(aMoisture); //выводим для тестирования
 
delay(100);
 
// если почва сухая, и вода в банке есть, то включаем полив
 
if ((aMoisture &gt;minMoisture)&amp;&amp;(aLevel&gt;levels[2])) {
 
digitalWrite(pinRelayPump, HIGH); //включаем насос
 
delay(delayPumpBefore*1000); //задержка на полив
 
digitalWrite(pinRelayPump, LOW); //выключаем насос
 
delay(delayPumpAfter*1000); //задержка на слив воды из
 
//шланга после выключения насоса
 
}
 
else {
 
digitalWrite(pinRelayPump, LOW);
 
}
 
}

Для адаптации программы к конкретному цветочному горшку надо произвести небольшую «тонкую настройку» системы:

  • во-первых, следует правильно установить время полива (delayPumpBefore), которое определяется паузой между включением и выключением насоса. Чем больше горшок, тем больше должна быть пауза и, как следствие, время полива;
  • во-вторых, надо установить правильное время после полива (delayPumpAfter), чтобы земля успела пропитаться, и система не включила повторный полив. Трубку подачи воды при этом удобно разместить рядом с датчиком влажности почвы, чтобы земля в районе датчика сразу пропитывалась.
Опубликовано

Модуль BLE Bluetooth HM-10/11

По материалам руководства к набору “Умный дом на базе Arduino. Большой набор + КНИГА

Модули Bluetooth оснащены последовательным портом, способным взаимодействовать с платой Arduino через контакты RX (прием) и TX (передача), и приемопередатчиком, использующим протокол беспроводной связи Bluetooth для взаимодействия «по воздуху» с другими устройствами, который понимают этот протокол (например, со смартфонами). Такой приемопередатчик функционирует как модем, преобразовывая сигналы протокола Bluetooth в обычный асинхронный последовательный протокол и обратно.

Существуют различные протоколы Bluetooth. Модули HM-10 и HM-11 поддерживают протокол Bluetooth 4.0, что дает возможность их подключения к смартфонам и на ОС Android, и на iOS (iPhone) — в отличие от популярных модулей HC-05 и HC-06, которые могут взаимодействовать только с ОС Android. HM-10/11 нельзя соединить с модулями HC-06 и HC-05, т. к. последние поддерживают протокол Bluetooth 2/2.1.

Наиболее существенным достоинством модулей Bluetooth BLE (Bluetooth Low Energy, Bluetooth LE) является их сверхмалое пиковое энергопотребление, среднее энергопотребление и энергопотребление в режиме простоя, что весьма важно для устройств с автономным питанием.


Примечание

Модуль HM-11, по своим эксплуатационным характеристикам аналогичен HM-10, но занимает меньшую площадь и имеет меньшее количество контактов.


Внешний вид, назначение контактов

bluetooth-hm-10

Рис. M5.1. Внещний вид и назначение контактов Bluetooth HM-10

Технические характеристики

Наименование Значение
Чип Bluetooth CC2540 или CC2541
Протокол связи Bluetooth 4.0 BLE
Радиус действия до 100 метров
Объем flash-памяти (для хранения прошивки и настроек), Мбит 8
Частота радиосигнала, ГГц 2,40 ÷ 2,48
Ток
  • в режиме установки связи — до 50 мА
  • после установки связи 9 мА
  • в режиме сна — 50 ÷ 200 µA
Напряжение питания, В + 2,5 В до + 3,3 В
Пароль по умолчанию 000000
Имя Bluetooth устройства по умолчанию HMSoft, BT05-A

До тех пор, пока модуль HM-10 не сопряжен ни с одним устройством, он находится в режиме команд и об этом сообщает мигающим светодиодом. При сопряжении с устройством светодиод начинает гореть постоянно, а модуль переходит в режим передачи данных.

Схема подключения

3-05-2-bluetooth

Рис. M5.2. Подключение Bluetooth HM-10

Тестируем подключение Bluetooth

  1. Установим терминальное приложение для смартфона. Их достаточно много, и функциональные возможности их примерно одинаковы. Предлагаем для смартфонов с OC Android популярное бесплатное приложение Serial Bluetooth Terminal, ориентированное на работу как с «классическими» модулями Bluetooth, так и с модулями, которые поддерживают протокол Bluetooth 4.0 BLE (рис. M5., а). Для iPhone и iPad можно использовать приложение HM10 Bluetooth Serial Lite (рис. M5.3, б).
3-05-3-bluetootch
а б

Рис. M5.3. а — окно установки Serial Bluetooth Terminal на Google Play; б — установка приложение HM10 Bluetooth Serial Lite для iOS

  1. Установив приложение на смартфон, откройте его. При этом Bluetooth на смартфоне должен быть включен.
  2. Подключите Bluetooth, как показано на рис. M5.2, а. Индикатор, расположенный на модуле Bluetooth, начнет мигать в ожидании соединения.
  3. Выберите в меню команду Device, а затем нажмите кнопку SCAN в правом верхнем углу окна (рис. M5.2, б).
а б

Рис. M5.4. Поиск устройств Bluetooth BLE в радиусе действия вашего телефона

  1. После недолгого поиска на экране появится список обнаруженых модулей Bluetooth (рис. M5.5, а). Ваш модуль может быть обозначен в списке на вкладке BLUETOOTH LE как HM-10 или BT05-A (в зависимости от производителя).
  2. Щелкните двойным щелчком на имени вашего модуля Bluetooth, и произойдет соединение модуля с платой Arduino через последовательный порт. При этом светодиодный индикатор на модуле перестанет мигать, а на экране смартфона появится надпись Connected (рис. M5.5, б).
а б

Рис. M5.5. Подключение к Bluetooth BLE

Совет

В зависимость от производителя конкретного устройства Android и версии операционной системы (для Android она должна быть выше 4.3) вы можете увидеть или не увидеть HM-10 среди устройств, обнаруженных Bluetooth (Bluetooth devices). Если ваш Android не находит HM-10 в своих настройках Bluetooth, попробуйте использовать приложение BLE Scanner app.

Взаимодействие смартфона и Arduino через Bluetooth BLE

Теперь, когда соединение Arduino и модуля Bluetooth установлено, осуществим обмен информацией между устройствами. Для этого:

  1. Временно отсоедините провода, подключенные к контактам D0 (RX) и D1(TX) платы Arduino, и загрузите код, приведенный в листинге M5.1.

Листинг M5.1. Обмен информацией между Arduino и модулем Bluetooth

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void setup() {
 
Serial.begin(9600);
 
Serial.println("poexali!");
 
}
 
void loop() {
 
if (Serial.available()) {
 
char c = Serial.read(); // читаем из software-порта
 
Serial.print(c); // пишем в hardware-порт
 
}
 
}

Если при загрузке скетча на Arduino не отключать эти провода, то компилятор выдаст ошибку, показанную на рис. M5.6. Конфликт связан с тем, что пины D0 и D1 также используются для связи с компьютером посредством USB.

Рис. M5.6. Ошибки загрузки скетча в Arduino

  1. Снова подключите провода к контактам D0 (RX) и D1(TX) и выполните сопряжение смартфона с модулем Bluetooth, как было показано на рис. M5.5.
  2. Выполнив сопряжение, можно поздороваться с хостом на другом конце Bluetooth-канала (рис. M5.7). Как можно видеть, приветствие прошло успешно!
3-05-7a-bluetootch 3-05-7b-bluetootch
а б

Рис. M5.7. Привет Arduino! — вводим на смартфоне (а) и получаем в Мониторе порта (б)

При отладке скетча вам придется многократно отключать провода от контактов D0 и D1 во время загрузки скетча в Arduino. Кроме того, одного порта вам может быть недостаточно. В этом случае целесообразно использовать библиотеку SoftwareSerial, которая предустановлена в Arduino IDE. Библиотека SoftwareSerial позволяет реализовать последовательный интерфейс не только на D0 и D1, но и на любых других цифровых выводах Arduino с помощью программных средств, дублирующих функциональность UART (отсюда и название «SoftwareSerial»). Кроме того, она дает возможность программно создавать несколько последовательных портов, работающих на скорости до 115200 бод.

  1. Подключите контакты TX и RX модуля Bluetooth к выводам D2 и D3 (RXD3, TXD2) платы Arduino (а не к D0 и D1, как вы делали ранее!).
  2. Загрузите код, приведенный в листинге M5.2.

Листинг M5.2. Сопряжение платы Arduino и модуля Bluetooth

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
#include &lt;SoftwareSerial.h&gt;
 
SoftwareSerial mySerial(2,3);//указываем пины RX и TX соответственно
 
void setup() {
 
pinMode(2,INPUT);
 
pinMode(3,OUTPUT);
 
Serial.begin(9600);
 
mySerial.begin(9600);
 
Serial.println("poexali!");
 
}
 
void loop() {
 
if (mySerial.available()) {
 
char c = mySerial.read(); // читаем из software-порта
 
Serial.print(c); // пишем в hardware-порт
 
}
 
if (Serial.available()) {
 
char c = Serial.read(); // читаем из hardware-порта
 
mySerial.write(c); // пишем в software-порт
 
}
 
}
  1. Введите в Мониторе порта любой текст (рис. M5.8, а) и нажмите кнопку Отправить — текст появится в окне терминала смартфона (рис. M5.8, б).
3-05-8a-bluetootch 3-05-8b-bluetootch
а б

Рис. M5.8. Привет Android! вводим в Мониторе порта (а) и получаем на смартфоне (б)

Управление светодиодом RGB по Bluetooth

Теперь осуществим на практике управление электронным прибором со смартфона по каналу Bluetooth.

1. Соберите схему, представленную на рис. M5.9.

3-05-9

Рис. M5.9. Управление RGB-светодиодом через Bluetooth

2. Загрузите скетч, приведенный в листинге M5.3.

Листинг M5.3. Управление светодиодом RGB через Bluetooth

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include &lt;SoftwareSerial.h&gt;
 
// Константы для хранения номеров контактов вывода:
 
const int greenPin = 9; //"зеленый" контакт LED RGB
 
const int bluePin = 10; //"синий" контакт LED RGB
 
const int redPin = 11; //"красный" контакт LED RGB
 
const int pinRX = 2; //RX – вход для приема данных -&gt; к TX bluetooth
 
const int pinTX = 3; //TX – выход для передачи данных -&gt; к RX bluetooth
 
int currentPin = 0; // текущий контакт для задания яркости
 
SoftwareSerial mySerial(pinRX,pinTX); // указываем пины rx и tx
 
void setup() {
 
pinMode(pinRX,INPUT);
 
pinMode(pinTX,OUTPUT);
 
pinMode(redPin, OUTPUT);
 
pinMode(greenPin, OUTPUT);
 
pinMode(bluePin, OUTPUT);
 
 
 
Serial.begin(9600);
 
mySerial.begin(9600);
 
Serial.println("poexali!");
 
}
 
void loop() {
 
if (mySerial.available()) {
 
char inByte = mySerial.read(); // читаем из software-порта
 
Serial.print(inByte); // пишем в hardware-порт
 
rgb(inByte); //включаем светодиод «цветом» inByte
 
}
 
 
 
if (Serial.available()) {
 
char c = Serial.read(); // читаем из hardware-порта
 
mySerial.write(c); // пишем в software-порт
 
rgb(c); //включаем светодиод «цветом» с
 
}
 
}
 
//функция для включения светодиода RGB
 
void rgb(byte cByte){
 
digitalWrite(currentPin,LOW);
 
// игнорируем любые другие значения:
 
if (cByte == 'r') {
 
currentPin = redPin;
 
}
 
if (cByte == 'g') {
 
currentPin = greenPin;
 
}
 
if (cByte == 'b') {
 
currentPin = bluePin;
 
}
 
digitalWrite(currentPin,HIGH);
 
}

3. Теперь, вводя символы r, g и b в Мониторе порта или на смартфоне, подключенном через модуль Bluetooth с помощью терминальной программы, мы можем изменять цвет светодиода RGB.