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

Источники питания

По материалам книги “Занимательные проекты на базе микроконтроллеров tinyAVR” (глава 1. «Источники питания»)

Занимательные проекты на базе микроконтроллеров tinyAVR

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

Батареи

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

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

Широко распространен угольно-цинковый гальванический элемент. Его корпус сделан из цинка (который служит отрицательным полюсом). Корпус заполнен пастой из хлорида цинка и хлорида аммония (которая служит электролитом). Положительный полюс батареи — угольный или графитовый стержень, окруженный смесью диоксида марганца и угольным порошком. По мере использования цинковая оболочка становится тоньше (вследствие химической реакции, ведущей к окислению цинка) и в конечном итоге электролит начинает вытекать из корпуса. Угольноцинковые батареи — самые дешевые. Выпускаются также щелочные батареи (рис. 1.16), которые похожи на угольно-цинковые, но в качестве электролита здесь применяется гидроксид калия. Номинальное напряжение угольно-цинковых и щелочных гальванических элементов равно 1,5 В.

Часто встречаются гальванические элементы на основе оксида серебра и лития. Батарейки на оксиде серебра (их напряжение равно 1,8 В) имеют гораздо более высокую удельную энергию, чем угольно-цинковые. В литиевых батареях используются различные химические соединения, в зависимости от комбинации которых напряжение может составлять от 1,5 до 3,7 В. На рис. 1.17 показаны литиевые и щелочные батарейки в форме таблеток.

Главная проблема с одноразовыми батареями состоит в том, что после разряда их необходимо сразу перерабатывать. В этом плане аккумуляторы гораздо привлекательнее: их можно несколько раз перезарядить (до того, как вам придется отправить их на переработку). Аккумуляторные батареи изготавливают как стандартныхразмеров, так и на заказ. Самые распространенные — свинцово-кислотные, никелькадмиевые, никель-металлогидридные, а также литий-ионные батареи. На рис. 1.18 показана литий-ионная батарея. Для зарядки аккумуляторных батарей требуются специальные зарядные устройства. Так, например, заряжать литий-ионную батарею зарядным устройством для никель-металлогидридных батарей нельзя, поскольку при этом батарея будет повреждена, что может привести даже к ее взрыву и пожару.

Рис. 1.16. Щелочные батареи типоразмеров 9 В и AAA

Рис. 1.17. Маленькая LR44 — щелочная батарея, большая CR2032 — литиевая батарея

Рис. 1.18. Литий-ионная батарея

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

Таблица 1.2. Обозначения батарей и их размеры

Обозначение Форма Длина, мм Диаметр/Длина, мм Высота, мм
ААА Цилиндр 44,5 12
АА Цилиндр 50,5 14,5
9V Прямоугольный параллелепипед 48,5 17,5 26,5
C Цилиндр 50 26,2
D Цилиндр 61,5 34,2

При выборе батареи необходимо учитывать следующие характеристики:

  • Энергетическая емкость. Выражается в ампер-часах (или в миллиампер-часах). Это важная характеристика, которая показывает, как долго “продержится” батарея до полного разряда. Помните, что чем больше емкость батареи, тем больше ее размеры.
  • Напряжение, выдаваемое батареей.
  • Условия хранения (когда батарея не используется).
  • Срок хранения. Показывает, сколько времени пройдет до полного саморазряда батареи. Не стоит покупать батареи про запас на десять лет вперед, если срок хранения составляет, к примеру, всего один год.
  • Рабочая температура. Все химические источники тока имеют плохие температурные характеристики, т. к. скорость протекания химических реакций сильно зависит от температуры. При слишком низких (и высоких) температурах батареи работают очень плохо.
  • Рабочий цикл. Некоторые батареи работают лучше тогда, когда они используются с перерывами. Рабочий цикл батареи показывает, можно ли включать батарею в непрерывном режиме без потери ее характеристик.

Батарея из фруктов

Для получения электричества можно использовать некоторые фрукты и овощи. Содержащиеся в них электролиты пригодны для изготовления простейших гальванических элементов. Для изготовления “фруктового” источника питания потребуется лимон, а также два электрода: медный и цинковый. Напряжение такого источника питания равно примерно 0,9 В. Величина тока зависит от площади электродов, контактирующих с электролитом, а также от качества самого электролита.

Для нашей “фруктовой” батареи потребуется несколько лимонов (это будет электролит) и несколько кусков меди и цинка (это будут электроды). В качестве меди мы возьмем кусок фольгированного текстолита, а в качестве цинка — полоски, вырезанные из корпуса обычной батареи.

Последовательность изготовления батареи.

  1. Начнем с куска текстолита. Его размер должен быть достаточным, чтобы на нем можно было создать три или четыре “острова”, на каждом из которых поместится половинка разрезанного лимона.
  2. Затем вскроем несколько батареек размера АА, сделаем из них цинковые полоски и зачистим их наждачной бумагой. Припаяем к каждой полоске по проводу. Вместо цинковых полосок подойдут даже гвозди. Гвозди обычно покрыты цинком, поэтому пригодны для изготовления батареи.
  3. На медной печатной плате нужно напильником (или пилой) вырезать “островки” и припаять к каждому из них второй конец провода (от цинковой полоски). На одну ячейку понадобится половина лимона, один медный островок и одна цинковая полоска.
  4. Положите половинки лимонов на медные островки. Сделайте на лимонах разрезы и вставьте в них цинковые полоски. На рис. 1.19 показана лимонная батарея из четырех элементов.

Рис. 1.19. “Лимонная” батарея

Адаптер переменного тока

Если вы используете адаптер переменного тока, то потребуется выпрямитель и емкостной фильтр (рис. 1.20). Выпрямитель можно собрать на отдельных диодах (например, 1N4001) либо взять готовый выпрямительный блок. Если источник питания выдает ток 500 мА, то диоды должны быть рассчитаны, по меньшей мере, на 1 А. Нужно учесть еще одну характеристику диода: максимальное обратное напряжение (Peak Inverse Voltage, PIV), которое диод может выдержать до пробоя. Так, например, максимальное обратное напряжение диода 1N4001 равно 50 В, а 1N4007 — 1000 В.

Рис. 1.20. Схема из выпрямителя и емкостного фильтра может использоваться как с переменным током, так и с постоянным

