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

Блум Джереми

ЧАСТЬ I

 

Общие сведения о платформе Arduino

В этой части

Глава 1. Начало работы, переключаем светодиод из Arduino

Глава 2. Цифровые контакты ввода-вывода шиотно-импульсная модуляция

Глава 3. Опрос аналоговых датчиков

 

ГЛАВА 1 Начало работы, переключаем светодиод из Arduino

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

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

• плата Arduino Uno;

• USB-кабель.

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

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

ПРИМЕЧАНИЕ РОССИЙСКИХ ПЕРЕВОДЧИКОВ

Плату Arduino, а также все электронные компоненты и инструменты можно приобрести в магазине компании "Амперка". Все необходимое для повторения опытов из этой книги можно найти в специальном разделе: http://amperka.ru/jeremy. Используйте кодовое слово JEREMY при покупке товаров из этого раздела для получения скидки. Кроме того, на сайте компании можно найти видеоуроки автора книги, переведенные на русский язык.

 

1.1. Знакомство с платформой Arduino

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

ПРИМЕЧАНИЕ

Вводный видеоурок по платформе Arduino можно найти на странице www.jeremyblum.com/2011/01/02/arduino-tutorial-series-it-begins/ и на сайте издательства Wiley.

- 28 -

При изучении платформы Arduino для повторения проектов из книги вам потребуются три главных компонента:

• основная плата Arduino;

• платы расширения;

• интегрированная среда разработки Arduino - Arduino IDE.

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

 

1.2. Аппаратная часть

Все платы Arduino содержат основные компоненты, необходимые для программирования и совместной работы с другими схемами (рис. 1.1 ):

• микроконтроллер Atmel;

• USB-интерфейс для программирования и передачи данных;

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

• контакты входов ввода-вывода; индикаторные светодиоды (Debug, Power, Rx, Тх);

• кнопку сброса;

• встроенный последовательный интерфейс программирования (ICSP).

 

1.3. Микроконтроллеры Atmel

Основной элемент платы Arduino - микроконтроллер Atmel. На большинстве плат Arduino, включая Arduino Uno, установлен микроконтроллер ATmega. На плате Arduino Uno, изображенной на рис. 1.1, вы видите микроконтроллер ATmega 328.

Исключением является плата Due, укомплектованная микроконтроллером ARM Cortex.

Микроконтроллер исполняет весь скомпилированный код программы. Язык Arduino предоставляет доступ к периферийным устройствам микроконтроллера: аналого-цифровым преобразователям (ADCs), цифровым портам ввода-вывода, коммуникационным шинам (включая I2C и SPI) и последовательным интерфейсам.

На плате все эти порты выведены на штырьковые контакты.

К тактовым контактам микроконтроллера ATmega подключен кварцевый резонатор на 16 МГц.

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

Рис. 1.1. Компоненты платы Arduino Uno

1. Кнопка сброса

2. USB — разъем

3. Конвертер - последовательного и USB интерфейсов

4. Разъем для подключения внешнего источника питания 7-12 В

5. Цифровые контакты ввода-вывода

6. Светодиод, предназначенный для отладки

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

8. Микроконтроллер ATmega 328

9. Входы аналого-цифрового преобразователя

10. Контакты питания и вспомогательные контакты

- 30 -

Большинство плат Arduino оснащено светодиодом отладки (Debug), подсоединенным к контакту 13, который позволит реализовать нашу первую программу (мигающий светодиод) без дополнительных компонентов.

 

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

Обычно программы микроконтроллера ATmega, написанные на С или Ассемблере загружаются в микроконтроллер через интерфейс ICSP с помощью программатора (рис. 1.2). Возможно, самая важная особенность Arduino - непосредственное программирование через USB-порт, без дополнительного программатора. Эту функцию обеспечивает загрузчик Arduino, записанный в микроконтроллер ATmega на заводе-изготовителе, и позволяющий загружать пользовательскую программу на плату Arduino по последовательному порту USART.

В случае Arduino Uno и Mega 2560 интерфейсом между кабелем USB и контактами USART на основном микроконтроллере служит дополнительный контроллер (ATmega 16U2 или 8U2 в зависимости от версии платы). На плате Arduino Leonardo установлен основной микроконтроллер ATmega 32U4, имеющий встроенный контроллер USB. В более старых платах Arduino функцию сопряжения между последовательным портом ATmega и интерфейсом USB выполняла специальная микросхема.

Загрузчик - это фрагмент программного кода, который записан в зарезервированное пространство памяти программы Arduino. Микроконтроллеры AVR обычно программируются с помощью ICSP, который взаимодействует с микроконтроллером через последовательный периферийный интерфейс (SPI). Этот способ предполагает наличие программатора, например, STK500 или ISP MKII ( см. рис. 1.2).

Рис. 1.2. AVR программатор ISP MKII

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

- 31 -

При подаче команды загрузки от IDE Arduino вспомогательный контроллер (ATmega 16U2 или 8U2 в случае Arduino Uno) сбрасывает основной микроконтроллер, подготавливая его к загрузке. Затем внешний компьютер начинает отправлять код программы, который микроконтроллер получает через соединение UART.

Загрузчики занимают в памяти довольно много места, потому что они реализуют простое программирование через USB без внешних аппаратных средств. Однако у них есть два основных недостатка: + они занимают место в памяти (приблизительно 2 Кбайт), которое могло бы пригодиться при написании программ; + при наличии загрузчика выполнение вашей программы всегда будет задерживаться на несколько секунд при начальной загрузке, поскольку загрузчик обрабатывает запрос на программирование.

Если у вас есть программатор (или другая плата Arduino, запрограммированная как программатор), то можно удалить загрузчик из своего контроллера ATmega и программировать его с помощью внешнего программатора.

 

1.5. Цифровые и аналоговые контакты ввода-вывода

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

 

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

Для большинства проектов достаточно 5-вольтового питания, получаемого по кабелю USB. Однако, при необходимости разработки автономного устройства, схема способна работать от внешнего источника от 6 до 20 В (рекомендуется напряжение 7-12 В). Внешнее питание может подаваться через разъем DC или на контакт Vin.

У Arduino есть встроенные стабилизаторы на 5 и 3,3 В:

• напряжение 5 В используется для всех логических элементов на плате, уровень на цифровых контактах ввода-вывода находится в пределах 0-5 В;

• напряжение 3,3 В выведено на отдельный контакт для подключения внешних устройств.

 

1.7. Платы Arduino

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

- 32 -

Arduino Uno (рис. 1.3) - основная плата линейки Arduino, она будет использоваться в большинстве примеров книги. Плата укомплектована микроконтроллером ATmega 328 и микросхемой 16U2 преобразователя USB. Микроконтроллер ATmega 328 может быть выполнен в исполнении DIP или SMD.

Рис. 1.3. Плата Arduino Uno

