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

Блум Джереми

ЧАСТЬ II Управление окружающей средой

 

В этой части

Глава 4. Использование транзисторов и управляемых двигателей

Глава 5. Работаем со звуком

Глава 6. USB и последовательный интерфейс

Глава 7. Сдвиговые регистры

 

Глава 4. Использование транзисторов и управляемых двигателей

Список деталей

Для повторения примеров главы вам понадобятся следующие детали:

• плата Arduino Uno;

• USB-кабель;

• батарея 9 В;

• разъем для батареи 9 В;

• стабилизатор напряжения L4940V5;

• электролитический конденсатор 22 мкФ;

• электролитический конденсатор 0, 1 мкФ;

• керамический конденсатор 1 мкФ;

• 4 синих светодиода;

• 4 резистора номиналом 1 кОм;

• биполярный n-p-n транзистор PN2222;

• диод 1N4004;

• перемычки;

• провода;

• ИК-датчик расстояния Sharp GP2YOA41SKOF ИК с кабелем;

• стандартный серводвигатель;

• двигатель постоянного тока;

• макетная плата;

• потенциометр;

• драйвер двигателя SN754410.

- 84 -

Электронные ресурсы к главе

На странице http://www.exploringarduino.com/content/ch4 можно загрузить код программ, видеоуроки и другие материалы для данной главы. Кроме того, листинги примеров можно скачать со страницы www.wiley.com/go/exploringarduino в разделе Downloads.

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

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

ПРИМЕЧАНИЕ

Если вы хотите узнать больше о двигателях и транзисторах, смотрите видеофильм, расположенный на интернет-странице

http://www.jeremyblum.com/2011/01/31/arduino-tutorial-5-motors-and-transistors/

ВНИМАНИЕ!

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

 

4.1. Двигатели постоянного тока

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

- 85 -

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

 

4.2. Борьба с выбросами напряжения

Двигатели постоянного тока обычно требуют ток больше, чем может выдать встроенный в Arduino блок питания, к тому же они могут создавать опасные выбросы напряжения. Для решения этой проблемы необходимо научиться эффективно изолировать двигатель постоянного тока от платы Arduino и подключать его к отдельному источнику питания. Транзистор позволит безопасно включать двигатель, а также управлять его скоростью с помощью методов ШИМ, рассмотренных в главе 2. Прежде чем собирать схему подключения двигателя постоянного тока, изображенную на рис. 4.1, рассмотрим основные компоненты схемы:

Q1 - n-p-n биполярный плоскостной транзистор действует как ключ, включая и выключая внешний источник питания 9 В. Существуют два типа биполярных плоскостных транзисторов: n-p-n и p-n-p. Мы будем применять транзисторы типа n-p-n. Говоря упрощенно, n-p-n транзистор представляет собой переключатель, управляемый напряжением, что позволяет подавать или отключать ток;

R1 - резистор номиналом 1 кОм, соединяющий контакт платы Arduino с базой транзистора;

Рис. 4.1. Схема включения двигателя постоянного тока

- 86 -

U 1 - двигатель постоянного тока;

С 1 - конденсатор для фильтрации помех, вызванных работой двигателя;

Dl - диод для защиты блока питания от обратного напряжения.

 

4.3. Использование транзистора в качестве переключателя

Транзисторы применяются во многих устройствах: от усилителей до компонентов центрального процессора в компьютерах и смартфонах. У нас транзистор будет работать в качестве простого электрически управляемого переключателя. Каждый биполярный транзистор имеет три контакта (рис. 4.2): эмиттер (Е), коллектор (С) и базу (В).

Рис. 4.2. Биполярный n-p-n транзистор

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

 

4.4. Назначение защитных диодов

Одна из проблем электродвигателей постоянного тока - наличие противо-ЭДС.

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

- 87 -

 

4.5. Назначение отдельного источника питания

В схеме, изображенной на рис. 4.1, двигатель подключен к отдельному источнику напряжением 9 В, а не к контакту 5 В разъема USB. Для данного примера подойдет также внешний источник с напряжением 5 В. Внешний источник питания необходим по двум причинам:

• уменьшается вероятность повреждения платы Arduino при неправильном подключении электродвигателя;

• ток и напряжение могут быть больше, чем обеспечивает встроенный в Arduino источник питания.

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

ВНИМАНИЕ!

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

 

4.6. Подключение двигателя

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

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

• убедитесь, что земля от батареи 9 В соединена с землей платы Arduino, для этого можно общую шину земли на макетной плате, как показано на рис. 4.3;

• убедитесь, что провод питания +9 В не подключен к проводу питания +5 В;

• убедитесь, что транзистор подключен правильно;

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

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

Вал двигателя должен начать вращаться. При подключении базы транзистора

- 88 -

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

Рис. 4.3. Подключение двигателя постоянного тока

4.7. Управление скоростью вращения двигателя с помощью шимпрограмма для управления скоростью вращения двигателя (листинг 4.1) будет похожа на программу регулировки яркости светодиодов ночника из главы 3. Появление на выходе платы Arduino ШИМ-сигнала вызывает быстрый запуск и остановку двигателя с разным периодом, что эквивалентно изменению скорости вращения.

- 89 -

Листинг 4.1. Автоматическое управление скорость двигателя - motor.ino

// Пример управления скоростью вращения двигателя

const int MOTOR=9;// Вывод 9 Arduino для подключения двигателя

void setup()

{

pinMode (MOTOR, OUTPUT);

}

void loop()

{

for (int i=0; i<256; i++)

{

analogWrite(MOTOR, i);

delay(10);

}

delay(2000);

for (int i=255; i>=0; i--)

{

analogWrite(MOTOR, i);

delay (10);

}

delay(2000);

}

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

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

Теперь изменим программу так, чтобы управлять скоростью вращения двигателя, регулируя положение ручки потенциометра. При полностью выведенном движке потенциометра двигатель остановлен, при полностью введенном - вал двигателя вращается с максимальной скоростью. Не забывайте, что контроллер Arduino работает очень быстро, цикл повторяется несколько тысяч раз в секунду! Поэтому малейшее изменение положения движка потенциометра сразу же сказывается на частоте вращения двигателя. Описанный алгоритм реализует программный код, приведенный в листинге 4.2. Загрузите программу в плату Arduino и регулируйте скорость вращения двигателя с помощью потенциометра.

- 90 -

Рис. 4.4 Схема подключения потенциометра для регулировки скорости вращения

Листинг 4.2. Регулирование скорости двигателя - motor_pot.ino

const int MOTOR=9;

const int POT=0;

int val = 0;

// Вывод 9 Arduino для подключения двигателя

// Вывод A0 Arduino для подключения потенциометра

void setup()

{

pinMode (MOTOR, OUTPUT);

}

void loop()

{

val = analogRead(POT);

val = map(val, 0, 1023, 0, 255);

analogWrite(MOTOR, val);

}

- 91 -

 

4.8. Управление направлением вращения двигателя постоянного тока с помощью Н-моста

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

Рис. 4.5. Схема работы Н-моста

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

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

ток течет в противоположном направлении, и направление вращения вала обратное.

Если H-мост находится в состоянии торможения, то обмотка замкнута, вращение замедляется и двигатель останавливается.

Необходимо помнить об опасности короткого замыкания цепей H-моста. Что произойдет, если все четыре выключателя будут замкнуты? Это вызовет короткое замыкание между шиной +9 В и землей. В результате батарея очень быстро нагреется, что может привести к ее разрыву. Кроме того, короткое замыкание может повредить H-мост или другие элементы схемы.

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

- 92 -

 

4.9. Сборка схемы Н-моста

Настала пора собрать схему H-моста. Возьмем микросхему SN754410-четырехканальный драйвер Н-полумоста. Два драйвера Н-полумоста образуют полный драйвер H-моста, как на рис. 4.5. Для управления одним электродвигателем постоянного тока используются два из четырех драйверов Н-полумоста. Если вы хотите сделать, например, радиоуправляемый автомобиль, можно управлять двумя колесами с помощью одной микросхемы SN754410. На рис. 4.6 приведена цоколевка микросхемы SN754410.

Рис. 4.6. Цоколевка микросхемы SN754410

Нумерация контактов на микросхемах начинается с левого верхнего угла и идет против часовой стрелки. На корпусе всегда имеется метка у контакта 1 (полукруг, точка или что-то другое).

Соответствие состояний входов и выходов драйвера SN754410 иллюстрирует табл. 4.1 (условные обозначения в таблице: Н - высокий уровень; L - низкий уровень; Х -безразличное состояние; Z -высокоимпедансное состояние).

Таблица 4.1. Состояния входов и выходов драйвера SN754410

Рассмотрим назначение контактов микросхемы SN754410:

• GND (контакты 4, 5, 12, 13)-выводы для подключения к земляной шине монтажной платы;

• Vcc2 (контакт 8)-напряжение питания двигателя (подсоедините к 9 В);

• Vccl (контакт 16)-напряжение питания микросхемы (подсоедините к 5 В);

- 93 -

• 1У и 2У (контакты 3 и 6) - выходы для подключения первого двигателя;

• IA и 2А (контакты 2 и 7)- коммугация первого двигателя, эти выводы соединены с управляющими контактами Arduino;

1,2 EN (контакт 1)- включение и отключение левого драйвера. Данный вывод соединен с ШИМ-контактами на плате Arduino, что позволяет динамически регулировать скорость двигателей;

• ЗУ и 4У (контакты 11 и 14)- выходы для подключения второго двигателя;

• Батарея

• Н-мост

• Двигатель постоянного тока

Рис. 4.7. Схема подключения Н-моста

- 94 -

ЗА и 4A (контакты 10 и 15)- коммутация второго двигателя, эти выводы соединены с управляющими контактами Arduino;

• 3,4 EN (контакт 9) - вывод включения или отключения правого драйвера. Он соединен с ШИМ-контактами на Arduino, что позволяет динамически регулировать скорость двигателей.

Проверьте монтаж по рис. 4.7. Потенциометр подключим позже.

Прежде чем приступать к программированию, проверим работоспособность схемы.

Подключите один из входных контакто? (2 или 7) микросхемы H-моста к шине 5 В, другой к земле. Двигатель начнет вращаться. Поменяйте подключение контактов 2 и 7, двигатель будет вращаться в другую сторону.

ВНИМАНИЕ!

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

 

4.10. Управление работой Н-моста

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

Анализируя рис. 4.5, делаем следующие выводы:

1. Для вращения двигателя один из выключателей должен быть замкнут, другой разомкнут.

2. Чтобы двигатель вращался в обратном направлении, замкнутый в n. 1 выключатель должен быть разомкнут, а разомкнутый - замкнут.

3. Для остановки двигателя оба выключателя должны быть разомкнуты.

ПРИМЕЧАНИЕ

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

Сначала напишем код функций для выполнения описанных действий (листинг 4.3).

Листинг 4.3. Вспомогательные функции для управления двигателем

// Вращение двигателя вперед с заданной скоростью (диапазон 0-255)

void forward (int rate)

{

digitalWrite(EN, LOW);

- 95 -

digitalWrite(MC1, HIGH);

digitalWrite(MC2, LOW);

analogWrite(EN, rate);

}

// Вращение двигателя в обратном направлении с заданной скоростью

//(диапазон 0-255)

void reverse (int rate)

{

digitalWrite(EN, LOW);

digitalWrite(MC1, LOW);

digitalWrite(MC2, HIGH);

analogWrite(EN, rate);

}

// Остановка двигателя

void brake()

{

digitalWrite(EN, LOW);

digitalWrite(MC1, LOW);

digitalWrite(MC2, LOW);

digitalWrite(EN, HIGH)

}

Обратите внимание, что в начале каждой функции на контакте EN всегда устанавливается низкий уровень, и затем задаются значения на входах блока управления MC1 и MC2. После установки значений на входах MC1 и MC2 можно снова включить ток. Подавая сигнал ШИМ на вход EN, можно управлять скоростью двигателя.