Амплитуда выпрямленного напряжения на конденсаторе фильтра в 1,4 раза выше среднеквадратического значения входного напряжения переменного тока. Значит, переменное напряжение в 10 В создаст на конденсаторе фильтра постоянное напряжение, равное примерно 14 В. Важно также правильно выбрать емкость и рабочее напряжение конденсатора фильтра. Чем больше емкость, тем меньше пульсации напряжения на выходе. При напряжении 14 В следует взять конденсатор с рабочим напряжением не менее 25 В. Схему, изображенную на рис. 1.20, можно использовать и с источником постоянного тока. При этом полярность подключенного источника тока не будет иметь значения.

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

Широко распространены трехвыводные стабилизаторы типа 78ХХ. Они выпускаются многими компаниями и изготавливаются в разных корпусах. Для питания процессора AVR следует выбрать стабилизатор 7805 с выходным напряжением 5 В. Он может выдавать выходной ток до 1 А и питаться постоянным напряжением от 9 до 20 В. Подойдет также микросхема LM317, напряжение на выходе которой (1,25 В и выше) можно настроить при помощи двух резисторов.

Стабилизатор напряжения — это активный компонент, и при работе он потребляет некоторый ток. Этот ток называется током покоя и имеет порядок десятков миллиампер. Существуют специальные стабилизаторы напряжения с очень малым током покоя. Микросхемы LP2950 и LP2951 — это линейные микромощные стабилизаторы с низким током покоя (около 75 мА) компании National Semiconductor, имеющие очень малое падение напряжения (примерно 40 мВ при высокоомной нагрузке и 380 мВ при максимальном токе в 100 мА). Они идеально приспособлены для систем с питанием от батарей. Более того, ток покоя микросхем LP2950/LP2951 при повышении напряжения на них увеличивается очень незначительно. Это самые популярные трехконтактные стабилизаторы с низким током покоя, именно поэтому мы используем их во многих наших проектах.

Питание от разъема USB

USB — это популярный интерфейс, который есть и в персональных компьютерах, и в ноутбуках. В основном он служит для обмена данными между компьютером и периферийными устройствами (такими, как видеокамера, клавиатура и т. д.). USB — это четырехпроводной интерфейс с двумя контактами для питания и двумя для обмена данными. Питание на USB подается с компьютера. Номинальное напряжение равно +5 В, но по спецификации USB 2.0 оно может составлять от +4,4 до +5,25 В. Внешние устройства, подключаемые к компьютеру, например, мышь, могут получать питание от USB. Этим напряжением можно питать и другие внешние схемы, которые не связаны компьютером. Мы применяем питание от USB для устройств, расположенных недалеко от компьютера. С разъема USB можно взять ток до 100 мА (можно получить и больше, но для этого нужно дать запрос с устройства). В табл. 1.3 приведены питающие и сигнальные контакты порта USB.

Таблица 1.3. Контакты разъема USB (для форм-факторов Mini и Micro)

Контакт Наименование Цвет провода Назначение
1 Vcc Красный +5 В
2 D Белый Сигнал данных –ve
3 D+ Зеленый Сигнал данных +ve
4 ID Бесцветный Идентификация устройства
5 Gnd Черный Заземление

Солнечная энергия

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

Генератор на эффекте Фарадея

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

Рис. 1.21. Генератор напряжения на эффекте Фарадея

Рис. 1.22. Сигнал на выходе генератора Фарадея

Корпусом служит трубка из оргстекла подходящего диаметра и длины. Внутри нее находится магнит. Поверх трубки намотана катушка из нескольких сотен витков медного изолированного провода. Концы трубки закрыты заглушками. Для генерирования напряжения конструкцию встряхивают, магнит перемещается по трубке и создает в медном проводе переменное напряжение, которое можно выпрямить и отфильтровать, например, при помощи схемы, показанной на рис. 1.20. Единственная проблема состоит в том, что вам придется трясти эту трубку ровно столько времени, сколько вы хотите вырабатывать напряжение. Как только магнит останавливается, генерация напряжения прекращается и сохраняется только остаточное напряжение на конденсаторе. Но во многих случаях и этого оказывается достаточно. Одно из возможных решений — применение ионисторов. Однако для их зарядки до требуемого напряжения вам может понадобиться потратить много времени и сил.

В качестве стабилизатора к такому источнику рекомендуем использовать микросхему LP2950.

На рис. 1.22 показана осциллограмма сигнала на выходе генератора Фарадея. Ее размах превышает 17 В.

Питание от энергии радиоволн

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

Рис. 1.23. Принцип питания от источника радиочастоты

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

Выполненная по этому принципу реальная система описана в документе “Wireless battery energizes low-power devices”: www.edn.com/article/CA6501085.html.

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

Обзор “малюток” Tiny

По материалам книги “Занимательные проекты на базе микроконтроллеров tinyAVR” (глава 1. «Обзор “малюток” Tiny»)

Занимательные проекты на базе микроконтроллеров tinyAVR

В соответствии с законом Мура степень интеграции микросхем по-прежнему увеличивается в два раза (ну, почти в два) каждые 18 месяцев. Это означает, что каждые полтора года изготовители интегральных полупроводниковых схем могут разместить на той же самой площади микросхемы в два раза больше транзисторов и прочих компонентов. Эта важная гипотеза была впервые высказана Гордоном Муром (одним из основателей компании Intel) в середине 1960 годов и, как это ни удивительно, по-прежнему остается верной (более или менее). Габариты персо- нального компьютера постоянно уменьшаются. Существуют различные модели компьютеров: настольные, переносные, карманные и т. д. Недавно появились так называемые компактные компьютеры (Small Form Factor PC). Это доступные по- требителю небольшие универсальные компьютеры со стандартным программным обеспечением. Действие закона Мура распространяется не только на персональные компьютеры, но и на бытовые электронные устройства: мой нынешний мобильный телефон (который имеет гораздо больше функций, чем предыдущий) значительно компактнее своего предшественника!

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

В стремлении к малогабаритным изделиям наше внимание привлекли компью- теры еще более компактных размеров: Tiny (“малютка”). В отличие от прочих ком- пьютеров, это миниатюрные специализированные компьютерные системы, кото- рые могут поместиться в нагрудном кармане рубашки. Многие изготовители поставляют наборы для сборки таких компьютеров (лидеры здесь — компании Microchip и Atmel). По размерам микросхема соизмерима с рисовым зернышком и все, что ей нужно, — это подходящий источник питания и схема сопряжения. За- программируйте микросхему соответствующим образом, и у вас получится свое собственное персональное электронное устройство, которое может быть совершен- но уникальным.

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

Микроконтроллеры tinyAVR компании Atmel