На плате Leonardo (рис. 1.4) установлен контроллер 32U4 со встроенным интерфейсом USB. Это уменьшает стоимость изделия и дает возможность использовать плату в качестве USB-устройства, например как эмулятор джойстика или клавиатуры.

Вы узнаете, как работать с этими функциями, в главе 6.

На плате Arduino Mega 2560 (рис. 1.5) установлен контроллер ATmega 2560, имеющий 54 цифровых входа-выхода, что позволяет подключать еще больше устройств. У Arduino Mega 2560 увеличено число аналоговых входов и последовательных портов (четыре против одного у Arduino Uno).

В отличие от остальных плат Arduino, использующих 8-разрядные контроллеры AVR, плата Due (рис. 1.6) создана на базе 32-разрядного процессора Atmel SAM3X8E ARM Cortex-M3 с тактовой частотой 84 МГц. Отличительные особенности платы: повышенная точность аналого-цифрового преобразователя, настраиваемая частота сигнала ШИМ, отдельные выводы цифроаналогового преобразователя, наличие встроенного последовательного порта.

Конструкция миниатюрной платы Arduino Nano (рис. 1. 7) такова, что ее можно установить в панельку для микросхем.

Плата Mega ADK (рис. 1.8) очень похожа на Arduino Mega 2560, но у Mega ADK есть дополнительная функциональность интерфейса USB, позволяющая ему соединяться с телефоном на базе Android.

Рис. 1.4. Плата Arduino Leonardo

Рис. 1.5. Плата Arduino Mega 2560

- 33 -

Рис. 1.6. Плата Arduino Due

Рис. 1.7 Плата Arduino Nano

- 34 -

Рис. 1.8. Плата Arduino Mega ADK

- 35 -

Уникальность платы Arduino LilyPad (рис. 1.9) в том, что она разработана как часть одежды. Ее можно вшить в ткань вместе с датчиками, светодиодами и т. п. Для программирования платы необходим кабель FTDI.

Рис. 1.9. Плата Arduino LilyPad

Как уже упоминалось во введении, Arduino - это открытая платформа. Поэтому в продаже можно найти десятки Arduino-совместимых устройств, которые будут работать с IDE Arduino и со всеми проектами, описанными в этой книге. Многие используют популярные платы Seeeduino, Adafruit 32U4, SparkFun Pro и миниплаты Arduino. Много сторонних плат разработано для конкретных приложений с дополнительной функциональностью, уже встроенной в плату. Например, ArduPilot - плата для автономного управления квадрокоптером (рис. 1.10).

Arduino-совместимые платы также применяются в качестве контроллера MakerBot и 3D-принтера.

Рис. 1.10. Квадрокоптер и контроллер ArduPilot Mega36

 

1.8. Запускаем первую программму

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

1.8.1. Загрузка и установка Arduino IDE

Зайдите на официальный сайт Arduino http://www.arduino.cc и загрузите последнюю версию Arduino IDE со страницы Download (рис. 1.11 ).

Download the Arduino Software

Рис. 1.11. Страница загрузки сайта Arduino.cc

После завершения загрузки разархивируйте загруженный файл. В папке вы найдете Arduino IDE. Новые версии IDE д л я Windows доступны в форме установщика, который инсталлирует программную среду Arduino автоматически.

- 37 -

1.8.2. Запуск IDE и подключение к Arduino

Подключите Arduino к компьютеру с помощью кабеля USB, как изображено на рис. 1.12. Компьютеры с операционной системой Mac и Linux установят драйверы автоматически.

Рис. 1.12. Соединение Arduino Uno с компьютером с помощью USB-кабеля

Если на вашем компьютере установлена операционная система OS Х, то при первом подключении появится сообщение о том, что было добавлено новое сетевое устройство. Нажмите кнопку Network Preferences (Системные настройки-> Сеть). В появившемся окне нажмите кнопку Apply (Подключить). Даже если будет выдано предупреждение Not Configured, устройство можно использовать. После этого выйдите из меню System Preferences (Системные настройки).

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

• дождитесь сообщения о неудачной попытке автоматической установки драйвера;

• нажмите кнопку Пуск и откройте Панель управления;

- 38 -

• перейдите на вкладку Система и безопасность (System and Security). Затем выберите раздел Система. Когда откроется окно Система, выберите опцию Диспетчер устройств (Device Manager);

• обратите внимание на порты (СОМ и LPT). Вы увидите открытый порт, в названии которого присутствует Arduino;

• щелкните правой кнопкой мыши и выберите опцию Обновить драйвер (Update Driver Software );

• щелкните мышью пункт Browse my computer for Driver software;

• для завершения установки найдите и выберите файл драйвера, расположенный в папке Drivers программного обеспечения для Arduino (но не в подкаталоге FTDI USB Drivers );

• в результате драйвер для Windows будет установлен.

Теперь запустите Arduino IDE. Все готово для загрузки первой программы на плату Arduino. Чтобы убедиться в этом, запустим программу Blink, которая будет мигать встроенным светодиодом. На большинстве плат Arduino есть светодиод, подключенный к цифровому контакту 13. Выполняем последовательность команд File -> Examples -> Basic и выбираем программу Blink. Откроется новое окно с кодом этой программы. Загрузим ее в плату Arduino в качестве примера, а затем проанализируем, чтобы понять, как писать собственные программы.

Прежде чем загружать программу в плату Arduino, необходимо указать тип платы и номер последовательного порта. Находим в меню опцию Tools -> Board (Сервис-> Плата) и выбираем из списка плату Arduino. В книге мы используем Arduino Uno, если у вас другая плата, выберите ее наименование.

Затем необходимо указать порт, к которому подсоединена плата. Переходим к опции Tools -> Serial Port (Сервис -> Последовательный порт) и выбираем последовательный порт. На компьютерах с Windows это будет СОМ*, где * - некоторое число, соответствующее номеру последовательного порта. На компьютерах с Linux и Мас порт обозначен как dev/tty.usbmodem* или /dev/tty.usbserial*, где* - строка алфавитно-цифровых символов.

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

Теперь можно загрузить первую программу. Нажимаем кнопку Upload (Загрузить), расположенную в левом верхнем углу Arduino IDE. В строке состояния, находящейся внизу, отображается процесс компиляции и загрузки программы. После загрузки программы светодиод, подключенный к выводу 13 Arduino, должен мигать оранжевым цветом с частотой один раз в секунду. Поздравляем! Ваша первая программа работает успешно.

- 39 -

1.8.3. Анализируем программу Blink

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

Рис. 1.13. Структура программы Blink

Цифрами на рис. 1.13 обозначено следующее:

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

2 - однострочный комментарий. Если поместить // на любую строку, компилятор проигнорирует весь текст строки после этого символа. Однострочный комментарий обычно поясняет определенную строку кода.