Значение переменной rate должно быть в диапазоне от 0 до 255. Основной цикл программы (листинг 4.4) считывает данные с потенциометра и в зависимости от результата вызывает требуемую функцию.

Листинг 4.4. Программа вызова вспомгательных функций

void loop()

{

val = analogRead(POT);

// Движение вперед

if (val > 562)

{

velocity = map(val, 563, 1023, 0, 255);

forward(velocity);

}

// Движение назад

else if (val < 462)

{

velocity = map(val, 461, 0, 0, 255);

- 96 -

reverse(velocity);

}

// Остановка

else

{

brake();

}

}

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

Рис. 4.8. Принцип управления двигателем

При значениях сигнала от потенциометра в диапазоне от 462 до 562 ( 100 отсчетов в районе средней точки) вызывается функция break() для остановки двигателя, при значениях от 562 до 1023 - функция запуска двигателя в прямом направлении forward(), при значениях от 0 до 462 - функция запуска двигателя в обратном направлении reverse(). Функция map() знакома вам из предыдущей главы. При определении обратной скорости значение потенциометра 461 соответствует значение скорости 0, а значение потенциометра 0 соответствует значение скорости 255.

Функция map() инвертирует значения так, что на вход они подаются в обратном порядке. Объединив цикл loop() со вспомогательными функциями и начальной установкой setup(), получим полный код программы управления скоростью и направлением движения двигателя с помощью потенциометра (листинг 4.5).

Листинг 4.5. Программа управления двигателем с помощью потенциометра

!! Управление двигателем с помощью Н-моста

const int EN=9;// Вход включения двигателя EN

const int MC1=3;// Вход 1 управления двигателем

const int MC2=2;// Вход 2 управления двигателем

const int POT=0;// Аналоговый вход 0 для подключения потенциометра

int val = 0;// Переменная для хранения значения потенциометра

int velocity = 0;// Переменная для хранения скорости двигателя (0-255)

void setup()

{

pinMode(EN, OUTPUT);

pinMode(MC1, OUTPUT);

pinMode(MC2, OUTPUT);

brake();// Остановка двигателя при инициализации

}

- 97 -

void loop()

{

val = analogRead(POT);

// Движение вперед

if (val > 562)

{

velocity = map(val, 563, 1023, 0, 255);

forward(velocity);

}

// Движение назад

else if (val < 462)

{

velocity = map(val, 461, 0, 0, 255);

reverse(velocity);

}

// Остановка

else

brake();

}

// Движение двигателя вперед с заданной скоростью

// (диапазон 0-255)

void forward (int rate)

{

digitalWrite(EN, LOW);

digitalWrite(MC1, HIGH);

digitalWrite(MC2, LOW);

analogWrite(EN, rate);

}

// Движение двигателя в обратном направлении с заданной скоростью

// (диапазон 0-255)

void reverse (int rate)

{

digitalWrite(EN, LOW);

digitalWrite(MC1, LOW);

digitalWrite(MC2, HIGH);

analogWrite(EN, rate);

}

// Остановка двигателя

void brake()

{

digitalWrite(EN, LOW);

digitalWrite(MC1, LOW);

digitalWrite(MC2, LOW);

digitalWrite(EN, HIGH);

}

- 98 -

Загрузите программу в плату Arduino и запустите на выполнение. Все работает, как ожидалось? Если нет, еще раз внимательно проверьте монтаж.

В качестве упражнения подключите к драйверу H-моста SN754410 второй двигатель постоянного тока и напишите программу управления двумя двигателями.

 

4.11. Управление серводвигателем

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

4.11.1. Стандартные сервоприводы и сервоприводы вращения

Проще всего приобрести стандартные сервоприводы. Они имеют фиксированный диапазон углов поворота ( обычно от 0 до 180 ° ) и содержат соединенный с приводным валом потенциометр, который определяет угол поворота сервопривода.

Управление сервоприводом происходит подачей прямоугольного импульса. Длительность импульса (в случае стандартного сервопривода) определяет угол поворота.

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

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

4.11.2. Принцип работы серводвигателя

В отличие от двигателей постоянного тока, серводвигатели имеют три контактных провода:

• питание (обычно красного цвета);

• земля (обычно коричневого или черного цвета);

• сигнальный вход ( обычно белый или оранжевый).

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

- 99 -

поэтому перед применением сервопривода желательно ознакомиться с документацией.

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

Белый/оранжевый - сигнал управления

Красный - питание

Черный/коричневый - земля

Рис. 4.9. Сервоприводы

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

Сервоприводы управляются по сигнальной линии с помощью прямоугольных импульсов регулируемой длительности. Для стандартного сервопривода подача импульса длительностью 1 мс приводит к установке сервопривода в положение 0 °, импульс длительностью 2 мс устанавливает сервопривод в положение 180°, импульса 1,5 мс - 90 °. После того как импульс подан, вал сервопривода устанавливается в определенную позицию и остается там до поступления следующей команды.

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

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

В примерах, изображенных на рис. 4.1 0, импульс подается каждые 20 мс. Длительность импульса возрастает от 1 до 2 мс, при этом угол поворота серводвигателя (показанный справа от графика импульсов) увеличивается от 0 до 180 °.

- 100 -

Рис. 4.10. Временные диаграммы управления серводвигателем

Как упоминалось ранее, для работы серводвигателя требуется ток, больший, чем выдает встроенный в Arduino блок питания. Однако большинство серводвигателей работает от напряжения 5 В, а не 9 или 12 В как двигатели постоянного тока. Несмотря на это, необходим отдельный блок питания серводвигателя.

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

• вход;

• выход;

• заземление.

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

Падение напряжения приводит к нагреву, поэтому необходимо позаботиться о теплоотводе (например, алюминиевом радиаторе). Для наших экспериментов возьмем 5-вольтовый стабилизатор напряжения L4940V5, который способен выдавать ток до 1,5 А. Схема включения стабилизатора приведена на рис. 4.11.101

Рис. 4.11. Схема включения стабилизатора напряжения

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

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

- 102 -

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

Пришло время подсоединить сервопривод. Сверяясь с монтажной схемой, подсоедините потенциометр к аналоговому входу A0, сигнальный вход сервопривода к цифровому входу 9 платы Arduino, убедитесь, что стабилизатор выдает напряжение 5 В. При соединении элементов обратите внимание на правильность подключения контактов стабилизатора и полярность включения конденсаторов (рис. 4.12).

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

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

 

4.12. Контроллер серводвигателя

В Arduino IDE предусмотрена библиотека Servo для упрощения управления сервоприводами. Чтобы работать с библиотекой, необходимо подключить ее к нашей программе. Затем следует прикрепить объект Servo к определенному выводу Arduino и задать угол вращения. Обо всем остальном позаботится библиотека. Самый простой способ проверить функционирование сервопривода - управление позицией вала с помощью потенциометра. Значение 0 потенциометра соответствует повороту сервопривода на 0°, значение 1023 - повороту на 180°. Загрузите код, приведенный в листинге 4.6, в плату Arduino, чтобы проверить все в действии.

Листинг 4.6. Управление положением серводигателя с помощью потенциомера - servp.ino

// Управление положением серводвигателя с помощью потенциометра

#include

const int SERV0=9; // Вывод 9 для подключения сигнального провода сервопривода

const int POT=0;// Подключение потенциометра к аналоговому входу A0

Servo myServo;

int val = 0;// Переменная для чтения показаний потенциометра

void setup()

{

myServo.attach(SERV0);

}

- 103 -

void loop()

{

val = analogRead(POT);// Чтение данных потенциометра

val = map(val, 0, 1023, 0, 179); // Преобразование к нужному диапазону

myServo.write(val);// Установить положение сервопривода

delay(15);

}

Оператор include, указанный в начале программы, добавляет функционал библиотеки Servo. Оператор Servo myServo создает объект сервопривода с именем myservo.

В том месте программы, где требуется действие с сервоприводом, будет ссылка на объект myServo. В функции setup() вы инициализируете сервопривод, присоединяя его к контакту 9 Arduino. Можно подсоединить к Arduino несколько сервоприводов, создав несколько объектов Servo и назначив каждому свой контакт Arduino.

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

 

4.1З. Создание радиального датчика расстояния

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

Так как инфракрасный свет является частью электромагнитного спектра, невидимой для человеческого глаза, подобная система может использоваться для создания "ночного видения". ИК-датчик расстояния работает следующим образом. Излучение ИК-светодиода воспринимается фотоприемником, который расположен рядом со светодиодом. Таким образом определяется расстояние до объекта, которое преобразуется в аналоговое напряжение и далее анализируется с помощью микроконтроллера. Даже если в комнате темно и расстояние до объекта неизвестно, дальномер позволит его узнать, потому что он работает в диапазоне, невидимом для человеческого глаза.

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

ПРИМЕЧАНИЕ

Вы можете посмотреть демонстрационный видеоклип работы датчика расстояния на сайте http://www.exploringarduino.com/content/ch4.

- 104 -

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

Рис. 4.13. ИК-датчик расстояния, установленный на сервоприводе

Затем подключаем сервопривод к контакту 9 платы Arduino, для питания сервопривода используем стабилизатор напряжения на 5 В. ИК-датчик расстояния соединяем с аналоговым входом A0. Четыре светодиода подключаем к контактам 3, 5, 6, и 11 через резисторы номиналом 1 кОм. На плате Arduino Uno предусмотрено шесть выводов ШИМ, но контакты 9 и 10 нельзя задействовать для создания ШИМсигналов, потому что аппаратный таймер, обеспечивающий ШИМ, занят библиотекой Servo. При желании увеличить число светодиодов, необходимо взять плату Arduino Mega или реализовать собственное программное обеспечение для формирования ШИМ.

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

Последний шаг - программирование датчика. Алгоритм работы системы следующий:

1. Поворот вала сервопривода в одну из четырех позиций.

2. Измерение расстояния.

3. Преобразование его в значение, которое подходит для управления светодиодом.

4. Изменение яркости соответствующего светодиода.

- 105 -

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

5. Выбор следующей позиции вала сервопривода.

6. Возврат к шагу 1.

Код программы приведен в листинге 4.7. Создайте в Arduino IDE новый проект, скопируйте этот код и загрузите его в плату Arduino.

Листинг 4.7. Программа ИК-датчика расстояния

// ИК-датчик расстояния

#include

const int SERV0=9; // Вывод 9 для подключения сигнального провода сервопривода

const int IR=0;// Подключение ИК-датчика расстояния к аналоговому входу A0

const int LED1=3; // Вывод светодиода 1

const int LED2=5; // Вывод светодиода 2

const int LED3=6; // Вывод светодиода 3

const int LED4=11; // Вывод светодиода 4

// Создание объекта Servo

Servo myServo;

- 106 -

int dist1 = 0;//Расстояние в первой области

int dist2 = 0;//Расстояние во второй области

int dist3 = 0;//Расстояние в третьей области

int dist4 = 0;//Расстояние в четвертой области

void setup()

{

myServo.attach(SERV0);

pinMode(LED1, OUTPUT);//Сконфигурировать

pinMode(LED2, OUTPUT);//контакты подключения

pinMode(LED3, OUTPUT);//четырех светодиодов

pinMode(LED4, OUTPUT);// как выходы

}

void loop()

{

// Поворот вала сервопривода по четырем позициям

dist1 = readDistance(15);

analogWrite(LED1, dist1);

delay(300);

dist2 = readDistance(65);

analogWrite(LED2, dist2);

delay(300);

dist3 = readDistance(115);

analogWrite(LED3, dist3);

delay(300);

dist4 = readDistance(165);

analogWrite(LED4, dist4);

delay(300);

}

int readDistance (int pos)

