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

Блум Джереми

Часть III. Интерфейсы передачи данных

 

В этой части

Глава 8. Интерфейсная шина I2C

Глава 9. Интерфейсная шина SPI

Глава 10. Взаимодействие с жидкокристаллическими дисплеями

Глава 11. Беспроводная связь с помощью радиомодулей ХВее

 

Глава 8. Интерфейсная шина I

2

C

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

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

плата Arduino Uno;

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

1 красный светодиод;

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

4 зеленых светодиода;

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

2 резистора номиналом 4,7 кОм;

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

I2C датчик температуры TC74A0-5.0VAT;

перемычки;

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

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

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

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

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

- 170 -

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

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

ПРИМЕЧАНИЕ

Вы можете шаг за шагом пройти данную главу, воспользовавшись демонстрационным видеоуроком, расположенным по адресу http://www.jeremyblum.com/2011/02/13/arduino-tutorial-7-I2C-and-processing/. Этот видеоклип доступен и на сайте издательства Wiley.

 

8.1. История создания протокола I

2

C

Чтобы уяснить, почему популярен тот или иной протокол связи, лучше всего посмотреть, как он развивался с течением времени. Протокол I2C был предложен фирмой Philips в начале 1980-х годов для обеспечения низкоскоростной связи между различными интегральными микросхемами. В 1990 году этот протокол был стандартизирован и другие компании начали его использовать, выпуская свои собственные совместимые чипы. Протокол часто называют "двухпроводным", поскольку связь осуществляется по двум шинам: линии синхронизации и линии передачи данных. Хотя не все двухпроводные протоколы, строго говоря, могут называться I2C (из-за неоплаты права на использование названия), но, как правило, их называют I2C-устройствами. Так же марку KLEENEX® часто ставят даже на тех тканях, которые не производит эта фирма. Если в описании какого-то устройства сказано, что оно поддерживает "двухпроводной" протокол связи, можно быть уверенным, что оно будет работать так, как описано в этой главе.

 

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

2

C

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

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

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

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

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

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

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

- 172 -

рим датчик температуры ТС74. Из рис. 8.2 видно, что этот датчик может иметь несколько разных адресов. В примерах данной главы у датчика TC74A0-5.0VAT (исполнение ТО-220) I2C-адрес задан как 1001000.

Рис. 8.2. Фрагмент технического описания датчика ТС74. расшифровка обозначения и варианты адресов I2C

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

В датчиках другого типа, например, AD7414 и AD7415 есть контакт (AS), который позволяет настроить адрес устройства I2C. Взгляните на данные датчика AD7414 из документации (рис. 8.3).

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

Table 4. 1 1 С Address Selection

Рис. 8.3. Фрагмент технического описания датчика AD7414. цоколевка и варианты адресов I2C

- 173 -

8.2.2. Требования к оборудованию и подтягивающие резисторы

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

 

8.3. Связь с датчиком температуры I2C

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

Основные шаги для управления любым I2C-устройством таковы:

• Мастер посылает стартовый бит.

• Мастер посылает 7-разрядный адрес ведомого устройства.

• Мастер устанавливает на шине данных "1" (чтение) или "0" (запись) в зависимости от того, хочет ли он отправить данные в ведомое устройство или получить данные от него.

• Ведомое устройство выставляет бит АСК (логический уровень низкий).

• В режиме записи, мастер передает один байт информации, ведомое устройство выдает бит АСК. В режиме чтения, мастер получает один байт и посылает бит АСК в ведомое после каждого байта.

• Когда связь завершена, мастер посылает стоп-бит.

8.3.1. Сборка схемы устройства

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

Обратите внимание, что выводы SDA и SCL датчика подключены к контактам А4 и

AS платы. Напомним, что SDA и SCL - это линия передачи данных и линия синхронизации, соответственно. Контакты Arduino А4 и AS мультиплексируются между аналого-цифровым преобразователем (АЦП) и аппаратным интерфейсом I2C.

При инициализации библиотеки Wire эти контакты подключены к контроллеру I2C

в ATmega, обеспечивая взаимодействие объекта Wire с I2C-устройствами. При этом

- 174 -

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

8.3.2. Анализ технического описания датчика

Теперь нужно написать программу, которая определяет действия Arduino для получения данных от I 2 С-датчика температуры. С помощью библиотеки Wire сделать это довольно легко. Чтобы не допустить ошибки, следует внимательно прочесть справочную информацию об алгоритме связи, который поддерживает именно этот чип. Давайте проанализируем протокол взаимодействия, представленный в таблицах и на графиках, показанных на рис. 8.5 и 8.6.

На рис. 8.6 показано, как осуществлять чтение и запись данных для датчика ТС74.

Микросхема имеет два регистра: в первом хранится значение текущей температуры

- 175 -

рис. 8.5. Протокол обмена датчика ТС74

в градусах Цельсия, во втором - информация о конфигурации чипа (включая режим ожидания и режим передачи данных). Это ясно из табл. 4.1 на рис. 8.6. Нет необходимости вникать в юоансы конфигурации, требуется только получить значение температуры от устройства. В табл. 4.3 и 4.4 на рис. 8.6 показано, как хранится информация о температуре внутри 8-разрядного регистра.

В секции Write Byte fonnat на рис. 8.5 показано, как прочитать значение температуры из ТС74:

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

• отправить на адрес устройства команду запроса (1 байт) на чтение информации от устройства;

• подождать прихода всех 8 битов информации о значении температуры.

Теперь становится понятно, как работать с подобными I2C-устройствами. Если вы еще не все уяснили, поищите в Интернете примеры программ подключения Arduino

- 176 -

Рис. 8.6. Страница из технического описания датчика ТС742

- 177 -

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

8.3.3. Написание программы

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

Листинг 8.1. Чтение данных с I 2 C-датчика температуры - read_temp.ino

// Чтение температуры из I2C-датчика

// и вывод значений в последовательный порт

// Подключение библиотеки Wire

#include

int temp_address=72; // Запись адреса 1001000

void setup()

{

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

Serial.begin(9600);

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

Wire.begin();

}

void loop()

{

// Отправка запроса

// Выбор устройства отправкой адреса устройства

Wire.beginTransmission(temp_address);

// Установка бита asking в 0 для чтения

Wire.write(0);

// Отправка стоп-бита

Wire.endTransmission();

// Чтение температуры из устройства

// Получить 1 байт по адресу устройства

Wire.requestFrom(temp_address, 1);

// Ожидание ответа

while(Wire.available() == 0);

// Чтение данных в переменную

int с = Wire.read();

// Перевод данных из шкалы Цельсия в шкалу Фаренгейта

int f = round(c*9.0/5.0 +32.0);

- 178 -

// Отправка значения в градусах Цельсия и Фаренгейта

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

Serial.print(c);

Serial.print("C ");

Serial.print(f);

Serial.println("F");

delay(500);

}

Рассмотрим программу подробнее. Команда Wire.beginTransmission() начинает общение с ведомым устройством, отправляя адрес (уникальный идентификатор) устройства. Команда wire.write(0) отправляет "0", указывая, что вы хотите читать из регистра температуры. Затем передаем стоп-бит, вызывая функцию Wire.endTransmission(), чтобы указать окончание записи на устройство. Далее мастер получает информацию от ведомого устройства I2C. Команда Wire.requestFrom() мастер запрашивает получение одного байта данных из I2C-устройства. Команда Wire.available() будет блокировать выполнение остальной части кода, пока данные не станут доступны на линии I2C. Наконец, 8-разрядное значение считывается в переменную командой Wire.read().

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

Теперь запустите код листинга 8.1 на плате Arduino и откройте монитор последовательного порта. Вы должны увидеть вывод данных в последовательный порт, который выглядит примерно так, как на рис. 8.7.

Рис. 8.7. Отправка данных из I2C-датчика температуры в последовательный порт

- 179 -

 

8.4. Проект, объединяющий регистр сдвига, последовательный порт и шину I

2

C

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

8.4.1. Создание системы мониторинга температуры

Сначала соберем схему устройства (рис. 8.8). По существу нужно лишь добавить сдвиговый регистр к схеме, изображенной на рис. 8.4.

Рис. 8.8. I2C-датчик температуры с гистограммным индикатором на основе сдвигового регистра

- 180 -

8.4.2. Модификация кода программы

Чтобы упростить последовательную связь с Processing-приложением и реализовать функциональность сдвигового регистра, в листинг 8.1 нужно внести два изменения.

Во-первых, измените операторы вывода данных в последовательный порт следующим образом:

Serial.print(c);

Serial.print("C,");

Serial.print(f);

Serial.print("F.");

Программа на Processing должна выдавать температуру в градусах Цельсия и Фаренгейта. Заменяя пробелы и символы возврата каретки запятыми и точками, можно отображать данные в виде, удобном для анализа.

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

Я выбрал диапазон от 24 до 31°С (75-88 F), но вы можете задать любой другой.

Листинг 8.2 содержит полный текст программы.

Листинг 8.2. Чтение данных с I 2 C-датчика температуры с отображением на светодиодной гистограмме и отправкой в последователный порт -

// Чтение температуры из I2C-датчика температуры,

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

// в Processing-приложение

// Подключение библиотеки Wire

#include

// Контакт для подключения вывода DATA

const int SER =8;

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

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

int temp_address = 72;

// Задание значений светодиодов