- 40 -

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

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

5 - цифровые контакты Arduino могут быть запрограммированы на ввод или вывод. Сконфигурировать их направление позволяет команда pinMode(), имеющая два параметра, указанных в круглых скобках. Первый параметр pinMode определяет номер контакта. Поскольку переменная led уже назначена ранее в программе, конфигурация задается для контакта 13. Второй параметр устанавливает направление контакта: INPUT (вход) или OUTPUT (выход). По умолчанию все контакты настроены на ввод. Чтобы сконфигурировать их на вывод, следует явно указать значение этого параметра OUTPUT. Поскольку нам нужно управлять светодиодом, контакт 13 должен быть выходом. Настройка конфигурации контакта сохраняется до тех пор, пока вы не измените его назначение на ввод.

6 - вторая обязательная функция во всех программах Arduino - loop(). Это оператор цикла.

7 - функция digitalWrite() устанавливает состояние выходного контакта: 5 или 0 В. Если светодиод подсоединен к контакту через резистор, то установка значения логической "1" позволит зажечь светодиод (вы узнаете больше об этом в следующей главе). Первый параметр функции digitalWrite() - номер контакта, которым требуется управлять. Второй параметр - значение, которое нужно задать: HIGH (5 В) или LOW (0 В). Контакт остается в этом состоянии, пока не будет изменен следующей командой digitalWrite().

8 - функция delay() имеет один аргумент - время задержки выполнения программы в миллисекундах. При вызове delay() Arduino останавливает выполнение программы на определенный интервал времени. В нашем примере задержка равна 1000 мс ( 1 с). Это приводит к свечению светодиода в течение одной секунды до выполнения следующей команды.

9- здесь вызвана функция digitalWrite(), чтобы выключить светодиод, устанавливая состояние контакта в LOW.

10 - снова делаем задержку на одну секунду, чтобы светодиод был погашен перед повторением цикла.

- 41 -

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

Резюме

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

• Из каких компонентов состоит плата Arduino.

• Как загрузчик Arduino позволяет запрограммировать плату Arduino через интерфейс USB.

• Каковы различия между основными платами Arduino.

• Как установить Arduino IDE и соединить плату Arduino с компьютером.

• Как загрузить и выполнить первую программу.

 

ГЛАВА 2 Цифровые контакты ввода-вывода шиотно-импульсная модуляция

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

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

• плата Arduino Uno;

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

• перемычки;

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

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

• кабель USB;

• кнопка;

• одноцветный светодиод 5 мм;

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

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

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

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

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

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

- 43 -

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

ПРИМЕЧАНИЕ

Видеоурок данной главы можно посмотреть на интернет-странице

http://www.jeremyblum.com/2011/01/10/arduino-tutorial-2-now-with-more-blinky-things/.

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

http://www.jeremyblum.com/2011 /01 /17 /electrical-engineering-basics-in-arduinotutorial-3/.

 

2.1. Цифровые контакты

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

• конфигурирование назначения цифровых выводов;

• подключение внешних компонентов;

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

• различие между цифровыми и аналоговыми выходами;

• широтно-импульсная модуляция (ШИМ).

 

2.2. Подключение внешнего светодиода

Мигающий светодиод из предыдущего примера был встроен в плату Arduino.

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

2.2.1. Работа с макетной платой

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

- 44 -

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

Шина питания Шина заземления (общая шина)

Шина питания Шина заземления (общая шина)

Область для установки элементов

Рис. 2.1. Электрические соединения макетной платы

 

2.3. Подсоединение светодиодов

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

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

- 45 -

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

Рис. 2.2. Подключение светодиода к плате Arduino Uno

 

2.3.1. Закон Ома и формула для расчета мощности

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

• напряжение представляет собой разность электрических потенциалов между двумя точками;

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

- 46 -

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

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

Закон Ома определяется следующим образом:

U = I·R, где U - напряжение в вольтах; I - ток в амперах; R - сопротивление в омах.

В электрической цепи каждый компонент обладает некоторым сопротивлением, что снижает напряжение. Закон Ома очень удобен для подбора значения резистора, подкточаемого последовательно со светодиодом. Светодиоды характеризуются определенной величиной падения напряжения и заданным значением рабочего тока. Чем больше ток через светодиод (не превышая максимально допустимого), тем ярче он светится. Для наиболее распространенных светодиодов максимальный ток равен 20 мА. Типовое значение падения напряжения для светодиода составляет около 2 в.

Рассмотрим схему, изображенную на рис. 2.3, и применим закон Ома для подбора резистора R1.

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

Предположим, что LED 1 - стандартный светодиод с прямым током 20 мА и падением напряжения 2 В. Напряжение питания 5 В должно перераспределиться между светодиодом и резистором. Поскольку доля светодиода составляет 2 В, оставшиеся 3 В должны быть приложены к резистору. Зная максимальное значение прямого тока через светодиод (20 мА), можно найти номинал резистора:

R = U/I= 3/0,02 = 150 Ом.

Таким образом, при сопротивлении резистора 150 Ом через него и светодиод протекает ток 20 мА. По мере увеличения сопротивления ток будет уменьшаться.

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

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

- 47 -

сеивания связано с ростом тепловыделения прибора. Для каждого компонента, как правило, задается максимально допустимая мощность. Максимальная мощность резистора в нашем примере равна 0,125 Вт. Формула для расчета мощности выглядит следующим образом:

Р = U·I, где Р - мощность, Вт; U- напряжение, В; I - сила тока, А.

Для резистора из схемы на рис. 2.3 при падении напряжения 3 В и силе тока 20 мА мощность равна

Р = 3·0,02 = 0,06 Вт.

Поскольку 60 мВт< 0,125 Вт = 125 мВт, следовательно, данный резистор не перегреется.

 

2.4. Программирование цифровых выводов

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

Каждая программа для Arduino должна включать две обязательные функции:

setup() И loop().

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

Для начала напишем простую программу, которая при запуске сконфигурирует контакт 9 как выход. В программе будут еще две функции: pinMode() - для конфигурации контакта и digitalWrite() - для установки значения HIGH (5 В) на этом контакте (листинг 2.1 ).

Листинг 2.1. Пример конфигурации

const int LED=9; // Константа - номер контакта светодиода

void setup()

{

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

digitalWrite(LED, HIGH); // Устанавливаем значение HIGH на выходе

}

void loop()

{

// В цикле ничего не выполняем

}

Соберите схему, как показано на рис. 2.2, и загрузите код листинга 2.1 в плату Arduino. Обратите внимание, что в этой программе я использовал оператор ини

- 48 -