Серия микроконтроллеров tinyAVR имеет много разновидностей. Число выво- дов может быть от 4 (у серии ATtiny4/5/9/10) и до 28 (у серии ATtiny48/88). Неко- торые микросхемы серии ATtiny48/88 имеют только 24 контакта. Широко приме- няется схема ATtiny13, которая имеет 8 контактов: два для питания и шесть для ввода/вывода. Это не слишком много, но даже при помощи шести контактов дос- тупны разнообразные возможности.

Из представленной далее в этой главе таблицы микросхем tinyAVR мы вы- брали для большинства наших проектов следующие: ATtiny13, ATtiny25/45/85 и ATtiny261/461/861. Они представляют собой весь спектр семейства Tiny. Все эти микросхемы снабжены статической памятью (SRAM) для программирования на языке С. Схема Tiny13 имеет всего 1 Кбайт памяти для хранения программ, а схемы Tiny861 и Tiny85 — 8 Кбайт. Схемы Tiny13 и Tiny25/45/85 совместимы по цоко- левке, но серия Tiny25/45/85 имеет больше памяти и функций. Если код не поме- щается в схеме Tiny13, то ее можно заменить схемой Tiny24/45/85 (в зависимости от требований к размеру памяти).

Почти все устройства, описанные в этой книге, отличаются привлекательным внешним видом благодаря большим светодиодным индикаторам. Новый метод управления большим числом светодиодов при помощи ограниченного числа управляющих выводов (Charlieplexing — “метод Чарли”) позволяет мультиплекси- ровать до 20 светодиодов, имея всего пять контактов ввода/вывода. Данный метод применялся для реализации привлекательных графических дисплеев и управления семисегментными индикаторами. В некоторых устройствах использованы графи- ческие жидкокристаллические дисплеи.

Любую описанную конструкцию можно собрать за один-два дня.

Микросхемы tinyAVR

Микросхемы tinyAVR отличаются друг от друга по нескольким признакам: по числу выводов, по размеру памяти, по типу корпуса (DIP — корпус с двумя рядами выводов по длинным сторонам; SOIC — то же для поверхностного монтажа; MLF — квадратный корпус для поверхностного монтажа), по периферийным функциям, по интерфейсам обмена и т. д. На рис. 1.1 показаны примеры микросхем tinyAVR в корпусах типа DIP, а на рис. 1.2 — в корпусах типа SOIC. Номенклатура микросхем постоянно меняется, поскольку компания Atmel регулярно добавляет новые устройства для замены старых. Последние изменения можно всегда посмот- реть на сайте по ссылке: www.avrgenius.com/tinyavr1.

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

Некоторые основные серии и схемы семейства tinyAVR приведены в табл. 1.1 и на рис. 1.1, 1.2.

Если в маркировке микросхемы имеется буква “А”, значит, схема выполнена по технологии picoPower и снабжена функцией для снижения потребления электро- энергии.

Рис. 1.1. Микроконтроллеры tinyAVR в корпусах DIP

Рис. 1.2. Микроконтроллеры tinyAVR в корпусах SMD

Таблица 1.1. Некоторые основные серии и микросхемы семейства tinyAVR

Номер п/п Серия/ Микросхема Описание
1 ATtiny4/5/9/10 Максимум 4 контакта ввода/вывода, рабочее напряжение 1,8–5,5 В, 32 байта SRAM, производительность до 12 MIPS (на частоте 12 МГц), Flash-память для хранения программ (1 Кбайт в ATtiny9/10 и 512 байт в ATtiny4/5), аналого- цифровой преобразователь (в ATtiny9/10)
2 ATtiny13 Максимум 6 контактов ввода/вывода, рабочее напряжение 1,8–5,5 В, 64 байта SRAM, 64 байта EEPROM, производи- тельность до 20 MIPS (на частоте 20 МГц), 1 Кбайт Flash- памяти для хранения программ, аналого-цифровой преобра- зователь (ADC)
3 ATtiny24/44/84 Максимум 12 контактов ввода/вывода, рабочее напряжение 1,8–5,5 В, 128/256/512 байт SRAM и 128/256/512 байтEEPROM (соответственно), производительность до 20 MIPS (на частоте 20 МГц), 2/4/8 Кбайт Flash-памяти для хранения программ (соответственно), аналого-цифровой преобразова- тель (ADC), температурный датчик (на кристалле), универ- сальный последовательный интерфейс (USI)
4 ATtiny25/45/85 Максимум 6 контактов ввода/вывода, рабочее напряжение 1,8–5,5 В, 128/256/512 байт SRAM и 128/256/512 байтEEPROM (соответственно), производительность до 20 MIPS (на частоте 20 МГц), 2/4/8 Кбайт Flash-памяти для хранения программ (соответственно), аналого-цифровой преобразова- тель (ADC), универсальный последовательный интерфейс (USI)
5 ATtiny261/461/8 61 Максимум 16 контактов ввода/вывода, рабочее напряжение 1,8–5,5 В, 128/256/512 байт SRAM и 128/256/512 байтEEPROM (соответственно), производительность до 20 MIPS (на частоте 20 МГц), 2/4/8 Кбайт Flash-памяти для хранения программ (соответственно), аналого-цифровой преобразова- тель (ADC), универсальный последовательный интерфейс (USI)
6 ATtiny48/88 Максимум 24/28 контактов ввода/вывода (в зависимости от корпуса), рабочее напряжение 1,8–5,5 В, 256/512 байт SRAM (соответственно), 64 байта EEPROM, производительность до 12 MIPS (на частоте 12 МГц), 4/8 Кбайт Flash-памяти для хранения программ (соответственно), аналого-цифровой преобразователь (ADC), последовательный внешний интер- фейс (SPI)
7 ATtiny43U Максимум 16 контактов ввода/вывода, рабочее напряже- ние 0,7–1,8 В, 256 байт SRAM, 64 байта EEPROM, произ- водительность до 1 MIPS на мегагерц, 4 Кбайт Flash- памяти для хранения программ, аналого-цифровой пре- образователь (ADC), температурный датчик (на кристал- ле), универсальный последовательный интерфейс (USI). Микросхема с низким энергопотреблением, встроенный преобразователь автоматически генерирует стабильное напряжение питания 3 В от низковольтного источника пи- тания (не ниже 0,7 В)

Архитектура tinyAVR

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

Память

