Простое управление приборами с компьютера.

Многие из нас наверно хотели бы управлять электрическими цепями через компьютер. А что? Неплохо было бы. Представь, звонит тебе друг, говорит: «Через 20 мин буду», тут проходит 20 минут, звонок в двери, но как не хочется вставать из-за компьютера, идти открывать двери и т.д. А представь иную ситуацию: звонок в двери, тут у тебя на мониторе выползает сообщение типа «У Вас гости», ты нажимаешь кнопку на компьютере - открывается магнитный замок на дверях, и ты орешь на весь дом: «Заходи», или тебе нужно включить электрочайник, свет или еще что то. В наше время это уже не фантастика, а вполне реалистично, только вот из-за плохой экономики далеко не каждый может позволить себе даже самый простейший «смарт-хаус», но если есть желание и прямые руки, то можно запросто сделать управление электрическими цепями через ПК.

В наше время достаточно много людей умеет программировать, они могут написать программку под компьютер, которая смогла бы управлять внешними устройствами, но как подключить тотже электрочайник к компьютеру? Ну, можно, к примеру, через LPT порт, только вот его уже редко где можно увидеть, что тогда остается? USB!!!

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

Итак, из чего же мы будем его делать? Те, кто интересовался данным вопросом, наверно уже слышали о модуле Ke-USB24A.

Описание:

Модуль Ke-USB24A предназначен для сопряжения внешних цифровых и аналоговых устройств, датчиков и исполнительных механизмов с компьютером через шину USB. Определяется как дополнительный (виртуальный) COM порт. Модуль имеет 24 дискретные линии ввода/вывода (либо лог. 0 либо лог. 1) с возможностью настройки направления передачи данных (вход/выход) и встроенный 10-ти разрядный АЦП. Для управления модулем предусмотрен набор текстовых команд управления (KE - команды).

Отличительные особенности:

  • интерфейсный модуль для сопряжения по шине USB
  • определяется ОС Windows/Linux как виртуальный COM порт
  • не требует дополнительных схемных элементов, сразу готов к работе
  • 24 дискретные линии ввода/вывода с возможностью независимой настройки направления передачи данных (вход/выход) и сохранения настроек в энергонезависимой памяти модуля
  • встроенный 10-ти разрядный АЦП с гарантированной частотой дискретизации до 400 Гц.
  • динамический диапазон напряжения входного аналогового сигнала для АЦП от 0 до 5 В.
  • набор готовых текстовых команд управления высокого уровня (KE - команды)
  • удобный форм-фактор в виде модуля с DIP-колодкой и разъемом USB-B
  • возможность питания как от шины USB, так и от внешнего источника питания (режим выбирается джампером на плате)
  • возможность сохранения данных пользователя в энергонезависимой памяти модуля (до 32 байт)
  • возможность изменения строкового дескриптора USB устройства
  • каждый модуль имеет уникальный серийный номер доступный программно
  • поддержка ОС Windows 2000, 2003, XP 32/64 bit, Vista 32/64 bit и Windows 7 32/64 bit
  • поддержка OS Linux

Вроде бы это то, что нам нужно, НО… цена этого чуда начинается от $40. Наверно у вас уже пропало желание его покупать.

Давайте лучше сами соберем подобный модуль, только чтобы он был доступный даже голодному студенту!

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

В качестве микроконтроллера возьмем широко распространенный ATmega8 (без индекса L в конце). Характеристики нашего модуля будут такие:

  • Подключение к ПК через USB.
  • определяется ОС Windows как USB HID устройство, не требующее драйверов .
  • Сразу готов к работе.
  • 7 линий вывода с логическим состоянием (активен / неактивен).
  • 2 линии вывода с плавным управлением напряжения от минимума до максимума. Только это не ЦАП (цифро-аналоговый преобразователь) а ШИМ (широтно-импульсная модуляция). Но с помощью фильтра можно легко превратить в ЦАП.
  • 7 линий ввода с логическим состоянием (активен / неактивен).
  • 1 АЦП (аналогово-цифровой преобразователь) с возможностью подключения внешнего источника опорного напряжения (ИОН).
  • Возможность заливать новую прошивку прямо через USB.

Почему я выбрал именно HID, а не виртуальный COM порт (CDC)? Во-первых, не нужны драйвера, во-вторых, HID в несколько раз меньше грузит микроконтроллер, чем CDC, так как данные запрашиваются не постоянно, а только тогда, когда этого требует хост (компьютер), и вообще, COM порт уже отмирает, сейчас аппаратных COM портов уже практически нет, остались только виртуальные. Логические линии вывода предназначены для управления только двумя состояниями - включенный или выключенный, при выключенном на выходе (ножке микроконтроллера) будет 0В при включенном - 5В, сюда вы можете подключить просто светодиод и управлять ним с ПК, а можете подключить реле (через транзистор) и управлять более мощной нагрузкой (освещение и т.д.). Линии вывода с регулировкой напряжения (ШИМ выход) позволяют плавно менять напряжение на ножке микроконтроллера от 0В до +5В с шагом 5/1024В. Линии ввода с логическим состоянием предназначены для мониторинга состояния кнопок, ключей и т.д. Когда линия замкнута на землю (корпус, GND), ее состояние = 0, если не замкнута - 1. АЦП позволяет измерять напряжение, сюда можно подключить потенциометр, аналоговый термодатчик, или еще что то, только напряжение, на этой ножке не должно превышать напряжение питания. В качестве источника опорного напряжения для АЦП можно использовать как внешний ИОН, так и напряжение питания модуля. Чтобы при перепрошивке не приходилось подключать микроконтроллер к программатору, сделаем возможность заливки прошивки прямо через USB, без использования внешнего программатора.