int vals[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {1,3,7,15,31,63,127,255};

void setup()

{

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

Serial.begin(9600);

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

Wire.begin();

- 181 -

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

pinMode(SER, OUTPUT);

pinMode(LATCH, OUTPUT);

pinMode(CLK, OUTPUT);

}

void loop()

{

// Отправка запроса

// Выбор устройства отправкой адреса устройства

Wire.beginTransmission(temp_address);

// Установка бита asking в 0 для чтения

Wire.write(0);

// Отправка стоп-бита

Wire.endTransmission();

// Чтение температуры из устройства

// Получить 1 байт по адресу устройства

Wire.requestFrom(temp_address, 1);

// Ожидание ответа

while(Wire.available() == 0);

// Присваивание полученного значения переменной

int с = Wire.read();

// Масштабирование температуры для светодиодной гистограммы

int graph = map(c, 24, 31, 0, 7);

graph = constrain(graph,0,7);

digitaJWrite(LATCH, LOW);

// LATCH - низкий - начало отправки

shiftOut(SER, CLK, MSBFIRST, vals[graph]); // Отправка, старший

// бит - первый

digitalWrite(LATCH, HIGH);

// LATCH - высокий, окончание отправки

// Перевод данных из шкалы Цельсия в шкалу Фаренгейта

int f = round(c*9,0/5,0 +32,0);

// Отправка значения в градусах Цельсия и Фаренгейта

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

Serial.print(c);

Serial.print("C,");

Serial.print(f);

Serial.print("F.");

delay(500);

}

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

- 182 -

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

8.4.3. Написание программы на Processing

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

Так как обновлять текст нужно в режиме реального времени, необходимо сначала узнать, как загрузить шрифты в программу на Processing. Откройте Processing приложение и создайте новый пустой проект. Сохраните файл, прежде чем продолжить. Затем через контекстное меню Tools -> Create Font вызовите окно, которое изображено на рис. 8.9.

Рис. 8.9. Загрузка шрифтов в Processing-приложение

Выберите свой любимый шрифт и размер (для этой программы я рекомендую размер около 200). После этого нажмите кнопку ОК. Шрифт будет автоматически установлен в папку data данного проекта.

Программа на Processing должна выполнить следующее:

• Сгенерировать графическое окно на компьютере для отображения данных температуры в градусах Цельсия и Фаренгейта.2

- 183 -

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

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

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

Листинг 8.3. Программа на Processing для отображения данных температуры - display_temp.pde

// Отображение температуры, получаемой с I2C-датчика

import processing.serial.*;

Serial port;

String temp_c = "";

String temp_f = "";

String data = "";

int index = 0;

PFont font;

void setup()

{

size(400,400);

// Измените "СОМ9" на имя вашего последовательного порта

port = new Serial(this, "СОМ9", 9600);

port.bufferUntil('.');

// Измените имя шрифта, выбранное вами

font = loadFont("AgencyFB-Bold-200.vlw");

textFont(font, 200);

}

void draw()

{

background(0,0,0);

fill(46, 209, 2);

text(temp_c, 70, 175);

fill(0, 102, 153);

text(temp_f, 70, 370);

}

void serialEvent (Serial port)

{

data = port.readStringUntil('.');

data = data.substring(0, data.length() - 1);

// Ищем запятую - разделитель данных по Цельсию и Фаренгейту

index = data.indexOf(",");

- 184 -

// Получить температуру в градусах Цельсия

temp_c = data.substring(0, index);

// Получить температуру по Фаренгейту

temp_f = data.substring(index+1, data.length());

}

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

Функция draw() заполняет фон окна черным цветом и выводит значения температуры по Цельсию и по Фаренгейту двумя цветами. С помощью команды fill() вы сообщаете Processing о цвете (в значениях RGB) следующего элемента, который будет добавлен на экран. Функция serialEvent() вызывается при наступлении события bufferuntil(), она считывает содержимое буфера в строку, а затем разбивает его, учитывая расположение запятой. Два значения температуры хранятся в переменных, которые затем выводятся в окно приложения.

Результат выполнения программы показан на рис. 8.10.

Рис. 8.10. Отображение температуры на Processing

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

ПРИМЕЧАНИЕ

Для просмотра демонстрационного видеофильма системы мониторинга температуры посетите страницу http:/lwww.exploringarduino.com/content/ch8. Этот видеофильм доступен также на сайте издательства Wiley.

- 185 -

Резюме

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

• Как организовать связь платы Arduino с несколькими I2C ведомыми 2 устройствами (если они имеют разные адреса) по двухпроводному протоколу I c.

• Как библиотека Wire облегчает связь с I2C-устройствами, подключенными к выводам А4 и А5 платы.

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

• Как генерировать шрифты для динамически обновляемых текстов в программе на Processing.

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

 

Глава 9. Интерфейсная шина SPI

Интерфейсная

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

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

• плата Arduino Uno;

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

• 1 красный светодиод;

• 1 желтый светодиод;

• 1 зеленый светодиод;

• 1 синий светодиод;

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

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

• динамик;

• цифровой SPI потенциометр МСР4231;

• перемычки;

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

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

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

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

Вы уже знакомы с двумя интерфейсами связи, используемыми платой Arduino: шиной I2C и последовательной шиной UART. В этой главе вы узнаете о третьем интерфейсе цифровой связи, поддерживаемом аппаратными средствами Arduino, о последовательной шине периферийного интерфейса (или SPI).

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

- 187 -

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

ПРИМЕЧАНИЕ

Вы можете шаг за шагом посмотреть демонстрационный видеоурок к главе, расположенный по адресу http://www.jeremyblum.com/2011/02/2011/02/20/ardulno-tutorial-8-spl-lnterfaces. Этот видеоурок также доступен на сайте издательства Wiley.

 

9.1. Общие сведения о протоколе SPI

Интерфейс SPI, разработанный компанией "Моторола", представляет собой полнодуплексный последовательный стандарт связи, который поддерживает одновременный двунаправленный обмен данными между ведущим устройством (мастером)

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

ВНИМАНИЕ!

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

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

В итоге получается, что обмен SPI в общей сложности можно настроить четырьмя способами (табл. 9.1).

Таблица 9.1. Режимы SP/ в Arduino IDE

No Режим SPI Полярность синхронизации Фаза синхронизации
1 Mode O LOW По фронту синхросигнала
2 Mode 1 LOW По спаду синхросигнала

- 188 -

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

No Режим SPI Полярность синхронизации Фаза синхронизации
3 Mode 2 HIGH По спаду синхросигнала
4 Mode 3 HIGH По фронту синхросигнала

 

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

Систему обмена данными через SPI несложно настроить. Для связи между мастером и всеми подчиненными устройствами используется три вывода:

• последовательный сигнал синхронизации (SCLK);

• выход ведущего, вход ведомого (MOSI);

• вход ведущего, выход ведомого (MISO).

У каждого ведомого устройства также есть контакт выбора данного устройства (контакт SS). Следовательно, общее число портов ввода-вывода, необходимых на мастер-устройстве, всегда будет 3+n, где n - число ведомых устройств. Пример SPI-системы с двумя ведомыми устройствами изображен на рис. 9.1.

Рис. 9.1. Пример конфигурации SPI-устройств

- 189 -

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

Любой интерфейс SPI содержит, как минимум, четыре линии передачи данных. Для каждого ведомого устройства добавляются дополнительные линии SS. Прежде чем отправлять или получать данные через SPI, нужно выяснить, что делают эти линии ввода-вывода и как они должны быть подключены (табл. 9.2).

Таблица 9.2. Описание линий ввода-вывода интерфейса SPI

Линии SPI Описание
MOSI Линия для отправки последовательных данных от ведущего устройства к ведомому
MISO Линия для отправки последовательных данных от ведомого устройства к ведущему
SCLK Линия синхронизации последовательных данных
SS Линия выбора ведомого устройства, активный уровень - низкий

В отличие от интерфейса I2C, подтягивающие резисторы здесь не требуются, и протокол полностью двунаправленный. Итак, чтобы подключить устройство SPI к плате Arduino, необходимо соединить его с контактами MOSI, MISO, SCLK и SS.

После этого все готово к использованию Arduino библиотеки SPI.

Так как SPI не является универсальным стандартом, некоторые производители устройств SPI могут по-разному называть линии связи SPI. Линию выбора ведомого иногда называют CS, линию синхронизации - CLK; контакты MOSI и MISO ведомых устройств называют входом последовательных данных (SDI) и выходом последовательных данных (SDO) соответственно.

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

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

Последовательность действий для связи с устройством SPI выглядит следующим образом:

1. У становить низкий уровень на линии SS устройства, с которым хотите установить связь.

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

3. На каждом такте отправлять 1 бит данных по линии MOSI или получать 1 бит данных по линии MISO.

- 190 -

4. Продолжать, пока передача (или прием) не закончится, и остановить переключения тактовой линии.

5. Установить на SS высокий уровень.

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

 

9.3. Сравнение SPI и I

2

C

Многие виды устройств, в том числе акселерометры, цифровые потенциометры, дисплеи и т. п., доступны и в SPI- и в I2C-версиях. Что лучше выбрать? В табл. 9.3

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

Таблица 9.3. Сравнение протоколов SPI и I2C

Преимущества SPI Преимущества I 2 C
Может работать на более высокой скорости Для организации обмена требуется только две линии
Легче программируется Имеет аппаратную поддержку Arduino
Не требует подтягивающих резисторов
Имеет аппаратную поддержку Arduino

 

9.4. Подключение цифрового потенциометра SPI

Теперь пора применить полученные знания на практике. Рассмотрим устройство управления яркостью светодиодов с помощью цифрового потенциометра ( кратко называемого digipot). В данном примере используем микросхему SPI цифрового потенциометра МСР4231 10ЗЕ. Доступно несколько вариантов данного чипа с различным значением сопротивления. Как и обычный потенциометр, цифровой имеет регулируемый вывод, который определяет сопротивление между двумя выводами микросхемы. Микросхема МСР4231 содержит два потенциометра на одном корпусе. Разрядность каждого из них составляет 7 бит, что определяет 128 значений в диапазоне от 0 до 10 кОм. Сначала с помощью цифрового потенциометра будем менять яркость свечения светодиода, а затем используем digipot для регулировки громкости динамика. Завершив эти два проекта, вы получите основу для реализации более сложных конструкций.

9.4.1. Техническое описание МСР4231

Прежде всего, следует изучить техническое описание микросхемы МСР4231, которое можно найти через поисковую систему Google. Ссылки на техническое опи-

- 191 -

сание для МСР4231 присутствуют на странице www.exploringarduino.com/content/ch9.

В техническом описании можно найти ответы на следующие вопросы:

• цоколевка микросхемы;

• какие выводы являются управляющими;

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

• какие команды SPI необходимы, чтобы управлять двумя потенциометрами.

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

Рис. 9.2. Цоколевка микросхемы МСР4231

При подготовке к работе с новым устройством необходимо сначала разобраться с назначением контактов. Вот назначение выводов МСР4231:

• РОА, POW и РОВ -выводы первого потенциометра;

• PIA, PIW и PIB-выводы второго потенциометра;

• VDD -вывод питания микросхемы 5 В;

• VSS -вывод подключения к земле;

• CS-контакт SS для интерфейса SPI, черта сверху означает, что активный уровень низкий (0 В -чип выбран, 5 В -не выбран);

• SDI и SDO - контакты последовательного ввода и вывода данных ( соответствуют MOSI и MISO);

• SCK -линия синхронизации SPI;

• SHDN и WP -контакты для выключения и защиты от записи, соответственно.

Для МСР4231 контакт WP не задействован и его можно игнорировать. Активный уровень на контакте SHDN низкий, как и на выводе CS. При низком уровне средний вывод потенциометра отключен. Чтобы потенциометр был всегда включен, необходимо соединить контакт SHDN непосредственно с шиной 5 В.

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

- 192 -

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

Прежде всего, выясним полное сопротивление потенциометра, обозначаемое R д в,

Доступны четыре варианта этого чипа, каждый с разным значением сопротивления (от 5 до 100 кОм). Далее используем вариант 103, сопротивление которого составляет примерно 10 кОм. Важно отметить, что цифровые потенциометры, как правило, имеют довольно большой разброс (из рис. 9.3 видно, что фактическое сопротивление может изменяться на ±20% ). Также следует отметить, что собственное сопротивление среднего вывода потенциометра составляет от 75 до 160 Ом. Это сопротивление нужно учитывать, особенно при управлении динамиком или светодиодом.

AC/DC CHARACTERISTICS (CONTINUED)

Рис. 9.3. Фрагмент технического описания микросхемы МСР4231

Далее разберемся с командами для управления цифровым потенциометром. На МСР4231 необходимо отправить две команды. Первая определяет выбор нужного потенциометра, вторая устанавливает текущее значение сопротивления выбранного потенциометра. Формат команд приведен на рис. 9.4.

Из рис. 9.4 ясно, что существуют два вида команд: 8-разрядные и 16-разрядные.

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

Рис. 9.4. Формат команд МСР4231

В техническом описании приведены адреса регистров, связанных с каждым потенциометром. Регистр первого потенциометра расположен в ячейке памяти по адресу 0, второго - по адресу 1. Зная это, можно отправить необходимые команды на установку значений для каждого потенциометра. Чтобы задать значение для первого потенциометра, первый байт будет содержать В00000000, а второй - величину сопротивления (0-128). Чтобы установить значение для второго потенциометра, первый байт будет равен B000 10000, а второй - величине сопротивления. Как видно из рис. 9.4, первые 4 бита первого байта- это адрес регистра памяти, следующие 2 бита- код команды (00 - для записи), следующие 2 бита - это старшие биты величины сопротивления (должны быть равны нулю, потому что максимальное значение для этого потенциометра составляет 128).

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

9.4.2. Описание схемы устройства

Чтобы в полной мере проверить знания протокола SPI, возьмем две микросхемы MCP4231, что даст нам четыре управляемых потенциометра. Каждый из них подключен последовательно со своим светодиодом (красным, желтым, зеленым и синим) и регулирует его яркость. Задействованы только две клеммы потенциометра.

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

Катод светодиода подключен к земле. Когда сопротивление цифрового потенциометра минимально, ток течет от источника 5 В через резистор 100 Ом и средний вывод потенциометра (имеющий сопротивление - 75 Ом) и далее через светодиод.

Когда сопротивление потенциометра максимально, ток течет через резистор 100 Ом, потенциометр (- 10 кОм), а затем через светодиод. Даже при полностью выведенном потенциометре сопротивление участка цепи будет 175 Ом, что достаточно для ограничения тока через светодиод. При увеличении и уменьшении сопротивления цифрового потенциометра меняется ток через светодиод, а следовательно, его яркость. Этот метод регулирования яркости может оказаться очень полезным, если заняты все выводы ШИМ.

- 194 -

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

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

- 195 -

Теперь, учитывая цоколевку, подсоединяем цифровые потенциометры к шине SPI.

На плате Arduino Uno контакт 13 - это SCK, контакт 12 - MISO, контакт 11 MOSI. Контакт 10 будем использовать как SS для одного чипа, а контакт 9 - как SS для другого чипа. Схема подключения приведена на рис. 9.6. Помните, что каждую из микросхем нужно подключить к своей линии SCK, MISO и MOSI.

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

9.4.3. Написание программы

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

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

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

• установить на выводе SS требуемой микросхемы низкий уровень;

• отправить байт команды на выбранный потенциометр;

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

• установить на выводе SS выбранной микросхемы высокий уровень.

Программа, приведенная в листинге 9.1, выполняет все описанные шаги: выбирает контакт SS, посылает байт выбора потенциометра и байт значения потенциометра по протоколу SPI. Функция SPI. begin() инициализирует аппаратный интерфейс SPI на плате Arduino и после этого для передачи данных по шине SPI можно использовать команду SPI. transfer().

Контакт выбора SS для первой микросхемы подключается к контакту 10 платы, для второй - к контакту 9. Функция settled() получает номер контакта SS, адрес регистра микросхемы и значение уровня потенциометра и передает данные в соответствующий чип. В цикле loop() яркость всех четырех светодиодов сначала увеличивается, а затем уменьшается. Загрузите программу на плату Arduino и увидите этот эффект.

ПРИМЕЧАНИЕ

Посмотреть видеоклип, демонстрирующий работу SPI цифрового потенциометра в качестве регулятора яркости, можно на странице http:/1 www.exploringarduino.com/content/ch9. Этот видеофайл доступен также на сайте издательства Wiley.

Освоив простой пример, в следующем разделе создадим более сложное устройство, добавив звуковой эффект.

- 196 -

Листинг 9.1. Управление несколькоими SPI цифровыми потенциометрами - SPI_led.ino

// Изменение яркости светодиодов не с помощью ШИМ,

// а регулировкой напряжения

// Подключение библиотеки SPI

#include

// При подключении библиотеки SPI

// по умолчанию используются контакты

// 11 = MOSI, 12 = MISO, 13 = CLK

const int SS1=10; // Контакт выбора SS микросхемы 1

const int SS2=9; // Контакт выбора SS микросхемы 2

const byte REG0=B00000000; // Команда записив регистр 0

// (выбор первого потенциометра)

const byte REG1=B00010000; // Команда записи в регистр 1

// (выбор второго потенциометра)

void setup()

{

// Настройка контактов выбора SS на выход

pinMode(SS1, OUTPUT);

pinMode(SS2, OUTPUT);

// Инициализация аппаратного SPI

SPI.begin();

}

// Подпрограмма выбора и отправки данных для каждого светодиода

// Chip 1 (SS 10) регистр 0 - красный

// Chip 1 (SS 10) регистр 1 - желтый

// Chip 2 (SS 9) регистр о - зеленый

// Chip 2 (SS 9) регистр 1 - синий

void setLed(int SS, int reg, int level)

{

digitalWrite(SS, LOW); // Установить SS в низкий уровень (выбор)

SPI.transfer(reg); // Отправка команды

SPI.transfer(level); // Отправка значения (0-128)

digitalWrite(SS, HIGH); // Установить SS в высокий уровень

}

void loop()

{

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

{

setLed(SS1, REG0, i);

setLed(SS1, REG1, i);

- 197 -

setLed(SS2, REG0, i);

setLed(SS2, REG1, i);

delay(10);

}

delay (300);

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

{

setLed ( SS1,REG0,i);

setLed ( SS1,REG1,i);

setLed(SS2,REG0,i);

setLed(SS2,REG1,i);

delay(10);

}

delay(300);

}

 

9.5. Создание световых и звуковых эффектов с помощью цифровых потенциометров SPI

Управление яркостью светодиодов- хороший пример для изучения протокола SPI, но менять яркость свечения можно и посредством ШИМ. Далее мы добавим в проект регулировку громкости звука, что невозможно реализовать с помощью ШИМ. Как упоминалось в главе 5, в Arduino IDE есть библиотека Топе, позволяющая генерировать на произвольном контакте платы Arduino меандр заданной частоты для воспроизведения звуков. Однако управлять громкостью звука при этом нельзя. Затем мы собрали регулятор громкости, включив потенциометр последовательно с динамиком. Теперь используем цифровой потенциометр SPI для создания различных звуковых эффектов.

ПРИМЕЧАНИЕ

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

9.5.1. Описание схемы устройства

Схема устройства похожа на предыдущую (см. рис. 9.6). Оставим три светодиода из четырех, а вместо последнего подключим динамик. Один вывод цифрового потенциометра, идущий к динамику, соединим через резистор с контактом платы Arduino, который будет генерировать сигнал различной частоты. Сформированный меандр проходит через цифровой потенциометр, который меняет напряжение на динамике, а следовательно, громкость звучания. Измените предыдущую схему так, как показано на рис. 9. 7.

- 198 -

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

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

9.5.2. Модификация программы

Внесем несколько простых изменений в нашу предыдущую программу для управления светодиодами (см. листинг 9.1). Добавьте переменную для контакта, подключенного к динамику, а также переменную для установки частоты сигнала, подаваемого на динамик. При желании внутри цикла loop() можно добавить операторы, увеличивающие частоту сигнала при каждой последующей итерации. Для установки громкости динамика подойдет та же самая функция setLed(), как и раньше, но ее название теперь вводит в заблуждение, так что рекомендуем его изменить. В листинге 9.2 она переименована в setReg().

- 200 -

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

{

setReg(SS1,REG0,i);

setReg(SS1,REG1,i);

setReg(SS2,REG0,i);

setReg(SS2,REG1,i);

delay(10);

}

delay(300);

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

{

setReg(SS1,REG0,i);

setReg(SS1,REG1,i);

setReg(SS2,REG0,i);

setReg(SS2,REG1,i);

delay(10);

}

delay(300);

freq = freq+100;

if (freq > 2000) freq = 100;

}