В архитектуре AVR предусмотрено два основных адресных пространства: па- мять данных и память программ. Кроме того, микросхемы имеют стираемую па- мять типа EEPROM для хранения данных. Flash-память для хранения программ организована как линейный массив 16-разрядных ячеек (поскольку размер всех команд AVR равен 16 или 32 бита). Адресное пространство внутренней памяти SRAM, внутренних регистров и регистров ввода/вывода общее. Младшие 32 байта заняты внутренними регистрами, следующие 64 байта — регистрами ввода/вывода; затем адресация SRAM продолжается с адреса 0х60. Внутренняя память EEPROM предназначена для временного хранения данных. На рис. 1.3 показана карта памяти микроконтроллеров семейства Tiny.

Рис. 1.3. Карта памяти микроконтроллеров семейства Tiny

Порты ввода/вывода

Порты ввода/вывода контроллеров AVR состоят из отдельных контактов, каж- дый из которых можно сконфигурировать для ввода или вывода. К любому вход- ному контакту можно присоединить нагрузку. Это необходимо для подключения датчиков, которые не выдают электрического сигнала (например, микропереклю- чателей). Каждый выходной буфер обеспечивает ток 40 мA, что позволяет напря- мую подключать светодиоды. Все контакты ввода/вывода защищены диодами по шинам питания и земли. На рис. 1.4 показана блок-схема портов ввода/вывода кон- троллеров AVR.

Рис. 1.4. Блок-схема порта ввода/вывода контроллеров семейства Tiny

Таймеры

В микросхемах tinyAVR обычно есть встроенные синхронные или асинхронные восьмиразрядные таймеры. Для синхронного тактирования служит сигнал от внут- реннего тактового генератора (или от делителя частоты), для асинхронного — внешний тактовый сигнал либо цепь фазовой автоподстройки частоты (Phase Lock Loop, PLL), которая работает на частоте до 64 МГц.

Рис. 1.5. Блок-схема таймера AVR

В состав некоторых контроллеров входят также 10- или 16-разрядные таймеры. Помимо счетчика, эти таймеры также имеют блоки сравнения, которые генерируют ШИМ-сигнал на контактах ввода/вывода. Таймеры могут работать в разных режи- мах (нормальный, захват, режим широтно-импульсной модуляции, сброс таймера по результату сравнения и т. д.). Каждый таймер имеет несколько связанных с ним источников прерываний, которые описываются в следующем разделе, посвящен- ном прерываниям. На рис. 1.5 показана блок-схема таймера AVR.

Прерывания

В контроллерах AVR предусмотрено несколько различных источников преры- ваний, которым выделены соответствующие векторы в адресном пространстве про- грамм. По умолчанию векторы прерываний занимают первые адреса в адресном пространстве программ. Самый младший адрес (0х0000) назначен вектору сброса, который вообще говоря, не является источником прерывания. Адрес прерывания определяет также и его приоритет. Чем ниже адрес, тем выше уровень приоритета прерывания. Поэтому сброс имеет самый высокий приоритет. Если одновременно происходит несколько прерываний, то первым выполняется прерывание с самым высоким приоритетом, за ним прерывание с более низким приоритетом и т. д. Пре- рывание приостанавливает нормальное выполнение основной программы и пере- ставляет счетчик команд на подпрограмму обработки прерывания (Interrupt Service Routine, ISR). После обработки прерывания счетчик команд устанавливается снова на основную программу. На рис. 1.6 показано выполнение кода ISR.

Рис. 1.6. Обработка прерывания

Каждому прерыванию присваивается свой бит разрешения, который для активи- зации прерывания должен быть установлен в логическую единицу (так же как и глобальный бит разрешения прерываний в регистре состояния). Глобальный бит разрешения прерываний при выполнении ISR по умолчанию сбрасывается, поэтому никакие другие прерывания произойти не могут (если только программа пользова- теля не выставила явным образом глобальный бит разрешения прерываний, чтобы разрешить вложенные прерывания (прерывания внутри другого прерывания)). Пе- риферийные устройства AVR (таймеры, интерфейс USI, АЦП, аналоговые компа- раторы и т. д.) имеют разные источники прерываний для различных состояний или режимов.

USI: универсальный последовательный интерфейс

Интерфейс USI обеспечивает основные аппаратные ресурсы для последователь- ного обмена. Этот интерфейс можно сконфигурировать для работы либо по трех- проводному протоколу (который совместим с последовательным периферийным интерфейсом SPI), либо по двухпроводному протоколу (который совместим с двух- проводным интерфейсом TWI). При минимальном управляющем программном обеспечении интерфейс USI допускает значительно более высокие скорости пере- дачи и требует меньше памяти для программ (чем чисто программные решения). Прерывания применяются для уменьшения нагрузки на процессор.

Аналоговый компаратор

Контроллеры AVR имеют компаратор, который измеряет аналоговое входное напряжение на двух входах и выдает цифровой выходной сигнал (0 или 1) в зави- симости от того, на каком входе (положительном или отрицательном) есть на- пряжение.

Рис. 1.7. Блок-схема аналогового компаратора

Положительный и отрицательный входы могут быть выбраны из нескольких контактов ввода/вывода. Изменение выхода компаратора можно использовать как источник прерывания. Выход компаратора можно увидеть на контакте выхода ана- логового компаратора (АСО). На рис. 1.7 показана блок-схема аналогового компа- ратора.

Аналого-цифровой преобразователь

Аналого-цифровой преобразователь (АЦП, ADC) представляет собой 10-разрядный преобразователь последовательного приближения с несколькими несимметричны- ми входами. В некоторых микросхемах есть также дифференциальные входы (для преобразования разности аналоговых напряжений в двух точках в цифровой код). Для повышения точности измерений иногда усиливают входное напряжение (до преобразования). Опорное напряжение для измерения можно брать с контактов AREF, VCC и от внутреннего источника опорного напряжения. На рис. 1.8 показа- на блок-схема аналого-цифрового преобразователя.

Рис. 1.8. Блок-схема аналого-цифрового преобразователя

Источники тактовых сигналов

Источники сигналов тактовой частоты: калиброванный RC-генератор, внешний тактовый генератор, кварцевый генератор, сторожевой генератор, низкочастотный кварцевый генератор, а также генератор с фазовой автоподстройкой частоты (PLL). Источник тактового сигнала можно задать (из этих вариантов) при помощи fuse- битов (конфигурационных ячеек). Частота сигнала от выбранного источника может быть впоследствии подвергнута предварительному делению (при помощи выстав- ления битов в регистре предварительного деления) во время инициализации программного обеспечения пользователя. Тактовый сигнал поступает в разные модули микросхемы (CPU, I/O, Flash и ADC):

  • CLK_CPU — синхронизирует те части системы, которые обеспечивают работу ядра AVR (внутренние регистры, регистр состояния и т. д.).
  • CLK_I/O — используется большинством модулей ввода/вывода (тайме- ры/счетчики, интерфейс USI, синхронные внешние прерывания и т. д.).
  • CLK_FLASH — управляет работой интерфейса Flash-памяти.
  • CLK_ADC — в отличие от других модулей ввода/вывода, АЦП получает от- дельный тактовый сигнал, чтобы во время работы АЦП можно было прервать другие тактовые сигналы (для снижения помех остальных цифровых цепей). Это позволяет получить более точные результаты аналого-цифрового преобра- зования. На рис. 1.9 показаны разные варианты подачи сигнала тактовой час- тоты.

