Однажды мне повезло выкроить время на посещение мероприятия
Hard StartUp в рамках нашего провинциального
hackspace. Сам я от выступления категорически отказался под предлогом бессистемного расстройства вокабулярия к концу рабочего дня, но послушал выступающих с интересом; явно бросалось в глаза, что докладчики испытывали недостаток в пульте дистанционного управления презентацией: приходилось просить листать слайды сидящего за ноутбуком человека.
Ясно, что радиокружок хакспейс выруливает в основном за счет энтузиазма его активистов и базы ИТМО, и у ребят просто могло отсутствовать нужное оборудование. Уверен, что это было не последнее их мероприятие с проведением презентаций, поэтому предлагаю свой Arduino-вариант аналогичного устройства - надеюсь, оно пригодится не только им.
Ингредиенты
Сначала создадим
прототип - из того, что найдется под рукой. Мне всегда несколько проще, потому что у меня под рукой целый
mk90.ru/store ;)
|
1. Плата Freeduino32u4 - содержит единственный чип ATmega32u4, который может изображать из себя клавиатуру, и поэтому именно ее мы будем подключать к компьютеру с презентацией;
|
|
2. Плата Freeduino Nano - будет находиться в руке у докладчика, считывая нажатия на кнопки прокрутки и передавая их Freeduino 32u4;
|
|
3. Кнопки, проводки и пара беспаечных макеток, чтобы не хвататься за паяльник по пустякам.
|
|
4. Комплект модулей беспроводной связи - наверное, самые дешевые устройства для передачи низкоскоростного информационного потока через эфир для небольших расстояний.
|
Немного теории
Прежде всего, вот заранее мой ответ фанатикам
IEEE 802.11, на вопрос "почему в списке нет wifi?!":
не палите из пушки по микробам! В нашей задаче не нужна маршрутизация, одновременная коммуникация между несколькими устройствами и повышенная проникающая способность радиоизлучения. Нас устроят гораздо более простые устройства - т.н. RF-трансиверы. В основном, они отличаются мощностью, несущей частотой и способом модуляции. Возьмем недорогой маломощный модуль, используемый в самоходных радиоуправляемых игрушках и работающий на нелицензируемой в России частоте
433 МГц, с модуляцией
ASK.
"
ASK" означает, что
частота и фаза сигнала остаются
постоянными, а для кодирования единицы и нуля
варьируется амплитуда. Подобные приемники и передатчики можно собрать и самостоятельно, подробнее об этом можно прочесть, например у Алексея Кравченко в книге
"10 практических устройств на AVR, книга 2".
Однако, слабые места такого решения тоже выглядят внушительно:
- два передатчика, работающие на одной несущей частоте, будут конфликтовать, мешая друг другу;
- приемник не имеет возможности отличить посылку от одного передатчика от посылки другого - надо позаботиться об идентификации программным способом;
- сильная подверженность помехам, радиус действия зависит от питающего напряжения;
- практически нулевая безопасность, шифрование аппаратно не поддерживается.
Что-то решается программно, что-то - схемотехнически, но самое главное - такие приемопередатчики поддерживаются ArduinoIDE с помощью специальной библиотеки
VirtualWire.
Схема
Рисуем схему, которая будет подключаться к USB:
И ту, которая в руке у лектора (с кнопочками):
Предполагаем пока, что обе платы питаются от компьютера, через USB.
Макет
Как бы не ругали беспаечную макетку за надежность контактов, на несложных схемах работать с ней весьма удобно. Я использую сочетание жестких и гибких проводов (вообще, это дело вкуса - гибкими быстрее, но менее наглядно). С платой 32u4:
С платой Freeduino Nano:
Кнопки устанавливать я поленился, выбрав в качестве имитации их нажатия втыкание проводка в дырочку рядом с соответствующим контактом Nano (естественно, другим концом провод воткнут в GND).
Скетчи
Как уже упоминалось, существует библиотека
VirtualWire. Она будет делать за нас всю нудную работу - не только управлять приемником и передатчиком, но и кодировать наше сообщение помехоустойчивым кодом, а также считать/проверять контрольную сумму всего сообщения. Выбирая пины Arduino-совместимой платы для подключения приемника и передатчика, я вполне сознательно выбрал те, с которыми библиотека работает по умолчанию (помните об этом, если будете менять схему - не забудьте передать соответствующие параметры библиотеке).
Скетч
передатчика:
#include <VirtualWire.h>
#define buttonsCount 3
int bState[buttonsCount];
int bNum[buttonsCount] = {2,3,4};
void setup() {
// buttons
for (byte i=0;i<buttonsCount;i++) {
bState[i] = HIGH;
pinMode(bNum[i],INPUT); // для ясности, после сброса все пины и так уже входы
digitalWrite(bNum[i],HIGH); // pullup
}
// инициализируем последовательный порт - только для отладки
Serial.begin(9600);
// инициализируем библиотеку VirtualWire
vw_setup(2000); // скорость обмена в бит/сек
}
void loop() {
for (byte i=0;i<buttonsCount;i++) {
if (digitalRead(bNum[i])!=bState[i]) {
if (bState[i] == HIGH) {
char key[2] = {i+1,'\0'};
vw_send((uint8_t *)key, strlen(key));
vw_wait_tx();
bState[i] = LOW;
} else bState[i] = HIGH;
}
}
delay(100);
}
Перед началом использования кнопок, в
setup включаем подтягивающие резисторы (зачем нужны подтягивающие резисторы, я уже
писал). Далее, сканируем изменение состояния кнопки и, если она перешла из состояния "свободна" в "нажато", генерируем и передаем через беспроводной модуль сообщение с номером кнопки (единственный байт со значением 1, 2 или 3). Задержка в конце - примитивная борьба с дребезгом.
Скетч
приемника:
#include <VirtualWire.h>
#define KEY_LEFT 80
#define KEY_RIGHT 79
#define KEY_ESC 41
#define KEY_F5 62
void setup() {
pinMode(13, OUTPUT); // для индикации приема
vw_setup(2000); // скорость обмена в бит/сек
vw_rx_start(); // инициализация и запуск приемника
}
void loop() {
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) // неблокирующее чтение
{
digitalWrite(13, HIGH); // Зажигаем светодиод L - принято сообщение
byte key = buf[0];
if (key==1) Keyboard.print(' ');
else {
{
KeyReport kbd = {0};
if (key==2) kbd.keys[0] = KEY_LEFT;
else kbd.keys[0] = KEY_RIGHT;
Keyboard.sendReport(&kbd);
}
{
KeyReport kbd = {0};
Keyboard.sendReport(&kbd);
}
}
digitalWrite(13, LOW);
}
delay(200);
}
Этот скетч будет корректно работать (и вообще скомпилируется) только с последним пропатченным
ядром ArduinoIDE для Freeduino 32u4 - там функция
sendReport сделана публичной, чтобы скетч был способен генерировать нажатия не только на символьные клавиши (буква 'A', цифра '8' или пробел), но и управляющие коды - (стрелки, F-клавиши и т.п.). После вызова
sendReport с кодом нажатой клавиши, нужно всегда делать еще один, чтобы сообщить о ее отпускании, в противном случае через некоторое время получим режим повтора.
В данном скетче кнопка №1 транслируется в пробел, кнопка №2 - стрелка влево, кнопка №3 - стрелка вправо. Функция vw_get_message вернет нам полученное сообщение только в том случае, если совпала подсчитанная контрольная сумма - но для нас это полностью прозрачно, просто учитывайте, что она избавляет нас от необходимости проверять достоверность принятой информации с точки зрения эфирных искажений нашего примитивного ASK-сигнала ;)
Roadmap
Итак, макет завелся. Что дальше?
Устройства для реальной жизни можно делать и на основе готовых плат Freeduino, и с помощью ЛУТ-а. Но имейте ввиду, что ATmega32u4 выпускается только в SMD (в отличие от ATmega328P).
По питанию приемника все понятно - экономить не надо. А вот с передатчиком придется повозиться - продумать батарейную схему питания, позаботиться об экономном расходовании ее ресурса.
Наконец, если будут донимать помехи, можно попробовать улучшить помехоустойчивость (повторять сообщение о нажатии в эфир несколько раз или припаять антеннки).
Все это вы уже можете начинать самостоятельно или же подождать моего продолжения, если когда оно появится ;)