Загрузите программу на плату Arduino и убедитесь, что меняется не только яркость светодиодов, но и громкость звука. На каждой итерации частота звука увеличивается на 100 Гц, пока не достигнет 2000 Гц. Громкость динамика регулирует тот же потенциометр, который управляет светодиодами.

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

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

+ яркость светодиодов можно устанавливать в зависимости от внешних факторов, например от температуры;

+ можно добавить кнопку, чтобы переключать громкость или частоту звука;

+ можно сопоставить световые эффекты с проигрыванием музыки.

ПРИМЕЧАНИЕ

Посмотреть видеоклип, демонстрирующий работу SPI-устройства для создания световых и звуковых эффектов, можно на странице http://www.exploringarduino.com/

content/ch9. Этот видеофайл доступен и на сайте издательства Wiley.

- 201 -

Резюме

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

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

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

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

• Как управлять SPI цифровыми потенциометрами с помощью библиотеки Arduino SPI.

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

• Как одновременно регулировать громкость и частоту звукового сигнала, используя библиотеку Tone и цифровой потенциометр SPI.

Листинг 9.2. Управление светодиодами и громкостью динамика с помощью SPI-потенциометров - LED_speaker.ino

// Изменение яркости светодиодов не с помощью ШИМ,

// а регулировкой входного напряжения