Схема устройства:

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

Печатная плата:

Ну и в результате получилось вот что:

Теперь разберемся, что куда будем подключать.

  1. USB - Порт. Думаю, его все знают.
  2. Индикатор питания.
  3. Логический вход 1.
  4. Логический вход 2.
  5. Логический вход 3.
  6. Логический вход 4.
  7. Логический вход 5.
  8. Логический вход 6.
  9. Логический вход 7.
  10. Вход АЦП.
  11. Вход для подключения ИОН.
  12. Этот контакт подключен к питанию устройства. Замкните перемычкой 12 и 13 контакты, чтобы напряжение ИОНа было равно напряжения питания.
  13. Логический выход 1.
  14. Логический выход 2.
  15. ШИМ выход 1.
  16. ШИМ выход 2.
  17. Логический выход 3.
  18. Логический выход 4.
  19. Логический выход 5.
  20. Логический выход 6.
  21. Логический выход 7.

Что такое GND?

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

Программа для микроконтроллера.

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

Итак, в исходниках находится файл usbconfig.h , в нем есть строки

#define USB_CFG_VENDOR_ID 0x10, 0x00

#define USB_CFG_DEVICE_ID 0x01, 0x00

#define USB_CFG_VENDOR_NAME "k","i","b","e","r","m","a","s","t","e","r",".","p","l",".","u","a"

#define USB_CFG_VENDOR_NAME_LEN 17

#define USB_CFG_DEVICE_NAME "U","S","B","-","C","o","n","t","r","o","l"

#define USB_CFG_DEVICE_NAME_LEN 11

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

Прошивка устройства.

В скачанных файлах в папке MCUusb_bootloader найдите файл main.hex - это usb-bootloader, его нужно залить в МК с помощью внешнего программатора. После заливки также нужно правильно установить фьюзы, в окне программатора STK500 должно выглядеть так:

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

После удачной прошивки, можно попробовать прошить устройство через бутлоадер. Как он работает? При включении МК (просто при подаче питания, или после ресета) сразу запускается бутлоадер, он проверяет условие, если оно истинно, то запускается инициализация бутлоадера (компьютер при этом находит устройство). В качестве условия у нас будет «Логический вход 1 = 0″, то есть, чтобы запустить бутлоадер, нужно замкнуть Логический вход 1 на GND и нажать на устройстве кнопку RESET, в диспетчере устройство должно появиться новое HID устройство, так же не требующее драйверов:

Такс, теперь в папке MCUUSB_Controldefault запускаем файл boot.bat , должно выскочить окошко, в котором будут бегать циферки:

Если окно сразу же закрылось, тогда вы сделали что то, не правильно. Если же все ок, тогда внешний программатор для этого устройства Вам уже не понадобится. Теперь можете отключить Логический вход 1 от GND. И на всякий случай, нажмите RESET. В диспетчере устройств так же должно появиться HID устройство (компьютер напишет, что найдено новое). Убедитесь, что в диспетчере появилось именно это устройство.

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

Для программистов Delphi написать программу управления HIDом не составит проблем, так как в интернете куча информации. А вот программистам C++ Builder не все так сладко, но, как оказалось, не так все и плохо. В интернете я нарыл библиотеку hidlibrary.h, вот с ее помощью мы будет работать с HID устройством.

Скачайте исходники и запустите USB Control.cbproj (C++ Builder 2010).

В файле hidlibrary.h в самом верху есть строка

Создадим форму, на форме будет один CheckListBox для управления логическими выходами, 2 ScrollBar для управления ШИМ каналами, один ListBox для отображения логических входов, один Label для отображения состояния АЦП и один таймер. Должно получиться вот такое:

Переименуйте СкрулБары в ScrollBar_PWM1 и ScrollBar_PWM2, в их свойствах установите Max=1023.

Создадим структуру

#pragma pack (push, 1)