Рис. 1.9. Источники сигнала тактовой частоты

Управление электропитанием и режимы ожидания

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

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

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

Сброс системы

Источники сигнала сброса контроллеров AVR:

  • Сброс по включению питания — микроконтроллер сбрасывается, когда напря- жение питания уменьшается до заданного порога срабатывания.
  • Внешний сброс — когда на контакте RESET присутствует низкий уровень сигнала.
  • Сброс по сторожевому таймеру — когда активизирован сторожевой таймер и его период ожидания истек.
  • Сброс по падению напряжения питания — когда активизирован детектор паде- ния напряжения и напряжение питания VCC оказывается ниже заданного порога срабатывания.

После сброса его источник может быть определен программно посредством проверки отдельных битов регистра состояния микроконтроллера. Во время сброса все регистры ввода/вывода устанавливаются в свои начальные значения, и про- грамма начинает выполнение с вектора сброса. На рис. 1.10 показана блок-схема различных источников сигнала сброса.

Рис. 1.10. Источники сигнала сброса

Программирование микроконтроллеров

Программирование контроллеров AVR включает в себя установку битов блокиро- вания, fuse-битов, программирование Flash-памяти, а также программирование внут- ренней памяти EEPROM. Эти данные могут быть считаны с контроллера вместе с байтами идентификации устройства. Микросхемы семейства Tiny можно запро- граммировать при помощи последовательного или параллельного способа. В этой книге (если не оговорено другое) мы применяли последовательное программирова- ние микроконтроллеров семейства Tiny. Здесь тоже есть два варианта: системное программирование (ISP) и последовательное программирование при высоком напря- жении (HVSP). HVSP применим (как альтернатива параллельному программирова- нию) только для восьмиконтактных микроконтроллеров (поскольку эти микросхемы имеют слишком мало контактов для параллельного программирования).

Системное программирование использует внутренний последовательный перифе- рийный интерфейс (SPI) контроллеров AVR для загрузки кода в память Flash и EEPROM. При этом также программируются биты блокирования и fuse-биты. Для такого программирования требуются только контакты VCC, GND, RESET и три сиг- нальных линии. В некоторых случаях для ввода/вывода (или других целей) может потребоваться контакт RESET. Если этот контакт сконфигурирован как контакт для ввода/вывода (при помощи бита RSTDISBL), то программирование в режиме ISP не- возможно и микросхему следует программировать при помощи параллельного про- граммирования или последовательного программирования при высоком напряжении. Для программирования контроллеров AVR есть еще один метод — система отладки debugWIRE (описана в следующем разделе). Последняя серия шестиконтактных мик- росхем компании Atmel (ATtiny4/5/9/10) не поддерживает описанных ранее вариантов

программирования и имеет новый встроенный интерфейс программирования TPI.

Биты блокирования служат для защиты программного обеспечения пользовате- ля (во избежание дублирования), а fuse-биты применяются для начальной настрой- ки контроллера, которая не может (и не должна) выполняться программным обес- печением пользователя. На рис. 1.11 показаны сигналы для последовательного программирования ISP.

Рис. 1.11. Сигналы для последовательного программирования

Отладочная система debugWIRE

Отладочная система debugWIRE — это однопроводной интерфейс для аппарат- ной отладки и программирования памяти Flash и EEPROM. Этот интерфейс вклю- чается посредством программирования fuse-бита DWEN. После включения этого интерфейса обмен данными между микросхемой и эмулятором происходит через контакт RESET. Таким образом, при программировании через этот интерфейс внешний сброс не работает. Протокол программирования в данном случае анало- гичен JTAG ICE mkII (популярный инструмент отладки компании Atmel). На рис. 1.12 показан отладочный интерфейс debugWIRE.

Рис. 1.12. Отладочный интерфейс debugWIRE

Составляющие проекта

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

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

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

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

Рис. 1.13. Процесс проектирования и разработки

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

Рис. 1.14. Элементы современного проекта с использованием микроконтроллера

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

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

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

Для работы устройства очень важен источник сигнала тактовой частоты. К сча- стью, такой источник обычно есть в самом микроконтроллере. Обычно это RC- генератор, который не очень точен и частота которого зависит от рабочего напря- жения, но для многих устройств этого вполне достаточно. Внешний источник так- товой частоты понадобится только для тех приложений, которые критичны к изме- рению времени. Все микроконтроллеры семейства AVR снабжены встроенным источником сигнала тактовой частоты и в большинстве проектов этой книги мы используем именно его. Скорость выполнения программы напрямую зависит от тактовой частоты. Однако высокая тактовая частота имеет и недостаток: система потребляет больше электроэнергии. Между тактовой частотой и потреблением энергии существует линейная зависимость. Если вы удвоите тактовую частоту, то потребление энергии также возрастет в два раза. Поэтому неразумно выбирать са- мую высокую рабочую частоту, лучше определить ее исходя из требуемой скоро- сти выполнения программы. Как мы покажем в проекте 1 (далее в этой же главе), выбрав самую низкую тактовую частоту, мы можем снизить потребляемую мощ- ность до минимума. Основные компоненты устройства показаны на рис. 1.15.

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

Рис. 1.15. Основные компоненты устройства

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

Шина SPI и библиотеки сторонних разработчиков

По материалам книги Т.Иго «Изучаем Arduino: инструменты и методы технического волшебства. 2-е изд.: пер. с англ.»  (Глава 11. Шина SPI и библиотеки сторонних разработчиков)

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

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

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


Мы уже познакомились с двумя основными методами цифровой передачи данных, поддерживаемыми платформой Arduino: шиной последовательного интерфейса УАПП (RS-232) и шиной I2C. В этой главе мы рассмотрим третий метод цифровой связи, поддерживаемый Arduino: шиной SPI[1].