// Подключение Arduino библиотеки SPI

#include

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

int freq = 100;

// При подключении библиотеки SPI

// по умолчанию используются контакты

// 11 = MOSI, 12 = MISO, 13 = CLK

const int SS1=10;// Контакт выбора SS микросхемы 1

const int SS2=9;// Контакт выбора SS микросхемы 2

const byte REG0=B00000000; // Команда записи в регистр 0

//(выбор первого потенциометра)

const byte REG1=B00010000; // Команда записи в регистр 1

//(выбор второго потенциометра)

void setup()

{

// Настройка выводов выбора SS на выход

pinMode(SS1, OUTPUT);

pinMode(SS2, OUTPUT);

// Инициализация аппаратного SPI

SPI.begin();

}

//Подпрограмма выбора и отправки данных

//Chip 1 (SS 10) регистр 0 - красный светодиод

//Chip 1 (SS 10) регистр 1 - желтый светодиод

//Chip 2 (SS 9) регистр 0 - зеленый светодиод

//Chip 2 (SS 9) регистр 1 - динамик

void setReg(int SS, int reg, int level)

{

digitalWrite(SS, LOW);// Установка SS в низкий уровень (выбор)

SPI.transfer(reg);// Отправка команды

SPI.transfer(level);// Отправка значения (0-128)

digitalWrite(SS, HIGH);// Установка SS в высокий уровень

}

void loop()

{

tone(SPEAKER, freq);// Частота звука

}

- 199 -

 

Глава 10. Взаимодействие с жидкокристаллическими дисплеями

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

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

• плата Arduino Uno;

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

• микрофон;

• цифровой SPI-потенциометр МСР4231;

• перемычки;

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

• динамик;

• две кнопки;

• вентилятор;

• 16х2-символьный ЖК-дисплей;

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

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

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

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

• датчик температуры ТС74AО-5.0 VAT I2C;

• набор перемычек;

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

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

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

- 203 -

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

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

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

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

ПРИМЕЧАНИЕ

Видеоурок о работе с жидкокристаллическим дисплеем находится по адрес?

http://www.jeremyblum.com/2011/07/31/tutorial-13-for-arduino-liquid-crystal-displays

Вы также можете найти этот видеофайл на сайте издательства Wiley.

 

10.1. Настройка жидкокристаллического дисплея

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

Наиболее распространены дисплеи, содержащие 16х2 символов, имеющие 16 (или 14, если нет подсветки) контактов в один ряд. Для рассмотренных далее примеров выбран 16-контактный ЖК-дисплей, на экране которого одновременно может отображаться 32 символа (16 столбцов и 2 строки).

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

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

Все параллельные ЖК-индикаторы имеют одинаковые выходы и их можно подключить в одном из двух вариантов: 4-контактном и 8-контактном. Для передачи информации служат четыре вывода, есть также контакты готовности данных, выбора режима команд или режима индикации, установки режимов чтения или записи данных. Назначение всех контактов приведено в табл. 10.1.

- 204 -

Рис. 10.1. ЖК-дисплей с припаянными штыревыми контактами

Таблица 10.1. Контакты параллельного ЖК-дисплея

Назначение контактов следующее:

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

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

- 205 -

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

• Сигнал на контакте EN сообщает, что данные готовы к приему или передаче.

• Контакты D4-D7 используются для передачи данных, а контакты DO-D3 остаются неподключенными.

Если ЖК-дисплей снабжен встроенной системой светодиодной подсветки с внутренним ограничивающим резистором, можно непосредственно подключить анод к +5 В, а катод к земле, если такого резистора нет, следует добавить токоограничивающий резистор в линию между анодом и катодом. Подробности необходимо уточнять в техническом описании конкретного дисплея.

В табл. 10.2 приведен рекомендуемый порядок соединения контактов ЖК-дисплея и платы Arduino. Можно подключить дисплей и к другим контактам ввода-вывода.

Рис. 10.2. Подключение ЖК-дисплея к макетной плате и Arduino

- 206 -

Таблица 10.2. Таблица соединения контактов

Контакты ЖК-дисплея Контакты Arduino
RS D2
EN D3
D4 D4
D5 D5
D6 D6
D7 D7

Подключите ЖК-дисплей к плате Arduino по схеме, приведенной на рис. 10.2.

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

 

10.2. Библиотека LiquidCrystal

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

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

http://arduino.cc/en/Reference/LiquidCrystal.

 

10.3. Вывод текста на дисплей

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

Сначала необходимо подключить библиотеку LiquidCrystal:

#include

Затем нужно инициализировать объект LiquidCrystal:

LiquidCrystal lcd (2,3,4,5,6,7);

Аргументы для инициализации объекта представляют собой контакты Arduino, подключенные к выводам ЖК-дисплея в следующем порядке: RS, EN, D4, DS, D6, D7. Чтобы настроить конфигурацию ЖК-индикатора, в функции setup() необходимо вызвать библиотечную функцию begin(), ее аргументы - число столбцов и строк вашего ЖК-дисплея:

lcd.begin (16, 2);

- 207 -

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

lcd.setCursor (0,1);

lcd.print ("Jeremy Blum");

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

ВНИМАНИЕ!

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

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

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

Листинг 10.1. Вывод текста и значений счетчика на экран ЖК-дисплея - LCD_text.ino

// Текст и значение инкрементируемого счетчика на экране

// Подключение библиотеки:

#include

// Начальное значение time = O

int time = 0;

// Инициализация экземпляра библиотеки LiquidCrystal

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup()

{

// Настройка экземпляра дисплея - число столбцов и строк:

lcd.begin(16, 2);

// Вывод текстового сообщения на экран дисплея

lcd.print("Jeremy's Display");

}

void loop()

{

// Установить курсор на вторую строку в первую позицию

lcd.setCursor(0,1);

- 208 -

// Вывод значения счетчика

lcd.print(time);

// Пауза 1 секунда

delay(1000);

// Увеличение значения счетчика

time++;

}

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

Команда lcd.begin (16, 2) задает размер дисплея: 16 столбцов и 2 строки. Поскольку первая строка не меняется, ее можно инициализировать в функции setup() командой lcd.print(). Обратите внимание, что команда выполняется без предварительной установки курсора, потому что по умолчанию текст выводится, начиная с позиции (0,0). В цикле курсор всегда возвращается в позицию (0, 1 ), поэтому при выводе значения переменной time каждый раз переписывается вторая строка. Экран обновляется раз в секунду и одновременно увеличивается счетчик времени.

 

10.4. Создание специальных символов и анимации

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

Создавать пользовательские символы просто. Если внимательно посмотреть на ЖК-дисплей, то видно, что каждое знакоместо состоит из матрицы 5х8 пикселов.

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

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

byte p20[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B10000,

- 209 -

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

};

Я назвал этот массив p2О, чтобы показать, что этот символ заполняет 20% пространства. В функции setup() вызываем библиотечную функцию createChar(), чтобы назначить данному массиву идентификатор ID пользовательского символа.

Пользовательские символы имеют ID от 0 до 7, вы можете в общей сложности сформировать восемь таких символов. Определим массив p20 как пользовательский символ с ID=0: lcd.createChar (0, p20);

Для отображения пользовательского символа на дисплее поместите курсор в нужное место и выполните команду lcd.write ( (byte) 0);

Добавьте остальные пользовательские символы и с помощью двух вложенных циклов в основном цикле программы loop() обновляйте прогресс-бар. Код данной программы приведен в листинге 10.2.

Листинг 10.2. Код прогресс-бара на экране дисплея - LCD_progress_bar.ino

// Прогресс-бар на ЖК-дисплее

// Подключение библиотеки LiquidCrystal

#include

// Инициализация экземпляра библиотеки LiquidCrystal

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

// Создание массивов для символов прогресс-бара

byte p20[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

};

byte p40[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B11000,

B11000,

- 210 -

B11000,

B11000,

B11000,

B11000,

B11000,

B11000,

};

byte p60[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B11100,

B11100,

B11100,

B11100,

B11100,

B11100,

B11100,

B11100,

};

byte p80 [8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B11110,

B11110,

B11110,

B11110,

B11110,

B11110,

B11110,

B11110,

};

byte p100[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B11111,

B11111,

B11111,

B11111,

B11111,

B11111,

B11111,

B11111,

};

void setup()

{

// Настройка экземпляра дисплея - число столбцов и строк:

lcd.begin(16, 2);

// Вывод текста на ЖК-дисплей

lcd.print("Jeremy's Display");

// Определение пользовательских символов

lcd.createChar(0,p20);

- 211 -

lcd.createChar(1,p40);

lcd.createChar(2,p60);

lcd.createChar(3,p80);

lcd.createChar(4,p100);

}

void loop()

{

// Курсор в начало второй строки

lcd.setCursor(0,1);

// Очистка второй строки

// 16 пробелов

lcd.print(" ");

// Перебор каждого символа на второй строке

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

{

// Перебор каждого значения (p20 - p100)

for (int j=0; j<5; j++)

{

lcd.setCursor(i, 1);// Столбец установки курсора

lcd. write (j);// Вывод символа

delay(100);// Задержка

}

}

}