struct status_t{

unsigned char logical_outputs;

unsigned char logical_inputs;

unsigned char ADC_DATA;

unsigned short int PWM1;

unsigned short int PWM2;

struct status_t DeviceStatus;

#pragma pack (pop)

#pragma pack нужна чтобы компилятор не выравнивал структуру. В logical_outputs хранятся состояние всех логических выходов, в побитном режиме, то есть, первый бит хранит состояние первого выхода, второй - второго и так до седьмого. Аналогично logical_inputs хранит состояние логических входов. В ADC_DATA хранится состояние АЦП, минимальное значение 0, максимальное - 255. В PWM1 хранится состояние первого ШИМ выхода (плавная регулировка напряжения), в PWM2 - состояние второго, минимальное значение 0, максимальное - 1023.

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

HIDLibrary hid;

И добавляем функцию connect().

Теперь данные с HID-устройства можно запросить с помощью функции hid.ReceiveData, указав в качестве параметра указатель на структуру, только перед запросом нужно проверить, подключено ли устройство:

А теперь давайте допишем нашу программу (или просто скачайте исходники, там все готовое).

Добавьте где нить в коде (лучше сразу после структуры) эти строки:

В свойствах таймера укажите Enabled = True, Interval = 500. Щелкните по нему дважды и в обработчике напишите

if (!connect()) return; // Выходим, если устройство не подключено

hid.ReceiveData(&DeviceStatus); // Читаем данные с устройства

for (char i = 0; i < 7; i++)

CheckListBox_LogOuts->Checked[i] = CheckBit(DeviceStatus.logical_outputs, i);

ScrollBar_PWM1->Position = DeviceStatus.PWM1;

ScrollBar_PWM2->Position = DeviceStatus.PWM2;

ListBox_LogInputs->Clear();

for (char i = 0; i < 7; i++)

ListBox_LogInputs->Items->Add(" Лог. вход "+IntToStr(i+1)+" = "+BoolToStr(CheckBit(DeviceStatus.logical_inputs, i)));

Label_ADC->Caption = DeviceStatus.ADC_DATA;

Думаю, тут все понятно и объяснений не требует.

Кликните дважды по CheckListBox, в обработчике напишите

Все, можно компилировать!

Тест-драйв.

Итак, все готово: устройство собрано, микроконтроллер прошит, программа для компьютера создана, можно протестировать.

Подключите устройство к ПК, запустите программу. Слева в листбоксе отображается состояние всех логических входов, если, к примеру, Логический вход 1 не замкнут на GND, тогда будет написано «Лог. вход 1 = -1″, если подключен, то «Лог. вход 1 = 0″. Вот скрин:

Под этим листбоксом отображается результат преобразования АЦП. Замкните вход АЦП на минус, тогда результат будет равен 0, замкните на + питания, результат будет 255. Можно подключить сюда потенциономер, или еще что. Напряжение на ножке АЦП можно вычислить по формуле: Напряжение_ИОН/255*результат_АЦП .

Теперь подключите какую то маленькую нагрузку к Логическом выходу 1 (светодиод или просто вольтметр). Поставьте галочку возле "Лог. выход 1" - светодиод загорится.

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

Завершение.

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



Как вам эта статья?

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

Схема устройства

За исходную схему была взята одна из схем , найденных в Internet и выглядела она вот так:

Но только с небольшим изменением: между 1-ым пином оптопары 4N25 и 2-ым пином LPT был добавлен резистор на 390 Ом, и еще добавлен светодиод для индикации включения. Схема была собрана в тестовом режиме, т.е. просто соединена проводами так как нужно и проверена. В этом варианте она просто включала и выключала старый советский фонарик.
Было решено, что если уже делать управление, то не для одного устройства, а минимум на 4 устройства (из расчёта: одна лампа на столе, люстра на два выключателя, запасная розетка). На данном этапе стало необходимо построение полной схемы устройства, начался выбор различных программ.
Были установлены:

  1. KiCAD
  2. Eagle
Посмотрев все их них я остановился на Eagle, так как в его библиотеке были «похожие» детали. Вот что получилось в нем:

На схеме использован порт DB9 т.е. обычный COM порт, это сделано из соображений экономии как места на плате, так и самих разъёмов (COM"вские у меня были), а так как мы будем использовать только 5 проводников, то этого нам хватит с запасом. Таким образом делаем еще и переходник с DB25 (LPT) на DB9 (COM), в моем случае делается он следующим образом:
LPT 2-9 pin = COM 1-8 pin - это управляющие пины данных;
LPT 18-25 pin (зачастую они соединены между собой) = COM 9 pin - это наша земля.
Так же в схеме используется дополнительное питание на 12В для питания реле, по плану это будет простое китайское зарядное или может быть крона на 9В (одно реле срабатывает нормально, надо проверить на 4 одновременно). Отдельное питание и гальваническая развязка с помощью оптопары используется для того чтобы обезопасить порт компьютера. При желании можно конечно запитаться от 12В блока питания компьютера, но это каждый делает сам и на свой страх и риск.

Необходимые детали для создания устройства
  1. COM порт - 1 шт
  2. коннектор питания - 1 шт
  3. светодиод зелёный - 4 шт
  4. оптопара 4n25 - 4 шт
  5. посадочное место под оптопару (у меня было только на 8 ног) - 4 шт
  6. резистор 390 Ом - 4 шт
  7. резистор 4,7 кОм - 4 шт
  8. транзистор КТ815Г - 4 шт
  9. реле HJR-3FF-S-Z - 4 шт
  10. зажимы на 3 контакта - 4 шт
  11. фольгированный текстолит

Подготовка схемы печатной платы

Попытавшись использовать Eagle для подготовки печатной платы я понял, что это будет сложновато и решил найти более простой вариант. Этим вариантом стала программа sprint layout 5 пусть она и в исполнении для windows, но без проблем запускается в wine под linux. Интерфейс у программы интуитивно понятный, на русском языке и в программе имеется достаточно понятная помощь (help). Поэтому все дальнейшие действия по разработке печатной платы производились в sprint layout 5 (далее SL5).
Хоть и многие используют данную программу для разработки плат своих устройств, в ней не оказалось необходимых мне деталей (даже в куче скачанных коллекций макросов). Поэтому пришлось сначала создать недостающие детали:
  1. COM порт (тот что был не совпал с моим, по отверстиям крепления)
  2. гнездо питания
  3. зажим на три контакта
  4. реле HJR-3FF-S-Z
Вид этих деталей:

После добавления необходимых деталей началось само проектирование печатной платы. Проходило оно в несколько попыток, было их около пяти. Каждый вариант платы печатался на картоне прокалывались отверстия и в них вставлялись детали. Собственно так и было выяснено, что мой COM порт не совпадает с тем который был в SL5. Так же всплыла небольшая ошибка в схеме реле - реально корпус реле был сдвинут на 2-3 мм. Естественно все ошибки были исправлены.
На первом печатном варианте выяснилось еще и не правильное подключение транзистора, были перепутаны два контакта.
После всех исправлений и подгонок получилось плата следующего вида:

В SL5 есть функция «Фотовид» для просмотра платы, вот как она выглядит в нем:

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

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

Подготовка печатной платы

Плату решено было делать методом ЛУТ (лазерно-утюговая технология). Далее весь процесс в фото.

Вырезаем необходимого размера кусок текстолита.

Берем самую мелкую наждачку и аккуратно зачищаем медную поверхность.

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

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

Далее необходимо подготовить раствор для травления. Я использовал для этого хлорное железо. На банке с хлорным железом написано, что раствор необходимо делать 1 к 3. Я немного отступил от этого и сделал 60 г хлорного железа на 240 г воды, т.е. получилось 1 к 4, не смотря на это травление платы происходило нормально, только немного медленнее. Обратите внимание на то, что процесс растворения сухого хлорного железа в воде идёт с выделением тепла, поэтому всыпать его в воду необходимо небольшими порциями и размешивать. Естественно для травления необходимо использовать не металлическую посуду, в моем случае это была пластиковая ёмкость (вроде от селёдки). У меня получился вот такой раствор:

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

Весь процесс травления у меня занял 45 минут, хватило бы и 40 минут, но я был просто занят ещё одним делом.
После травления промываем плату с мылом отрываем скотч с леской и получаем:

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

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

Первое устройство подошло

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

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

После сверления необходимо провести лужение платы. Для этого я использовал старый способ - паяльник, флюс ТАГС и олово. Хотелось попробовать с использованием сплава Розе, но его не найти у нас в городе.

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

Далее необходимо промыть плату для удаления остатков флюса, так как ТАГС водоотмывной, то делать это можно или водой или спиртом. Я сделал что-то среднее - отмывал старой водкой и протирал ватными палочками. После всех этих действий наша плата готова.

Монтаж деталей

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

После монтажа деталей идём и подключаем устройство к компьютеру через LPT, для этого спаян переходник с DB25(LPT) на DB9(COM) в следующем виде:

  • 2 пин DB25 к 1 пину DB9
  • 3 пин DB25 к 2 пину DB9
  • 4 пин DB25 к 3 пину DB9
  • 5 пин DB25 к 4 пину DB9
  • 6 пин DB25 к 5 пину DB9
  • 7 пин DB25 к 6 пину DB9
  • 8 пин DB25 к 7 пину DB9
  • 21 пин DB25 (можно любой с 18 по 25) к 9 пину DB9
Так как в качестве провода использовалась обычная витая пара, то не хватило одного проводка, но для данного устройства достаточно только пяти проводов, так что данный вариант подходит. В качестве включаемой нагрузки у нас выступает простой советский фонарик. Ну и в качестве блока питания - универсальный китайский блок питания (4 коннектора и питание от 3 до 12 в). Вот все в сборе:

А вот уже устройство работает:

На этом закончился ещё один вечер и монтаж остальных деталей был оставлен на следующий день.

А вот и уже полностью собранное устройство:

Ну и небольшое видео о том как это работает (качество не очень, не было чем снять нормально)

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

Программная часть

Естественно для управления LPT портом нужно какое-то ПО, но так как у меня дома linux, то было решено просто написать простейшую программку самому, а в последствии её уже дописать и адаптировать как надо. Выглядела она примерно так:
#include
#include
#include
#include
#define BASE 0x378
#define TIME 100000
int main ()
{
int x = 0x0F;
int y = 0x00;
if (ioperm (BASE, 1, 1))
{
perror ("ioperm()");
exit (77);
}
outb (x, BASE);
return 0;
}

Данная программка отправляет в LPT порт 0x0F = 00001111, т.е. подает 1 на 2-5 пины (Data0-Data3), а это и есть наше управляющее напряжение между 2-5 пинами и землей (18-25 пины), таким образом будут включаться все четыре реле. Точно так же действует программа для отправки 0x00 в порт для отключения, просто вместо x отправляется y - outb (y, BASE). Еще можно прочитать состояние порта:
#define BASEPORT 0x378 /* lp1 */
...
printf("статус: %d\n", inb(BASEPORT));
...

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

В последствии программа была доработана так, что бы передавая ей параметры командной строки можно было указывать с каким устройством и что сделать.
Вывод «sw --help»:
Программа для управления реле через LPT порт.
У программы может быть один или два параметра.
Формат параметров: sw [номер устройства] [действие]
номер устройства - от 1 до 8
действие - "on", "off", "st" - включение, выключение, статус
Пример: "sw 2 on" для включения второго устройства или "sw --help" для вывода помощи

PS если кому понадобится, то потом могу где-нибудь выложить файл схемы платы в sl5 и исходник программки управления.

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

Схема устройства показана на рис.1. Его основа - микросхема 74HC595, представляющая собой 8-разрядный сдвиговый регистр с последовательным вводом и последовательным и параллельным выводами информации. Параллельный вывод осуществляется через буферный регистр с выходами, которые имеют три состояния. Информационный сигнал подают на вход SER (вывод 14), сигнал записи - на вход SCK (вывод 11), а сигнал вывода - на вход RSK (вывод 12). На микросхеме DA1 собран стабилизатор напряжения 5 В для питания регистра DD1.

Рисунок 1. Схема устройства

Устройство подключают к одному из СОМ-портов компьютера. Информационные сигналы поступают на контакт 7 розетки XS1, сигналы завиписи информации - на контакт 4, а сигналы вывода информации - на контакт 3. Сигналы СОМ-порта согнласно стандарту RS-232 имеют уровни около -12 В (лог.1) и около +12 В (лог.0). Сопряжение этих уровней с входными уровнями регистра DD1 выполнено с помощью резисторов R2, R3, R5 и стабилитронов VD1-VD3 с напряжением стабилизации 5,1 В.

Сигналы управления внешними приборами формируются на выходах Q0-Q7 регистра DD1. Высокий уровень равен напряжению питания микросхемы (около 5 В), низкий - менее 0,4 В. Эти сигналы являются статическими и обновляются на момент поступления высокого уровня на вход RSK (вывод 12) регистра DD1. Светодиоды HL1-HL8 предназначены для наблюдения за работой устройства.

Управление устройством осуществляется с помощью разработанной автором программы UmiCOM. Внешний вид главного окна программы показан на рис.2.

Рисунок 2. Внешний вид программы UniCOM

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

Управление приборами можно осуществлять и с помощью внешних контактных датчиков, которые подключают к входам 1-3 и линии +5 В. Они должны работать на замыкание или размыкание контактов. Пример схемы подключения датчиков показан на рис.3.

Рисунок 3. Подключение контактных датчиков

При нажатии на экранную клавишу "Настройка входов" открывается окно "Согласование входов и выходов" (рис.4. ), где выбирают входы, которые будут изменять состояние выходов. Имитировать работу входов можно нажимая на экранные клавиши "1", "2", "3" основного окна программы. В тех случаях, когда приборами нельзя управлять с помощью логических уровней, следует применить реле, схема подключения которого показана на рис.5 , или транзисторную оптопару (рис.6. ).

Рисунок 4. Согласование входов и выходов

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

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

Большинство деталей монтируют на печатной плате из односторонего фольгированного стеклотекстолита толщиной 1...1,5 мм, чертеж которой показан на рис.7. Резисторы R1-R6 монтируют на выводах розетки XS1.

Рисунок 7. Чертеж печатной платы

В устройстве применены резисторы С2-23. МЛТ, оксидные конденсаторы - К50-35 или импортные, розетка XS1 - DB9F. Помимо указанных на схеме стабилитронов, можно применить BZX55C5V1 или отечественные КС174А, светодиоды - любые. Питают устройство от стабилизированного или нестабилизированного источника питания нпаряжением 12 В и током до 100 мА.

Устройство компьютерного управления
различными приборами, схема которого показана на рис. 1, функцио­нально подобно
описанному в , но подключается к USB-порту компьюте­ра, который (в отличие
от СОМ-порта) сегодня есть в каждом из них. Единственная мик­росхема устройства
- распространенный мик­роконтроллер ATmega8. Он необходим для орга­низации
связи по шине USB. Хотя в нем и отсут­ствует специализирован­ный аппаратный
модуль, эта функция выполняется программно. Резистор R1, подклю­ченный между
положи­тельным выводом источ­ника питания и линией D-шины USB, переводит ее в низкоскоростной
режим LS со скоростью обмена 1,5 Мбит/с, что и позво­ляет расшифровывать по­сылки
компьютера про­граммным способом. Ре­зисторы R4 и R5 устра­няют переходные
процес­сы, возникающие при об­мене информацией, что увеличивает стабильность работы.
Конденсатор С1 блокирует импульсные по­мехи в цепи питания, что также улучшает
стабиль­ность работы устройства. Диоды VD1 и VD2 служат для понижения напряже­ния
питания микроконт­роллера приблизительно до 3,6 В - это требуется для
согласования уровней с шиной USB. Сигналы управления приборами формируются на
выходах РВ0-РВ5 и РС0, РС1 микроконтроллера. Высокий логический уровень -
напряжение око­ло 3,4 В. Напряжение низкого уровня близко к нулю. К выходам
можно под­ключать приборы, потребляющие ток не более 10 мА (от каждого выхода).
Если требуются большие значения тока или напряжения, то следует использовать узлы
согласования, показанные в на рис. 5 и 6.

Устройство собрано на макетной плате,
печатная не разрабатывалась. Применены резисторы МЛТ, конденса­торы С2 и С3 -
керамические высоко­частотные, С1 - К50-35 или аналогич­ный импортный. Диоды
кремниевые с падением напряжения на переходе около 0,7 В. Программа для микро­контроллера
разработана в среде Bascom-AVR версии 1.12.0.0. Для работы с шиной USB
использована библиотека swusb.LBX, которая выполняет программное декодирование сигналов
USB в режиме реаль­ного времени. Полученный в результате компиляции код программы
из файла с расши­рением HEX следует загрузить во FLASH-память микроконт­роллера.
Для этого был ис­пользован программатор совместно со встроенной в Bascom-AVR
утилитой. Состоя­ние разрядов конфигурации микроконтроллера должно со­ответствовать
показанному на рис. 2. При первом подключении устройства к компьютеру опе­рационная
система обнаружит новое USB HID совместимое устройство с именем
“uniUSB” и установит необходимые драйверы. Через несколько се­кунд
устройство настроено и готово к использованию.

Для работы с ним была создана программа
UniUSB. Она пред­ставлена в двух вариантах: для 32-разрядных (х86) и 64-раз­рядных
(х64) операционных систем семейства Windows. Работа 32-разрядной версии проверена
в операционных системах Windows 98, Windows ХР, Windows 7, а 64-разрядной -
только в Windows ХР х64. Программа UniUSB написана на языке PureBasic (версия
4.31) с исполь­зованием библиотеки пользовательс­ких функций HID_lib,
поддерживающей работу с USB HID устройствами. Внеш­ний вид окна программы
показан на рис. 3. В одной папке с ее исполняемым файлом должен находиться
файл, называющийся UniUSB_Код.txt или UniCOM_Код.txt. Последний вариант необходим
для совместимости с про­граммой UniCOM, предложенной в . В этом файле
хранится сценарий управ­ления внешними приборами. При запуске программы данные
из файла загружаются в таблицу, расположенную в главном окне, а при завершении
рабо­ты сохраняются в файле. Щелчок левой кнопкой мыши по ячейкам таблицы поз­воляет
изменять их состояние: 1 - высокий логический уровень, 0 или пусто - низкий
логический уровень. Для добавления или удаления столбца таблицы нужно по ней
щелкнуть правой кнопкой мыши и в появившемся меню выбрать требуемое действие.

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

Учтите, операционная система Windows
- многозадачная! Это означает, что процессорное время делится между множеством
иногда скрытых от пользователя процессов, которые вы­полняются по очереди с
учетом уста­новленных в системе приоритетов. По­этому не стоит ожидать большой
точно­сти выдерживания интервалов времени менее 100 мс. Для кратковременной
остановки пе­ребора столбцов используйте кнопку Повторное нажатие на нее
продолжит перебор с места остановки. Кнопка полностью прекращает перебор столб­цов
таблицы. Если в процессе обмена информацией между компьютером и устройством
произойдет сбой либо уст­ройство будет отключено от разъема USB компьютера,
программа сообщит об ошибке, выведя в строке состояния соответствующее
сообщение.

ЛИТЕРАТУРА

1. Носов Т. Управление приборами
через СОМ-порт компьютера. - Радио, 2007, № 11,0.61,62.

2. Рыжков А. US-программатор
микро­контроллеров AVR и AT89S, совместимый с AVR910. - Радио, 2008, № 7, с.
28, 29.

От редакции . Программы для микро­контроллера и компьютера находятся
на нашем FTP-сервере по адресу ftp:// ftp.radio.ru/pub/2011/02/uniUSB.zip

В статье сделана попытка предоставить пошаговую инструкцию - как соединить самодельное устройство USB HID на микроконтроллере AVR и компьютер с операционной системой Windows 7 x64 , чтобы обмениваться данными и управлять портами микроконтроллера. Пример приложения управляет через USB ножкой порта микроконтроллера (к ней подключен индикационный светодиод). Есть возможность также прочитать состояние состояние светодиода - потушен он или горит. Топик предназначен для новичков, поэтому большая просьба к знатокам программирования - приберегите тухлые яйца и гнилые помидоры иронические комментарии для более удобного случая.

Используемое программное обеспечение

1 . Для микроконтроллера - библиотека V-USB компании Objective Development и IDE Atmel Studio 6 компании Atmel. Нужно также скачать и установить тулчейн WinAVR для компиляции firmware микроконтроллера (для спецов это необязательно, потому что можно обойтись тулчейном, который входит в состав Atmel Studio).
2 . Для написания программы Windows (ПО хоста) использовалась библиотека LibUsbDotNet Тревиса Робинсона и IDE Visual Studio C# 2010 компании Microsoft.

Все программное обеспечение, кроме Visual Studio 2010, бесплатное, хотя есть возможность использовать Visual Studio C# 2010 Express бесплатно в течение ограниченного срока. Все действия проводились в среде операционной системы Windows 7 x64, но наверняка подойдет и любая другая операционная система семейства Windows (Windows XP и более свежая).

Используемое железо

Благодаря библиотеке V-USB для создания устройства USB HID подойдет любой микроконтроллер AVR. Если Вы дружите с паяльником, то даже можете собрать подключение к USB самостоятельно по одной из опубликованных схем. Такая схема (взята из пакета V-USB ) в качестве примера приведена на картинке.

Чтобы экономить время и усилия, лучше использовать готовую макетную плату. Особенно удобно, если в плату будет записан USB-загрузчик (bootloader), тогда не понадобится покупать программатор для перепрошивки платы. Я использовал макетную плату AVR-USB-MEGA16 с микроконтроллером ATmega32A, в ней загрузчик есть (USBasploader, эмулирующий поведение программатора USBasp). Вот так платка выглядит в натуральную величину:

Можно взять также metaboard (на нем стоит ATmega168 или ATmega328), или даже программатор на микроконтроллере ATmega8. Подобные железки можно дешево купить на ebay.com или dx.com .

Создание firmware микроконтроллера с помощью Atmel Studio 6 и библиотеки V-USB

Сделайте новый проект в Atmel Studio 6 (далее просто AS6). Когда AS6 предложит выбрать микроконтроллер, выберите Atmega32 без буквы A , не Atmega32A (хотя на плате стоит Atmega32A ) - это важно, так как тулчейн WinAVR не видит разницы, он знает только Atmega32. Эти микроконтроллеры по внутреннему устройству идентичны, так что для нас разницы нет, а для AS6 есть.

Теперь нужно правильно настроить компилятор. В верхнем меню AS6 нажите Tools , далее Options.. и появится вот такое окно:

Слева в списке выберите Toolchain . Справа появится список Flavours. Этим словечком Atmel закодировала возможные варианты используемого инструментария (тулчейны).

Примечание. В списке уже присутствует тулчейн Native, который используется по умолчанию (Default). Тулчейн Native - это компилятор GCC вместе с заголовочными файлами и библиотеками, которые предоставляют необходимую среду компилирования исходного кода для микроконтроллера. Этот тулчейн предоставила Atmel, он устанавливается автоматически вместе с установкой AS6. Как я уже упоминал, для компиляции можно использовать и этот тулчейн, но тогда в исходный код примеров V-USB (на основе примера USB HID будет работать наше устройство USB) придется вручную вносить исправления. Они несложные, но для новичков будет лучше добавить сюда тулчейн WinAVR, и использовать для компиляции именно его.
Для добавления в список Flavours тулчейна WinAVR нажмите кнопку Add Flavour , появится следующее окно:

В верхней строчке этого окна введите имя компилятора WinAVR (произвольное), а в нижней строке введите полный путь, куда установлен сам компилятор тулчейна (с указанием папки \bin) и нажмите кнопку Add . В списке Flavours появится добавленный компилятор, как показано на скриншоте.

Выделите мышкой наш новый добавленный компилятор WinAVR и нажмите кнопку Set As Default (сделать его тулченом по умолчанию), и нажмите OK. После этой процедуры наша AS6 будет использовать компилятор WinAVR.

Пора настроить свойства нашего проекта, для этого курсором в Solution Explorer левым щелчком выберите имя проекта и нажмите Alt+F7 (меню Project -> Properties), появится окно с настройками:

Сделайте следующие настройки:

  • В разделе AVR/GNU C Compiler -> Symbols добавляем в поле -D строчку F_CPU=12000000UL - это соответствует частоте микроконтроллера 12 МГц (такой кварц установлен на моей макетной плате AVR-USB-MEGA16).
  • В разделе AVR/GNU Assemler -> General в поле Assembler flag надо добавить -DF_CPU=12000000UL .
  • В разделе AVR/GNU C Compiler -> Optimization в поле Optimization Level должно стоять Optimize for size (-Os) .
Далее очень важный момент - в левой части окна, в списке выберите раздел Advanced , как показано на рисунке ниже.

В выпадающем списке Toolchain Flavour выберите добавленный компилятор WinAVR, чтобы при компилировании проекта AS6 использовала его. На этом настрока AS6 закончена.

Далее необходимо в созданный проект добавить файлы исходного кода проекта - см. папку firmware\VUSB, файлы VUSB.c, usbdrv.c, usbdrvasm.S и oddebug.c. Проект ASS6 создан на основе одного из примеров библиотеки V-USB: hid-custom-rq, который изначально компилировался с помощью утилиты make из командной строки. На основе библиотеки V-USB можно найти много других примеров кода - в основном это устройства USB HID (мыши, клавиатуры, устройства ввода и вывода), но есть также и устройства USB CDC (виртуальный COM-порт). Если Вам лень самому создавать проект, просто откройте в AS6 файл проекта VUSB.atsln, в нем уже сделаны все необходимые настройки и добавлены все нужные файлы.

Если у Вас используется другая макетная плата, то нужно правильно настроить файл usbconfig.h . Это конфигурационный файл библиотеки V-USB, в нем задаются многие настройки и параметры (VID, PID, ножки микроконтроллера, значения для дескрипторов и другие настройки). Подробное описание всех настроек дано в комментриях этого файла. Основное внимание следует уделить назначению выводов микроконтроллера, которые используются под сигналы USD D+ и D- (макроопределения USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT, USB_CFG_DPLUS_BIT), к этим ножкам предъявляются особые требования. Конфигурационный файл usbconfig.h из архива предназначен под разводку ножек макетной платы AVR-USB-MEGA16, и он гарантированно работает. Моргать программа будет светодиодом, который уже имеется на макетной плате и подключен к ножке 0 порта B.

Создание программы для компьютера (ПО хоста)

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

Примечание. Программа была создана на основе примера консольного приложения из той же библиотеки V-USB. Компиляция исходного кода консольного приложения выполнялась с помощью makefile и пакета MinGW, и использовала библиотеку LibUSB. В нашем примере мы будем использовать графическую среду Visual Studio и библиотеку LibUsbDotNet. Однако главный цимус использования LibUsbDotNet вовсе не в том, что теперь легко и удобно можно делать не только консольные, но и графические приложения. Самый большой плюс - теперь не нужен драйвер фильтра, который таскала за собой библиотека LibUSB много лет. Для тех, кто в танке, драйвер фильтра - это особая программная надстройка над библиотекой LibUSB, через которую осуществлялся обмен данными с устройствами USB на платформе Windows. Теперь этот атавизм не нужен.
Запустите Microsoft Visual C# 2010 Express и создайте новый проект на основе Windows Form. Теперь нужно подключить к проекту библиотеку LibUsbDotNet.dll . В обозревателе решений нажмите правой кнопкой мыши на названии проекта, и выберите «Добавить ссылку».

Появится ещё одно окно

Здесь нужно найти путь на диске, где находится библиотека LinUsbDotNet.dll (по умолчанию она устанавливается папку C:\Program Files\LibUsbDotNet, но лучше сделать копию файла DLL в рабочий каталог проекта. После подключения библиотеки её нужно объявить в проекте, для этого добавьте в главный модуль программы (файл Form1.cs) строки:

Using LibUsbDotNet; using LibUsbDotNet.Info; using LibUsbDotNet.Main;
Перейдите к визуальному редактору формы, и приведите её приблизительно к такому виду (добавьте 3 кнопки Button и 3 текстовых метки Label):

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

Примечание. Иногда для идентификации устройства дополнительно используется уникальный серийный номер или отдельный текстовый дескриптор - когда к компьютеру подключено несколько устройств USB с одинаковыми VID и PID, но это не наш случай. Поскольку обычно у каждого USB-устройства, подключенного к компьтеру, своя пара VID/PID, отличающаяся от других устройств, то найти нужное устройство и обратиться к нему не составляет проблем.
VID это идентификатор производителя (Vendor ID), а PID - идентификатор устройства (Product ID). Наше USB-устройство имеет VID: 0x16C0 , PID: 0x05DF , эти значение указаны в конфигурационном файле usbconfig.h (об этом файле мы уже упоминали) проекта микроконтроллера AS6. Чтобы ПО хоста обратилась к именно к нашему USB-устройству, нужно инициализировать объект MyUsbFinder такими же параметрами VID: 0x16c0, PID: 0x05df, как указаны в файле usbconfig.h . Для этого в область определения глобальных переменных класса Form1 добавьте следующий код:

Public static UsbDevice MyUsbDevice; public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x16c0, 0x05df);
После того как мы определились с каким USB-устройством будем работать, можно к нему подключаться, и это удобно сделать в момент старта программы (открытия окна формы). Для этого выберите основную форму программы, и в редакторе свойств создайте обработчик события загрузки Form1_Load. В теле обработчика введите следующий код:

Private void Form1_Load(object sender, EventArgs e) { MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder); if (MyUsbDevice != null) { label2.Text = " подключено!"; } else label2.Text = " не найдено!"; }
Сделайте обработчик события клика на кнопке button1 («Вкл»), для этого сделайте в визуальном редакторе на кнопке двойной щелчок, и добавьте в тело обработчика события код:

Private void button1_Click(object sender, EventArgs e) { // Передать пакет, который включает светодиод на макетной плате AVR-USB-MEGA16. UsbSetupPacket packet = new UsbSetupPacket((byte)(UsbCtrlFlags.RequestType_Vendor | UsbCtrlFlags.Recipient_Device | UsbCtrlFlags.Direction_Out), 1, (short)1, 0, 0); int countIn; byte data = new byte; MyUsbDevice.ControlTransfer(ref packet, data, 0, out countIn); }
Для обработчика кнопки «Выкл» добавьте код:

Private void button3_Click(object sender, EventArgs e) { // Передать пакет, который погасит светодиод на макетной плате AVR-USB-MEGA16. UsbSetupPacket packet = new UsbSetupPacket((byte)(UsbCtrlFlags.RequestType_Vendor | UsbCtrlFlags.Recipient_Device | UsbCtrlFlags.Direction_Out), 1, (short)0, 0, 0); int countIn; byte data = new byte; MyUsbDevice.ControlTransfer(ref packet, data, 0, out countIn); }
Код для обработки кнопки «Чтение»:

Private void button2_Click(object sender, EventArgs e) { //Получение данных от макетной платы AVR-USB-MEGA16 - состояние светодиода. UsbSetupPacket packet = new UsbSetupPacket((byte)(UsbCtrlFlags.RequestType_Vendor | UsbCtrlFlags.Recipient_Device | UsbCtrlFlags.Direction_In), 2, (short)0, (short)0, (short)0); int countIn; byte data = new byte; if (MyUsbDevice.ControlTransfer(ref packet, data, 1, out countIn) && (countIn == 1)) { label3.Text = "Прочитано значение " + data.ToString(); } }
Обработчик события закрытия формы (завершение работы программы) гасит светодиод, если он горит:

Private void Form1_FormClosed(object sender, FormClosedEventArgs e) { UsbSetupPacket packet = new UsbSetupPacket((byte)(UsbCtrlFlags.RequestType_Vendor | UsbCtrlFlags.Recipient_Device | UsbCtrlFlags.Direction_Out), 1, (short)0, 0, 0); int countIn; byte data = new byte; MyUsbDevice.ControlTransfer(ref packet, data, 0, out countIn); }

Как пакеты USB декодируются в firmware микроконтроллера

Прием и обработка данных на стороне микроконтроллера осуществляется в функции usbFunctionSetup (находится в главном модуле VUSB.c проекта firmware AS6). Вот эта функция:

UsbMsgLen_t usbFunctionSetup(uchar data) { usbRequest_t *rq = (void *)data; if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){ DBG1(0x50, &rq->bRequest, 1); /* отладочный вывод: печатаем наш запрос */ if(rq->bRequest == CUSTOM_RQ_SET_STATUS){ if(rq->wValue.bytes & 1){ /* установить LED */ LED_PORT_OUTPUT |= _BV(LED_BIT); }else{ /* очистить LED */ LED_PORT_OUTPUT &= ~_BV(LED_BIT); } }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){ static uchar dataBuffer; /* буфер должен оставаться валидным привыходе из usbFunctionSetup */ dataBuffer = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0); usbMsgPtr = dataBuffer; /* говорим драйверу, какие данные вернуть */ return 1; /* говорим драйверу послать 1 байт */ } }else{ /* вызовы запросов USBRQ_HID_GET_REPORT и USBRQ_HID_SET_REPORT не реализованы, * поскольку мы их не вызываем. Операционная система также не будет обращаться к ним, * потому что наш дескриптор не определяет никакого значения. */ } return 0; /* default для нереализованных запросов: не возвращаем назад данные хосту */ }
Наше устройство USB HID простейшее, и реагирует оно только на управляющие передачи (control transfer), которые проходят через конечную точку 0 (default control endpoint). По типу запроса (поле bRequest) декодируется направление передачи данных. Если CUSTOM_RQ_SET_STATUS, то это данные, предназначаемые для микроконтроллера. Данные декодируются и микроконтроллер выполняет заложенную там команду. В этом случае в самом первом по порядку принятом байте данных закодировано состояние светодиода - если там в младшем бите единичка, то светодиод включается, а если нолик, то гаснет. Если же в поле bRequest принято значение CUSTOM_RQ_GET_STATUS, то в ответ заполняется буфер текущим состоянием светодиода, и данные буфера отправляются обратно хосту. Все очень просто, и при желании поведение кода можно легко переделать под свои нужды.

Видео, как это работает:

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