{

myServo.write(pos);

delay(600);

int dist = analogRead(IR);//Чтение данных с датчика расстояния

dist = map(dist, 50, 500, 0, 255); //Преобразование к нужному диапазону

dist = constrain(dist, 0, 255);

return dist;//Выдача значения, соответствующего расстоянию

}

В программе есть функция readDistance(), которая поворачивает вал сервопривода на определенный угол, измеряет расстояние, масштабирует его, а затем возвращает полученное значение в цикл loop(). Какой диапазон значений выбрать для свето

- 107 -

диодов, зависит от конкретной ситуации. У меня для самого дальнего объекта датчик выдавал значение 50, до ближайших - 500.

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

Резюме

В этой главе вы узнали следующее:

• Как работают двигатели постоянного тока.

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

• Как управлять скоростью и направлением вращения двигателя с помощью ШИМ и H-моста.

• Что серводвигатели точно позиционируются и управляются с помощью Arduino библиотеки Servo.

• Как создать вторичный источник питания 5 В от батареи 9 В с помощью стабилизатора напряжения.

• Что ИК-датчики получают инфракрасный сигнал, отраженный от объекта, и возвращают аналоговые значения, соответствующие расстоянию до данного объекта.

• Что комментарии важны для отладки и совместного использования программ.

 

Глава 5. Работаем со звуком

Работаем

Список деталей

Для повторения примеров главы вам понадобятся следующие детали:

• плата Arduino Uno;

• USB-кабель;

• 4 кнопки;

• 5 резисторов номиналом 10 кОм;

• 1 резистор номиналом 150 Ом;

• перемычки;

• провода;

• макетная плата;

• потенциометр 10 кОм;

• динамик 8 Ом.

Электронные ресурсы к главе

На странице http://www.exploringarduino.com/content/ch5 можно загрузить программный код, видеоуроки и другие материалы для данной главы. Кроме того, листинги примеров можно скачать со страницы www.wiley.com/go/exploringarduino в разделе Downloads.

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

Как известно, у человека пять органов чувств. Мы не будем задействовать вкус при общении с электронными компонентами, ведь никому не придет в голову облизывать Arduino! Запах нам тоже не пригодится, если вы почувствуете запах от платы, то скорее всего схема сгорела. Остаются осязание, зрение и слух. При работе с потенциометром и кнопками требуется осязание, а при включении светодиодов зрение. Без употребления остался только слух. Эта глава посвящена созданию звука с помощью Arduino, так что теперь ваши устройства обретут собственный "голос".

- 109 -

Генерировать звук с помощью Arduino можно несколькими способами. Самый простой способ - использование функции tone(), которую мы рассмотрим в данной главе. Существуют также различные дополнительные платы, подключаемые к основной плате Arduino с помощью штыревых разъемов и расширяющие музыкальные возможности Arduino. Некоторые из плат расширения мы рассмотрим в последующих главах. Если у вас плата Arduino Due, то для генерации звуков подойдет встроенный цифроаналоговый преобразователь (ЦАП).

 

5.1. Свойства звука

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

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

Теперь посмотрим, как эти знания помогут нам сгенерировать звуки с помощью платы Arduino?

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

На рис. 5.1 изображены графики, соответствующие трем фортепианным нотам: низкой, средней и высокой. В качестве примера рассмотрим ноту До первой октавы с частотой 261,63 Гц. Громкоговоритель, гитарная струна или фортепиано, при воспроизведении этой ноты генерирует звуковую волну, совершающую 261,63 колебаний в секунду. Можно рассчитать период колебания волны ( 1 /261,63 = 3,822 мс), что соответствует полному колебанию на графике. Плата Arduino позволяет задать период для меандра, устанавливая таким образом тембр каждой ноты. Важно отметить, что Arduino не может на самом деле создать синусоидальную волну, которая распространена в реальном мире. Меандр является цифровым периодическим сигналом - это мгновенное переключение между двумя уровнями: высоким и низким (см. рис. 3.1). В результате по-прежнему возникает волна давления, обусловливающая звук, но звучание не вполне соответствует синусоидальной волне.

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

- 110 -

Рис. 5.1. Звуковые волны с различной частотой и амплитудой

 

5.2. Как динамик воспроизводит звук

Динамики, как и двигатели, которые мы рассмотрели в предыдущей главе, используют электромагниты для преобразования электрического сигнала в механическое перемещение. Внимательно исследуйте металлическую деталь на задней стенке динамика. Заметили что-то необычное? К ней прилипают металлические предметы, потому что это магнит. Все станет понятно, если посмотреть на рис. 5.2, иллюстрирующий устройство динамика.

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

 

5.3. Использование функции tone() для генерации звуков

В Arduino IDE есть встроенная функция для генерации звуков произвольной частоты. Функция tone() формирует меандр с заданной частотой и выдает его на выбранный вами выходной контакт Arduino.

- 111 -

Рис. 5.2. Устройство динамика

Аргументы tone():

• первый аргумент устанавливает номер контакта Arduino для генерации волны;

• второй аргумент задает частоту сигнала;

• третий (необязательный) аргумент определяет продолжительность звучания;

• если этот аргумент не установлен, звук продолжается до тех пор, пока не вызвана функция noTone().

Функция tone() взаимодействует с одним из аппаратных таймеров контроллера ATmega, поэтому ее можно вызвать и продолжать работать с Arduino, а звук будет играть в фоновом режиме.

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

 

5.4. Включение файла заголовка

Когда дело доходит до воспроизведения музыкальных звуков, полезно создать заголовочный файл, определяющий частоты для музыкальных нот. Это делает программу более понятной при составлении простых музыкальных мелодий. Те, кто знаком с нотными знаками, знают, что ноты обозначаются буквами. В Arduino IDE есть специальный файл, содержащий значения частот для всех нот. Не ищите его в каталогах, а просто зайдите на сайт www.exploringarduino.com/content/ch5 и

- 112 -

скачайте на рабочий стол. Затем в Arduino IDE создайте пустой новый файл. Как вы, наверное, заметили, Arduino IDE создает новый файл внутри папки с одноименным названием. Добавляя в эту папку новые файлы, вы можете включать их в свою программу, в результате код будет лучше структурирован. Скопируйте файл pitches.h, сохраненный на рабочем столе, в папку, созданную Arduino IDE, для нового проекта. Теперь заново откройте в Arduino IDE этот файл. Обратите внимание на две вкладки (рис. 5.3).

Рис. 5.3. Окно Arduino IDE с двумя вкладками заголовочных файлов

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

#include "pitches.h"

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

 

5.5. Подключение динамика

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

- 113 -

Рис. 5.4. Схема включения динамика и регулятора громкости

Рис. 5.5. Монтажная схема подключения динамика

- 114 -

Так же, как и при подключении светодиодов, необходимо поставить токоограничивающий резистор последовательно с динамиком. В предыдущих главах упоминалось, что каждый вывод Arduino может выдать ток не более 40 мА. Внутреннее сопротивление нашего динамика равно 8 Ом (как и для большинства имеющихся в продаже динамиков). Это сопротивление обмоток провода, которые составляют электромагнит. Напомним, что закон Ома гласит U = I·R. Выходное напряжение для вывода Arduino 5 В и ток не должен превышать 40 мА. Отсюда определяем, что минимальное сопротивление должно быть R = 5 В/40 мА = 125 Ом. Поскольку сопротивление динамика 8 Ом, то минимальное сопротивление токоограничивающего резистора получается 125 - 8 = 117 Ом. Ближайший номинал резистора 150 Ом.

Регулируя сопротивление, можно изменять громкость динамика. Сделаем это проще, включив последовательно с резистором потенциометр (рис. 5.4). На схеме R1 -резистор 150 Ом, R2-потенциометр 10 кОм.

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

Подключите динамик к плате Arduino в соответствии со схемой, изображенной на рис. 5.4, и проверьте правильность монтажа по рис. 5.5.

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

 

5.6. Создание мелодии

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

5.6.1. Использование массивов

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

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

int numbers[4]На русском: http://wiki.amperka.ru/видеоуроки:1-первые-шаги.
;

При необходимости можно инициализировать массив значениями при объявлении.

При объявлении массива таким способом указывать число элементов массива

- 115 -

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

// Оба варианта объявления верны

int numbers[4]На русском: http://wiki.amperka.ru/видеоуроки:1-первые-шаги.
= {-7, 0, 6, 234};

int numbers[] = {-7, 0, 6, 234};

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

analogWrite(9,numbers[2]Не расслабляйтесь!
Обучение без исправления ошибок, невозможно!
);

Обратите внимание, что индекс 2 представляет собой третье значение в массиве, поскольку нумерация начинается с нуля. Изменить одно из значений массива можно так: numbers[2]Не расслабляйтесь!
Обучение без исправления ошибок, невозможно!
= 10;

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

5.6.2. Создание массивов нот и определение их длительности звучания

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

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

Листинг 5.1. Пример мелодии

// Массив нот

int notes [] = {

NOTE_A4, NOTE_E3, NOTE_A4, 0,

NOTE_A4, NOTE_E3, NOTE_A4, 0,

NOTE_E4, NOTE_D4, NOTE_B4, NOTE_A4, NOTE_В4, NOTE_C4, NOTE_D4,

NOTE_E4, NOTE_E3, NOTE_A4, 0

};

// Массив длительностей звучания нот в мс

int times[] = {

250, 250, 250, 250,

250, 250, 250, 250,

125, 125, 125, 125, 125, 125, 125, 125,

250, 250, 250, 250

};

- 116 -

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

Сначала попробуйте воспроизвести мою мелодию, а затем попытайтесь создать свою собственную!

ПРИМЕЧАНИЕ

Послушать аудиозапись можно на странице www.exploringarduino.com/content/ch5 или на сайте издательства Wiley.

5.6.3. Написание программы воспроизведения звука

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

Листинг 5.2. Проигрыватель мелодий - music.ino

// Проигрывание мелодии на динамике

#include "pitches.h" // Заголовочный файл со значениями частоты нот

const int SPEAKER=9; // Вывод подключения динамика

// Массив нот

int notes[] = {

NOTE_A4, NOTE_ЕЗ,NOTE_A4, 0,

NOTE_A4, NOTE_ЕЗ,NOTE_A4, 0,

NOTE_E4, NOTE_D4,NOTE_C4, NOTE_84, NOTE_A4, NOTE_B4, NOTE_C4, NOTE_D4,

NOTE_E4, NOTE_ЕЗ,NOTE_A4, 0

};

// Массив длительностей звучания нот в мс

int times [) = {

250, 250, 250, 250,

250, 250, 250, 250,

125, 125, 125, 125, 125, 125, 125, 125,

250, 250, 250, 250

};

void setup()

{

- 117 -

// Выбор каждой ноты перебором массива нот

for (int i = 0; i < 20; i++)

{

tone(SPEAKER, notes[i], times[i]);

delay(times[i]);

}

}

void loop()

{

// Чтобы повторить воспроизведение, необходимо нажать кнопку Reset

}

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

Пианино

Соберите схему изображенную на рис. 5.6.

рис. 5.6. Пианино

Листинг 5.3. Пианино

#define NOTE_C 262 //Hz

#define NOTE_D 294 //Hz

#define NOTE_E 330 //Hz

#define NOTE_G 392 //Hz

#define NOTE_A 440 //Hz

const int SPEAKER=9; //Speaker on Pin 9

const int BUTTON_C=7; //Button Pin

const int BUTTON_D=6; //Button Pin

const int BUTTON_E=5; //Button Pin

const int BUTTON_G=4; //Button Pin

const int BUTTON_A=3; //Button Pin

void setup()

{

//No setup needed

//Tone function sets outputs

}

void loop()