В начале каждого цикла во все 16 позиций второй строки выводится символ пробела ( строка очищается). Внешний цикл for() перебирает все 16 знакомест строки.

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

ПРИМЕЧАНИЕ

Для просмотра видеоклипа, демонстрирующего отображение прогресс-бара на ЖК-дисплее, посетите страницу http://www.exploringarduino.com/content/ch10. Этот видеоклип доступен также на сайте издательства Wiley.

 

10.5. Создание регулятора температуры

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

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

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

- 212 -

10.5.1. Монтаж схемы устройства

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

Один из выводов кнопок подключен к шине питания, а другой - к контакту Arduino и через резистор 10 кОм на землю.

Один вывод динамика подключен к контакту Arduino, а другой - через резистор 150 Ом к земле. Частота звука устанавливается программно.

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

Рис. 10.3. Схема регулятора температуры с ЖК-дисплеем

- 213 -

10.5.2. Отображение данных на ЖК-дисплее

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

Надписи "Current:" и "Set:" всегда будут неизменными, их можно вывести на экран один раз. Так как температура представлена в виде двух цифр, местоположение двух надписей " 0 С" тоже будет фиксированным. Текущее значение температуры будет отображаться в позиции (8,0) и обновляться при каждом цикле loop(), значение пороговой температуры размещено в позиции (8, 1) и обновляется при нажатии кнопки. Значок включения вентилятора будет отображаться в нижней правой части дисплея в позиции (15,1) и обновляться, когда изменяется состояние.

При работе программы ЖК-дисплей будет выглядеть примерно так, как показано на рис.10.4.

Рис. 10.4. Отображение данных на ЖК-дисплее

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

Листинг 10.3. Массивы, опредеяющие пользовательские символы

// Пользовательский символ градуса

byte degree[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

В00110,

В01001,

В01001,

В00110,

B00000, B00000, B00000, B00000,

};

// Символ "вентилятор включен"

byte fan_on[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

В00100,

B10101,

В01110,

B11111,

В01110,

- 214 -

B10101,

B00100,

B00000,

};

// Символ "вентилятор выключен"

byte fan_off[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

B00100,

B00100,

B00100,

B11111,

B00100,

B00100,

B00100,

B00000,

};

Вывод данных на экран ЖК-дисплея будет осуществлен в функции setup(). Размещаем курсор в нужной позиции и с помощью библиотечных функций print() и write() выводим надписи на экран (листинг 10.4).

Листинг 10.4. Вывод иформации на экран ЖК-дисплея

// Создаем пользовательские символы

lcd.createChar(0, degree);

lcd.createChar(1, fan_off);

lcd.createChar(2, fan_on);

// Отображаем статические надписи на экране ЖК-дисплея

lcd.setCursor(0,0);

lcd.print("Current:");

lcd.setCursor(10,0);

lcd.write ( (byte) 0);

lcd.setCursor(11,0);

lcd.print("C");

lcd.setCursor(0,1);

lcd.print("Set:");

lcd.setCursor(10,1);

lcd.write ( (byte) 0);

lcd.setCursor(11,1);

lcd.print("C");

lcd.setCursor(15,1);

lcd.write(1);

В каждом цикле loop() обновляем текущее значение температуры и состояние значка включения вентилятора. Перед этим помещаем в нужное место курсор.

- 215 -

10.5.3. Установка порогового значения температуры с помощью кнопок

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

// Переменные, используемые при устранении дребезга кнопок

boolean lastDownTempButton = LOW;

boolean currentDownTempButton = LOW;

boolean lastUpTempButton = LOW;

boolean currentUpTempButton = LOW;

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

Листинг 10.5. Функция устранения дребезга двух кнопок

// Функция проверки дребезга для нескольких кнопок

boolean debounce(boolean last, int pin)

{

boolean current = digitalRead(pin);

if (last != current)

{

delay (5);

current = digitalRead(pin);

}

return current;

}

В основном цикле программы loop() проверяем состояние кнопок, устраняем дребезг, изменяем при нажатии кнопки значение переменной пороговой температуры set_temp и обновляем значение на экране ЖК-дисплея (листинг 10.6).

Листинг 10.6. Программа установки пороговой температуры с помощью двух кнопок

// Устранение дребезга нескольких кнопок

currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);

currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);

// Уменьшить значение set_temp

if (lastDownTempButton == LOW && currentDownTempButton == HIGH)

{

set_temp--;

}

- 216 -

// Увеличить значение set_temp

else if (lastUpTempButton == LOW && currentUpTempButton == HIGH)

{

set_temp++;

}

// Вывести значение set_temp на ЖК-дисплей

lcd.setCursor(8,1);

lcd.print(set_temp);

// Изменить последние значения статуса кнопок

lastDownTempButton = currentDownTempButton;

lastUpTempButton = currentUpTempButton;

В листинге 10.6 запускаем функцию устранения дребезга debounce() для каждой кнопки, а затем изменяем переменную set_temp заданной пороговой температуры при нажатии одной из кнопок. Потом значение температуры обновляется на экране ЖК-дисплея.

10.5.4. Добавляем вентилятор и звуковое оповещение

Теперь добавим фрагмент кода для управления вентилятором и динамиком. Хотя ЖК-дисплей и так информирует нас обо всем, никогда не помешает дополнительное звуковое оповещение о событиях. Например, подача звукового сигнала перед включением вентилятора. В этом примере мы используем команды tone() в паре с задержкой delay() и notone(). Чтобы задать длительность звука, можно указать второй аргумент команды tone(). Добавив переменную состояния, можно устанавливать звуковое оповещение динамиком только один раз при превышении порогового значения температуры.

Фрагмент кода, приведенный в листинге 10.7, проверяет температуру и управляет динамиком, вентилятором и индикатором вентилятора на ЖК-дисплее.

Листинг 10.7. Выдача звукового оповещения при превышении пороговой температуры

// Стало жарко!

if (с>= set_temp)

// Издать звук динамиком

if ( !one_time)

{

tone(SPEAKER, 400);

delay(500);

one time = true;

}

- 217 -

// Выключить динамик

else

{

noTone (SPEAKER);

}

// Включить вентилятор и знак на ЖК-дисплее

digitalWrite(FAN, HIGH);

lcd.setCursor(15,1);

lcd.write(2);

}

// Стало прохладнее

else

{

// Выключить динамик

// Сбросить состояние one time в false

// Выключить вентилятор и значок на ЖК-дисплее

noTone(SPEAKER);

one time = false;

digitalWrite(FAN, LOW);

lcd.setCursor(15,1);

lcd.write(1);

}

Переменная one_time позволяет выдать однократный, а не непрерывный звуковой сигнал. После того как динамик издает звук длительностью 500 мс частотой 400 Гц, переменная устанавливается в true и сбрасывается в false только тогда, когда температура падает обратно ниже заданного порога.

10.5.5. Итог всего: полная программа

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

Полный текст программы приведен в листинге 10.8. Загрузите ее на плату Arduino и сравните результаты с видеоклипом, демонстрирующим систему в действии.

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

// Это программа автоматического регулятора температуры

// Для вывода температуры используются 2 знака

// Использует библиотеку Wire с установкой адреса

#include

#define TEMP ADDR 72

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

#include

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

- 218 -

// Пользовательский символ градуса

byte degree[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

В00110,

В01001,

В01001,

В00110,

B00000, B00000, B00000, B00000,

};

// Пользовательский символ "вентилятор включен"

byte fan_on[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

800100,

810101,

B01110,

B11111,

В01110,

B10101,

B00100,

B00000,

};

// Пользовательский символ "вентилятор выключен"

byte fan_off[8]На русском: http://wiki.amperka.ru/видеоуроки:5-моторы-и-транзисторы.
= {

В00100,

B00100,

B00100,

B11111,

B00100,

B00100,

B00100,

B00000,

};

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

const int SPEAKER=8;

const int DOWN_BUTTON =9;

const int UP_BUTTON =10;

const int FAN =11;

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

boolean lastDownTempButton = LOW;

boolean currentDownTempButton = LOW;

boolean lastUpTempButton = LOW;

boolean currentUpTempButton = LOW;

int set_temp = 23; // Значение граничной температуры

boolean one time = false; // Флаг звука динамика

- 219 -

void setup()

{

pinMode(FAN, OUTPUT);

// Создание объекта Wire (I2С-датчик температуры)

Wire.begin();

// Настройки дисплея (число столбцов и строк)

lcd.begin(16, 2);

// Определить пользовательские символы

lcd.createChar(0, degree);

lcd.createChar(1, fan_off);

lcd.createChar(2, fan_on);

// Вывод закрепленных сообщений на дисплее

lcd.setCursor(0,0);

lcd.print("Current:");

lcd.setCursor(10,0);

lcd. write ( (byte) 0);

lcd.setCursor(11,0);

lcd.print("C");

lcd.setCursor(0,1);

lcd.print("Set:");

lcd.setCursor(10,1);

lcd.write ( (byte) 0);

lcd.setCursor(11,1);

lcd.print("C");

lcd.setCursor(15,1);

lcd.write(1);

}

// Функция проверки на дребезг для нескольких кнопок

boolean debounce(boolean last, int pin)

{

boolean current = digitalRead(pin);

if (last != current)

{

delay(5);

current = digitalRead(pin);

}

return current;

}

void loop()

{

// Получить значение от датчика температуры

Wire.beginTransmission(TEMP_ADDR);

Wire.write (0);

Wire.endTransmission();

Wire.requestFrom(TEMP_ADDR, 1);

- 220 -

// Ожидаем передачу

// Получить 1 байт

while(Wire.available()==0);

int с = Wire.read();

// Установить курсор

// и вывести текущее значение

lcd.setCursor(8,0);

lcd.print(c);

// Проверка на дребезг для двух кнопок

currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);

currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);

// Уменьшить пороговое значение температуры

if (lastDownTempButton== LOW && currentDownTempButton == HIGH)

{

set_temp--;

}

// Увеличить пороговое значение температуры