циализации константы перед определением значения контакта Arduino. Обычно для хранения значений, которые могут изменяться во время выполнения программы, предназначены переменные. Поставив оператор const до объявления переменной, вы говорите компилятору, что это переменная "только для чтения" и она не будет изменяться во время выполнения программы. Всем экземплярам переменной LED в программе будет присвоено значение 9. В виде констант рекомендуется определять значения, которые не будут меняться при выполнении программы. Далее в некоторых примерах этой главы встретится иная ситуация: значения, которые могут изменяться при выполнении программы.

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

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

 

2.5. Использование цикла

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

Листинг 2.2. Изменение частоты мигания светодиода

const int LED=9; // Константа - номер контакта светодиода

void setup()

{

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

}

void loop()

{

for (int i=100; i<=1000; i=i+100)

{

digitalWrite(LED, HIGH);

delay(i);

digitalWrite(LED, LOW);

delay(i);

}

}

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

- 49 -

Оператор for всегда содержит три выражения, разделенные точкой с запятой:

• первое выражение присваивает начальное значение переменной-счетчику цикла.

В нашем примере переменная i получает начальное значение 100;

• второе выражение указывает, когда цикл должен остановиться. Операторы в теле цикла будут выполняться снова и снова, пока условие истинно. Запись <= означает меньше или равно. Таким образом, этот цикл будет выполняться тех пор, пока переменная i меньше или равна 1000;

• последнее выражение указывает, что должно произойти с переменной i каждый раз после выполнения операторов тела цикла. В нашем примере, значение счетчика цикла увеличивается на 100.

Чтобы лучше понять работу оператора for, подробно рассмотрим, что происходит за два прохода цикла:

1. Значение переменной i равно 100, 100 меньше или равно 1000, значит выполнять код в теле цикла.

2. На контакте 9 установлено значение HIGH, светодиод горит 100 мс (текущее значение i).

3. На контакт 9 подано значение LOW, светодиод потушен 100 мс (текущее значение i).

4. В конце цикла значение переменной i увеличивается на 100, теперь i равно 200.

5. 200 меньше или равно 1000, цикл повторяется снова.

6. На контакте 9 установлено значение HIGH, светодиод горит 200 мс (текущее значение i).

7. На контакт 9 подано значение LOW, светодиод потушен 200 мс (текущее значение i).

8. В конце цикла значение переменной i увеличивается на 100, теперь i равно 300.

9. Этот процесс повторяется, пока i не превосходит 1000 и затем i снова принимает значение 100 и все повторяется заново.

Итак, вы разобрались с работой цифровых контактов платы Arduino. Далее мы расскажем, как с помощью ШИМ сформировать аналоговые сигналы на цифровых контактах платы Arduino.

 

2.6. Широтно-импульсная модуляция с помощью analogWrite()

Вы освоили контроль над цифровыми контактами Arduino. Они очень удобны для переключения светодиодов, управления реле и двигателями постоянного тока. Но что делать, если необходимо вывести напряжение, отличное от 0 и 5 В. С помощью контактов одной только платы Arduino Uno это невозможно. Придется задействовать цифроаналоговый преобразователь или взять плату Arduino Due или добавить внешнюю микросхему ЦАП.

- 50 -

Тем не менее, можно сымитировать генерацию аналоговых значений на цифровых контактах с помощью широтно-импульсной модуляции (ШИМ). Для некоторых контактов Arduino сформировать ШИМ-сигнал можно командой analogWrite().

Контакты, которые могут выдавать ШИМ-сигнал на определенные периферийные устройства, помечены символом - на плате Arduino. На Arduino Uno контакты 3, 5, 6, 9, 10, 11 поддерживают выдачу ШИМ-сигнала. При наличии Arduino Uno проверить команду analogWrite() можно с помощью схемы, изображенной на рис. 2.1.

Если уменьшить напряжение на контакте 9 Arduino, яркость свечения светодиода должна стать меньше, потому что снизится ток, текущий через него. Этого эффекта можно добиться с помощью ШИМ и команды analogWrite().

Функция analogWrite() имеет два аргумента: номер контакта и 8-разрядное значение в диапазоне от 0 до 255, устанавливаемое на этом контакте.

В листинге 2.3 приведен код программы генерации ШИМ-сигнала на контакте 9 для плавного управления яркостью светодиода.

Листинг 2.3. Плавное изменение яркости светодиода — fade.ino

const int LED=9; // Константа номера контакта светодиода

void setup()

{

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

}

void loop()

{

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

{

analogWrite(LED, i);

delay (10);

}

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

{

analogWrite(LED, i);

delay(10);

}

}

Что будет происходить со светодиодом при выполнении листинга 2.3? Вы будете наблюдать, как свечение светодиода изменяется от тусклого к яркому в одном цикле for, а затем от яркого к тусклому в другом цикле for. Все это будет происходить в основном цикле loop() до бесконечности. Обязательно обратите внимание на различие двух циклов for. В первом цикле выражение i++ является сокращением кода i=i+1. Аналогично, запись i-- эквивалентна коду i=i-1. Первый цикл плавно зажигает светодиод до его максимальной яркости, второй - постепенно гасит его.

- 51 -

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

Чтобы понять все тонкости, разберемся, как на самом деле работает ШИМ. Рассмотрим графики, представленные на рис. 2.4.

ШИМ представляет собой изменение скважности ( отношения периода к длительности импульса) прямоугольной последовательности импульсов. Скважность можно трактовать как процент времени, когда прямоугольный импульс имеет уровень HIGH, ко всему периоду повторения. Скважность 50% означает, что половину периода сигнал имеет высокий уровень, а половину - низкий.

Рис. 2.4. ШИМ-сигналы с различной скважностью

Функция analogWrite() устанавливает скважность последовательности прямоугольных импульсов в зависимости от значения, передаваемого ей:

• значение аргумента analogWrite(), равное нулю, задает скважность 0% (всегда LOW);

• значение 255 -скважность 100% (всегда HIGH);

• значение 127 соответствует скважности 50% (половина времени HIGH, половина времени LOW).

На графиках рис. 2.4 видно, что для сигнала со скважностью 25% значение HIGH действует в течение четверти периода, а остальные 75% времени установлено значение LOW. Частота прямоугольной последовательности импульсов в случае

- 52 -

с Arduino составляет приблизительно 490 Гц. Другими словами, уровень сигнала меняется от высокого (5 В) к низкому (0 В) приблизительно 490 раз каждую секунду.

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

 

2.7. Считывание данных с цифровых контактов

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

2.7.1. Считывание цифровых входов со стягивающим резистором

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

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

Прежде чем написать программу опроса состояния кнопки, важно понять назначение резистора в этой схеме. Почти для всех цифровых входов необходим дополнительный стягивающий (pull-down) или подтягивающий (pull-up) резисторы для установки "значения по умолчанию" на входном контакте. Представьте себе, что в схеме на рис. 2.5 нет резистора 10 кОм. В этом случае при нажатии на кнопку на выводе будет значение HIGH. Но что происходит, когда кнопка не нажата? В такой ситуации входной контакт не привязан ни к чему, как говорят, "висит в воздухе".