{

while (digitalRead(BUTTON_C))

tone(SPEAKER, NOTE_C);

while(digitalRead(BUTTON_D))

tone(SPEAKER, NOTE_D);

while(digitalRead(BUTTON_E))

tone(SPEAKER, NOTE_E);

while(digitalRead(BUTTON_G))

tone(SPEAKER, NOTE_G);

while(digitalRead(BUTTON_A))

tone(SPEAKER, NOTE_A);

//Stop playing если ни одна кнопка не нажата

noTone(SPEAKER);

}

Резюме

В этой главе вы узнали следующее:

• Как динамики создают вибрацию воздуха, которая распространяется в пространстве и воспринимается нашей барабанной перепонкой в виде звука.

• Что изменение электрического тока индуцирует магнитное поле, которое генерирует звук из громкоговорителя.

• Как создавать звуки произвольной частоты и длительности с помощью функции tone().

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

• Что громкость можно регулировать потенциометром, соединенным последовательно с динамиком.

 

Глава 6. USB и последовательный интерфейс

Список деталей

Для повторения примеров главы вам понадобятся следующие детали:

• плата Arduino Uno;

• плата Arduino Leonardo;

• USB-кабель А - В (для Uno );

• USB-кабель А - микро В (для Leonardo );

• светодиод;

• RGB-светодиод с общим катодом;

• резистор номиналом 150 Ом;

• 3 резистора номиналом 220 Ом;

• 2 резистора номиналом 10 кОм;

• кнопка;

• фоторезистор;

• датчик температуры ТМР36;

• двух.координатный джойстик (Spark.Fun, Parallax или Adafruit);

• перемычки;

• провода;

• макетная плата;

• потенциометр.

Электронные ресурсы к главе

На странице http://www.exploringarduino.com/content/ch6 можно загрузить программный код, видеоуроки и другие материалы для данной главы. Кроме того, листинги примеров можно скачать со страницы www.wiley.com/go/exploringarduino в разделе Downloads.

- 119 -

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

Обычно для загрузки программ из компьютера в микроконтроллер нужны внешние аппаратные средства, такие как программатор AVR ISP MKII. Замечательная особенность любой платы Arduino - возможность запрограммировать ее через USB-интерфейс. Это позволяет программировать Arduino без специального программатора. В плату Arduino уже встроен программатор, что дает возможность напрямую подключаться к интегрированному универсальному синхронно/асинхронному приемопередатчику ATmega (USART). Через этот интерфейс можно обмениваться данными между Arduino и компьютером или между Arduino и другими устройствами, поддерживающими протокол (включая другие платы Arduino).

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

 

6.1. Реализация последовательного интерфейса в Arduino

Как уже упоминалось во введении к данной главе, в разных платах Arduino последовательный интерфейс выполнен по-разному. Различия есть как в аппаратной, так и в программной реализации: неодинаковы типы микросхем преобразователей и перечень поддерживаемых функций. Сначала мы рассмотрим различия аппаратных интерфейсов на платах Arduino.

ПРИМЕЧАНИЕ

Чтобы узнать больше о последовательном интерфейсе, посмотрите видеоурок на странице http://www.jeremyblum.com/2011 /02/07/arduino-tutorial-6-serial-communicationand-processing/ или на сайте издательства Wiley.

Для начала необходимо понять разницу между последовательным портом и USB.

Если вы молоды, то наверное даже не сталкивались с последовательным портом (или RS-232), т. к. его давно уже вытеснил USB-интерфейс. Внешний вид стандартного последовательного порта изображен на рис. 6.1.

Фирменные платы Arduino снабжены последовательным портом и подключаются к компьютеру с помощью 9-контактного разъема. В настоящее время еще можно встретить компьютеры, оснащенные такими портами, хотя давно существуют адаптеры от RS232 к USB. У микроконтроллера ATmega328, который установлен на

- 120 -

плате Arduino Uno, есть один аппаратный последовательный порт. Он соединен с контактами Тх (передача) и Rx (прием), к которым можно получить доступ на цифровых выводах 0 и 1. Как мы узнали в главе 1, плата Arduino снабжена загрузчиком, который позволяет программировать ее по последовательному интерфейсу.

Это как раз те выводы, которые "мультиплексированы" (т. е. выполняют более одной функции), они используются и как линии приема-передачи кабеля USB. Но последовательный порт и USB-интерфейс несовместимы. В Arduino эта проблема решается двумя способами. Первый - применение дополнительной микросхемыпреобразователя (так сделано на платах Arduino Uno). Второй способ- использование микроконтроллера, имеющего встроенный USB-интерфейс (например, микроконтроллер 32U4 в Arduino Leonardo ).

Рис. 6.1. Последовательный порт

 

6.2. Платы Arduino с внутренним или внешним преобразователем FTDI

На многих платах Arduino (и их клонах) установлена дополнительная интегральная схема для преобразования USB в последовательный порт. FTDI - популярный чип, выполняющий единственную функцию: конвертирование между последовательным портом и USB. Когда компьютер подключается к микросхеме FTDI, она появляется в системе как "Virtual Serial Port", и доступ к нему аналогичен 9-проводному порту прямо в вашем компьютере. Плата Arduino Nano с установленной микросхемой преобразователя FTDI изображена на рис. 6.2.

ПРИМЕЧАНИЕ

Для обеспечения правильного взаимодействия компьютера с адаптером FTDI необходимо установить драйверы. Найти последние версии драйверов для Windows, OS Х и Linux можно на странице http://www.ftdichip.com/DriversNCP.htm. Ссылка на данную страницу есть на сайте Exploring Arduino.

Иногда для уменьшения размера платы чип FTDI встраивают в кабель (USB-кабель с чипом FTDI изображен на рис. 6.3) или устанавливают на дополнительной плате адаптера (рис. 6.4).

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

- 121 -

Микросхема FTDI

Рис. 6.2. Плата Arduino Nano с чипом FTDI

Рис. 6.3. Кабель FTDI

Рис. 6.4. Плата адаптера FTDI Sparkfun

Далее перечислены платы Arduino со встроенным чипом FTDI. Большинство из них уже не выпускается, тем не менее, продается еще много клонов этих плат:

• Arduino Nano;

• Arduino Extreme;

• Arduino NG;

• Arduino Diecimila;

• Arduino Duemilanove;

• Arduino Mega ( original).

А вот список плат, рассчитанных на работу с внешним адаптером FTDI:

• Arduino Pro;

• Arduino Pro Mini;

- 122 -

LilyPad Arduino;

Arduino Fio;

Arduino Mini;

Arduino Ethemet.

 

6.3. Платы Arduino с дополнительным микроконтроллером для преобразования USB в последовательный порт

Плата Arduino Uno была первой платой, где для преобразования USB в последовательный порт применен дополнительный контроллер. Функционирует все точно так же, но с небольшими техническими различиями. На рис. 6.5 изображен последовательный адаптер 8U2, установленный в Arduino Uno (в новых версиях используется преобразователь 16U2).

Микроконтроллер Atmel 8U2 или 16U2

Рис. 6.5. Чип 8U2 на плате Arduino Uno

Вот краткий перечень различий:

• в операционной системе Windows для плат с новым адаптером требуется специальный драйвер. Этот драйвер поставляется в комплекте с загруженной версией Arduino IDE (драйверы для операционных систем OS Х и Linux не нужны);

• использование второго микроконтроллера в качестве адаптера позволило при подключении передавать в компьютер идентификатор производителя и код продукта. Ранее при подключении платы Arduino к компьютеру она определялась

- 123 -

как последовательное устройство. Плата Arduino с адаптером 8U2 и 16U2 определяется компьютером как устройство Arduino;

вспомогательный микроконтроллер можно перепрограммировать ( он работает на прошивке LUF А, которая эмулирует конвертер USB), следовательно, есть возможность изменить прошивку, чтобы плата Arduino определялась, например, как джойстик, клавиатура или MIDI-устройство. При замене прошивки плату Arduino придется программировать через программатор, например AVR ISP MKII.

Вот список плат Arduino со вспомогательным микроконтроллером для преобразования USB в последовательный порт:

• Arduino Uno;

• Arduino Mega 2560;

• Arduino Mega ADK (на основе 2560);

• Arduino Due (эту плату можно запрограммировать непосредственно).

 

6.4. Платы Arduino с микроконтроллером, снабженным встроенным интерфейсом USB

Плата Arduino Leonardo была первой платой, имеющей только одну микросхему, выполняющую функции и программируемого пользователем микроконтроллера, и интерфейса USB. На плате Arduino Leonardo (и ее клонах) установлен микроконтроллер 32U4, поддерживающий прямую передачу через USB. Это дает несколько преимуществ.

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

Вот список плат Arduino, снабженных микроконтроллером со встроенным интерфейсом USB:

• Arduino Due ( ее также можно запрограммировать через вспомогательный микроконтроллер);

• LilyPad Arduino USB;

• Arduino Esplora;

• Arduino Leonardo;

• Arduino Micro.

- 124 -

 

6.5. Платы Arduino с возможностями USB-хоста

Некоторые платы Arduino обладают возможностями USB-хоста, что позволяет подсоединить к ним традиционные USB-устройства (клавиатуры, мыши, телефоны на базе Android). Естественно, для поддержки этих устройств потребуются дополнительные драйверы. Например, нельзя просто так соединить веб-камеру с Arduino Due и сразу же ожидать получения фотографий. Arduino Due поддерживает класс USB Host, что позволяет подключить к USB-порту клавиатуру или мышь. Arduino Mega ADK поддерживает протокол Android Open Accessory Protocol (АОА), что упрощает обмен данными между Arduino и устройством на базе Android. Прежде всего, это нужно для управления вводом-выводом Arduino из приложения, работающего на устройствах на базе Android.

Возможности USB-хоста поддерживают две платы: Arduino Due и Arduino Mega ADK (на основе Mega 2560).

 

6.6. Опрос Arduino с компьютера

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

6.6.1. Пример вывода данных

Для вывода данных в терминал существуют три функции:

• Serial.begin (baud_rate);

• Serial.print ( "Message");

• Serial.println ("Message"),

где baud_rate и message- переменные, задаваемые пользователем.

Как вы уже знаете, функция Serial. begin() вызывается один раз в начале программы в setup(), чтобы настроить последовательный порт для связи. После этого можно вызвать функции Serial.print() и serial.println() для передачи данных в последовательный порт. Единственное различие между ними состоит в том, что функция serial.println() добавляет символ перевода в конце строки. Чтобы поэкспериментировать с этими функциями, соберем простую схему, подключив потенциометр к контакту A0 платы Arduino, как показано на рис. 6.6.

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

Рис. 6.6. Схема подключения потенциометра

Листинг 6.1. Тестовая программа ввода значений потенциомтре в последовательный порт - pot.ino

// Тестовая программа вывода значений потенциометра в последовательный порт

const int POT=0; // Подключение потенциометра к аналоговому входу A0

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта на скорости 9600

}

- 126 -

void loop()

{

int val = analogRead(POT);// Чтение данных с потенциометра

int per = map(val, 0, 1023, 0, 100);// Перевод в процентное значение

Serial.print("Analog Reading: ");

Serial.print(val);// Вывод аналогового значения

Serial.print(" Percentage: ");

Serial.print(per);// Вывод значения в процентах

Serial.println("%");

delay(1000);// Ожидание 1 сек перед получением новых данных

}

6.6.2. Использование специальных символов

Вы также можете передавать различные "специальные" (или управляющие) символы, которые позволяют изменить форматирование последовательных данных при выводе на печать. Управляющий символ начинается с обратного слэша (\), за которым следует символ команды. Есть много специальных символов, но два из них представляют наибольший интерес: табуляция и переход на новую строку. Чтобы вставить символ табуляции, нужно добавить к строке управляющую последовательность \t. Символ перехода на новую строку вставляют, добавляя к строке \n.

Это особенно полезно, если вы хотите перейти на новую строку в начале передаваемой строки, а не в конце, как делает функция serial.println(). Если, по некоторым причинам, вы на самом деле хотите напечатать последовательность символов \n или \t в строке, это можно сделать с помощью последовательностей \\n или \\t, соответственно. Листинг 6.2 представляет собой модификацию листинга 6.1, но с использованием управляющих символов для отображения данных в табличной форме.