else if (lastUpTempButton == LOW && currentUpTempButton

{

set_temp++;

}

// Вывод порогового значения на экран

lcd.setCursor(8,1);

lcd.print(set_temp);

currentDownTempButton;

lastDownTempButton

lastUpTempButton = currentUpTempButton;

// Очень жарко!

if (с >= set_temp)

{

// Однократный звуковой сигнал на динамик

if ( ! one_time)

{

tone(SPEAKER, 400);

delay ( 500);

one time = true;

}

// Отключить вывод звука

else

{

noTone (SPEAKER);

}

// Включить вентилятор и вывести значок на дисплей

digitalWrite(FAN, HIGH);

lcd.setCursor(15,1);

lcd.write(2);

}

- 221 -

//Не жарко!

else

{

// Выключить динамик

// Сбросить состояние one time в false

// Выключить вентилятор и значок на ЖК-дисплее

noTone(SPEAKER);

one time = false;

digitalWrite(FAN, LOW);

lcd.setCursor(15,1);

lcd.write(1);

}

}

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

ПРИМЕЧАНИЕ

Посмотреть видеоклип, демонстрирующий действие автономного терморегулятора, можно на странице http://www.exploringarduino.com/content/ch10. Этот видеофайл доступен также на сайте издательства Wiley.

 

10.6. Как усовершенствовать проект

Функциональные возможности описанной программы можно расширить. Вот несколько советов по улучшению проекта:

• Для увеличения мощности подключить вентилятор через транзистор.

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

• Добавить светодиоды для визуальной индикации предупреждений.

• Сделать звуковое оповещение в виде мелодии.

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

Резюме

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

• Как подключить ЖК-дисплей к плате Arduino по стандартной схеме.

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

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

• Как объединить датчики, двигатели, кнопки и ЖК-дисплей в едином автономном устройстве.

 

Глава 11. Беспроводная связь с помощью радиомодулей ХВее

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

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

• 2 платы Arduino (рекомендуется Uno или Leonardo);

• USB-кабели для программирования плат Arduino;

• источники питания для каждой платы Arduino;

• адаптер SparkFun USB ХВее Explorer;

• 2 радиомодуля ХВее Series 1;

• 2 платы расширения ХВее shield;

• кнопка;

• пьезозуммер;

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

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

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

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

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

• набор перемычек;

• 2 макетные платы.

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

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

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

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

- 223 -

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

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

Радиомодули ХВее позволяют осуществить связь между Arduino и компьютером или между несколькими платами Arduino. Далее мы расскажем об этом подробно.

ПРИМЕЧАНИЕ

Видеоурок по работе с радиомодулями ХВее находится по адресу http://www.jeremyblum.com/2011/02/27/arduino-tutorial-9-wireless-communication/. Этот видеофайл доступен также на сайте издательства Wiley.

 

11.1. Общие сведения о беспроводной связи ХВее

Название говорит само за себя. Беспроводная связь позволяет связывать и общаться двум и более устройствам без проводов. Беспроводные передатчики передают данные через свободное пространство, излучая электромагнитные волны на определенной частоте. Существуют различные технологии передачи для разных диапазонов, чтобы предотвратить взаимные помехи. Правительственные учреждения, например Федеральная комиссия по связи (FCC) в США, регулируют эти вопросы, публикуя правила распределения частот. Модуль ХВее передает данные на частоте 2,4 ГГц, на которой работают и многие другие устройства, например WiFi-маршрутизаторы. Это диапазон частот ISM (выделенный промышленным, научным и медицинским учреждениям), отведенный для нелицензионного использования беспроводной связи. Модули ХВее соответствуют стандарту IEEE 802.15.4, который содержит перечень правил эксплуатации беспроводных персональных сетей (PAN).

Модули ХВее, как правило, соединяют согласно конфигурации Р AN "точка-точка" или "точка-многоточка" (рис. 11.1). Схема "точка-точка" удобна, когда необходимо заменить проводную последовательную связь между двумя удаленными устройствами беспроводной. Конфигурация "точка-многоточка" часто используется для создания распределенных сетей датчиков.

Рис. 11.1. PAN-конфигурации

- 224 -

11.1.1. Радиомодули ХВее

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

Все модули ХВее имеют 20 контактов. В этой главе рассмотрим устройства ХВее серии 1, работающие по стандарту 802.15.4. С их помощью можно реализовать PAN-конфигурации "точка-точка" и "точка-многоточка", но они не поддерживают стандарт ZigBee. У вас могут оказаться и модули других типов, но скорее всего это будут ХВее S 1 (рис. 11.2).

Рис. 11.2. Модули ХВее Series 1

ПРИМЕЧАНИЕ

Следует помнить, что ХВее модули серий 1 и 2 несовместимы друг с другом. Для начинающих я рекомендую модули серии 1, т. к. они намного проще в настройке.

Есть различия и внутри каждой серии. Для большинства модулей выпускаются модификации Pro и non-Pro, они полностью совместимы, но габариты, стоимость, энергопотребление и дальность действия первых больше (примерно 1 миля для Pro и 300 футов для non-Pro). Я рекомендую начинать с более дешевой версии модулей и переходить на Pro, если вам понадобится большая дальность.

Кроме того, существуют модули ХВее для частот 2,4 ГГц и 900 МГц. Частота 900 МГц дает выигрыш в дальности действия, такой сигнал лучше проникает сквозь строительные конструкции, но она разрешена не во всех странах. Модули, работающие на частотах 2,4 ГГц и 900 МГц, несовместимы друг с другом.

- 225 -

Наконец, ХВее-модули поставляются с различными вариантами исполнения антеы: встроенными, внешними, с отдельными антенными модулями и внешними переходниками для антенн. Как правило, внешняя антенна обеспечивает лучшие характеристики, но занимает больше места.

В наших примерах будем использовать модули ХВее серии 1, non-Pro, с рабочей частотой 2,4 ГГц со встроенной антенной, работающие в режиме последовательного обмена данными. Маркировка и назначение контактов модуля приведены на рис. 11.3.

Рис. 11.3. Фрагмент технического описания модуля ХВее Series 1. маркировка и назначение контактов

ВНИМАНИЕ!

Для питания модуля ХВее необходимо напряжение 3,3 В, при подаче питания 5 В модуль выйдет из строя.

- 226 -

11.1.2. Платы расширения для ХВее

Существуют специальные переходники - платы расширения (рис. 11.4 ), позволяющие легко подключить модуль ХВее к плате Arduino. Есть несколько разновидностей ХВее-переходников, обладающих одинаковыми функциями и незначительно отличающихся друг от друга.

Рассмотрим функции плат расширения ХВее.

Arduino Wireless Shield

Sparkfun ХЬее Shield

Cooking Hacks ХВее Shield

Рис. 11.4. Внешний вид различных плат расширения для подключения модулей ХВее

Стабилизатор 3,3 В

Большинство плат Arduino работает от источника 5 В, логические уровни также находятся в диапазоне от 0 (низкий уровень) до 5 В (высокий уровень). Напряжение питания модулей ХВее равно 3,3 В, логические уровни тоже другие. Хотя у Arduino есть встроенный стабилизатор на 3,3 В, его ток недостаточен для питания ХВее-модуля. Поэтому на большинстве ХВее-переходников установлен линейный стабилизатор для питания модуля ХВее.

Согласование логических уровней

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

Светодиодные индикаторы

На большинстве плат расширения установлены два светодиодных индикатора:

+ Associate -мигает, когда модуль работает в режиме последовательного обмена данными;

+ RSSI-загорается на короткое время при получении данных.

- 227 -

Перемычка или переключатель выбора UART

Модули ХВее общаются с Arduino через последовательный универсальный асинхронный приемопередатчик (UART) по контактам Rx и Тх. На многих платах Arduino (кроме Mega и Due) есть один доступный UART, который к тому же осуществляет USB-соединение с компьютером для программирования и отладки. На плате Leonardo тоже один UART (контакты Rx и Тх), но они не дуплексированы, т. к. программный интерфейс USB непосредственно встроен в микроконтроллер.

В случае платы Arduino Uno возникает вопрос: как модуль ХВее и компьютер подключить к одному разъему UART. Схема соединения контактов Rx и Тх (при подключении модуля ХВее через плату расширения) приведена на рис. 11.5.

Рис. 11.5. Возможность возникновения коллизий в линиях UART

Обратите внимание на надпись "Коллизии" на рис. 11.5. Подумайте, что произойдет, если модуль ХВее и ваш компьютер будут одновременно передавать данные на плату Arduino. Как Arduino узнать, откуда приходят данные? Если данные будут передаваться одновременно, произойдет так называемая коллизия, и информация исказится. Значит, плата Arduino не сможет одновременно общаться с компьютером и модулем ХВее по последовательному порту. Решить эту проблему можно двумя способами:

• отсоединять переходник ХВее при программировании платы Arduino;

• установить на переходнике ХВее перемычку или переключатель для подключения к плате Arduino.

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

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

Для соединения платы Arduino с модулями ХВее служит аппаратный UART-интерфейс (контакты 0 и 1 на плате Arduino). Эти выводы также используются для

- 228 -

подключения к компьютеру по USB. Большинство переходников также осуществляет соединение между ХВее и платой Arduino через аппаратный последовательный порт. Можно не отсоединять переходник ХВее при программировании платы Arduino, если воспользоваться библиотекой SoftwareSerial. Эта библиотека позволяет определить два произвольных цифровых контакта платы Arduino в качестве выводов Rx и Тх при соединении с переходником ХВее-. Но на переходнике ХВее обязательно должен быть переключатель для выбора контактов платы Arduino в качестве Rx и Тх. На переходнике Sparkfun ХВее установлен такой переключатель, коммутирующий контакты 2 и 3 платы Arduino в качестве линий Rx и Тх. Если на вашем переходнике есть такой переключатель, можно организовать взаимодействие с радиомодулями ХВее с помощью библиотеки SoftwareSerial.

 

11.2. Настройка модулей ХВее

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

11.2.1. Настройка с помощью USB-адаптера

Модули ХВее можно запрограммировать так же, как и плату Arduino, через интерфейс USB. Существуют два способа: с помощью платы Arduino и преобразователя