А поскольку вывод физически не подключен ни к 0 В, ни к 5 В, чтение значения может дать неожиданный результат. Электрические помехи на близлежащих выводах могут привести к тому, что значение напряжения будет колебаться между HIGH и LOW. Чтобы предотвратить это, стягивающий резистор подключают так, как показано на рис. 2.5.

- 53 -

Рис. 2.5. Подключение кнопки и светодиода к плате Arduino

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

• через практически нулевое сопротивление нажатой кнопки к шине 5 В;

• через высокое сопротивление резистора на землю.

В соответствии с законом Ома ток всегда будет идти по пути наименьшего сопротивления. Большая часть тока будет протекать через замкнутую кнопку и на входе установится уровень HIGH.

ПРИМЕЧАНИЕ

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

- 54 -

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

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

Листинг 2.4. Включение светодиода с помощью кнопки — led_button.ino

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

const int BUTTON=2; // Контакт 2 для подключения кнопки

void setup()

{

pinMode (LED, OUTPUT); // Сконфигурировать контакт светодиода как выход

pinMode (BUTTON, INPUT); // Сконфигурировать контакт кнопки как вход

}

void loop()

{

if (digitalRead(BUTTON) == LOW)

{

digitalWrite(LED, LOW);

}

else

{

digitalWrite(LED, HIGH);

}

}

коде листинга 2.4 реализованы некоторые новые элементы: функция digitalRead() и оператор if/else. Константа BUTTON типа int добавлена для контакта кнопки. Кроме того, в функции setup() конфигурируем контакт BUTTON как вход.

Это необязательно, т. к. выводы Arduino являются входами по умолчанию. Функция digitalRead() считывает значение сигнала на входе. Если кнопка нажата, digitalRead() возвращает значение HIGH (лог. 1). Если кнопка не нажата, то получаем LOW (лог. 0).

Проверяем содержимое внутри оператора if(). Если условие внутри оператора if() истинно (кнопка не нажата, digitalRead() ==LOW), вызываем функцию digitalWrite (LED, LOW) (гасим светодиод). В противном случае (кнопка нажата) выполняем код после оператора else (включаем светодиод функцией digitalWrite(LED, HIGH)).

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

- 55 -

 

2.8. Устранение "дребезга" кнопок

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

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

Рис. 2.6. Эффект дребезга кнопок

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

1. Сохраняем предыдущее и текущее состояния кнопки (при инициализации LOW).

2. Считываем текущее состояние кнопки.

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

4. Подождав 5 мс, считываем состояние кнопки и делаем его текущим состоянием кнопки.

5. Если предыдущее состояние кнопки было LOW, а текущее - HIGH, переключаем состояние светодиода.

- 56 -

6. Устанавливаем предыдущее состояние кнопки в качестве текущего.

7. Возвращаемся к шагу 2.

Данный алгоритм - прекрасный пример для изучения функций. Функция - это оператор, который может принимать входные аргументы, выполнять фрагмент кода с их использованием и, возможно, возвращать результат. Не зная этого, вы уже встречали функции в программах. Например, digitalWrite() - это функция, которая принимает в качестве аргументов номер контакта и значение ( HIGH или LOW), и устанавливает это значение на контакте. Чтобы упростить программу, можно определить свои собственные функции для инкапсуляции действий, которые придется повторять неоднократно.

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

Листинг 2.5. Подавление дребезга кнопки — debounce.ino

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

const int BUTTON=2; // Контакт 2 для подключения кнопки

boolean lastButton = LOW;// Переменная для сохранения предыдущего

// состояния кнопки

boolean currentButton = LOW;// Переменная для сохранения текущего

// состояния кнопки

boolean ledOn = false;// Текущее состояние светодиода

//(включен/выключен)

void setup()

{

pinMode (LED, OUTPUT);// Сконфигурировать контакт светодиода как выход

pinMode (BUTTON, INPUT);//Сконфигурировать контакт кнопки как вход

}

/*

* Функция сглаживания дребезга

* принимает в качестве аргумента предыдущее состояние кнопки

* и выдает фактическое.

*/

boolean debounce(boolean last)

{

boolean current = digitalRead(BUTTON);// Считать состояние кнопки

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

{

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

current = digitalRead(BUTTON);// Считываем состояние кнопки

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

}

}

- 57 -

void loop()

{

currentButton = debounce(lastButton);

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

{

ledOn = !ledOn;// Инвертировать значение состояния светодиода

}

lastButton = currentButton;

digitalWrite(LED, ledOn);// Изменить статус состояния светодиода

}

Теперь рассмотрим текст листинга 2.5 подробнее. Сначала заданы номера контактов для подключения кнопки и светодиода. Затем объявлены три глобальные логические переменные, которые будут изменяться в программе (значение глобальной переменной можно менять в любой части программы). Каждой из трех переменных присвоены начальные значения (LOW, LOW и false). Далее в программе значения этих переменных могут изменяться с помощью оператора присваивания =.

Рассмотрим функцию подавления дребезга кнопки boolean debounce(). Эта функция принимает логическую переменную (имеющую только два состояния: true/false, HIGH/LOW, вкл./выкл., 1/0) предыдущего состояния кнопки и возвращает текущее значение состояния кнопки. Внутри функции текущее состояние кнопки сравнивается с предыдущим с помощью оператора != (не равно). Если состояния отличаются, то кнопка, возможно, нажата. Затем ожидаем 5 мс (этого достаточно, чтобы состояние кнопки стабилизировалось после дребезга), прежде чем проверить состояние кнопки снова. Затем вновь проверяем состояние кнопки. Как вы помните, функции могут возвращать результат. Данная функция возвращает текущее значение булевой локальной переменной, которая объявлена и используется только в функции debounce(). Когда функция debounce() вызывается из основного цикла, возвращенное значение записывается в глобальную переменную currentButton, которая была определена в начале программы.

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

Если ранее состояние кнопки было LOW, а теперь HIGH, значит, кнопка была нажата и нужно инвертировать значение переменной lecton. Это действие выполняет опера-

- 58 -

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

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

 

2.9. Создание управляемого ночника на RGB-светодиоде

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

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

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

Вы можете настроить циклическое переключение цветов светодиода при каждом нажатии на кнопку. В данном случае удобно добавить функцию для установки цвета светодиода в следующее состояние. В программе, представленной в листинге 2.6, определено семь цветов и состояние, когда светодиод не горит. С помощью функции analogWrite() можно задать свои цветовые комбинации. Единственное отличие цикла loop() от предыдущего примера - увеличение числа состояний светодиода (по кругу от 0 до 7).

Загрузите программу в плату и поэкспериментируйте с разноцветным ночником.