Листинг 6.2. Табличная разметка с использованием управляющих символов - pot_tabular.ino

// Табличная разметка с использованием управляющих символов

const int POT=0; // Подключение потенциометра к аналоговому входу A0

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта на скорости 9600

}

void loop()

{

Serial.println("\nAnalog Pin\tRaw Value\tPercentage");

Serial.println("------------------------------------------");

- 127 -

for (int i = 0; i < 10; i++)

{

int val = analogRead(POT);//Чтение данных потенциометра

int per = map(val, 0, 1023, 0, 100);//Перевод в процентное значение

Serial.print("AO\t\t");

Serial.print(val);//Вывод аналогового значения

Serial.print("\t\t");

Serial.print(per);//Вывод процентного значения

Serial.println ( "%");

delay(1000);

//Ожидание 1 сек перед получением новых данных

}

}

При повороте движка потенциометра данные, выдаваемые в последовательный порт, должны выглядеть примерно так, как на рис. 6.7.

Рис. 6. 7. Скриншот терминала последовательного порта с данными в виде таблицы

6.6.3. Изменение представлений типа данных

Функции Serial.print() и Serial.println() позволяют вывести данные в конкретном формате. Есть опции для представления данных в различных форматах, включая шестнадцатеричный, восьмеричной и двоичный. По умолчанию принят деся

- 128 -

тичный формат ASCII. У функций Serial.print() и Serial.println() есть дополнительный второй параметр, который определяет формат выводимых данных.

В табл. 6.1 приведены примеры вывода одинаковых данных (число 23) в различных форматах и их отображения в мониторе последовательного порта.

Таблица 6.1. Тип последовательных данных

Формат Код Отображение данных
Decimal Serial.println(23); 23
Hexadecimal Serial.println(23,HEX); 17
Octal Serial.println(23,0CT); 27
Binary Serial.println(23,BIN); 00010111

6.6.4. Общение с Arduino

Что хорошего в общении с Arduino, если разговор идет только в одном направлении? Теперь, когда мы разобрались, как Arduino посьшает данные на компьютер, давайте попробуем это сделать. Вы, наверное, заметили, что в окне монитора последовательного порта Arduino IDE сверху есть поле ввода текста, а снизу - раскрывающееся меню (рис. 6.8).

Рис. 6.8. Скриншот терминала последовательного порта с полем ввода текста и выбранной опцией конца строки в раскрывающемся меню

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

- 129 -

В отличие от некоторых других терминальных программ, монитор последовательного порта Arduino IDE при нажатии клавиши или кнопки Отправить посылает всю командную строку. Другие последовательные терминалы, например Putty (www.exploringarduino.com), посылают символы сразу после их ввода.

6.6.5. Чтение информации из компьютера или другого последовательного устройства

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

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

Плата Arduino в качестве транслятора данных

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

Чтобы сделать это, потреб ую тся две новые функции:

• Serial.available() - возвращает число символов (или байтов), которые на даый момент сохранены во входном последовательном буфере Arduino. Каждый раз, когда это число отлично от нуля, символ считывается и отправляется обратно на компьютер;

• serial. read() - читает и возвращает следующий символ, который находится в буфере.

Обратите внимание, что каждый вызов к функции Serial. read() возвратит из буфера только один байт, поэтому вы должны повторять эту функцию, пока serial. available() возвращает ненулевое значение. Каждый раз, когда Функция serial. read() получает байт, буфер очищается, и можно принимать следующий байт. Теперь можно загрузить программу из листинга 6.3 на плату Arduino.

Листинг 6.3. Эхо последовательного порта - 'echo.ino

// Эхо каждого символа

char data;

// Текущий входящий символ

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта на скорости 9600

}

- 130 -

void loop()

{

// Вывод только при получении данных

if (Serial.available() > 0)

{

data = Serial.read(); // Чтение байта из буфера

Serial.print(data);// Вывод в последовательный порт

}

}

Запустите монитор последовательного порта и напечатайте что-нибудь в поле ввода текста. Как только вы нажмете кнопку Отправить, все, что вы набрали, вернется назад в компьютер и отобразится в окне монитора последовательного порта. Поскольку в меню выбрана опция Newline, для каждой команды добавляется символ перевода строки (\n), следовательно, каждый ответ отображается с новой строки.

Поэтому вместо функции serial.println() в листинге 6.3 указана функция Serial.print()

Различие между char и int

При отправке алфавитно-цифрового символа через монитор последовательного порта мы на самом деле не отправляем "5" или "А". Мы посылаем байт, который компьютер интерпретирует как символ. В случае последовательной связи для представления всех букв, цифр, символов и специальных команд используется кодировка ASCII. Основной набор символов ASCII (рис. 6.9) представляет собой 7-битовый набор, содержащий 128 символов и команд.

При получении значения, отправленного с компьютера, данные должны быть считаны, как char (см. листинг 6.3). Даже если вы ожидаете из последовательного терминала отправки числа, вам необходимо прочитать байт, как символ, а затем при необходимости конвертировать его. Если вы измените программу листинга 6.3, объявив переменную data как int, то, отправив значение 5, в последовательный монитор вернется значение 53 (десятичное представление символа "5"). Вы можете убедиться в этом, посмотрев на рис. 6.9.

Тем не менее, в Arduino часто необходимо отправлять числовые значения. Как это сделать? Существует несколько способов. Во-первых, можно просто сравнить сами символы. Если вы хотите зажечь светодиод при отправке из монитора цифры 1, то можно непосредственно сравнить значения символов:

if(Serial.read() == '1')

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

int val = Serial.read() - '0'

Такой способ не годится для чисел больше 9, потому что они содержат несколько цифр. В этом случае нас выручит функция parseInt(), входящая в Arduino IDE, ко

- 131 -

Рис. 6.9. Набор символов ASCII

торая извлекает из последовательного потока данных целые числа. Далее мы подробно рассмотрим описанные методы.

Отправка ОДИНОЧНЫХ символов для управления светодиодом

Начнем с написания программы, которая использует простое сравнение символов для управления состоянием светодиода. Вы будете отправлять символ "1 ", чтобы включить светодиод, и "0", чтобы выключить его. Соедините светодиод с контактом 9 платы Arduino, как показано на рис. 6.10.

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

- 132 -

Рис. 6.10. Подсоединение светодиода к контакту 9 платы Arduino

Листинг 6.4. Управление светодиодом последовательной отправкой символов- single_char_control.ino

// Переключение состояния светодиода отправкой одиночного символа

const int LED=9;

char data;// Переменная для хранения получаемого символа

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта

// на скорости 9600

pinMode(LED, OUTPUT);

}

- 133 -

void loop()

{

// Если в буфере есть символ

if (Serial.available() > 0)

{

data = Serial.read(); // Чтение байта из буфера

// Включение светодиода

if (data == '1')

{

digitalWrite(LED, HIGH);

Serial.println ( "LED ON");

}

// Выключение светодиода

else if (data == '0')

{

digitalWrite(LED, LOW);

Serial.println ( "LED OFF");

}

}

}

Обратите внимание, что вместо простого оператора else применен оператор else if. Это необходимо, потому что в опции терминала установлена отправка символа перевода строки при каждой передаче. Получив символ перевода строки, функция Serial.read() определит, что он не равен '0' или '1', в результате со светодиодом ничего не произойдет. Если бы мы использовали оператор else, то отправка и '0' и '1' приводила бы к откточению светодиода. При отправке '1' светодиод будет включен и немедленно выкточен снова, когда будет получена последовательность \n!

Отправка последовательности цифр для управления RGB-светодиодом

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

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

- 134 -

• необходимо различать цифры и запятые;

• последовательность символов нужно привести к целочисленному формату, чтобы использовать функцию analogWrite();

• числовое значение может состоять из одной, двух или трех цифр.

К счастью, в Arduino IDE есть очень удобная функция для анализа последовательности цифр - Serial. parseInt(). При каждом вызове этой функции она ожидает прихода в буфер последовательности цифр и затем преобразует ее в целое число.

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

Чтобы посмотреть, как действует эта функция, загрузите программу листинга 6.5

на плату Arduino.

Рис. 6.11. Подключение RGB-светодиода к Arduino

- 135 -

Листинг 6.5. Последовательное управление RGB-светодиодом - list_control.ino

// Отправка многосимвольных значений

// Константы выводов RGB-светодиода

const int RED =11;

const int GREEN =10;

const int BLUE =9;

// Переменные значений выводов RGB

int rval = 0;

int gval = 0;

int bval = 0;

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта

// на скорости 9600

// Установить контакты на выход OUT

pinMode(RED, OUTPUT);

pinMode(GREEN, OUTPUT);

pinMode(BLUE, OUTPUT);

}

void loop()

{

// Пока в буфере есть данные

while (Serial.available() > 0)

{

rval = Serial.parseInt(); // Первое ЧИСЛО

gval = Serial.parseInt(); // Второе число

bval = Serial.parseInt(); // Третье число

if (Serial. read() == '\n') // Конец передачи

{

// Установка яркости светодиода

analogWrite(RED, rval);

analogWrite(GREEN, gval);

analogWrite(BLUE, bval);

}

}

}

Программа осуществляет поиск трех целочисленных значений, пока не обнаружит символ перевода строки (\n). Как только это произойдет, полученные значения переменных используются для установки яркости светодиодов. Откройте монитор последовательного порта и введите три значения от 0 до 255, разделенные запятой, например "200,30, 180". Попробуйте получить различные цвета, вводя разные цифры.

- 136 -

 

6.7. Создаем компьютерное приложение

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

В этой книге выбран язык программирования Processing, потому что он очень похож на язык Arduino, с которым вы уже знакомы. На самом деле, язык программирования Arduino основан на Processing! Другие популярные языки программирования, для которых существуют обширные библиотеки для работы с последовательным портом, - Python, РНР, Visual Basic, С и т. п. Сначала выясним, как читать передаваемые последовательные данные в Processing, а затем узнаем, как с его помощью создать простой графический интерфейс пользователя (GUI) для отправки команд на плату Arduino.

6.7.1. Интерфейс Processing

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

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

6.7.2. Установка Processing

Сначала необходимо установить Processing на вашей машине. Делается это так же, как и в главе 1, когда устанавливали Arduino IDE. Зайдите на страницу

http://processing.org/download/ (или найдите ссылку на скачивание на www.exploringarduino.com) и скачайте заархивированный пакет в соответствии с вашей операционной системой. Затем распакуйте его и программа будет готова к работе!

Запустите Processing, и вы должны увидеть окно программы, которое выглядит как на рис. 6.12.

6.7.3. Плата Arduino управляет приложением на Processing

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

- 137 -

Рис. 6.12. Графический интерфейс Processing. Узнаете?

Скопируйте код из листинга 6.6 и загрузите его на плату Arduino. Arduino посылает обновленное значение от потенциометра в последовательный порт компьютера каждые 50 мс. Если отправлять данные быстрее, приложение на Processing не будет успевать их обрабатывать и буфер последовательного порта на вашем компьютере переполнится.

Листинг 6.6. Программа для отправки даных в компьютер - pot_to_processing/arduino_read_pot

// Отправка данных от потенциометра на компьютер

const int POT=0;// Подключение потенциометра к выводу A0

int val;// Переменная для хранения значения потенциометра

void setup()

{

Serial.begin(9600); // Инициализация последовательного порта

// на скорости 9600

}

void loop()

{

- 138 -

val = map(analogRead(POT), 0, 1023, 0, 255);//Чтение значения потенциометра

Serial.println(val);//Отправка значения

delay(50);//Задержка 50 мс

}

Теперь напишем код для обработки входящих данных.