USB ( см. главу 6) или через специальный адаптер ХВее USB. Для программирования модулей ХВее я настоятельно рекомендую приобрести адаптер ХВее USB, например, популярный SparkFun ХВее USB Explorer (рис. 11.6).

Рис. 11.6. Адаптер SparkFun ХВее USB Explorer

- 229 -

Первый вариант программирования (не рекомендуется)

Я не рекомендую программировать модули ХВее с помощью платы Arduino Uno, т. к. при неосторожности можно повредить плату. Если вы все же хотите запрограммировать модули ХВее с использованием платы Arduino, то возникнет проблема коллизии данных, которую мы упоминали ранее. Чтобы предотвратить коллизии, следует удалить с платы микросхему процессора ATmega, присоединить модуль к плате через переходник ХВее и подключить Arduino к компьютеру USB-кабелем. После этого все команды с компьютера будут приходить на ХВее.

ПРИМЕЧАНИЕ

Удалить можно только микросхему, вставленную в панельку. Изъять процессор с платы Uno SMD или другой с припаянным чипом ATmega невозможно.

Второй вариант программирования (рекомендуется)

Использовать SparkFun USB ХВее Explorer очень просто: вставьте ХВее-модуль в гнездо на адаптере, подключите SparkFun USB ХВее Explorer к компьютеру с помощью USB-кабеля, и можно программировать. Адаптер SparkFun USB ХВее Explorer реализует USB-интерфейс с помощью тех же контроллеров FTDI, что и последние платы Arduino. Далее в этой главе применим адаптер для установки беспроводной связи между компьютером и Arduino с подключенным модулем ХВее.

11.2.2. Настройка модуля ХВее и его подключение к компьютеру

Параметров настройки модулей ХВее очень много и на описание всех понадобится отдельная книга. Здесь мы рассмотрим наиболее важные (рис. 11. 7):

• ID (идентификатор PAN-сети)- все модули ХВее, которые будут обмениваться данными друг с другом, должны быть отнесены к одной сети.

• МУ ( собственный адрес) - уникальный адрес идентификации каждого модуля ХВее в пределах определенной персональной сети.

• DL (адрес назначения)- уникальный адрес модуля ХВее, с которым вы хотите обмениваться данными.

Рис. 11.7. Параметры настройки сети ХВее с конфигурацией "точка-точка"

- 230 -

BD ( скорость передачи данных) -скорость обмена данными для модулей ХВее.

Мы будем использовать значение по умолчанию (9600 бод).

Обратите внимание, что значения параметров МУ и DL для каждого модуля ХВее меняются местами, т. к. собственный адрес одного модуля является адресом назначения для другого, и наоборот. Идентификатор сети PAN в наших примерах равен

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

• 0-1200 бод;

• 1 -2400 бод;

• 2 -4800 бод;

• 3 -9600 бод (по умолчанию);

• 4 -19 200 бод;

• 5-38 400 бод;

• 6 -57 600 бод;

• 7 -115 200 бод.

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

11.2.3. Настройка ХВее с помощью Windows-приложения X-CTU

Теперь нужно запрограммировать модули ХВее с параметрами, указанными на рис. 11. 7. Если вы работаете в операционной системе Windows, то можете воспользоваться приложением X-CTU, предоставляющим удобный графический интерфейс. Если у вас нет компьютера с операционной системой Windows, сразу перейдите к следующему разделу, где описана настройка модулей ХВее с помощью последовательного терминала в Linux или OS Х.

Отыскать ссылку для скачивания самой последней версии X-CTU с сайта Digi

можно через поиск Google. Ссылку на скачивание X-CTU вы можете найти также на странице http://www.exploringarduino.com/content/ch11. Выполните следующие действия:

1. Загрузите программу установки, установите X-CTU и запустите приложение.

В результате появится окно, показанное на рис. 11.8. Слева будет выведен список доступных СОМ-портов.

2. Выберите СОМ-порт, к которому подключена ваш адаптер ХВее Explorer и нажмите кнопку Test/Query ( см. рис. 11.8). Если программируете новый модуль ХВее, по умолчанию настроенный на скорость 9600 бод, должно появиться окно подтверждения текущей информации о конфигурации, считанной с модуля (рис. 11.9).

- 231 -

Рис. 11.8. Главное окно программы X-CTU

Рис. 11.9. Окно X-CTU - подтверждение запроса

- 232 -

3. Перейдите к экрану настройки модема и нажмите кнопку Read, чтобы отобразить все доступные параметры настройки на вашем ХВее-модуле. Результат должен выглядеть примерно так, как показано на рис. 11.10.

Рис. 11.10. Окно X-CTU- конфигурация модема

4. Теперь установите значения PAN ID, адрес источника, адреса отправителя и получателя. Можно задать множество других опций конфигурации, но мы в этой книге ограничиваемся только четырьмя перечисленными параметрами. Чтобы изменить значение настройки, просто щелкните по ней мышью. У становите следующие значения: ID-1234; DL - 1001; МУ - 1000.

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

Вы настроили свой первый модуль ХВее! Теперь аккуратно извлеките один модуль из адаптера ХВее Explorer и установите другой. Выполните описанные действия со вторым модулем ХВее, поменяв значения параметров DL и МУ, чтобы модули могли обмениваться данными между собой. На рис. 11.12 показана конфигурация для второго ХВее-модуля.

- 233 -

Рис. 11.11. Запись настроек в модуль ХВее

Рис. 11.12. Настройки для второго модуля ХВее

- 234 -

Ваши модули ХВее настроены и готовы для связи друг с другом. Назначив им идентификатор PAN ID, отличный от значения по умолчанию, вы уменьшаете вероятность помех другим сетям ХВее. Теперь можно сразу перейти к разделу 11.3.

11.2.4. Настройка модулей ХВее из последовательного терминала

Если у вас нет компьютера с операционной системой Windows, придется настраивать модули ХВее через последовательный терминал. Этот процесс одинаков для Linux и Mac. Запустим системное приложение screen. Как и в главе 1, с помощью IDE Arduino выясним имя порта подключения для нашего адаптера ХВее Explorer.

Посмотреть имя можно в меню Сервис-> Последовательный порт.

Затем открываем терминал и выполняем следующие действия:

1. В терминале вводим команду, например

screen /dev/ttyUSB6 9600

(/dev/ttyusb6 замените на имя вашего порта подключения). При нажатии клавиши инициируется соединение с адаптером и экран гаснет. После подключения при вводе команд они не будут отображаться на экране. Сначала я объясню процесс программирования, а потом приведу список команд. Чтобы запрограммировать радиомодуль ХВее, необходимо выполнить следующие действия:

• установить модуль ХВее в режим программирования;

• назначить ID PAN (ATID);

• задать адрес источника (АТМУ);

• задать адрес получателя (ATDL);

• записать настройки в энергонезависимую память модуля ХВее (А TWR).

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

2. Введите команду +++ и ждите, не нажимайте , пока терминал не ответит ок, это указывает, что модуль ХВее вошел в режим программирования.

3. Введите команду ATID1234 и нажмите , значение идентификатора сети будет равно 1234.

4. Введите команду ATMY1000 и нажмите , значение адреса источника будет равно 1000.

5. Введите команду ATDL1001 и нажмите , адрес назначения будет установлен 1001.

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

- 235 -

7. Чтобы убедиться, что все настроено верно, введите одну из команд ATID, АТМУ или ATDL без значений и нажмите клавишу , при этом на дисплей будет выведено текущее значение параметра.

ПРИМЕЧАНИЕ

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

После завершения всех предьщущих шагов, установите в адаптер другой модуль ХВее. Проделайте шаги 2-7, но поменяйте значения для команд АТМУ и ATDL так, чтобы модули ХВее были настроены на обмен данными друг с другом.

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

 

11.3. Соединяемся с компьютером по беспроводной сети

Настроив модули ХВее, пора начать их использование. Самое простое - организовать беспроводной обмен между компьютером и Arduino. Запрограммировать плату Arduino непосредственно через соединение ХВее невозможно, поэтому загружать и тестировать программы будем с помощью USB-интерфейса. А после загрузки готовой программы на Arduino USB-кабель можно отключить и общаться с Arduino по беспроводной связи ХВее.

 

11.3.1. Автономное питание платы Arduino

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

Питание от USB с компьютера или сетевого адаптера

Если плата Arduino подключена через USB-кабель к компьютеру, то теряется смысл беспроводного соединения. Можно подключить плату к одному USB-порту компьютера, а модуль ХВее будет общаться с платой USB ХВее Explorer, подключенной к другому USB-порту компьютера. Способ подойдет для тестирования беспроводной связи, но бесполезен с точки зрения практического применения. В данном варианте необходимо убедиться, что правильно выбран последовательный порт для просмотра данных адаптера USB ХВее Explorer в мониторе последовательного порта или в приложении Processing.

Можно использовать 5-вольтовый сетевой блок питания с USB-выходом. При этом отпадает привязка к компьютеру. Подобные адаптеры широко применяются для зарядки iPhone, Android-устройств, а также других планшетов и смартфонов. На рис. 11.13 показан стандартный сетевой USB-адаптер для американских розеток.

- 236 -

Рис. 11.13. Сетевой 5-вольтовый USB-адаптер

Питание от батареи

Можно питать плату Arduino от батареи, подключив ее к разъему питания или входу Vin. С этих входов напряжение поступает на встроенный стабилизатор, который выдает напряжение 5 В для питания микропроцессора и других компонентов. На рис. 11.14 показана 9-вольтовая батарея со встроенным выключателем и разъемом питания.

Вместо 9-вольтовой батареи можно использовать несколько батареек АА с напряжением 1,5 В. Если соединить последовательно четыре таких батарейки, получится напряжение около 6 В. Минимальное падение напряжения на встроенном в Arduino стабилизаторе равно 1 В. При входном напряжении 5,5 В на шине питания будет

рис. 11.14. Батарея 9 В

- 237 -

4,5 В. Можно рассчитывать, что плата будет работать и при напряжении 4,5 В, что приемлемо для платы на базе ATMega, хотя и ниже напряжения при питании от USB.

Сетевые источники питания

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

• размеры разъема (диаметр 2,1 мм с плюсовым центральным контактом (рис. 11.15) );