Поменяйте цвет RGB-светодиода, изменив значения в функции analogWrite() на свои собственные.

Листинг 2.6. Управляемый ночник на светодиоде - rgb_nightlight.ino

const int BLED=9; // Контакт 9 для вывода BLUE RGB-светодиода

const int GLED=10; // Контакт 10 для вывода GREEN RGB-светодиода

const int RLED=11; // Контакт 11 для вывода RED RGB-светодиода

const int BUTTON=2; // Контакт 2 для входа кнопки

boolean lastButton = LOW; // Предыдущий статус кнопки

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

int ledMode = 0; // Значение статуса RGB-светодиода

void setup()

{

pinMode (BLED, OUTPUT); // Сконфигурировать BLUE контакт светодиода как выход

- 59 -

pinMode (GLED, OUTPUT); // Сконфигурировать GREEN контакт светодиода как выход

pinMode (RLED, OUTPUT); // Сконфигурировать RED контакт светодиода как выход

pinMode (BUTTON, INPUT); // Сконфигурировать контакт кнопки как вход

}

/*

* Функция сглаживания дребезга

* принимает в качестве аргумента предыдущее состояние кнопки

* и выдает фактическое.

*/

boolean debounce(boolean last)

{

boolean current = digitalRead(BUTTON); // Считать состояние кнопки

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

{

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

current = digitalRead(BUTTON); // Считываем состояние кнопки

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

}

}

/*

* Выбор режима светодиода.

* Передача номера режима и установка заданного режима светодиода.

*/

void setMode(int mode)

{

// Красный

if (mode == 1)

{

digitalWrite(RLED, HIGH);

digitalWrite(GLED, LOW);

digitalWrite(BLED, LOW);

}

// Зеленый

else if (mode == 2)

{

digitalWrite(RLED, LOW);

digitalWrite(GLED, HIGH);

digitalWrite(BLED, LOW);

}

// Синий

else if (mode == 3)

{

digitalWrite(RLED, LOW);

- 60 -

digitalWrite(GLED, LOW);

digitalWrite(BLED, HIGH);

}

// Пурпурный (Красный+ Синий)

else if (mode == 4)

{

analogWrite(RLED, 127);

analogWrite(GLED, 0);

analogWrite(BLED, 127);

}

// Бирюзовый (Синий+ Зеленый)

else if (mode == 5)

{

analogWrite(RLED, 0);

analogWrite(GLED, 127);

analogWrite(BLED, 127);

}

// Оранжевый (Зеленый+ Красный)

else if (mode == 6)

{

analogWrite(RLED, 127);

analogWrite(GLED, 127);

analogWrite(BLED, 0);

}

// Белый (Зеленый+ Красный+ Синий)

else if (mode == 7)

{

analogWrite(RLED, 85);

analogWrite(GLED, 85);

analogWrite(BLED, 85);

}

// Выключен (mode = 0)

else

{

digitalWrite(RLED, LOW);

digitalWrite(GLED, LOW);

digitalWrite(BLED, LOW);

}

}

void loop()

{

currentButton = debounce(lastButton); // Чтение статуса кнопки

if (lastButton == LOW && currentButton == HIGH) // Если нажата кнопка

{

- 61 -

ledMode++; // Инкремент переменной статуса светодиода

lastButton = currentButton;

// Прошли по циклу все режимы

// свечения светодиода

// Сброс на начальный вариант =0

if (ledMode == 8)

ledMode = 0;

setMode(ledMode); // Изменить режим светодиода

}

}

Рис. 2.7. Монтажная схема ночника

Стягивающий резистор

- 62 -

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

Вы можете самостоятельно изменить этот проект. Например, добавить кнопки для управления каждым выводом RGB-светодиода. Или реализовать дополнительный режим мигания каждым цветом, взяв код из главы 1. Возможности для творчества безграничны.

Резюме

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

Как работать с макетной платой.

Как выбрать резистор для ограничения тока светодиода.

Как подключить внешний светодиод к плате Arduino.

Как использовать ШИМ, как замену аналогового вывода.

Как считывать состояние кнопки.

Как подавить дребезг кнопки.

Для чего нужны подтягивающий и стягивающий резисторы.

 

Глава 3 Опрос аналоговых датчиков

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

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

• плата Arduino Uno;

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

• перемычки;

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

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

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

• кабель USB;

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

• датчик температуры ТМР36 (или тобой другой аналоговый датчик на 5 В);

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

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

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

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

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

- 64 -

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

ПРИМЕЧАНИЕ

Видеоурок данной главы можно посмотреть на интернет-странице

http://www.jeremyblum.com/2011/01/24/arduino-tutorial-4-analog- inputs/.

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

http://www.jeremyblum.com/2010/06/20/lets-get-digital-or-analog/.

 

3.1. Понятие об аналоговых и цифровых сигналах

Данные об окружающем мире все устройства неизбежно получают в аналоговом виде. Вспомните ночник из предыдущей главы. Для: управления цифровым входом там была кнопка. Переключатель - это цифровое устройство, он имеет только два возможных состояния: включено или выключено, HIGH или LOW, 1 или 0, и т. д. Цифровая информация представляет собой серию бинарных (цифровых) данных. Каждый бит принимает только одно из двух возможных значений.

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

 

3.2. Сравнение аналоговых и цифровых сигналов

Графики на рис. 3.1 показывают, чем отличаются друг от друга аналоговые и цифровые сигналы. Слева прямоугольные импульсы, амплитуда которых принимает только два значения: 0 и 5 вольт. Точно так же, как с кнопкой из предыдущей главы: только HIGH или LOW. Справа изображен фрагмент косинусоидального сигнала.

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

- 65 -

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

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

Естественно, есть разумный диапазон, в пределах которого меняется освещенность (измеряется в люксах - световом потоке на единицу площади). Можно обосновано ожидать значение показаний между 0 люкс (для совершенно черного) и 130 000 люкс на прямом солнечном свете. Если бы измерительный прибор был абсолютно точен, то можно получить бесконечное число значений в данном диапазоне.

Рис. 3.1. Аналоговые и цифровые сигналы

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

 

3.3. Преобразование аналогового сигнала в цифровой

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

- 66 -

Точность АЦП зависит от его разрядности. На плате Arduino Uno установлен 10-разрядный АЦП. Это означает, что АЦП может разделить аналоговый сигнал на 210 различных значений. Следовательно, Arduino может присвоить 210 = 1024 аналоговых значений, от 0 до 1023.

Опорное напряжение определяет максимальное напряжение на входе АЦП, его значение соответствует коду 1023. При нулевом входном напряжении АЦП выдает на выходе 0, при входном напряжении 2,5 В на выходе будет значение 512 (половина от 1023), при входном напряжении 5 В выходной код равен 1023. Чтобы лучше понять это, посмотрите на графики для трех.разрядного АЦП, изображенные на рис. 3.2. В принципе, опорное напряжение АЦП можно изменить, но в наших устройствах опорным будет напряжение 5 В.