Программа из листинга 6.7 считывает данные из буфера последовательного порта и регулирует яркость цвета на экране вашего компьютера в зависимости от полученного значения. Скопируйте листинг 6.7 и внесите одно важное изменение. В программе на Processing должен быть указан конкретный последовательный порт получения данных. Замените "COM3" на номер вашего последовательного порта. Помните, что в Linux и Mac он будет выглядеть примерно как /dev/ttyUSBO. Если вы не уверены, скопируйте точное название порта из Arduino IDE.

Листинг 6.7. Код Processing для получения данных и изменения цвета экрана - pot_to_processing/processing_display_color

// Программа на Processing для чтения переменной и изменения цвета экрана

// Подключение и инициализация библиотеки Serial

import processing.serial.*;

Serial port;

float brightness = 0; // Переменная Для хранения значения потенциометра

void setup()

{

// Размер окна

size(500,500);

port = new Serial(this, "COM3", 9600); // Инициализация

// последовательного порта

port.bufferUntil('\n');// Символ конца строки

}

void draw()

{

background(0,0,brightness);

}

// Перерисовать окно

void serialEvent(Serial port)

{

brightness = float(port.readStringUntil('\n')); // Получить переменную

}

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

- 139 -

нить (кнопка с изображением треугольника в верхнем левом углу окна), при этом должно появиться небольшое окно. При повороте движка потенциометра цвет окна должен меняться от черного к синему (рис. 6.13).

Рис. 6.13. Изменение цвета окна Processing-приложения

Теперь, когда вы видели результат, для лучшего понимания рассмотрим, как это работает. В отличие от Arduino, библиотека serial не импортируется автоматически. Объявив import processing. serial. * и Serial port, вы импортируете библиотеку serial и создаете объект serial под названием port.

Как и в Arduino, в Processing тоже есть функция setup(), которая работает только в начале программы. В этом примере функция setup() задает последовательный порт и создает окно размером 500x500 пикселов командой size (500, 500). Команда port = new Serial (this, "COM3", 9600) сообщает Processing о создании экземпляра последовательного порта. Экземпляр (под названием port) будет работать и общаться на COM3 (или другом последовательном порту) со скоростью 9600 бод.

Скорость обмена данными между платой Arduino и программой на компьютере должна быть задана одинаковой, в противном случае возникнут ошибки. Команда port.bufferuntil ( '\n') сообщает Processing-приложению о буферизации последовательного ввода до получения символа новой строки ('\n' ).

Вместо loop() в Processing есть другие специальные функции. В нашем примере использованы функции draw() и serialEvent(). Функция draw() похожа на loop() в Arduino, она работает непрерывно и обновляет экран. Функция background() задает цвет окна, имеет три аргумента для установки значений красного, зеленого и синего компонентов цвета. В нашем примере значение с потенциометра управляет интенсивностью синего компонента, а красный и зеленый установлены в нуль. При желании программу можно переделать, чтобы регулировать интенсивность других компонентов. Поскольку интенсивности RGB цветов являются 8-битовыми значениями от 0 до 255, значения потенциометра масштабируются функцией map() перед передачей.

Функция serialEvent() вызывается всякий раз, когда выполняется условие bufferuntil(), указанное в функции setup(). При каждом появлении символа пере

- 140 -

вода строки срабатывает функция serialEvent(). Передаваемые данные считываются в виде строки с помощью port. readStringUntil ( ' \n ' ). Строка представляет собой последовательность символов и ее необходимо преобразовать в число с плавающей точкой, вызвав функцию float(). Результат присваивается переменной brigthness, определяющей цвет фона окна приложения.

Чтобы остановить программу и закрыть последовательный порт, нажмите кнопку Стоп в окне Processing-приложения (это квадратик, расположенный рядом с кнопкой Выполнить).

ПРИМЕЧАНИЕ

SudoGlove - это перчатка-манипулятор для передачи команд на радиоуправляемый автомобиль и другую аппаратуру. Я разработал на Processing дисплей для графического отображения значений датчиков, удобный при отладке SudoGlove. Больше узнать об этом можно на www.sudoglove.com. Скачать исходный код приложения можно по адресу www.jeremyblum.com/2011/03/25/processing-based-sudoglove-visualdebugger/. Этот исходный код есть также на сайте издательства Wiley.

6.7.4. Отправка данных из Processing-приложения в Arduino

Следующий шаг - передать данные из Processing-приложения на плату Arduino.

Подсоедините RGB-светодиод к плате Arduino, как показано на рис. 6.11, и загрузите в нее программу считывания строки из трех значений, разделенных запятыми для установки красной, зеленой и синей интенсивности (см. листинг 6.5). Теперь сделаем так, чтобы вместо отправки трехсимвольной строки из последовательного монитора можно было выбрать цвет, используя палитру цветов.

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

Сопутствующие файлы из папки данных ( data) будут загружены автоматически.

Файл hsv.jpg (изображение для выбора цвета) есть среди электронных ресурсов к этой главе. Скачайте и поместите его в папку data в том же каталоге, что и программа. Processing-приложение по умолчанию сохраняет файлы проекта в папке Мои документы. Структура папки проекта показана на рис. 6.14.

Листинг 6.8. Processing-приложение для установки цвета RGB-светодиода - processing_control_rgb/processing_control_RGB

import processing.serial.*;// Подключение библиотеки serial

PImage img;

Serial port;

void setup()

{

size(640,256);

img = loadimage("hsv.jpg");// Загрузка фоновой картинки

- 141 -

port=new Serial(this, "СОМ9", 9600); // Открыть последовательный

// порт

}

void draw()

{

background(0);// Цвет фона

image(img,0,0);// Изображение

}

void mousePressed()

{

color с=get(mouseX, mouseY); // Получить RGB-цвет по позиции

// курсора мыши

String colors=int(red(c))+","+int(green(c))+","+int(blue(c))+"\n";

// Сформировать строку значений цвета

print(colors);// Вывод для отладки

port.write(colors);// Отправка переменной в Arduino

}

Рис. 6.14. Структура папки проекта

При запуске программы вы увидите всплывающее окно, показанное на рис. 6.15.

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

- 142 -

Рис. 6.15. Экран выбора цвета в Processing

Теперь посмотрим на код программы и проанализируем, как он работает. Как и раньше, импортируется библиотека serial и создается объект port. Создается также объект Pimage с именем img. Он будет формировать фоновое изображение.

В процедуре setup() инициализируется последовательный порт, создается окно в размер изображения, а само изображение импортируется в объект img вызовом функции img=LoadImage ( "hsv. jpg").

В функции draw() изображение загружается в окно командой image ( img, о, о) с двумя аргументами: Img - само изображение, а о, о - координаты для размещения изображения (верхний левый угол окна приложения).

При нажатии кнопки мыши вызывается функция mousePressed(). Цвет пиксела, где вы щелкнули мышью, сохраняется в объекте color с именем с. Метод get() сообщает приложению, откуда можно получить цвет (в данном случае из координат курсора мыши). Затем преобразуем значение в строку, состоящую из целых значений красного, зеленого и синего компонентов цвета. Эти значения также выводятся в монитор последовательного порта.

Включите плату Arduino и загрузите в нее код из листинга 6.5. Запустите Processing-приложение и настройте цвет светодиода, подключенного к Arduino, выбирая цвет из палитры.

- 143 -

 

6.8. Изучаем особенности работы с Arduino Leonardo (и другими платами на основе процессора 32U4)

Leonardo, как и другие платы, построенные на микроконтроллерах с поддержкой интерфейса USB, обладают уникальной способностью эмулировать такие устройства, как, например, клавиатура и мышь. Далее рассмотрим этот вопрос подробнее.

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

Совет

Если плата "зависла" в режиме эмуляции мыши или клавиатуры, чтобы перепрограммировать ее, нажмите и отпустите кнопку Reset, удерживая нажатой кнопку Загрузить в Arduino IDE.

При первом подключении платы Leonardo к компьютеру необходимо установить драйверы, как и для Arduino Uno (см. главу 1). Инструкции для установки Leonardo можно найти по адресам http://arduino.cc/en/Guide/ArduinoLeonardoMicro#toc8 или www.exploringarduino.com.

6.8.1. Эмуляция клавиатуры

Благодаря уникальной возможности Leonardo эмулировать USB-устройства, Плату Arduino легко превратить в клавиатуру. В результате можно отправлять комбинации клавиш в виде команд компьютеру или записывать данные непосредственно в файл, открытый на компьютере.

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

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

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

Кнопка для включения/выключения записи снабжена функцией устранения дребезга ( см. главу 2). В процессе записи плата Arduino опрашивает датчики и раз в се-

- 144 -

Рис. 6.16. Схема подключения датчиков температуры и освещенности

кунду отправляет в компьютер данные, разделенные запятой. При этом загорается светодиодный индикатор. Поскольку Arduino постоянно опрашивает состояние кнопки, то задержку 1000 мс перед каждой отправкой данных формирует не функция delay(), а функция millis(), которая возвращает количество миллисекунд с последнего сброса платы Arduino. Вы можете посылать данные каждый раз, когда функция millis() выдает значение, кратное 1000 мс, фактически создавая задержку между посылками, равную 1 с. Это реализует оператор остатка деления по модулю (%). Если, например, вы выполните операцию 1000%1000, то результат будет равен нулю, т. к. 1000/1000 = 1 с нулевым остатком. 1500%1000 вернет 500, потому что 1500/1000= 1 с остатком 500. Выполняя деление по модулю millis() на 1000, по

- 145 -

лучим нулевой результат каждый раз, когда millis() выдает значение, кратное 1000, т. е. каждую секунду.

Изучите код листинга 6.9 и загрузите его на плату Arduino Leonardo. Убедитесь, что вы выбрали опцию Arduino Leonardo из меню Инструменты -> Board в Arduino IDE.

Листинг 6.9. Запись данных освещенности и температуры - csv_logger.ino

// Запись данных температуры и освещенности

const int TEMP=0;// Датчик температуры к аналоговому входу 0

const int LIGHT=1;// Датчик освещенности к аналоговому входу 1

const int LED=3;// Светодиод к выводу 13

const int BUTTON=2; // Кнопка к выводу 2

boolean lastButton = LOW;//Последнее состояние кнопки

boolean currentButton = LOW;//Текущее состояние кнопки

boolean running = false;//По умолчанию запись выключена

int counter = 1;//Индекс записываемых данных

void setup()

{

pinMode (LED, OUTPUT);// Контакт светодиода как выход OUTPUT

Keyboard.begin();// Запуск эмуляции клавиатуры

}

void loop()

{

currentButton = debounce(lastButton);// Чтение состояния

if (lastButton == LOW && currentButton==HIGH) // Если нажатие...

running = !running;// Переключить статус записи

lastButton = currentButton;// Установить статус кнопки

if ( running)// Запись включена

{

digitalWrite(LED, HIGH);// Включить светодиод

if (millis() % 1000 == 0)// Прошло 1000 мс

{

int temperature = analogRead(TEMP); // Чтение данных

// с датчика температуры

int brightness = analogRead(LIGHT); // Чтение данных

// с датчика освещенности

Keyboard.print(counter);// Вывод индекса данных

Keyboard.print(",");// Вывод разделителя

Keyboard.print(temperature);// Вывод температуры

Keyboard.print(",");// Вывод разделителя

Keyboard.println(brightness);// Вывод освещенности

// и символа новой строки

counter++;// Инкремент индекса

}

- 146 -

else

{

digitalWrite(LED, LOW);// Запись выключена, погасить светодиод

}

}

}

/*

* Функция устранения дребезга кнопки

* Получает предыдущий и возвращает текущий статус.

*/

boolean debounce(boolean last)

{

boolean current = digitalRead(BUTTON); // Чтение состояния кнопки

if (last != current)// Состояние изменилось...

{

delay(5);// Ждем 5 мс

current = digitalRead(BUTTON);// Чтение состояния кнопки

}

return current;// Возврат текущего состояния кнопки

}