• напряжение питания (желательно 7-12 В);

• максимальный ток (чем выше ток, тем больше устройств можно подключить к плате Arduino ). Блок с током 1 А довольно распространен и обеспечивает более чем достаточную мощность для платы Arduino и некоторых дополнительных компонентов.

Рис. 11.15. Разъем сетевого адаптера с плюсовым центральным контактом

11.3.2. Пример 1: беспроводное управление цветом окна на компьютере

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

1. Загрузите программу, которая позволяет изменить цвет окна обработки с помощью потенциометра, подключенного к Arduino. Сделайте это до установки переходника ХВее на плату Arduino, чтобы избежать коллизий UART, которые обсуждались ранее в этой главе. Если на переходнике есть перемычка или переключатель для выбора режима подключения/отключения ХВее к UART, то сам переходник при программировании платы Arduino можно не извлекать. Уточните это в документации на ваш переходник ХВее. Код программы, читающий данные потенциометра и передающий их на компьютер, приведен в листинге 11.1.

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

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

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

int val;

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

- 238 -

void setup()

{

Serial.begin(9600); // Запуск последовательного порта

}

void loop()

{

val = map(analogRead(POT), 0, 1023, 0, 255); //

//Чтение и масштабирование данных

//Отправка данных

Serial.println(val);

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

}

2. Отключите плату Arduino от компьютера и подсоедините к ней переходник вместе с модулем ХВее. Подключите потенциометр к аналоговому входу 0, как показано на электрической схеме, изображенной на рис. 11.16.

3. Для питания платы Arduino используйте один из методов, описанных в предыдущем разделе. Я выбрал сетевой USB-адаптер питания.

4. Подключите ХВее USB Explorer с другим запрограммированным модулем ХВее к компьютеру с помощью кабеля USB. Если модули настроены правильно, Rx светодиод на переходнике USB ХВее Explorer будет быстро мигать в момент получения данных.

5. Перед использованием приходящих данных в Processing-приложении откройте монитор последовательного порта в Arduino IDE. Выберите последовательный порт, к которому подключен ваш переходник USB ХВее Explorer, и убедитесь, что данные поступают в компьютер (рис. 11.17).

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

Листинг 11.2. Программа на Processlng для чтения последовательных данных и установки цвета экрана - pot_to_processing/processlng_d,splay_color

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

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

import processing.serial.*;

Serial port;

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

void setup()

{

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

size(500,500);

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

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

- 239 -

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

}

void draw()

{

background(0,0,brightness);// Перерисовать окно

}

void serialEvent (Serial port)

{

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

}

Рис. 11.16. Схема соединения платой Arduino с потенциометром и переходником ХВее

- 240 -

Рис. 11.17. Данные, переданные по беспроводному каналу в монитор последовательного порта

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

11.3.3. Пример 2: управление RGB-светодиодом

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

Сначала загрузим программу (листинг 11.3) на плату Arduino. Подобный пример был рассмотрен в главе 6. Принимаем строку значений RGB и устанавливаем цвет RGB-светодиода.

Листинг 11.3. Управление RGB-светодиодом через последовательный порт - processing_control)RGB/list_control

// Отправка многоразрядных значений

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

const int RED =11;

const int GREEN =10;

const int BLUE =9;

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

int rval=0;

int gval=0;

int bval=0;

- 241 -

void setup()

{

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

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

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

pinMode(RED, OUTPUT);

pinMode(GREEN, OUTPUT);

pinMode(BLUE, OUTPUT);

}

void loop()

{

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

while (Serial.available() > 0)

{

rval=Serial.parselnt(); //Первое число

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

bval=Serial.parselnt(); //Третье ЧИСЛО

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

{

// Установить яркость R,G,B светодиода

analogWrite(RED, rval);

analogWrite(GREEN, gval);

analogWrite(BLUE, bval);

}

}

}

Далее соединяем элементы, как вы делали в главе 6 (рис. 11.18). К плате Arduino присоединяем переходник ХВее и модуль ХВее.

Как и в предыдущем разделе, подключаем адаптер USB ХВее Explorer к компьютеру и запускаем программу на Processing (листинг 11.4).

Убедитесь, что файл hsv.jpg находится в папке data в каталоге программы. И не забудьте установить правильное имя последовательного порта.

Листинг 11.4. Программа на Processing для установки цвета RGB-светрдиода processing_control_RGB/processing_control_RGB.pde

import processing.serial.*;

PImage img;

Serial port;

// Подключение библиотеки serial

void setup()

{

size(640,256);

// Загрузка фоновой картинки

img = loadImage("hsv.jpg");

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

}

- 242 -

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

}

Рис. 11.18. Соединение Arduino и RGB-светодиода

- 243 -

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

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

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

 

11.4. Беспроводной дверной звонок

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

ПРИМЕЧАНИЕ

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

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

11.4.1. Разработка системы

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

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

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

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

- 244 -

Рис. 11.19. Структура системы беспроводного звонка

11.4.2. Оборудование для передатчика

Начнем с передатчика. Вам нужно подключить кнопку с резистором к цифровому входу платы Arduino с установленным на ней переходником с модулем ХВее (рис. 11.20).

Тип платы Arduino не имеет принципиального значения, но важно отметить, что последовательное соединение на плате Leonardo будет работать по-другому, нежели на Uno. На платах Uno и Micro один и тот же процессор управляет последовательным обменом и выполняет программу, а на Leonardo и Mega для этих целей

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

- 245 -

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

Программные различия рассмотрим далее.

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

Совет

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

11.4.3. Оборудование для приемника

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

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

- 246 -

Теперь необходимо выбрать тип платы Arduino и способ питания приемника. Я использовал плату Uno, подключенную к сетевому USB-адаптеру. Подойдет также батарея или USB-кабель, соединенный с компьютером. Функциональность приемника можно расширить, добавив светодиоды или компьютерное Processing-приложение.

11.4.4. Программа для передатчика

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

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

Код программы зависит от того, какую плату Arduino вы выбрали. Как уже упоминалось, в случае Arduino Uno контакты Rx/Tx (0/1) выполняют функции как UART, так и USB. При программировании Uno или Mega необходимо удалить переходник ХВее или задать на нем требуемое положение перемычек (переключателей).

При программировании платы Leonardo (или другой платы со встроенным USB-интерфейсом) отсоединять переходник ХВее не нужно.

Код листинга 11.5 написан для Arduino Leonardo, если у вас плата Uno, то замените в коде Seriall на Serial.

Листинг 11.5. Код передатчика для беспроводного дверного замка - doorbell/transmitting_arduino

// Код передатчика Arduino для беспроводного дверного замка

const int BUTTON =12; // Вывод кнопки к контакту 12

void setup()

{

//Для платы Leonardo выводы Rx/Tx

//не мультиплексированы с USB r

//Код для Leonardo (Seriall = RX/TX)

// Для UNO измените Seriall на Serial

Seriall.begin(9600);

}

void loop()

{

Seriall.println(digitalRead(BUTTON)); // Отправка статуса кнопки

// Небольшая задержка

delay(50);

}

В функции setup() последовательный порт подключается к модулю ХВее и начинает работать со скоростью 9600 бод. Каждые 50 мс происходит опрос цифрового

- 247 -

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

11.4.5. Программа для приемника

Программа для приемника сложнее, чем для передатчика. Текст программы приемника, приведенный в листинге 11.6, написан для платы Arduino Uno U. В случае платы Arduino Leonardo замените в коде serial на Seriall.

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

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

В функции setup() инициализируем подключение по последовательному порту.

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

Полный текст программы для приемника приведен в листинге 11.6. Загрузите программу на плату Arduino, не забыв перед этим переключить перемычки на переходнике ХВее (или отсоединить его).

Листинг 11.6. Программа для приемника беспроводного дверного замка - doorbell/receiving_arduino

// Код приемника беспроводного дверного замка

const int RED=11;

// Выход 11 - красный контакт RGB-светодиода

const int GREEN =10; // Выход 10 - зеленый контакт RGB-светодиода

const int SPEAKER =8; // Выход 8 подключения пьезоизлучателя

char data;

int onLED = GREEN;

- 248 -

int offLED = RED;

int freq = 131;

unsigned long prev_time = 0;

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

// и частоты звука

void setup()

{

Serial.begin(9600);

}

void loop()

{

// Для переключения звука и цвета светодиода

// прошло 100 мс?

if (millis() >= prev_time + 100)

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

if (onLED == GREEN)

{

onLED = RED;

offLED = GREEN;

}

else

{

onLED = GREEN;

offLED = RED;

}

// Переключение частоты звука

if ( freq == 261)

{

freq =131;

}

else

{

freq=261;

}

// Корректировка времени для переключения

// Текущее время становится предыдущим

prev_time = millis();

// Проверить наличие данных из последовательного порта

if (Serial.available() > 0)

{

// Чтение байта данных

data = Serial.read();

- 249 -

// Кнопка нажата - включаем звук и свет

if (data == '1')

{

digitalWrite(onLED, HIGH);

digitalWrite(offLED, LOW);

tone(SPEAKER, freq);

}

// Кнопка отпущена - выключаем звук и свет

else if (data == '0')

{

digitalWrite(onLED, LOW);

digitalWrite(offLED, LOW);

noTone(SPEAKER);

}

}

}

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

Второй оператор if() в цикле loop() проверяет наличие и значение входящих последовательных данных. Если приходит 0, свет и звук выключаются, если 1 - цвет и частота звука выставляются в соответствии со значениями переменных onLed, offLed, freq.

ПРИМЕЧАНИЕ

Посмотреть видеоурок, демонстрирующий работу беспроводного звонка, можно на странице http://www.exploringarduino.com/content/ch11. Этот видеофайл доступен также на сайте издательства Wiley.

Резюме

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

• Что выпускается множество разновидностей модулей ХВее.

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

• Как настроить модули ХВее из программы X-CTU (для ОС Windows) или с помощью терминала (для операционных систем Linux и Mac).

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

• Как установить беспроводную связь между компьютером и платой Arduino с помощью модулей ХВее.

• Как с помощью модулей ХВее организовать беспроводную связь между двумя платами Arduino.

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