Рис. 3.2. Трехразрядное аналого-цифровое преобразование

У трех.разрядного АЦП 3 бита разрешения, поскольку 23 = 8, следовательно, у него есть 8 уровней, от 0 до 7. Любому аналоговому значению, которое поступает на вход такого АЦП, на выходе соответствует код от 0 до 7. На рис. 3.2 показано, что уровни входного напряжения преобразуются в выходные дискретные цифровые коды, с которыми может оперировать микроконтроллер. Чем выше разрядность, тем больше уровней, которые доступны для представления каждого значения. Как упоминалось, у Arduino Uno АЦП имеет 1024 уровней, а не 8, как на рис. 3.2.

ПРИМЕЧАНИЕ

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

http://www.arduino.cc/en/Reference/AnalogReference.

- 67 -

 

3.4. Считывание аналоговых датчиков с помощью Arduino. Команда analogRead()

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

Мы начнем с простых экспериментов с потенциометром и аналоговым датчиком.

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

 

3.5. Чтение данных с потенциометра

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

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

ПРИМЕЧАНИЕ

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

Прежде чем использовать потенциометр для управления другим оборудованием, посмотрим, как считать значение сопротивления потенциометра с помощью АЦП и передать через последовательный порт Arduino для просмотра значений на компьютере. Для чтения значения аналогового входа предусмотрена функция analogRead(), для вывода значений в последовательный порт Arduino IDE - функция serial.pritln(). Наберите и загрузите в плату Arduino программу из листинга 3.1.68

Рис. 3.3. Подключение потенциометра

Рис. 3.4. Измерение напряжения с помощью мультиметра

- 69 -

Листинг 3.1. Программа чтения данных потенциометра - pot.ino

// Программа чтения данных с потенциометра

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

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

void setup()

{

Serial.begin(9600);

}

void loop()

{

val = analogRead(POT);

Serial.println(val);

delay(500);

}

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

В каждой итерации цикла переменная val получает аналоговое значение, считанное командой analogRead() с входа, соединенного со средним контактом потенциометра (в нашем случае это вход A0). Далее это значение функция serial.println() выводит в последовательный порт, соединенный с компьютером. Затем следует задержка в полсекунды (чтобы числа выводились не быстрее, чем вы можете их прочитать).

После загрузки на плату Arduino вы заметите, что светодиод тх, расположенный на плате, мигает каждые 500 мс (по крайней мере, так должно быть). Этот индикатор показывает, что плата Arduino передает данные через последовательный USB-интерфейс на компьютер. Для просмотра данных подойдут любые терминальные программы, но в Arduino IDE есть встроенный монитор последовательного порта, для запуска которого нажмите кнопку, обведенную кружком на рис. 3.5.

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

Пример отображения данных показан на рис. 3.6.

Рис. 3.5. Кнопка запуска монитора последовательного порта

Рис. 3.6. Вывод данных в последовательный порт

- 71 -

ПРИМЕЧАНИЕ

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

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

 

3.6. Использование аналоговых датчиков

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

• акселерометры для обнаружения наклона (применяются в смартфонах и планшетах);

• магнитометры для фиксации магнитных полей (необходимы при создании цифровых компасов);

• инфракрасные датчики для определения расстояния до объекта;

• датчики для измерения температуры.

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