Подробнее рассмотрим некоторые новые функциональные возможности, реализованные в этой программе. Как и ранее при инициализации последовательного порта, клавиатура инициализируется оператором Keyboard.begin() в функции setup().

В цикле loop() Arduino проверяет состояние кнопки и запускает программу устранения дребезга. При нажатии на кнопку значение переменной статуса записи инвертируется. Это достигается применением оператора ! к переменной running.

Когда программа находится в режиме записи, отправка данных выполняется раз в 1000 мс, благодаря описанному ранее приему. Функции эмулированной клавиатуры и последовательного порта очень похожи. Команда Keyboard.print() отправляет строку в компьютер. После получения данных аналоговых датчиков программа передает данные в компьютер в виде нажатия клавиш. Благодаря команде Keyboard.println() Arduino эмулирует нажатие клавиши (или )

после отправки строки. Индекс данных и оба аналоговых значения при выводе разделяются запятой.

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

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

- 147 -

ПРИМЕЧАНИЕ

Посмотрите демонстрационный видеоклип со страницы

http://www.exploringarduino.com/content/ch6.

6.8.2. Отправка команд для управления компьютером

Плата Leonardo пригодна и для эмуляции нажатия комбинаций клавиш. На компьютерах с операционной системой Windows нажатие комбинации клавиш + блокирует экран компьютера (в Linux существует комбинация ++ ). Можно, например, по сигналу от датчика освещенности заблокировать компьютер, когда выключается свет. В OS Х для блокировки компьютера предусмотрены комбинации ++ или ++ +, которые Leonardo не может сформировать, т. к. невозможно смоделировать нажатие клавиш и . Рассмотрим, как заблокировать компьютер с Windows. Подойдет схема, показанная на рис. 6.16, хотя будет использоваться только датчик.

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

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

Листинг 6.10. Блокировка компьютера по сигналу от датчика освещенности - lock_computer.ino

// Блокировка компьютера при выключении света

const int LIGHT=1;//Датчик освещенности на контакт 1

//Значение с датчика освещенности для блокировки компьютера

const int THRESHOLD =500; //

void setup()

{

Keyboard.begin();

}

void loop()

{

int brightness = analogRead(LIGHT); // Чтение данных датчика

- 148 -

if (brightness < THRESHOLD)

{

Keyboard.press(KEY_LEFT_GUI);

Keyboard.press('1');

delay (100);

Keyboard.releaseAll();

}

}

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

ПРИМЕЧАНИЕ

Вы можете посмотреть демонстрационный видеоклип, расположенный на странице http://www.exploringarduino.com/content/ch6.

В этом примере реализованы две новые функции для эмулятора клавиатуры:

Keyboard.press() И Keyboard.releaseAll(). Запуск Keyboard.press() эквивалентен удержанию клавиши нажатой. Если вы хотите сэмулировать нажатие клавиш и , запустите Keyboard.press() для каждой клавиши. Выдержав паузу, вызовите функцию Keyboard. releaseAll(), чтобы завершить нажатие комбинации клавиш. Список специальных клавиш можно найти на сайте http://arduino.cc/en/Reference/KeyboardModifiers.

6.8.3. Эмуляция мыши

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

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

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

Собрав схему, можно загрузить программу на плату Leonardo. Скопируйте и запустите код листинга 6.1 1 и поуправляйте курсором с помощью джойстика и кнопок; курсор на экране компьютера должен реагировать соответствующим образом.

- 149 -

Рис. 6.17. Схема мыши на основе джойстика и платы Leonardo

Листинг 6.11. Программа управления курсором мыши для Leonardo - mouse.ino

// Создаем мышь !

const int LEFT_BUTTON=4;//Вход для левой кнопки мыши

const int MIDDLE_BUTTON=3;//Вход ДЛЯ средней кнопки мыши

const int RIGHT_BUTTON =2;//Вход для правой кнопки мыши

const int X_AXIS=0;//Аналоговый вход для оси х джойстика

const int Y_AXIS=1;//Аналоговый вход для оси у джойстика

void setup()

{

- 150 -

Mouse.begin();

}

void loop()

{

int xVal=readJoystick(X_AXIS);//Получить отклонение джойстика по оси х

int yVal = readJoystick(Y_AXIS);//Получить отклонение джойстика по оси у

Mouse.move(xVal, yVal, 0);//Перемещаем мышь

readButton(LEFT_BUTTON, MOUSE_LEFT);// Чтение состояния левой кнопки

readButton(MIDDLE_BUTTON, MOUSE_MIDDLE);//Чтение состояния средней кнопки

readButton(RIGHT_BUTTON, MOUSE_RIGHT); //Чтение состояния правой кнопки

delay(5);

}

int readJoystick(int axis)// Чтение значения джойстика, масштабирование

{

int val = analogRead(axis);

// Чтение аналогового значения

val = map(val, 0, 1023, -10, 10); // Масштабирование значения

if (val <= 2 && val >= -2)

// Убрать дрейф мыши

return 0;

else// Вернуть значение

return val;

}

// Чтение состояния кнопок и отправка команд мыши

void readButton(int pin, char mouseCommand)

{

// Если кнопка нажата, эмулируем нажатие, если она еще не быпа нажата

if (digitalRead(pin) == HIGH)

{

if ( ! Mouse.isPressed (mouseCommand) )

{

Mouse.press(mouseCommand);

}

}

// Отпустить нажатие мыши

else

{

if (Mouse.isPressed(mouseCommand))

- 151 -

{

Mouse.release(mouseCommand);

}

}

}

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

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

Функция readJoystick() считывает и масштабирует значения от джойстика. По каждой координате джойстик выдает ряд значений от 0 до 1024, полученных от АЦП.

Но курсор мыши перемещается по относительным координатам и передача Mouse.move() нулевого значения соответствует отсутствию движения по этой оси.

Передача положительного значения для оси х будет перемещать курсор мыши вправо, а отрицательного - влево. Чем больше величина, тем дальше будет перемещаться курсор. Таким образом, в функции readJoystick() значения от 0 до 1023 масштабируем к диапазону от -10 до 10.

Для устранения дрейфа предусмотрен небольшой запас в районе нуля, где курсор мыши должен быть неподвижен. Это связано с тем, что во время нахождения рукоятки джойстика в среднем положении фактическое значение может колебаться вокруг 512. Мы должны быть уверены, что при отпускании джойстика курсор мыши не будет двигаться самопроизвольно. Значения х и у передаются функции mouse.move(), что приводит к перемещению курсора на экране. Третий аргумент функции mouse.move() определяет движение колеса прокрутки.

Функция readButton() служит для определения состояния каждой из трех кнопок.

Функция определяет текущее состояние мыши с помощью команды mouse.isPressed() и опрашивает мышь через функции Mouse.press() и Mouse.release().

ПРИМЕЧАНИЕ

Демонстрационный видеоклип эмулятора мыши для управления компьютером с помощью джойстика можно посмотреть на странице http://www.exploringarduino.com/content/ch6.

Резюме

В этой главе вы узнали следующее:

• Как подключить плату Arduino к компьютеру через USB-преобразователь последовательного порта.

- 152 -

• Как осуществляется преобразование USB-интерфейса в последовательный порт на различных платах Arduino.

• Как можно отправлять данные с Arduino в компьютер через USB-интерфейс.

• Как форматировать отправляемые данные с помощью специальных символов.

• Что последовательные данные передаются в виде символа, который можно преобразовать в целые числа различными способами.

• Как отправлять данные в виде списков с разделителями-запятыми и преобразовывать их в команды с помощью встроенных функций.

• Как можно передать данные из Arduino внешнему приложению на языке Processing.

• Что можно отправлять данные из Processing-приложения на периферийные устройства, подключенные к Arduino.

• Что плата Arduino Leonardo может эмулировать клавиатуру и мышь.

 

Глава 7. Сдвиговые регистры

Список деталей

Для повторения примеров главы вам понадобятся следующие детали:

• плата Arduino Uno;

• USB-кабель А - В (для Uno );

• 8 красных светодиодов;

• 3 желтых светодиода;

• 5 зеленых светодиодов;

• 8 резисторов номиналом 220 Ом;

• сдвиговый регистр SN74HC595N в DIP-корпусе;

• инфракрасный датчик расстояния GP2YOA41 SKOF с кабелем;

• перемычки;

• макетная плата.

Электронные ресурсы к главе

На странице http://www.exploringarduino.com/content/ch7 можно загрузить программный код, видеоуроки и другие материалы для данной главы. Кроме того, листинги примеров можно скачать со страницы www.wiley.com/go/exploringarduino в разделе Downloads.

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

Чем дальше вы продвигаетесь в создании новых устройств на основе Arduino, тем чаще возникает мысль: "Что будет, если закончатся контакты платы Arduino?" Например, в одном из популярных проектов плата Arduino управляет множеством мигающих светодиодов. Осветите свою комнату! Иллюминируйте свой компьютер!

Украсьте светодиодами свою собаку! Последнее, пожалуй, перебор.

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

- 154 -

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

В этой главе, как и в большинстве предыдущих, в качестве платформы используем Arduino Uno. Для экспериментов подойдет и любая другая плата Arduino, но выбор всегда должен быть обоснованным и оптимально соответствовать конкретному проекту. Вы спросите, почему бы не взять Arduino с большим количеством контактов, например Mega 2560 или Due? Конечно, это совершенно разумный способ для реализации устройств, где требуется множество контактов. Тем не менее вы, как инженеры, всегда должны помнить при проектировании обо всех нюансах. Когда вычислительной мощности Arduino Uno вполне хватает, но недостаточно цифровых выходов, можно просто добавить несколько сдвиговых регистров. Это будет дешевле и компактнее, чем выбор более мощной платы. Однако программный код окажется сложнее, и возможно потребуется больше времени для его отладки.

 

7.1. Что такое сдвиговый регистр

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

Рис. 7.1. Входы и выходы регистра сдвига

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

- 155 -

 

7.2. Последовательная и параллельная передача данных

Существуют два способа передачи нескольких битов данных. Напомним, что Arduino, как и все микроконтроллеры, представляет собой цифровое устройство, т. е. "понимает" только "0" и "1". Если вы хотите управлять восьмью светодиодами, необходимо передать 8 бит информации. Ранее мы это делали в параллельном режиме с помощью функций digitalWrite() и analogWrite(). В качестве примера параллельной передачи данных, предположим, что нам необходимо включить 8 светодиодов, подключенных к 8 цифровым выходам. При этом все биты будут переданы на цифровые контакты примерно в одно время. В главе 6 была описана последовательная передача данных, при которой за фиксированный интервал времени передается 1 бит данных. Сдвиговые регистры позволяют легко конвертировать последовательные и параллельные методы передачи данных. Эта глава посвящена регистрам последовательно-параллельного сдвига (SIPO), которые называют просто регистрами сдвига. С их помощью можно принимать данные последовательно, а выводить параллельно на выходы регистра. Кроме того, можно каскадировать сдвиговые регистры и управлять множеством цифровых выходов, используя всего три контакта Arduino.

7.3. Сдвиговый регистр 7 4НС595

В качестве сдвигового регистра мы будем применять микросхему 74НС595, цоколевка которой изображена на рис. 7.2.

Рис. 7.2. Цоколевка микросхемы 74НС595

7.3.1. Назначение контактов сдвигового регистра

Назначение контактов сдвигового регистра:

• QA - QH - восемь параллельных выходов сдвигового регистра;

• GND - соединяется с земляной шиной платы Arduino;

- 156 -

• SER - это вход данных (DA ТА на рис. 7.1 ). По этому входу передаются 8 последовательных битов данных для установки значений на параллельных выходах;