В отличие от шины I2C, шина SPI имеет несколько линий для обмена данными, а также использует отдельную линию для выбора каждого ведомого устройства. Хотя это увеличивает число проводов, в результате также устраняется необходимость в уникальном адресе для каждого ведомого устройства. Обычно с шиной SPI легче работать, чем с шиной I2C; она также обеспечивает более высокую скорость передачи данных. В этой главе мы узнаем, как использовать встроенные аппаратные возможности SPI платы Arduino для взаимодействия с цифровым акселерометром. В частности, мы рассмотрим, как находить и устанавливать библиотеки сторонних разработчиков для облегчения сопряжения со сложным оборудованием. Для иллюстрации полезности этого подхода мы с помощью акселерометра будем управлять яркостью светодиода и выдавать звуковые сигналы, создав своего рода инструмент, реагирующий на движение звуковыми и визуальными эффектами.


Примечание

В первом издании этой книги для демонстрации принципов работы шины SPI использовалась микросхема цифрового потенциометра MCP4231, поддерживающая возможности SPI. В последнее время эти микросхемы трудно найти и, кроме того, проекты на их основе не особенно стимулируют умственные способности, по сравнению с применением акселерометра. Но если вы хотите узнать, как реализовать сопряжение цифрового потенциометра с платой Arduino, это можно сделать, просмотрев учебный фильм на эту тему по ссылке blum.fyi/spi-digipot-tutorial.

Общие сведения о шине SPI

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

Внимание!

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

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

Таким образом, две опции для фазы сигнала тактирования и два варианта его полярности определяют четыре способа конфигурации шины SPI. В таблице 11.1 приведены все четыре возможные комбинации фазы и полярности тактового сигнала и соответствующие режимы в библиотеке SPI языка Arduino.

Таблица 11.1. Режимы связи шины SPI

Режим SPI Полярность сигнала тактирования Фаза сигнала тактирования
Режим 0 Низкий уровень при простое Захват данных по положительному перепаду сигнала тактирования
Режим 1 Низкий уровень при простое Захват данных по отрицательному перепаду сигнала тактирования
Режим 2 Высокий уровень при простое Захват данных по отрицательному перепаду сигнала тактирования
Режим 3 Высокий уровень при простое Захват данных по положительному перепаду сигнала тактирования

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

Подключение устройств SPI

Конфигурация системы обмена данными по шине SPI сравнительно проста. Для взаимодействия между ведущим устройством и всеми ведомыми устройствами предусмотрены три линии:

  • SCLK (serial clock) — последовательный тактовый сигнал.
  • MOSI (master out, slave in) — выход ведущего, вход ведомого.
  • MISO (master in, slave out) — вход ведущего, выход ведомого.

Кроме этих линий, для каждого ведомого устройства требуется отдельная линия для его выбора. Эта линия называется SS (slave select — выбор ведомого). Таким образом, общее число линий и контактов ввода-вывода ведущего устройства всегда будет равно 3 + n, где n обозначает число ведомых устройств.

На рис. 11.1 показан пример системы связи по шине SPI с двумя ведомыми устройствами.

image1

Рис. 11.1. Стандартная схема организации связи по шине SPI (Рисунок создан в программе EAGLE)

Конфигурация интерфейса SPI

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

Таблица 11.2. Линии шины SPI

Линия шины SPI Описание
MOSI(выход ведущего, вход ведомого) Передача последовательных данных от ведущего устройства ведомому устройству
MISO(вход ведущего, выход ведомого) Передача последовательных данных от ведомого устройства ведущему устройству
SCLK(последовательный тактовый сигнал) Сигнал, синхронизирующий последовательные данные с принимающим устройством, чтобы оно знало, когда считывать входные данные
SS(выбор ведомого) Линия для выбора ведомого устройства. Установка на этой линии сигнала низкого уровня означает выбор данного ведомого устройства для обмена данными с ведущим устройством. Как правило, одновременно следует активировать только одну линию выбора ведомого устройства

В отличие от шины I2C для линий шины SPI подтягивающие резисторы не требуются, поскольку контакты ввода-вывода устройств сконфигурированы для работы в двухтактном режиме, а не в режиме открытого стока. Связь осуществляется в полнодуплексном режиме (т. е. она полностью двунаправленная). Чтобы подключить SPI-устройство к плате Arduino, нужно просто соединить соответствующие контакты MOSI, MISO, SCLK и SS обоих устройств. При этом следует иметь в виду уровни напряжения питания и логических сигналов. Если используется плата Arduino с питанием 5 В (как Arduino Uno), то подключаемое к ней ведомое SPI-устройство также должно поддерживать работу с логическими уровнями величиной 5 В.

О НАЗВАНИЯХ ЛИНИЙ

Поскольку протокол SPI официально не стандартизован, некоторые производители устройств SPI могут по-разному именовать линии связи для своих устройств. Например, линия SS (slave select — выбор ведомого) иногда называется CS (chip select — выбор микросхемы), линия SCLK (serial clock — последовательный тактовый сигнал) может называться просто CLK (clock — тактовый сигнал) или SCK (вариант SCLK), а контакты MOSI и MISO ведомых устройств иногда обозначаются как SDI (serial data in — вход последовательных данных) и SDO (serial data out —выход последовательных данных). В этой главе употребляются все разновидности наименований сигналов, согласно их применению производителями соответствующих устройств.

Протокол передачи данных SPI

Передача данных по протоколу SPI синхронизуется с помощью сигнала тактирования и управляется посредством линии SS для выбора ведомого устройства. Поскольку все устройства на шине SPI подключены к одним и тем же линиям MOSI, MISO и SCLK, посылаемые ведущим устройством сигналы видимы всем ведомым устройствам. Выбор устройства, которое должно реагировать на эти сигналы, осуществляется с помощью соответствующей линии SS. Важно отметить, что это означает необходимость следить за тем, чтобы в любой разрабатываемой программе низкий (активный) уровень одновременно подавался только на одну линию SS выбора ведомого устройства. Базовая процедура связи с устройством SPI следующая:

  1. Подаем сигнал низкого уровня на линию SS ведомого устройства, с которым необходимо выполнить обмен данными.
  2. Подаем на линию тактирования прямоугольный сигнал с частотой меньшей или равной скорости обмена в бодах, поддерживаемой ведомым устройством.
  3. В каждом цикле сигнала тактирования передаем один бит по линии MOSI и принимаем один бит по линии MISO.
  4. Продолжаем до тех пор, пока не будут переданы или приняты все данные, после чего снимаем сигнал тактирования с линии SCLK.
  5. Снова устанавливаем на линии SS сигнал высокого уровня.

Сравнительные характеристики протоколов SPI, I2C и UART