• Инфракрасный датчик расстояния Sharp. (Описание датчика приведено на странице http://www.exploringarduino.com/parts/lR-Distance-Sensor, разъем для подключения - http://www.exploringarduino.com/parts/JST-Wire.)

Инфракрасные датчики Sharp измеряют расстояние от датчика до объекта. По мере удаления объекта напряжение на выходе датчика уменьшается. Рисунок на странице 5 технического описания датчиков Sharp ( скачать можно по адресу

http://exploringarduino.com/wp-content/uploads/2013/06/GP2YOA-datasheet.pdt)

показывает связь между выходным напряжением и расстоянием до объекта.

• Датчик температуры ТМР36. (Описание приведено на странице http://www.exploringarduino.com/parts/TMP36.)

Датчик температуры ТМР36 позволяет легко преобразовать выходной уровень напряжения в показания температуры в градусах Цельсия. Каждые 10 мВ выходного напряжения соответствуют 1°С. Формула для преобразования выходного напряжения (в мВ) в температуру (в °С) выглядит так: Т= (Uвых - 500)/10.

Смещение 500 мВ необходимо для работы с температурами ниже 0°С. Эта зависимость приведена на рис. 3. 7.

- 72 -

Рис. 3.7. Зависимость выходного напряжения от температуры для различных датчиков

• Трехосевой аналоговый акселерометр. (Описание приведено на странице

http://www.exploringarduino.com/parts/TriAxis-Analog-Accelerometer.)

Трехосевые акселерометры предназначены для определения ориентации объекта. Аналоговые акселерометры выдают значения, соответствующие смещению объекта по каждой оси: Х, У и Z (для каждой оси разном контакте). С помощью тригонометрических преобразований и закона всемирного тяготения можно определить позицию объекта в трехмерном пространстве. Напряжение питания многих акселерометров равно 3,3 В, поэтому для получения правильных значений в программе нужно предусмотреть установку опорного напряжения analogReference(), а вывод питания акселерометра подсоединить к контакту 3,3 В платы Arduino.

• Двухосевой аналоговый гироскоп. (Описание датчика приведено на странице

http://www.exploringarduino.com/parts/DualAxis-Analog-Gyroscope.)

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

Посмотрите пример взаимодействия гироскопа с платой Arduino в моем проекте SudoGlove (http://www.jeremyblum.com/portfolio/sudoglove-hardware-controller/).

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

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

- 73 -

 

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

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

Для начала подсоедините к плате Arduino Uno RGB-светодиод, как в главе 2, и датчик температуры к выходу A0 (рис. 3.8).

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

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

- 74 -

Прежде всего, определите приемлемый для вас температурный диапазон. Используя программу из листинга 3.1, определите аналоговые значения для верхнего и нижнего порогов температуры. Для меня нижний порог комфортной температуры составляет 20°С, что соответствует аналоговому значению 143. У вас эта цифра может быть другой. Следите за показаниями в мониторе последовательного порта при наступлении нижнего и верхнего предела температуры. Эти значения можно получить из графика на рис. 3.7 или из формулы, связывающей температуру (в °С) с входным напряжением (в мВ):

Температура (°С)х10 = Напряжение (мВ)- 500.

Напряжение 700 мВ соответствует температуре 20°С. Расчет по формуле (или просто анализ показаний монитора последовательного порта) дает для 22°С цифровое значение 147, для 18°С- 139. Эти величины выберем для нижнего и верхнего значений комфортной температуры, чтобы изменять цвет светодиода. Функция analogRead() будет считывать показания датчика температуры, digitalWrite() устанавливать цвет светодиода.

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

Листинг 3.2. Программа температурного оповещателя - tempalert.ino

// Температурный оповещатель

// Контакт

const int BLED=9; // Контакт 9 для вывода BLUE RGB-светодиода

const int GLED=10; // Контакт 9 для вывода GREEN RGB-светодиода

const int RLED=11; // Контакт 9 для вывода RED RGB-светодиода

const int TEMP=0; // A0 для подключения датчика температуры

const int LOWER_BOUND=139; // Нижний порог

const int UPPER_BOUND=147; // Верхний порог

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

void setup()

{

pinMode(BLED, OUTPUT); // Сконфигурировать BLUE контакт светодиода как выход

pinMode(GLED, OUTPUT); // - - GREEN - -

pinMode(RLED, OUTPUT); // - - RED - -

}

void loop()

{

val = analogRead(TEMP);

- 75 -

if (val < LOWER_BOUND)

{

digitalWrite(RLED, LOW);

digitalWrite(GLED, LOW);

digitalWrite(BLED, HIGH);

}

else if (val > UPPER_BOUND)

{

digitalWrite(RLED, HIGH);

digitalWrite(GLED, LOW);

digitalWrite(BLED, LOW);

}

else

{

digitalWrite(RLED, LOW);

digitalWrite(GLED, HIGH);

digitalWrite(BLED, LOW);

}

}

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

 

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

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

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

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

 

3.9. Резистивный делитель напряжения

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

- 76 -

Рассмотрим нерегулируемый резистивный делитель (рис. 3.9) и напряжение на его выходе. Обозначение A0 на рис. 3.9- это аналоговый вход A0 на плате Arduino.

Зависимость выходного напряжения делителя от входного:

Uвых = Uвх (R2/(R1 + R2)).

В нашем случае на вход делителя подано напряжение 5 В, а выход подключен к аналоговому контакту A0 платы Arduino. Если R1 и R2 одинаковы (как, например, 10 кОм), то 5 В делится пополам, и на аналоговом входе будет 2,5 В. Проверьте это, подставив значения в формулу:

Uвых = 5 В (10 кОм/(10 кОм+ 10 кОм))= 2,5 В.

Рис. 3.9. Простой делитель напряжения

Рис. 3.10. Фоторезистор

Теперь предположим, что один из этих резисторов переменный, например фоторезистор (рис. 3.1 0). Сопротивление фоторезистора зависит от интенсивности падающего на него света. Я использовал фоторезистор с номинальным сопротивлением 200 кОм. В полной темноте его сопротивление около 200 кОм, при ярком свете оно падает почти до нуля. От того, какой резистор (R1 или R2) поменять на фоторезистор, и от номинала постоянного резистора будет зависеть масштаб и точность показаний. Попробуйте поэкспериментировать с различными конфигурациями и посмотрите через монитор последовательного порта, как меняются показания.

В качестве примера заменим R1 на фоторезистор, а R2 возьмем постоянным с номиналом 10 кОм (рис. 3.11 ). Для данного упражнения можно оставить на плате RGB-светодиод и подключить его как одноцветный.

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

- 77 -

ли значения 200 (темнота) и 900 (максимальное освещение). У вас могут быть другие цифры. Они зависят от условий освещения, значения резистора R2 и характеристик фоторезистора.

Рис. 3.11. Подключение фоторезистора

 

3.10. Управление аналоговыми выходами по сигналу от аналоговых входов

Напомним, что функция analogWrite() позволяет изменять яркость светодиода. Но не забывайте, аргумент этой функции 8-разрядный, т. е. находится в диапазоне от 0 до 255, в то время как АЦП выдает значения от 0 до 1023. В языке программирова

- 78 -

ния Arduino есть удобные функции для пропорционального преобразования значений от одного диапазона к другому: map() и constrain(). Синтаксис функции map() выглядит следующим образом:

output = map(value, fromLow, fromHigh, toLow, toHigh).

Здесь value - преобразуемое значение (напряжение на аналоговом входе). fromLow и fromHigh - это нижняя и верхняя границы текущего диапазона. В нашем примере это минимальная и максимальная освещенность в помещении (200 и 900). toLow и toHigh - нижняя и верхняя границы нового диапазона. Аргумент функции analogWrite() должен быть в диапазоне от 0 до 255. Но мы хотим меньшей освещенности сопоставить большую яркость светодиода, т. е. минимальным значениям на аналоговом входе должны соответствовать максимальные значения на выводах светодиода. У доб но, что функция map() делает это автоматически. Функция map() осуществляет линейное отображение. Например, если fromLow и fromHigh равны 200 и 900, соответственно, а toLow и toHigh равны 255 и 0, то 550 превратится в 127, потому что 550 находится посередине между 200 и 900, а 127 посередине между 255 и 0. Следует учесть, что функция map() не ограничивает значения, если они выходят за границы диапазона. Если value окажется меньше 200 (для нашего примера), то output будет больше 255. Это неудобно, т. к. передать функции analogWrite() значение, превышающее 255, нельзя. Для ограничения значений есть Функция constrain(), синтаксис которой выглядит следующим образом:

output = constrain(value, min, max).

При передаче значения из функции map() в функцию constrain() можно установить аргумент min равным 0 и max - 255, тогда величины, выходящие за рамки этого диапазона, будут ограничены. Теперь все готово, чтобы написать программу управляемого ночника. Посмотрим, как будет выглядеть окончательно наш проект (листинг 3.3).

Листинг 3.3. Программа управляемого ночника - nightlight.ino

// Автоматический ночник

const int RLED=9; // Контакт 9 для ШИМ-вывода RED RGB-светодиода

const int LIGHT=0; // Контакт A0 для входа фоторезистора

const int MIN_LIGHT=200; // Нижний порог освещенности

const int MAX_LIGHT=900; // Верхний порог освещенности

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

void setup()

{

pinMode(RLED, OUTPUT); // Сконфигурировать RED-контакт светодиода как выход

}

- 79 -

void loop()

{

val = analogRead(LIGHT); // Чтение показаний фоторезистора

val = map(val, MIN_LIGHT, MAX_LIGHT, 255, 0); // вызов функции map()

val = constrain(val, 0, 255); // ограничение границ

analogWrite(RLED, val); // управление светодиодом

}

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

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

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

Резюме

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

• Чем отличаются аналоговые сигналы от цифровых.

• Как преобразовать аналоговые сигналы в цифровые.

• Как считать аналоговый сигнал с потенциометра.

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

• Как взаимодействовать через интерфейс с аналоговыми датчиками.

• Как создать собственные аналоговые датчики.

• Как ограничить значения для управления аналоговыми выходами.