• SRCLK- это тактовый вход (CLOCK на рис. 7.1). При подаче импульса высокого напряжения HIGH на этот вход происходит считывание одного бита данных с входа DA ТА в сдвиговый регистр. Для получения всех 8 битов данных необходимо подать 8 импульсов на этот контакт;

• RCLK - это вход (LA ТСН на рис. 7.1) называется также защелкой и служит для одновременного вывода последовательных данных на параллельные выходы.

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

7.3.2. Принцип действия сдвиговых регистров

Регистр сдвига является синхронным устройством, он принимает данные по нарастающему фронту тактового сигнала. Каждый раз, когда сигнал на входе CLOCK меняется с низкого на высокий, все значения, хранящиеся в восьми выходных ячейках, смещаются на одну позицию. Данные из последней ячейки либо сбрасываются, либо передаются на выход QH' (при каскадном подключении микросхемы 74НС595). Одновременно последовательные данные на входе DATA сдвигаются на одну позицию. За восемь тактов предыдущие значения в ячейках регистра уходят, а новые загружаются. Подача высокого уровня на вход LATCH выводит значения, хранящиеся в ячейках, на выходы регистра. Этот процесс проиллюстрирован на рис. 7.3.

Предположим, вы хотите включить некоторые из светодиодов, подключенных к параллельным выходам сдвигового регистра, например к выходам QA, QC, QE, QG. В двоичном представлении на параллельных выходах должно быть значение 10101010. Теперь посмотрим, как действует регистр. Установим низкий уровень на входе LATCH, чтобы значения на параллельных выходах не изменялись во время загрузки новых данных в ячейки регистра. Затем, подавая импульсы на вход CLOCK, значения на входе DATA загружаем и сдвигаем по ячейкам. После загрузки в регистр всей последовательности данных, устанавливаем на входе LATCH высокий уровень для вывода значений из ячеек на параллельные выходы.

- 157 -

Рис. 7.3. Перемещение данных по сдвиговому регистру

- 158 -

7.3.3. Передача данных из Arduino

в сдвиговый регистр

Теперь можно написать программу для передачи данных из Arduino в сдвиговые регистры. Воспользуемся встроенной в Arduino IDE функцией shiftOut() для поразрядной выдачи данных на контакт платы Arduino. Эта функция принимает четыре аргумента:

• номер контакта DATA;

• номер контакта CLOCK;

• порядок выдачи битов;

• значение, выдаваемое на выход.

Например, если вы хотите зажечь светодиоды как в предыдущем примере, можно вызвать функцию shiftout() следующим образом:

shiftOut(DATA, CLOCK, MSBFIRST, 810101010);

Константы DATA и с1оск - номера контактов Arduino для передачи данных. Аргумент MSBFIRST показывает, что самый старший бит (крайний слева бит в двоичном числе) будет отправлен первым. Можно передавать данные с параметром LSBFIRST, который начнет передачу с младшего бита. Последний параметр - это передаваемые данные. Знак в перед числом указывает Arduino IDE, что данные представлены в двоичном виде.

Теперь соберем схему устройства. Подключим регистр сдвига к плате Arduino следующим образом: вывод DATA к контакту 8 платы, LATCH к контакту 9, CLOCK к контакту 10.

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

Теперь, зная как работают сдвиговые регистры и используя встроенную в Arduino IDE функцию shiftOut(), мы можем написать программу управления светодиодами (листинг 7.1).

Листинг 7.1. Программа управления светодиодами с помощью сдвигового регистра - alternate.ino

const int SER=8; // Контакт для подключения вывода DATA

const int LATCH =9;// Контакт для подключения вывода LATCH

const int CLK =10; // Контакт для подключения вывода CLOCK

void setup()

{

// Установить контакты на вывод (OUTPUT}

pinMode(SER, OUTPUT);

pinMode(LATCH, OUTPUT);

pinMode(CLK, OUTPUT);

- 159 -

digitalWrite(LATCH, LOW);// LATCH - низкий

shiftOut(SER, CLK, MSBFIRST, 810101010); // Старший бит - первый

digitalWrite(LATCH, HIGH);// LATCH - высокий

}

void loop() {; }

Рис. 7.4. Подключение 8 светодиодов к сдвиговому регистру

Поскольку регистр сдвига фиксирует полученные данные, отправляем их только один раз в функции setup(). Полученные значения хранятся до следующего изменения. Эта программа выполняет те же шаги, что показаны на рис. 7.3. На выводе

- 160 -

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

Как видим, нам удалось получить восемь цифровых выходов из трех портов ввода-вывода. Уже неплохо. Но что делать, если нужно еще больше? Это возможно! Последовательно подключая несколько сдвиговых регистров, теоретически можно добавить сотни цифровых выходов, задействуя только три контакта Arduino. Но в таком случае потребуется внешнее питание. Посмотрите на рис. 7.2, там есть неиспользованный контакт QH'. Когда значения смещаются по ячейкам, они на самом деле не отбрасываются, а поступают на вывод QH'. Подключив выход QH' к входу DA ТА другого сдвигового регистра, а также соединив выводы LATCH и CLOCK

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

Можете попробовать подключить еще один регистр сдвига и дважды вызвать функцию shiftout() (за один раз функция shiftOut() может обрабатывать только 8 разрядов данных).

7.3.4. Преобразование между двоичным и десятичным форматами

В листинге 7.1 данные для включения светодиодов передавались в виде двоичной строки. Это позволяет наглядно отобразить включенные и выключенные светодиоды. Тем не менее, данные можно записать в десятичном виде, преобразовав их из двоичного (base2) в десятичный (base 1 0) формат. Каждый разряд двоичного числа (начиная с младшего, самого правого) представляет следующую степень числа 2.

Преобразовать двоичное представление числа в десятичное очень просто. Рассмотрим этапы преобразования двоичного кода в десятичный (рис. 7.5).

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

Двоичное значение каждого бита представляет собой увеличивающуюся степень числа 2. В нашем случае биты 7, 5, 3, 1 установлены в единицу. Таким образом, чтобы найти десятичный эквивалент, вы складываете 2 7, 2 5, 2 3 и i. Полученное десятичное значение равно 170. Можно доказать, что это эквивалентно, подставив десятичное значение в код из листинга 7.1.

Замените строку с shiftout() на следющую:

shiftOut(DATA, CLOCK, MSBFIRST, 170);

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

-161 -

7.4. Создание световых эффектов с помощью СДВИГОВОГО регистра

В предыдущем примере мы создали с помощью регистра сдвига и светодиодов неподвижное изображение. Гораздо интереснее отображать динамичную информацию. В следующих примерах используем сдвиговые регистры для создания анимационных эффектов "бегущего всадника" и "гистограммы".

7.4.1. Эффект "бегущий всадник"

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

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

В программе передаем функции shiftout() десятичные значения комбинаций светодиодов. В цикле выбираем значение из массива и отправляем в сдвиговый регистр. Код программы приведен в листинге 7.2.

0000000* | 1 | t=1

000000*0 | 2 | t=2

00000*00 | 4 | t=3

0000*000 | 8 | t=4

000*0000 | 16 | t=5

0*000000 | 64 | t=7

*0000000 | 128 | t=8

0*000000 | 64 | t=9

00*00000 | 32 | t=10

000*0000 | 16 | t=11

0000*000 | 8 | t=12

00000*00 | 4 | t=13

000000*0 | 2 | t=14

Рис. 7.6. Пошаговое представление эффекта "бегущий всадник"

- 162 -

Листинг 7.2. Световой эффект "бегущий всадник" - lightrider.ino

// Создание световой анимации "бегущий всадник"

const int SER=8;// Контакт для подключения вывода DATA

const int LATCH =9;// Контакт для подключения вывода LATCH

const int CLK =10;// Контакт для подключения вывода CLOCK

// Последовательность включения светодиодов

int seq[14]1 миля (США) ≈ 1,6 км; 1 фут ≈ 30 см. - Ред.
= {1,2,4,8,16,32,64,128,64,32,16,8,4,2};

void setup()

{

// Установить контакты на вывод (OUTPUT)

pinMode(SER, OUTPUT);

pinMode(LATCH, OUTPUT);

pinMode(CLK, OUTPUT);

}

void loop()

{

for (int i = 0; i < 14; i++)

{

digitalWrite(LATCH, LOW);// LATCH - низкий

shiftOut(SER, CLK, MSBFIRST, seq[i]); // Старший бит - первый

digitalWrite(LATCH, HIGH);// LATCH - высокий

delay(100);// Скорость анимации

}

}

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

ПРИМЕЧАНИЕ

Для просмотра демонстрационного видеоклипа программы lightrider зайдите по адресу http://www.exploringarduino.com/content/ch7. Видеоклип также доступен на сайте издательства Wiley.

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

- 163 -

Рис. 7.7. Схема устройства, реализующего эффект "гистограммы расстояния"

Зная принцип действия аналогового датчика и регистра сдвига, вы в состоянии самостоятельно выбрать пороги расстояния и соответствующие им комбинации включенных и выключенных светодиодов (рис. 7.8).

Из главы 3 ясно, что диапазон используемых значений для ИК-датчика расстояния не должен превышать 10 бит (у меня максимальное значение оказалось равно 500, у вас оно возможно отличается). Лучше всего самостоятельно проверить дальность действия датчика и уточнить соответствующие значения. Все десятичные комбинации гистограммы хранятся в массиве из девяти элементов. Ограничиваем максимальное расстояние и приводим значения к диапазону от 0 до 8. Листинг 7.3 иллюстрирует программную реализацию эффекта гистограммы.

Листинг 7.3 Гистограмма отображения расстояния - bargraph.ino

// Гистограмма расстояния

const int SER=8;// Контакт для подключения вывода DATA

const int LATCH =9; // Контакт для подключения вывода LATCH

- 164 -

const int CLK =10;// Контакт для подключения вывода CLOCK

const int DIST =0;// Контакт для подключения датчика расстояния

// Возможные значения светодиодов

int vals[9]На русском: http://wiki.amperka.ru/видеоуроки:6-serial-и-processing.
= {0,1,3,7,15,31,63,127,255};

// Максимальное значение расстояния

int maxVal = 500;

// Минимальное значение расстояния

int minVal = 0;

void setup()

{

// Установить контакты на вывод (OUTPUT)

pinMode(SER, OUTPUT);

pinMode(LATCH, OUTPUT);

pinMode(CLK, OUTPUT);

}

void loop()

{

int distance = analogRead(DIST);

distance = map(distance, minVal, maxVal, 0, 8);

distance = constrain(distance,0,8);

digitalWrite(LATCH, LOW);// LATCH - низкий - начало отправки

shiftOut(SER, CLK, MSBFIRST, vals[distance]); // Старший бит - первый

digitalWrite(LATCH, HIGH);// LATCH - высокий

delay (10);// Скорость анимации

}

Рис. 7.8. Комбинации включенных и выключенных светодиодов и соответствующие им десятичные значения

- 165 -

Загрузите программу на плату Arduino, запустите на выполнение и перемещайте руку вперед-назад перед датчиком расстояния. Вы должны увидеть, что гистограмма реагирует на движение руки. Если устройство работает неправильно, отрегулируйте значения maxVal и minVal, чтобы лучше соответствовать показаниям датчика расстояния. Для контроля значений, которые вы получаете на различных расстояниях, можно инициализировать последовательное соединение в заголовке setup() и вызвать функцию Serial.println(DIST) сразу после выполнения шага analogRead(DIST).

ПРИМЕЧАНИЕ

Для просмотра демонстрационного видеоклипа программы, формирующей гистограмму расстояния, зайдите по адресу http://www.exploringarduino.com/content/ch7. Этот видеоклип доступен также на сайте издательства Wiley.

Резюме

В этой главе вы узнали следующее:

• Как работают сдвиговые регистры.

• Чем отличается последовательная и параллельная передача данных.

• В чем различие между десятичной и двоичной формой представления данных.

• Как создать световую анимацию с помощью сдвигового регистра.