Многие устройства, включая акселерометры, цифровые потенциометры и дисплеи поддерживают как протокол SPI, так и протокол I2C. (В частности, акселерометр, с которым мы будем работать далее в этой главе, поддерживает оба протокола.) Это означает, среди прочего, что если вы хотите организовать взаимодействие между несколькими платами Arduino, то для этого можно разработать программу, которая будет работать с шиной SPI, I2C или RS-232 (UART). Но как решить, какой из протоколов выбрать? В таблице 11.3 приведены сравнительные характеристики этих трех протоколов, включая их преимущества и недостатки. В конечном итоге, решение будет зависеть от того, какой из них, по вашему мнению, легче всего реализовать и который лучше всего отвечает требованиям вашей задачи.

Таблица 11.3. Сравнительные характеристики протоколов SPI, I2C и UART

SPI I2C UART (RS-232)
Обеспечивает наивысшую скорость передачи данных Максимальная скорость передачи данных сильно зависит от физических свойств шины: длины линий, количества подключенных к ней устройств, значений сопротивлений повышающих резисторов и т.п. Скорость передачи в бодах должна быть согласована между обоими участвующими в обмене устройствами до начала обмена
В целом, с этим протоколом легче работать, чем с протоколом I2C. Требует всего лишь две линии связи Практически не требует никаких протокольных накладных расходов, в результате чего легко поддается реализации
Не требует повышающих резисторов для линий связи Поддерживает взаимодействие устройств с разными уровнями напряжения питания Нет предопределенных ведущего и ведомого устройств. Протокол определяется разработчиком
Количество ведомых устройств ограничено только количеством доступных контактов SS на ведущем устройстве Количество ведомых устройств ограничено доступностью микросхем с конкретных адресом ведущего устройства Поддержку нескольких ведомых устройств трудно реализовать
Поддерживает аппаратное и программное обеспечение платформы Arduino Поддерживает аппаратное и программное обеспечение платформы Arduino Поддерживает аппаратное и программное обеспечение платформы Arduino
  1. Англ. Serial Peripheral Interface — последовательный синхронный периферийный интерфейс — Пер.
Опубликовано

Шина I2C

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

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

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


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

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


Примечание

На веб-странице электронных ресурсов книги для этой главы (https://www.exploringarduino.com/content2/ch10) можно просмотреть учебный видеофильм о шине I2C.

История создания протокола I2C

Работу коммуникационного протокола намного легче понять, если знать, как он эволюционировал с течением времени. Протокол I2C был разработан компанией Philips Semiconductors в начале 80-х годов прошлого столетия для обеспечения сравнительно низкоскоростной связи между разными микросхемами. К 90-м годам прошлого столетия протокол был стандартизирован, и другие компании начали использовать его, выпуская совместимые с ним микросхемы. Этот протокол часто называют двухпроводным протоколом, поскольку для обмена данными в нем предусмотрено всего лишь два провода: для данных и для сигнала тактирования. Хотя не все устройства законно используют для связи двухпроводный протокол (поскольку их производители не уплатили за это), обычно их все равно называют I2C-устройствами. Можно провести аналогию с копировальными аппаратами, которые называются ксероксами, хотя они не выпускаются компаний Xerox, которая была первой, создавшей копировальный аппарат электрографического типа с порошковым красящим элементом под этим торговым названием. Поэтому, если для устройства указывается, что оно использует двухпроводный протокол связи, то можно быть в большой степени уверенным, что этот протокол работает, как описано в этой главе.

Вам, возможно, также встретятся устройства, применяющие другой двухпроводный протокол, называющийся SMBus (System Management Bus — системная управляющая шина). Этот протокол разработан компаниями Intel и Duracell на основе протокола I2C и очень похож на него. Но в нем заданы немного другие пределы электрических сигналов, определен алгоритм обнаружения ошибок, а также реализована явная поддержка необязательной сигнальной линии для прерываний, позволяющая ведомым устройствам уведомлять ведущее об определенных событиях. Обычно, устройства SMBus и I2C можно без проблем одновременно подключать к одной шине, если четко соблюдать требования, изложенные в справочных листках.

Схема подключения устройств I2C

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

image1

Рис. 10.1. Стандартная схема организации связи через шину I2C (Рисунок создан в программе EAGLE)

Взаимодействие и идентификация устройств

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

Все команды и запросы, отправляемые ведущим устройством, могут приниматься всеми ведомыми устройствами шины. Поэтому необходимо каким-либо образом обеспечить связь только с тем устройством, которому предназначены посылаемые данные. Эта задача решается присвоением каждому ведомому устройству уникального 7-разрядного адреса или идентификационного номера (ID-номер). Когда ведущее устройство инициирует сеанс связи, оно передает ID-номер требуемого ведомого устройства. Ведомые устройства реагируют на данные в шине только тогда, когда эти данные обозначены их ID-номером. Некоторые устройства I2C имеют настраиваемый адрес, тогда как другим присваивается постоянный адрес при изготовлении. Таким образом, чтобы подключить к шине несколько экземпляров устройства одного типа, необходимо, чтобы каждое из них имело уникальный ID-номер.

Поэтому, например, датчики температуры выпускаются с разными заранее запрограммированными адресами шины I2C, поскольку обычно к одной шине необходимо подключить несколько таких датчиков. Для экспериментов этой главы мы будем применять датчик температуры линейки TC74. Из справочного листка на этот датчик можно увидеть, что он предлагается с несколькими разными адресами. (рис. 10.2.) Для описанных далее экспериментов мы возьмем датчик температуры TC74A0-5.0VAT с адресом 1001000. Данный датчик является версией этой микросхемы с питанием 5 В и корпусом типа TO-220.

image2

Рис. 10.2. Возможные адреса для датчика температуры TC74 (Источник: © Microchip Technology Incorporated. Репродукция с разрешения)

Эта микросхема предлагается с восемью разными ID-номерами; таким образом, к одной шине I2C можно подключить восемь таких датчиков и индивидуально считывать данные с каждого из них. Когда позже в этой главе мы будем заниматься разработкой программ для взаимодействия с этим датчиком температуры, непременно запишите ID-номер своего устройства, чтобы посылать ему команды по правильному адресу.

Другие микросхемы I2C, например AD7414 and AD7415 (другой I2C цифровой датчик температуры, выпускаемый компанией Analog Devices), оснащаются контактами выбора адреса (AS — address select), посредством которых им можно присвоить определенный I2C-адрес. На рис. 10.3 приводится фрагмент справочного листка для микросхемы датчика AD7414, на котором показана ее цоколевка, а также таблица присвоения ей адреса I2C.

image3

Рис. 10.3. Настройка адреса I2C для микросхемы датчика температуры AD7414 (Источник: Авторские права принадлежат компании Analog Devices, Inc. с 2019 г. Все права сохраняются)

Как можно видеть на рис. 10.3, предлагается четыре варианта микросхемы AD7414: два с контактом выбора адреса AS и два без такого контакта. Для микросхем с контактом выбора адреса AS можно задать один из трех адресов, подключив этот контакт к шине питания, шине земли или оставив его неподключенным.

РЕКОМЕНДАЦИИ ПО ВЫБОРУ КОМПОНЕНТОВ ДЛЯ РАЗРАБОТЧИКА УСТРОЙСТВ

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

Если вы планируете изготовить большое количество этих печатных плат, тогда большую роль в выборе компонентов может сыграть такой фактор, как экономия затрат. Стоимость микросхемы AD7414 при покупке одного экземпляра составляет $2,59, но при покупке партии в 3000 шт. уменьшается до $1,16 за экземпляр. Если вы планируете изготовить несколько тысяч таких плат, то можете сэкономить большую сумму денег, установив на каждую плату три экземпляра одного устройства, а не три разных устройства[1].

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

Аппаратные требования и повышающие резисторы

Возможно, вы заметили в схеме на рис. 10.1, что для обеих линий шины I2C стандартной конфигурации требуются повышающие резисторы. Номинал этих резисторов зависит от типа подключенных к шине ведомых устройств и их количества. В этой главе мы будем использовать повышающие резисторы номиналом 4,7 кОм для обеих линий шины; это стандартное значение, которое указывается во многих справочных листках.

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

Воспроизведение звуковых файлов на 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).


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

Инструменты для работы через последовательный порт

Рассмотренные нами ранее (см. разд. «Доступ к интерфейсу командной строки») программы эмуляции терминала позволяют получать доступ к удаленным компьютерам через Интернет, но их возможности этим не исчерпываются. Посредством таких программ можно подключаться и к последовательному порту компьютера. Сравнительно недавно в большинстве случаев подключение к Интернету осуществлялось не через какое-либо широкополосное соединение, а через обычные телефонные линии с помощью модема, подключаемого к последовательному порту компьютера. А на заре развития компьютерных коммуникаций многие пользователи таким образом подключались к доскам объявлений (bulletin boards, BBS) и с помощью систем меню программ эмуляции терминала оставляли сообщения, загружали файлы и обменивались сообщениями с другими пользователями этой же доски объявлений. В настоящее время последовательные порты в большинстве случаев эмулируются программными драйверами и служат для связи с различными устройствами USB и прочими периферийными устройствами. Через такие же последовательные порты осуществляется и программирование микроконтроллеров, и обмен данными между ними и компьютером.

В проектах этой книги для подключения микроконтроллера к последовательному порту компьютера также используются программы терминала. Существует большое число терминальных программ — как платных, так и бесплатных. Одной из них является замечательная бесплатная программа CoolTerm, разработанная Роджером Майером (Roger Meier), которую можно загрузить с веб-сайта http://freeware.the-meiers.org. Программа работает как на компьютерах под macOS, так и под Windows, — и это сейчас моя самая любимая программа. Если вы решите пользоваться ею, поступите правильно и сделайте пожертвование, так как автор разрабатывал ее в свое свободное время. Для пользователей Windows хорошей альтернативой может стать уже упомянутая ранее программа PuTTY (рис. 1.6), поскольку, кроме подключения по ssh, она также может открывать последовательные порты. Вы можете избрать и совсем простой путь — воспользоваться классической программой Screen (под лицензией GNU), исполняющейся в окне терминала. Эту программу можно также использовать и на компьютерах под масOS, но она обладает меньшей функциональностью, чем программа CoolTerm.

Рис. 1.6. Установка типа подключения и последовательного порта в PuTTY

Кто получит порт?

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

Программа CoolTerm

Запустите программу CoolTerm (рис. 1.7) и щелкните мышью на значке Options. В открывшемся диалоговом окне Connection Options выберите из раскрывающегося списка Port последовательный порт, к которому подключен микроконтроллер Arduino. Имена портов в macOS представлены в формате вида:

/dev/ tty.usbmodem1441

В Windows порты именуются COM1, COM2, COM3 и т. д. Чтобы узнать наверняка, к какому порту подсоединен ваш микроконтроллер Arduino, проверьте список портов при отсоединенном устройстве, а затем — при подсоединенном. Порт, появившийся в списке после подсоединения микроконтроллера, и будет его портом. Чтобы открыть порт и подключить к нему микроконтроллер, нажмите кнопку Connect на панели инструментов главного окна программы. Чтобы отключить микроконтроллер и закрыть порт, нажмите кнопку Disconnect.

Рис. 1.7. Окно программы терминала CoolTerm

Программа GNU Screen

Пользователи Linux и macOS для работы с последовательным портом также могут использовать программу CoolTerm (см. рис. 1.7) или же альтернативную ей программу GNU Screen.

На Ubuntu версии 15 программу GNU Screen можно установить, выполнив команду:

$ sudo apt-get install screen

Чтобы начать работу с GNU Screen в macOS или Linux, откройте окно терминала и выполните соответствующую команду:

$ ls /dev/tty —* # macOS

$ ls /dev/tty* # Linux

В результате исполнения этой команды в терминале будет выведен список последовательных портов, доступных в системе. Формат имен последовательных портов в macOS и Linux более сложный, чем формат COM1, COM2 и т. д., используемый в Windows, так как каждый порт в этих ОС имеет уникальное имя. Выберите необходимый последовательный порт и выполните команду:

$ screen номер_порта скорость_обмена

Например, чтобы открыть последовательный порт в macOS для подключения к микроконтроллеру Arduino со скоростью 9600 битов в секунду, выполняется команда:

screen /dev/tty.usbmodem1441 9600

Соответствующая ей команда в Linux будет иметь вид:

screen /dev/ttyUSB0 9600

В результате выполнения такой команды окно терминала очищается, устанавливается подключение микроконтроллера к последовательному порту и все, что вводится в терминал, отправляется на открытый последовательный порт. При этом вводимый текст на экране не отображается, но информация, получаемая на последовательный порт от микроконтроллера, отображается на экране в виде символов ASCII. Чтобы закрыть последовательный порт, нажмите комбинацию клавиш <Ctrl>+<A>, а затем — <Ctrl>+<\>.

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