Створюємо найпростіший usb-пристрій для спілкування зі своєю програмою. Основи розробки та програмування найпростіших USB-пристроїв Особливості програмування HID-пристроїв

Головна / Корисна інформація


рис.1 Ілюстрація роботи Android пристрою в режимах USB Host та Accessory (рисунок із сайту http://developer.android.com)

Зазначимо, що використання USB не єдиний спосіб зв'язку з тим же саморобним пристроєм. Android дозволяє використовувати ще , NFC, Wi-Fi P2P, SIP, а також стандартне мережне підключення. Так що в арсеналі розробника достатньо можливостей для здійснення своїх найсміливіших задумів.

Іншим найпоширенішим варіантом зв'язку з різними пристроями досі є використання перехідника USB-COM. Матеріал у мережі із застосуванням перехідника USB-COM в Android є - див., наприклад, . Популярність такого підключення обумовлена ​​наявністю великої кількості вже розроблених з використанням різних мікроконтролерів пристроїв, зв'язок з якими здійснюється за допомогою COM-порту (послідовного порту), що років 10 тому було майже стандартним способом передати дані від комп'ютера до саморобної "залізниці".

У порівнянні з COM-портом, використання USB дозволяє суттєво підвищити швидкість передачі даних та зробити цей процес зручним для користувача. Швидкість передачі, яка навіть у разі низькошвидкісних пристроїв (клавіатури, миші, джойстики), становить 10-1500 Кбіт/c, простота та невисока вартість кабельної системи та підключень, самоідентифікація пристроїв з автоматичним конфігуруванням, приховування деталей електричного підключення від кінцевого користувача (плюс можливість відключення кабелю без вимикання пристроїв), контроль помилок та його відновлення лише на рівні протоколу - ось незаперечні переваги даної технології (див. , с.12).

Взагалі, говорячи про використання USB для передачі даних, незайвим буде згадати книгу П.Агурова «Інтерфейс USB». Вона, хоча часто критикується в мережі та випущена останній раз у 2006 році, неодноразово допомогла знайти правильне рішення при пошуку інформації з різних аспектів застосування цієї технології. У книзі розглянуті питання: від вибору мікросхеми та схемотехніки для контролера до написання програми мікроконтролера та прикладів програмування передачі даних протоколом USB з боку комп'ютера. Не можна не вказати і "першоджерело" даних з цього питання - сайт некомерційної організації USB IF (USB Implementers Forum), що займається розробкою специфікацій цього інтерфейсу., щоправда цей матеріал англійською мовою. Однак саме там ви знайдете вичерпну інформацію про пристрій USB. Є непоганий переведення частин специфікації - . Цікавим програмними рішеннями з боку мікроконтролера також можна переглянути посилання.

Ця стаття адресована насамперед тим, у кого є якийсь електронний пристрій (розроблений самостійно або кимось ще), протокол обміну даними з яким добре відомий (наприклад, вже є програма, яка працює з цим пристроєм у Windows/Linux) і хотілося б мати програму, яка працює з ним в Android.

Трохи про класи USB-пристроїв

Необхідно відзначити, що розробка програмного забезпечення для обміну даними з конкретним пристроєм залежить від його реалізації на рівні мікроконтролера. Привести приклади програм зв'язку для всіх типів USB-пристроїв в рамках однієї статті, зі зрозумілих причин неможливо (початкові відомості про програмування різних типів пристроїв можна почерпнути в ). Однак, ми обмежимося тим, що наведемо код, який реалізує пошук пристрою та доступ до його контрольних точок для обміну інформацією. Також розберемо відправку даних на прикладі одного з типів USB-пристроїв, а саме класу пристроїв HID (human interface device - клас пристроїв для взаємодії з людиною). Цей клас включає «повільні» пристрої, такі як клавіатура, миша, джойстик і прикладів його реалізації за допомогою різних мікроконтролерів в мережі достатньо (є, наприклад, і в ).

Чому саме клас HID так сподобався виробникам різних саморобних пристроїв? Процитуємо Вікіпедію: «Окрім детальних специфікацій класичних пристроїв введення (типу клавіатур та мишок) стандарт HID визначає особливий клас пристроїв без детальних специфікацій. Цей клас називається USB HID Consumer Control і є по суті нерегламентований канал зв'язку з пристроєм. При цьому пристрій користується тими ж стандартними для операційної системи драйверами, що і мишка з клавіатурою. Таким чином, можна створити USB пристрій, який не вимагає створення та інсталяції спеціальних драйверів у більшості поширених комп'ютерних операційних систем». Залишається додати тільки, що ця специфікація працює і в ОС Android (не виключаючи прошивок CyanogenMod).

Одним з варіантів обміну даними з HID-пристроєм є передача переривань (interrupt transfer), яка використовується в тому випадку, коли необхідно передати пакети даних невеликого розміру (максимальний розмір пакета залежить від швидкості передачі і становить від 64 до 1024 байт) через заданий часовий інтервал. Пакет передачі називається репортом (англ. - report, див. с.71, 95). Такої довжини репорту зазвичай цілком вистачає для обміну інформацією з саморобним пристроєм, 64 байти інформації в одному пакеті, наприклад, - це досить багато для контролера, адже для передачі станів світлодіода або найпростішого датчика достатньо 1 біт інформації.

Необхідні інструменти

Отже, нам знадобляться - планшет або телефон з Android версії не нижче 3.1. Тут слід зазначити, що вищевказаний USB Host API повністю реалізований не на всіх мобільних пристроях (про це згадується і на сайті developer.android.com, див. посилання). У деяких планшетах/телефонах роз'єм USB використовується лише для заряджання та зв'язку з комп'ютером. Ще раз надішлю читача до списку мобільних пристроїв, придатних чи непридатних для наших дослідів (див. ).

Потрібно також будь-який USB-пристрій (для перших дослідів буде достатньо звичайного USB-флеш-накопичувача), перехідник OTG (On-The-Go - див. рис. 2) та/або шнур USB для зв'язку з пристроєм. У Вікіпедії з приводу OTG говориться: «При підключенні через USB OTG ранг пристрою (провідний або ведений) визначається наявністю або відсутністю перемички між контактами 4 та 5 у штекері кабелю. В USB OTG кабелі така перемичка встановлюється лише в одному з двох роз'ємів (див. ). Відповідно, нам потрібна така перемичка з боку мобільного пристрою.


Рис.2 Відмінності у схемі звичайного USB-кабелю та OTG-кабелю (рисунок із сайту http://tech.firstpost.com)

Такий кабель OTG для Вашого пристрою можна спаяти і самостійно. Для цього необхідно купити в радіомагазині відповідний роз'єм плюс автор, наприклад, використовував старий кабель від переносного жорсткого диска:

Непоганою підмогою буде також програма USB Device Info, встановлена ​​зі сховища Google Play Market. Програма вміє визначати підключені до USB-роз'єму планшета/телефону пристрою як за допомогою Java API, так і за допомогою ядра Linux. Тобто, якщо Ваш пристрій не визначився за допомогою Java USB Host API у USB Device Info, то, мабуть, марно буде використовувати для цього мобільного пристрою будь-яку (в тому числі і свою) Android-програму, написану за допомогою Java та USB Host API.

Іноді також дуже корисною буває інформація, що виводиться командою lsusb операційної системи Linux. З ключами -v і -d lsusb виводить про USB-пристрій все, або майже все, що необхідно розробнику програмного забезпечення для пристроїв цього класу (див. рис.3).


Рис.3 Приклад виведення команд lsusb та lsusb -v -d

Далі, необхідний комп'ютер із встановленим Android SDK та інтегрованим середовищем розробки (IDE) Eclipse з плагіном ADT (хоча можна обійтися і лише SDK). Як створити і встановити програму для Android можна подивитися, наприклад, в , або в Інтернеті.

Ну і, звичайно, потрібно хоча б і бажання досягти результату, без нього ніяк! Зазначу, що на з'ясування деяких технічних питань застосування USB в Android автором, знадобилися тижні копіткого пошуку інформації.

Класи Java для роботи з USB в Android API

Отже, як мовиться на сайті розробників USB Host API для Android (див. ) - «Перш ніж почати, важливо зрозуміти які класи ви будете використовувати в роботі». У таблиці 1 наведено опис найважливіших класів для роботи з USB Host API (спроба перекладу інформації з http://developer.android.com).

Таблиця 1. Опис класів для роботи з USB в Android

Назва класу Опис
UsbManager Дозволяє вам переглянути і комунікувати з підключеними USB-пристроями.
Дозволяє визначати підключений USB-пристрій та обмінюватися з ним даними.
UsbDevice Встановлюють з'єднані USB прилади і містять методи для його доступу до identifying information, interfaces, and endpoints.
Представляє підключений USB-пристрій та містить методи для доступу до його ідентифікаційної інформації, інтерфейсів та кінцевих точок.
UsbInterface Встановлюють interface of USB device, який defines set functionality for the device. A device може мати один або більше interfaces on which to communicate on.
Представляє інтерфейс USB-пристрою, який визначає набір функцій для даного пристрою. Один пристрій може мати один або кілька інтерфейсів обміну інформацією.
UsbEndpoint Представляють функцію endpoint, яка є комунікаційним каналом для цієї сторінки. У розділі може бути один або більше кінців, і зазвичай має вхід і вихідні пункти для двох способів спілкування з ним.
Представляє кінцеву точку інтерфейсу, яка і є каналом зв'язку для цього інтерфейсу. Інтерфейс може мати одну і більше кінцевих точок, і зазвичай має кінцеві точки для отримання інформації та її передачі.
UsbDeviceConnection Встановлюють зв'язок до пристрою, який передає дані на кінці. Ця категорія дозволить вам перейти до денного back and forth sychronously або asynchronously.
Це «підключення» до цього пристрою. Необхідно передачі даних у кінцеву точку. Цей клас дозволяє отримувати дані або передавати їх синхронно або асинхронно.
UsbRequest Вони представляють асинхронний запит на комунікацію з пристроєм через UsbDeviceConnection.
Асинхронний запит на обмін даними з пристроєм через UsbDeviceConnection.
UsbConstants Defines USB constants , що відповідають definitions in linux/usb/ch9.h of Linux kernel.
Визначає константи, які відповідають визначенням Linux Linux в linux/usb/ch9.h.

Практично у всіх випадках застосування USB Host API програміст використовує ці класи у роботі. Алгоритм їх застосування виглядає приблизно так: визначаємо пристрої (мета – програмний доступ до класу UsbDevice), підключені до хоста (мобільного пристрою) за допомогою UsbManager. Коли програмний доступ пристрою отримано, необхідно визначити відповідні UsbInterface та UsbEndpoint для спілкування з ним. Як тільки ви отримали кінцеву точку, відкрийте UsbDeviceConnection, щоб спілкуватися з USB-пристроєм. Якщо кінцева точка працює у режимі асинхронної передачі, використовуємо клас UsbRequest.

Спробуймо з усім цим розібратися створивши простий додаток, який, використовуючи цей API, визначить підключений до хосту з ОС Android пристрій і виведе про нього деяку інформацію на екран телефону або планшета.

Створюємо проект

У Eclipse проект створюється з допомогою пунктів меню File->New->Android Application Project. Зауважимо також, що код, наведений нижче запозичений з прикладних прикладів, що поставляються з Android SDK (папка android sdk samples/android-N(API Level)/USB) йдеться про програму управління USB-іграшкою Missile Launcher (див. рис. 4 ) Приклади програм завантажуються через Android SDK Manager (потрібно відзначити пункт - Samples for SDK). У лістингах, наведених нижче, приклади коду мають коментарі, які пояснюють суть того, що відбувається.


Рис.4 Забавна іграшка "Ракетозапуск"

Створюючи проект, не забудьте відзначити потрібний API Level в опції Minimum Requared SDK (API Level 12, що відповідає версії Android 3.1 /Honeycomb/, або вище). У проекті буде дуже простий інтерфейс користувача – головне вікно (Activity) та TextView для виведення інформації. Подібний проект докладно розглянуто у .

У створеному автоматичному класі для Activity нашого проекту необхідно визначити такі екземпляри класів для роботи з USB:

private TextView lgView;
private UsbManager mUsbManager;
private UsbDevice mDevice;
private UsbDeviceConnection mConnection;
private UsbEndpoint mEndpointIntr;

LgView = (TextView) findViewById(R.id .logTextView );

та отримуємо доступ до класу UsbManager

MUsbManager = (UsbManager) getSystemService(Context .USB_SERVICE );

Створимо ще обробник події onResume(). Досягнемо мети - щоб інформація про підключені пристрої оновлювалася при активізації вікна нашої програми (див. Лістинг 1).

Лістинг 1. Обробник події onResume()

public void onResume() (
super .onResume();

//Заповнюємо контейнер списком пристроїв
HashMap< String , UsbDevice>deviceList = mUsbManager.getDeviceList();
Iterator< UsbDevice>deviceIterator = deviceList.values() .iterator() ;

lgView.setText ("Devices Count:" + deviceList.size());

while (deviceIterator.hasNext() ) (
UsbDevice device = (UsbDevice) deviceIterator.next ();

//Приклад визначення ProductID пристрою
\n "+ "Device ProductID: " + device.getProductId() );
}
//визначаємо намір, описаний у фільтрі
// Наміри AndroidManifest.xml
Intent intent = getIntent();
lgView.setText(lgView.getText() + " \n "+ "intent:" + intent) ;
String action = intent.getAction();

//якщо пристрій підключено, передаємо посилання в
//У функцію setDevice()
UsbDevice device = (UsbDevice) intent.getParcelableExtra (UsbManager.EXTRA_DEVICE ) ;
if (UsbManager.ACTION_USB_DEVICE_ATTACHED .equals (action) ) (
setDevice(device);
lgView.setText(lgView.getText() + " \n " + "UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) is TRUE") ;
) else if (UsbManager.ACTION_USB_DEVICE_DETACHED .equals (action) ) (
if (mDevice != null && mDevice.equals (device) ) (
setDevice(null);
lgView.setText(lgView.getText() + " \n " + "UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) is TRUE") ;
}
}

Далі, для Activity створимо функцію setDevice(), необхідну роботи з нашим пристроєм (див. Лістинг 2). У обробнику onResume() і функції setDevice() ми точно виконали алгоритм застосування USB Host API, описаний у попередньому розділі.

Лістинг 2. Функція setDevice()

private void setDevice(UsbDevice device) (
lgView.setText(lgView.getText() + " \n "+ "setDevice" + device);

//Визначаємо доступні інтерфейси пристрою
if (device.getInterfaceCount ()! = 1) (

LgView.setText(lgView.getText() + " \n "+ "could not find interface"));
return;
}
UsbInterface intf = device.getInterface (0);

//Визначаємо кінцеві точки пристрою
if (intf.getEndpointCount () == 0 ) (

LgView.setText(lgView.getText() + " \n "+ "could not find endpoint");
return;
) else (
lgView.setText(lgView.getText() + " \n "+ "Endpoints Count:" + intf.getEndpointCount ());
}

UsbEndpoint epIN = null;
UsbEndpoint epOUT = null;

//Шукаємо кінцеві точки для передачі по перериванням
for (int i = 0; i< intf.getEndpointCount () ; i++ ) {
if (intf.getEndpoint (i) .getType () == UsbConstants.USB_ENDPOINT_XFER_INT ) (
if (intf.getEndpoint (i) .getDirection () == UsbConstants.USB_DIR_IN ) (
epIN = intf.getEndpoint (i);
lgView.setText(lgView.getText() + " \n "+ "IN endpoint:" + intf.getEndpoint (i) );
}
else (
epOUT = intf.getEndpoint(i);
lgView.setText(lgView.getText() + " \n "+ "OUT endpoint:" + intf.getEndpoint (i) );
}
) else ( lgView.setText ( lgView.getText () + " \n " + "не наставте для INTERRUPT_TRANSFER") ; }
}

MDevice = device;
mEndpointIntr = epOUT;

//відкриваємо пристрій передачі даних
if (device != null ) (
UsbDeviceConnection connection = mUsbManager.openDevice (device) ;
if (connection != null && connection.claimInterface (intf, true ) ) (

LgView.setText(lgView.getText() + " \n "+ "open device SUCCESS!" );
mConnection = connection;

) else (

LgView.setText(lgView.getText() + " \n "+ "open device FAIL!" );
mConnection = null;
}
}
}
}

На додаток до наведеного коду, який, як напевно здогадався уважний читач, відкриває пристрій для прийому-передачі даних, залишається лише задіяти протокол обміну даними, який, повторюся, повинен бути добре відомий розробнику. Наведемо лише, як було обіцяно, код, який відправить HID пристрою деякий пакет даних message використовуючи передачу переривань, клас UsbRequest і відповідну кінцеву точку - див. Лістинг 3.

Лістинг 3. Приклад коду для надсилання даних пристрою

//Визначення розміру буфера для відправки
//виходячи з максимального розміру пакета
int bufferDataLength = mEndpointIntr.getMaxPacketSize();

lgView.setText(lgView.getText() + " \n "+ mEndpointIntr.getMaxPacketSize());

ByteBuffer buffer = ByteBuffer.allocate (bufferDataLength + 1);

UsbRequest request = New UsbRequest() ;

buffer.put (message);

request.initialize (mConnection, mEndpointIntr);

request.queue (buffer, bufferDataLength);

if (request.equals (mConnection.requestWait ()))

// відправка пройшла успішно
//lgView.setText(lgView.getText() + "\n" + "sending CLEAR!!!");

catch (Exception ex)

//щось не так...
//lgView.setText(lgView.getText() + "\n" + "sending not clear...");

Фільтрування пристроїв в AndroidManifest.xml

Хоча в нашому додатку немає потреби в пошуку конкретного пристрою з відомими VID (Vendor-ID) та PID (Product-ID), інженери Google не наводять прикладів додатків без секції intent-filter у маніфест файлі, і автору не вдалося домогтися роботи програми без фільтрації пристроїв в AndroidManifest.xml.

Нагадаю, що Vendor-ID та Product-ID – це унікальні ідентифікатори USB-пристроїв. Тобто, використовуючи фільтрацію, можна створити програму, яка взаємодіє лише з певним пристроєм чи якимось класом пристроїв. Зазначимо, що виробники пристроїв повинні узгодити ці номери з USB IF.

Додаток, маніфест файл якого наведено в лістингу 4, а файл з умовою фільтрації в лістингу 5, наприклад, успішно розпізнає підключені до мобільного пристрою USB-флеш-накопичувачі, але не розпізнає клавіатуру і миші, що є у автора. Ця програма разом з вихідним кодом можна завантажити за посиланням.

Лістинг 4. Файл AndroidManifest.xml


" > http://schemas.android.com/apk/res/android"
> package="uk.learn2prog.usbhostexample"
android:versionCode="1"
android:versionName="1.0" >


android:minSdkVersion ="12"
android:targetSdkVersion ="14" />


android:allowBackup ="true"
android:icon ="@drawable/ic_launcher"
android:label ="@string/app_name"
android:theme ="@style/AppTheme" >

android:name = "ru.learn2prog.usbhostexample.MainActivity"
android:label ="@string/app_name" >
>

"android.intent.category.DEFAULT" />

"android.intent.category.LAUNCHER" />

>

>

>
"android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource ="@xml/device_filter" />
>
>

>

Лістинг 5. Файл фільтра device_filter.xml (каталог /res/xml)

>

>

Операції зі складання та встановлення нашої програми нічим не відрізняються від звичайних (див. приклади в , ). Хочу звернути увагу на дії фільтра намірів - при підключенні пристрою до хоста ОС запитує користувача про запуск нашої програми.

Література/Посилання: 11.
12.
13. http://developer.android.com/guide/topics/connectivity/usb/host.html - огляд класів, необхідних для роботи з USB в Android
14. посилання на вихідні програми

Шина USB (Universal Serial Bus - універсальна послідовна шина) з'явилася 15 січня 1996 при затвердженні першого варіанту стандарту фірмами - Intel, DEC, IBM, NEC, Northen Telecom і Compaq.

Основна мета стандарту, поставлена ​​перед розробниками – створити можливість користувачам працювати в режимі Plug&Play з периферійними пристроями. Це означає, що пристрій повинен бути підключений до працюючого комп'ютера, автоматичне розпізнавання його негайно після підключення та наступної установки відповідних драйверів. Крім цього, бажано живлення малопотужних пристроїв подавати із самої шини. Швидкість шини має бути достатньою для переважної більшості периферійних пристроїв. Контролер USB повинен займати лише одне переривання незалежно від кількості підключених до шини пристроїв, тобто вирішити проблему нестачі ресурсів на внутрішніх шинах IBM PC сумісного комп'ютера.

Практично всі завдання були вирішені в стандарті на USB і навесні 1997 стали з'являтися комп'ютери, обладнані роз'ємами для підключення USB пристроїв. Зараз USB стала настільки активно впроваджуватися виробниками комп'ютерної периферії, що, наприклад, у комп'ютері iMAC фірми Apple Computers є тільки USB як зовнішній шина.

Можливості USB 1.0 такі:

1. висока швидкість обміну даними (full-speed) - 12 Мб іт/с;

2. максимальна довжина кабелю високої швидкості обміну – 5 метрів;

3. низька швидкість обміну даними (low-speed) – 1,5 Мб іт/с;

4. максимальна довжина кабелю для низької швидкості обміну – 3 метри;

5. максимальна кількість підключених пристроїв – 127;

6. можливе одночасне підключення пристроїв із різними швидкостями обміну;

8. максимальний струм споживання одне пристрій – 500 мА.

Тому доцільно підключати до USB 1.0 практично будь-які периферійні пристрої, окрім цифрових відеокамер та високошвидкісних жорстких дисків. Особливо зручний цей інтерфейс для підключення приладів, що часто підключаються/відключаються, таких як цифрові фотокамери.
Можливість використання лише двох швидкостей обміну даними обмежує застосованість шини, але суттєво зменшує кількість ліній інтерфейсу та спрощує апаратну реалізацію.
Живлення безпосередньо від USB можливе лише для пристроїв з малим споживанням, таких як клавіатури, миші, джойстики тощо.

Сигнали USB передаються по 4-х проводовому кабелю, схематично показаному на малюнку нижче:

Рисунок 2.6.1 – Сигнальні дроти USB

Тут GND - ланцюг загального дроту для живлення периферійних пристроїв, Vbus - +5 і для ланцюгів живлення. Шина D+ призначена передачі даних по шині, а шина D- для прийому даних.
Кабель для підтримки повної швидкості шини (full-speed) виконується як кручена пара, захищається екраном і може використовуватися для роботи в режимі мінімальної швидкості (low-speed). Кабель для роботи лише на мінімальній швидкості (наприклад, для підключення миші) може бути будь-яким та неекранованим.
Роз'єми, що використовуються для підключення периферійних пристроїв, поділяються на серії: роз'єми серії «A» (вилка та розетка) призначені лише для підключення до джерела, наприклад комп'ютера, роз'єми серії «B» (вилка та розетка) тільки для підключення до периферійного пристрою.

USB рознімання мають наступну нумерацію контактів, показану в таблиці 2.6.1.

Таблиця 2.6.1 – Призначення та маркування контактів USB

У 1999 році той же консорціум комп'ютерних компаній, який ініціював розробку першої версії стандарту на шину USB, почав активно розробляти версію USB 2.0, яка відрізняється введенням додаткового високошвидкісного (Hi-speed) режиму. Смуга пропускання шини збільшена в 40 разів, до 480 Мбіт/с, що уможливило передачу відеоданих по USB.
Сумісність усієї раніше випущеної периферії та високошвидкісних кабелів повністю зберігається. Контролер стандарту 2.0 вже інтегрований в набір системної логіки пристроїв, що програмуються (наприклад, материнська плата персонального комп'ютера).

У 2008 році компаніями Intel, Microsoft, Hewlett-Packard, Texas Instruments, NEC та NXP Semiconductors створено специфікацію стандарту USB 3.0. У специфікації USB 3.0 роз'єми та кабелі оновленого стандарту фізично та функціонально сумісні з USB 2.0, проте на додаток до чотирьох ліній зв'язку, додано ще чотири. Тим не менш, нові контакти в роз'ємах USB 3.0 розташовані окремо від старих на іншому ряді контактів. Специфікація USB 3.0 підвищує максимальну швидкість передачі інформації до 5 Гбіт/с - що значно більше 480 Мбіт/с, які може забезпечити USB 2.0. Крім того, збільшена максимальна сила струму з 500 мА до 900 мА на один пристрій, що дозволяє живити деякі пристрої, що вимагають окремого блоку живлення.

Припустимо, розроблено USB-пристрій, з яким необхідно працювати за допомогою комп'ютера. Цього можна досягти мінімум двома способами:

1. розробка повнофункціонального драйвера операційної системи;

2. використання інтерфейсу спеціального класу USB – пристроїв, званих HID (Human Interface Device) пристроями.

Перший спосіб універсальний: володіючи достатніми знаннями в області написання драйверів, можна запрограмувати роботу з будь-яким пристроєм на будь-якій швидкості USB. Але це досить складне завдання.

Другий спосіб полягає в наступному. Існує підтримуваний сучасними операційними системами інтерфейс для пристроїв взаємодії комп'ютера та людини або пристроїв HID, таких як:

1. клавіатури, миші, джойстики;

2. різні датчики та зчитувачі;

3. ігрові рульове управління та педалі;

4. кнопки, перемикачі, регулятори.

Будь-який такий пристрій, якщо він виконує вимоги до пристроїв HID, буде автоматично розпізнаний системою і не вимагатиме написання спеціальних драйверів. Крім того, їх програмування, як правило, набагато простіше написання спеціалізованого драйвера пристрою. На жаль, спосіб має істотний недолік: швидкість обміну інформацією HID-пристроєм сильно обмежена і становить максимум 64 кБ/с.

Принципово на основі HID-технології можна організувати взаємодію з будь-яким пристроєм, навіть якщо воно не є в строгому значенні інтерфейсним пристроєм людини та комп'ютера. Це дозволяє відмовитися від трудомісткої розробки унікального драйвера пристрою та заощадити час на розробку нового USB-пристрою. На стороні хоста обміном із пристроєм керуватиме стандартний HID-драйвер, включений у постачання операційної системи. Потрібно лише виконати з боку пристрою мінімальні вимоги протоколу USB-HID.

Багато USB-прилади, які з першого погляду не потрапляють під визначення пристроїв взаємодії з людиною, логічніше все ж реалізувати як HID-пристрою. Таке явище часто зустрічається в галузі виробничого обладнання, яке останнім часом переживає масове впровадження USB-технологій. Наприклад, розглянемо лабораторне джерело живлення з можливістю завдання параметрів вихідних сигналів з комп'ютера за допомогою USB-інтерфейсу. Безпосередньо джерело харчування безперечно не є засобом взаємодії з людиною. Однак, у цьому випадку функції, що реалізуються за допомогою USB-підключення, дублюють клавіатуру, регулятори та індикатори, встановлені на приладі. А ці органи управління саме потрапляють під визначення HID. Відповідно блок живлення з цими USB-функціями найлогічно організувати як HID-пристрій.

У розглянутому прикладі для нормальної роботи достатньо буде невеликої швидкості передачі даних, в інших випадках прилади можуть бути дуже вимогливі до швидкості обміну. Низька швидкість передачі є головним обмеженням HID-варіанту побудови пристрою, що в порівнянні з 12 Мбіт/сек повної швидкості USB 1.0-шини виглядає великим мінусом HID-технології у питанні вибору конкретної USB-реалізації. Однак для багатьох завдань комунікації зазначеної швидкості цілком вистачає і HID-архітектура як спеціалізований інструмент займає гідне місце серед засобів організації обміну даними.

HID-пристрої бувають двох типів: що беруть участь (завантажувальні) і які беруть участь у початковому завантаженні комп'ютера. Найбільш яскравим прикладом завантажувального USB-HID пристрою є клавіатура, робота якої починається зі стартом комп'ютера.

При розробці пристрою HID необхідно забезпечити такі вимоги, що накладаються специфікацією:

1. повношвидкісний HID-пристрій може передавати 64000 байт кожну секунду або по 64 байта кожні 1 мс; низькошвидкісний HID-пристрій має можливість передати до 800 байт в секунду або по 8 байт кожні 10 мс.

2. HID-пристрій може призначити частоту свого опитування визначення того, чи є в нього свіжі дані передачі.

3. Обмін даними з HID-пристроєм здійснюється за допомогою спеціальної структури, яка називається репортом (Report). Кожен певний репорт може містити до 65 535 байт даних. Структура репорту має дуже гнучку організацію, що дозволяє описати будь-який формат передачі. Для того, щоб конкретний формат репорту став відомий хосту, мікроконтролер повинен містити спеціальний опис – дескриптор репорту.

Реалізується USB взаємодія безпосередньо на мікроконтролері декількома способами:

1. використанням контролера з апаратною підтримкою, наприклад, AT90USB*, фірми atmega;

2. використанням програмної емуляції usb-інтерфейсу будь-якому микроконтроллере.

Для програмної реалізації в даний час існує ряд готових рішень під різні сімейства мікроконтролерів. Для AVR мікроконтролерів, наприклад, Atmega8 можна використовувати такі вільні бібліотеки мовою Сі:

Обидві досить прості у використанні забезпечують повну емуляцію USB 1.1 low-speed пристроїв за винятком обробки помилок зв'язку та електричних характеристик і запускаються практично на всіх AVR контролерах з мінімум 2 кілобайтами flash-пам'яті, 128 байтами RAM і частотою від 12 до 20 МГц.

Для написання програм з підтримкою Windows USB HID пристроїв потрібні заголовні файли hid*, що входять до складу WDK (Windows Driver Kit), або можна використовувати бібліотеку hidlibrary, що вільно розповсюджується, або іншу аналогічну.

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

Контрольні питання

  1. У чому відмінність дроту D- та GND у USB? Чому не можна використовувати один спільний дріт для живлення та сигналу?
  2. Скільки режимів швидкості роботи USB існує на сьогоднішній день (включаючи версію 3.0)?
  3. Що таке HID-пристрій? Чому для їхньої роботи в сучасних ОС не потрібно написання драйверів?
  4. Чи можна реалізувати USB пристрої за допомогою мікропроцесора, який не має вбудованої підтримки інтерфейсу?
  5. Які основні відмінності від USB 3.0 від попередніх версій?

Хороша книга, багато що пояснює. Стане в нагоді тим, хто хоче зрозуміти як відбувається передача даних по шині USB.

Вступ 1
Для кого ця книга: 2
Що ви знайдете у книзі 2
Програмні вимоги 3
Апаратні вимоги 4
Про програмний код 4
Короткий опис розділів 4
Позначення 6
Подяки 7
ЧАСТИНА I. ВСТУП У USB 9
Розділ 1. Що таке USB 11
1.1. Історія USB 11
1.2. Порівняння USB з іншими інтерфейсами 14
1.3. Основні поняття USB 16
1.3.1. Загальна архітектура шини 16
1.3.2. Фізична та логічна архітектура шини 16
1.3.3. Складові USB 18
1.3.4. Властивості USB-пристроїв 18
1.3.5. Властивості хабів 19
1.3.6. Властивості хоста 20
1.4. Приклади USB-пристроїв 20
1.4.1. Миша та клавіатура., 21
1.4.2. Монітори 21
1.4.3. Перехідники USB-to-COM та USB-to-LPT 22
1.4.4. Сканери 23
1.4.5. Модеми 23
1.4.6. Звукові колонки 24
1.4.7. Флеш-диски 25
1.4.8. Хаби 28
1.4.9. Вимірювальна техніка 28
1.4.10. Екзотичні пристрої 29
1.5. Мережеве з'єднання через USB 30
1.5.1. Конвертер USB-Ethernet 31
1.5.2. Пряме з'єднання через порт USB 31
1.6. Передача даних 31
1.6.1. Принципи передачі 32
1.6.2. Механізм переривань 32
1.6.3. Інтерфейси хост-адаптера 32
1.6.4. Можливість прямого доступу до пам'яті 34
1.6.5. Режими передачі даних 34
1.7. Встановлення та конфігурування USB-пристроїв 35
1.7.1. Налаштування BIOS для USB 38
1.7.2. Усунення проблем 41
1.8. Обмеження USB 45
1.9. Якщо ви купуєте комп'ютер 46
1.9.1. HS і USB 2.0 - не одне й те саме! 46
1.9.2. Системна плата 47
1.9.3. Корпус 48
1.9.4. USB для "старих" моделей комп'ютерів 48
1.10. Інтернет-ресурси до цього розділу 49
Розділ 2. Апаратне забезпечення USB 51
2.1. Кабелі та роз'єми 51
2.1.1. Типи кабелів 52
2.1.2. Довжина кабелю 53
2.1.3. Роз'єми 53
2.2. Фізичний інтерфейс 55
2.2.1. Кодування даних 57
2.2.2. Ідентифікація пристроїв 58
2.3. Харчування 59
2.3.1. Типи живлення USB-пристроїв 59
2.3.2. Управління енергоспоживанням 60
2.3.3. Вхід у режим низького енергоспоживання 61
2.4. Інтернет-ресурси до цього розділу 61
ЧАСТИНА ІІ. ВНУТРІШНЯ ОРГАНІЗАЦІЯ USB 63
Розділ 3. Внутрішня організація шини 65
3.1. Логічні рівні обміну даними 65
3.1.1. Рівень клієнтського програмного забезпечення 66
3.1.2. Рівень системного драйвера USB 67
3.1.3. Рівень хост-контролера інтерфейсу 68
3.1.4. Рівень шини периферійного пристрою 68
3.1.5. Рівень логічного USB-пристрою 69
3.1.6. Функціональний рівень USB-пристрою 69
3.2. Передача даних за рівнями 69
3.3. Типи даних 71
3.4. Синхронізація при ізохронній передачі 73
3.5. Кадри 77
3.6. Кінцеві точки 78
3.7. Канали 79
3.8. Пакети 81
3.8.1. Формат пакетів-маркерів IN, OUT, SETUP та PING 83
3.8.2. Формат пакета SOF 83
3.8.3. Формат пакета даних 84
3.8.4. Формат пакета підтвердження< 84
3.8.5. Формат пакету SPLIT*84
3.9. Контрольна сума 85
3.9.1. Алгоритм обчислення CRC 86
3.9.2. Програмне обчислення CRC 87
3.10. Транзакції 90
3.10.1. Типи транзакцій 91
3.10.2. Підтвердження транзакцій та керування потоком 92
3.10.3. Протоколи транзакцій 93
Розділ 4. Внутрішня організація пристрою 96
4.1. Запити до USB-пристроїв 96
4.1.1. Конфігураційний пакет 96
4.1.2. Стандартні запити до пристроїв 99
4.1.3. Дескриптори пристрою 105
Глава 5. Внутрішня організація хоста та хабів 123
5.1. Хаби 123
5.1.1. Взаємодія хост-контролера з хабом 126
5.1.2. Дескриптор хаба 127
5.1.3. Запити хабів 129
5.1.4. Запит CLEAR_HUB_FEATURE 130
5.1.5. Запит CLEAR PORT_FEATURE 130
5.1.6. Запит GET_BUS_STA ТЕ 131
5.1.7. Запит GET_HUB_DESCRfPTOR 131
5.1.8. Запит GET_HUB_STATUS 131
5.1.9. Запит GET_PORT_STA TUS 132
5.1.10. Запит SET_HUB_DESCRIPTOR 134
5.1.11. Запит SET_HUB_FEATURE 134
5.1.12. Запит SET PORT FEATURE. 134
5.2. Спільна робота пристроїв з різними швидкостями 135
Розділ 6. USB без ПК 137
6.1. Рознімання OTG 138
6.2. Типи OTG-пристроїв 138
6.3. Дескриптор OTG-пристрою 139
6.4. Інтернет-ресурси до цього розділу 140
ЧАСТИНА ІІІ. ПРАКТИКА ПРОГРАМУВАННЯ 141
Розділ 7. Підтримка USB у Windows 143
7.1. Модель WDM 144
7.2. Взаємодія з драйвером USB 146
Глава 8. HID-пристрої *149
8.1. Властивості HID-пристрою 149
8.2. Порядок обміну даними з HID-пристроєм 151
8.3. Встановлення HID-пристрою 152
8.4. Ідентифікація пристрою HID 152
8.4.1. Ідентифікація завантажувальних пристроїв 153
8.4.2. Дескриптор конфігурації пристрою HID 153
8.4.3. HID-дескриптор 154
8.4.4. Дескриптор репорта 156
8.5. Структура дескриптора репорту 156
8.5.1. Структура елементів репорту 156
8.5.2. Типи елементів репорту 157
8.5.3. Приклади дескрипторів 165
8.6. Запити до пристрою HID 168
8.6.1. Запит GET_REPORT. 169
8.6.2. Запит SET_REPORT 169
8.6.3. Запит GETJDLE. 170
8.6.4. Запит SETJDLE 170
8.6.5. Запит GET_PROTOCOL 171
8.6.6. Запит SET_PROTOCOL 171
8.7. Інструментальні засоби 171
8.8. Взаємодія з HID-драйвером 172
Розділ 9. Вступ до WDM 181
9.1. Драйверні шари 183
9.2. Символьні імена пристроїв 184
9.3. Основні процедури драйвера WDM 189
9.3.1. Процедура DriverEntry 190
9.3.2. Процедура AddDevice 192
9.3.3. Процедура Unload 194
9.3.4. Робочі процедури драйвера 196
9.3.5. Обслуговування запитів IOCTL 203
9.4. Завантаження драйвера та звернення до процедур драйвера 209
9.4.1. Процедура роботи з драйвером 209
9.4.2. Реєстрація драйвера 210
9.4.3. Звернення до робочих процедур 217
9.4.4. Зберігання драйвера всередині файлу 218
9.5. Інструменти створення драйверів 220
9.5.1. NuMega Driver Studio 220
9.5.2. Jungo WinDriver 220
9.5.3. Jungo KernelDriver 220
Розділ 10. Специфікація PnP для USB 221
10.1. Загальні відомості про систему Plug and Play 221
10.1.1. Завдання та функції Plug and Play 221
10.1.2. Запуск процедури PnP 222
10.1.3. Програмні компоненти PnP 224
10.2. Plug and Play для USB 225
10.2.1. Конфігурація пристроїв USB 226
10.2.2. Нумерація пристроїв USB 226
10.2.3. PnP-ідентифікатори пристроїв USB 228
10.3. Отримання списку USB-пристроїв 229
10.4. INF-файл 234
10.4.1. Структура INF-файлу 234
10.4.2. Секція Version 235
10.4.3. Секція Manufacturer 237
10.4.4. Секція DestinationDirs 239
10.4.5. Секція опису моделі 241
10.4.6. Секція xxx.AddReg та xxx.DelReg. 242
10.4.7. Секція ххх.LogConfig 244
10.4.8. Секція xxx.CopyFiles 244
10.4.9. Секція Strings 245
10.4.10. Зв'язки секцій 246
10.4.11. Створення та тестування INF-файлів 247
10.4.12. Встановлення пристроїв за допомогою INF-файлу 248
10.5. Гілки реєстру для USB 249
Розділ 11. Функції BIOS 251
11.1. Сервіс BIOS 1АН 251
11.1.1. Функція В101Н - визначення PCI BIOS 252
11.1.2. Функція В102Н - пошук PCI-пристрою за ідентифікаторами
пристрої та виробника 253
11.1.3. Функція В103Н - пошук PCI-пристрою за кодом класу 254
11.1.4. Функція В108Н - читання регістра конфігурації (Byte) 255
11.1.5. Функція ВЮ9Н - читання регістра конфігурації (Word) 256
11.1.6. Функція В10АН - читання регістра конфігурації (DWord) 256
11.1.7. Функція В10ВН - запис регістра конфігурації (Byte) 257
11.1.8. Функція В10СН - запис регістра конфігурації (Word) 257
11.1.9. Функція B10DH – запис регістра конфігурації (DWord) 258
11.2. Приклад використання 259
ЧАСТИНА IV. СТВОРЕННЯ USB-ПРИСТРІЙ 283
Розділ 12. USB-периферія 285
12.1. Мікросхеми Atmel 286
12.1.1. Мікроконтролери з архітектурою MSC-51 286
12.1.2. Контролери хабів 289
12.1.3. Мікропроцесори-хаби з ядром AVR 289
12.1.4. Інші мікросхеми Atmel 290
12.2. Мікросхеми Cygnal 291
12.2.1. Мікропроцесори C8051F320 та C8051F321 291
12.2.2. Інші мікросхеми Cygnal 293
12.3. Мікросхеми FTDI 296
12.3.1. Мікросхеми FT232AM та FT232BM 297
12.3.2. Мікросхеми FT245AM та FT245BM 298
12.3.3. Мікросхема FT2232BM 299
12.3.4. Мікросхема FT8U100AX 300
12.3.5. Налагоджувальні комплекти та модулі 301
12.3.6. Драйвери 302
12.3.7. Додаткові утиліти 303
12.3.8. Інші модулі 304
12.4. Мікросхеми Intel 304
12.5. Мікросхеми Microchip 308
12.6. Мікросхеми Motorola 308
12.7. Мікросхеми Philips 309
12.7.1. Мікросхеми USB 310
12.7.2. Хаби 311
12.7.3. Інші мікросхеми Philips 313
12.8. Мікросхеми Texas Instruments 314
12.9. Мікросхеми Trans Dimension 317
12.10. Мікросхеми захисту живлення 318
12.11. Інтернет-ресурси до цього розділу 319
Глава 13. HID-пристрій на основі Atmel АТ89С5131 322
13.1. Структурна схема АТ89С5131 322
13.2. USB-реєстри АТ89С5131 324
13.2.1. Реєстр USBCON 324
13.2.2. Реєстр USBADDR 326
13.2.3. Реєстр USBINT 327
13.2.4. Реєстр USBIEN 328
13.2.5. Реєстр UEPNUM. 329
13.2.6. Реєстр UEPCONX 330
13.2.7. Реєстр UEPSTAX. 331
13.2.8. Реєстр UEPRST. 334
13.2.9. Реєстр UEPINT. 335
13.2.10. Реєстр UEPIEN 336
13.2.11. Реєстр UEPDATX 337
13.2.12. Реєстр UBYCTLX 337
13.2.13. Реєстр UFNUML 338
13.2.14. Реєстр UFNUMH. 338
13.3. Схемотехніка АТ89С5131 338
13.4. Інструменти програмування 339
13.4.1. Компілятор 341
13.4.2. Програматор 342
13.5. Програма для мікропроцесора 349
13.5.1. Перша версія програми для АТ89С5131 349
13.5.2. Додаємо рядкові дескриптори 369
13.5.3. Додавання кінцевих точок 374
13.5.4. Створення HID-пристрою 377
13.5.5. Обмін даними з HID-пристроєм 381
13.6. Читання репортів у Windows 388
13.7. Додаткові функції Windows ХР 396
13.8. Пристрій з кількома репортами 397
Розділ 14. Створення USB-пристрою на основі ATMEL АТ89С5131 402
14.1. He-HID-пристрій 402
14.2. Створення драйвера за допомогою Driver Studio 405
14.2.1. Декілька слів про бібліотеку Driver Studio 407
14.2.2. Інші класи Driver Studio 411
14.2.3. Створення шаблону драйвера за допомогою Driver Studio 412
14.2.4. Дороблення шаблону драйвера 422
14.2.5. Базові методи класу пристрою 423
14.2.6. Реалізація читання даних 426
14.2.7. Установка драйвера 428
14.2.8. Програма читання даних 429
14.2.9. Читання даних з кінцевих точок інших типів 438
14.2.10. "Чистий" USB-драйвер 439
Розділ 15. Використання мікросхем FTDI 457
15.1. Функціональна схема FT232BM 457
15.2. Схемотехніка FT232BM 460
15.3. Функції D2XX 460
15.4. Перехід від СОМ до USB 465
15.4.1. Опис схеми перетворювача 465
15.4.2. Встановлення швидкості обміну 467
ЧАСТИНА V. ДОВІДНИК 469
Розділ 16. Базові функції Windows 471
16.1. Функції CreateFile та CloseHandle: відкриття та закриття об'єкта.471
16.1.1. Додаткові відомості 472
16.1.2. Значення, що повертається 472
16.1.3. Приклад виклику 472
16.2. Функція Read File: читання даних 473
16.2.1. Додаткові відомості 474
16.2.2. Значення, що повертається 474
16.2.3. Приклад виклику 474
16.3. Функція WriteFile: передача даних 475
16.3.1. Додаткові відомості 476
16.3.2. Значення, що повертається 476
16.3.3. Приклад виклику 476
16.4. Функція ReadFileEx. АРС-читання даних 477
16.4.1. Значення, що повертається 479
16.4.2. Додаткові відомості 479
16.4.3. Приклад виклику 479
16.5. Функція WriteFileEx: АРС-передача даних 480
16.5.1. Значення, що повертається 481
16.5.2. Приклад виклику 481
16.6. Функція WaitForSingleObject очікування сигнального
стану об'єкта 482
16.6.1. Значення, що повертається 482
16.7. Функція WaitForMultipleObjects: очікування сигнального
стану об'єктів 483
16.7.1. Значення, що повертається 484
16.8. Функція GetOverlappedResult результат асинхронної операції 484
16.8.1. Значення, що повертається 485
16.9. Функція DeviceIoControl: пряме керування драйвером 485
16.9.1. Значення, що повертається 487
16.10. Функція QueryDosDevice: отримання імені пристрою
за його DOS-ім'ям 487
16.10.1. Значення, що повертається 488
16.10.2. Приклад виклику 488
16.11: Функція Define Dos Device: операції з DOS-іменем пристрою 489
16.11.1. Значення, що повертається 490
16.11.2. Приклад виклику 490
Розділ 17. Функції HID API. 492
17.1. Функція HidD_Hello: перевірка бібліотеки 492
17.2. Функція HidD_GetHidGuid: отримання GUID 492
17.3. Функція HidD_GetPreparsedData: створення описувача пристрою 493
17.4. Функція HidD_FreePreparsedData: звільнення описувача пристрою 493
17.5. Функція HidD_GetFeature: отримання FEATURE-репорту 494
17.6. Функція HidD_SetFeature: передача FEATURE-репорту 494
17.7. Функція HidD_GetNumInputBuffers: отримання числа буферів 495
17.8. Функція HidD_SetNumInputBuffers: встановлення числа буферів 495
17.9. Функція HidD_GetAttribntes: отримання атрибутів пристрою 495
17.10. Функція HidD_GetMamifactnrerStnng. отримання рядка виробника 496
17.11. Функція HidD_GetProductString отримання рядка продукту 497
17.12. Функція HidD_ Get Serial MumberString. отримання рядка
серійного номера 497
17.13. Функція HidD_GetIndexedString. отримання рядка за індексом 498
17.14. Функція HidDjGetlnputReporr. отримання INPUT-репорту 498
17.15. Функція HidD_SetOutputReport. передача OUTPUT-репорту 499
17.16. Функція HidP_GetCaps: отримання властивостей пристрою 499
17.17. Функція HidP_MaxDataListLength: одержання розмірів репортів 500
Глава 18. Хост-контролер UCH 502
18.1. Регістри керування хост-контролером 502
18.1.1. Реєстр команди USB (USBCMD) ..504
18.1.2. Регістр стану USB (USBSTS) 506
18.1.3. Реєстр управління перериваннями (USBINTR) 506
18.1.4. Реєстр номера кадру (FRNUM) 507
18.1.5. Регістр базової адреси кадру (FLBASEADD) 508
18.1.6. Регістр модифікатора початку кадру (SOFMOD) 508
18.1.7. Регістр стану та управління порту (PORTSC) 509
18.2. Структури даних хост-контролера UCH 510
18.2.1. Список кадрів 510
18.2.2. Дескриптор передачі i 511
18.2.3. Заголовок черги 514
18.3. Обробка списку дескрипторів UCH 516
Розділ 19. Інструменти 518
19.1. Засоби Microsoft Visual Studio 518
19.1.1. Depends 518
19.1.2. Error Lookup 518
19.1.3. GuidGen 518
19.2. Засоби Microsoft DDK 520
19.2.1. DeviceTree 520
19.2.2. DevCon .- 521
19.2.3. Chklnf та Genlnf. 526
19.3. Засоби CompuWare Corporation 527
19.3.1. Monitor 527
19.3.2. SymLink 527
19.3.3. EzDriverlnstaller 527
19.3.4. WdmSniff 527
19.4. Засоби Syslntemals 528
19.4.1. WinObj 528
19.5. Засоби USB Forum 531
19.5.1. HID Descriptor Tool 531
19.6. Засоби HDD Software 533
19.7. Засоби Sourceforge 533
ДОДАТКИ 535
Додаток 1. Додаткові функції 537
Додаток 2. Таблиця ідентифікаторів мов (LangID) 539
Додаток 3. Таблиця кодів виробників (Vendor ID, Device ID) 543
Додаток 4. Опис компакт-диска 546
Література 548
Предметний покажчик 549

Вступ
Для кого ця книга
Що ви знайдете у книзі
Програмні вимоги
Апаратні вимоги
Про програмний код
Короткий опис глав
Позначення
Подяки
Зворотній зв'язок
Частина I. Загальні відомості про USB
Розділ 1. Специфікація USB
1.1. Що таке USB і навіщо це треба
1.1.1. Загальна архітектура USB
1.1.2. Фізична та логічна архітектура USB
1.1.3. Складові USB
1.1.4. Властивості USB-пристроїв
1.1.5. Принципи передачі
1.1.6. Механізм переривань
1.1.7. Режими передачі даних
1.1.8. Логічні рівні обміну даними
1.1.8.1. Рівень клієнтського ПЗ
1.1.8.2. Рівень системного драйвера USB
1.1.8.3. Рівень хост-контролера інтерфейсу
1.1.8.4. Рівень шини периферійного USB-пристрою
1.1.8.5. Рівень логічного USB-пристрою
1.1.8.6. Функціональний рівень USB-пристрою
1.1.9. Передача даних за рівнями
1.1.10. Типи передачі даних
1.1.11. Кадри
1.1.12. Кінцеві точки
1.1.13. Канали
1.1.14. Пакети
1.1.14.1. Формат маркер-пакетів IN, OUT, SETUP та PING
1.1.14.2. Формат пакета SOF
1.1.14.3. Формат пакету даних
1.1.14.4. Формат пакета підтвердження
1.1.14.5. Формат пакету SPLIT
1.1.15. Контрольна сума
1.1.15.1. Алгоритм обчислення CRC
1.1.15.2. Програмне обчислення CRC
1.1.16. Транзакції
1.1.16.1. Типи транзакцій
1.1.16.2. Підтвердження транзакцій та керування потоком
1.1.16.3. Протоколи транзакцій
1.2. Запити до USB-пристроїв
1.2.1. Конфігураційний пакет
1.2.2. Стандартні запити до USB-пристроїв
1.2.2.1. Отримання стану GET_STATUS
1.2.2.2. Скидання якості CLEAR_FEATURE
1.2.2.3. Роздільна здатність SET_FEATURE
1.2.2.4. Завдання адреси на шині SET_ADDRESS
1.2.2.5. Отримання дескриптора GET_DESCRIPTOR
1.2.2.6. Передача дескриптора SET_DESCRIPTOR
1.2.2.7. Отримання коду конфігурації GET_CONFIGURATION
1.2.2.8. Завдання коду конфігурації SET_CONFIGURATION
1.2.2.9. Отримання коду налаштування інтерфейсу GET_INTERFACE
1.2.2.10. Встановлення коду налаштування інтерфейсу SET_INTERFACE
1.2.2.11. Визначення номера кадру синхронізації SYNC_FRAME
1.2.2.12. Обробка стандартних запитів
1.2.3. Дескриптор пристрою
1.2.3.1. Дескриптор пристрою
1.2.3.2. Уточнюючий дескриптор пристрою
1.2.3.3. Дескриптор конфігурації
1.2.3.4. Дескриптор інтерфейсу
1.2.3.5. Дескриптор кінцевої точки
1.2.3.6. Дескриптор рядка
1.2.3.7. Специфічні дескриптори
1.2.3.8. Порядок отримання дескрипторів
1.3. Система Plug and Play (PnP)
1.3.1. Конфігурування USB-пристроїв
1.3.2. Нумерація USB-пристроїв
1.3.3. PnP-ідентифікатори USB-пристроїв
1.3.4. Символьні імена пристроїв
1.4. Модель WDM
Розділ 2. Програмування мовою C для мікроконтролера
2.1. Загальні відомості про мову С для мікроконтролерів
2.2. Використання стандартних бібліотек
2.3. Програмування для АТ89С5131
2.3.1. Файл ініціалізації
2.3.2. Структури дескрипторів
2.3.3. Структура проекту
Розділ 3. Інструменти
3.1. Програматори
3.1.1. Програматор Flip
3.1.2. Програматор ER-Tronik
3.2. Інструменти створення драйверів
3.2.1. NuMega Driver Studio
3.2.2. Jungo WinDriver
3.2.3. Jungo KernelDriver
3.3. Засоби Microsoft Visual Studio
3.3.1. Depends (Dependency Walker)
3.3.2. Error Lookup
3.3.3. GuidGen
3.4. Засоби Microsoft DDK
3.4.1. DeviceTree
3.4.2. DevCon
3.4.2.1. Ключ classes
3.4.2.2. Ключ driverfiles
3.4.2.3. Ключ hwids
3.4.2.4. Ключ rescan
3.4.2.5. Ключ stack
3.4.2.6. Ключ status
3.4.3. Chklnf та Genlnf
3.5. Кошти CompuWare Corporation
3.5.1. Monitor
3.5.2. SymLink
3.5.3. EzDriverlnstaller
3.5.4. WdmSniff
3.6. Засоби Syslnternals
3.6.1. WinObj
3.7. Засоби USB Forum
3.7.1. HID Descriptor Tool
3.8. USB Command Verifier
3.9. Засоби HDD Software
3.10. Кошти Sourceforge
3.11. Програма моніторингу Bus Hound
Розділ 4. Принципи використання функцій Win32 в.
4.1. Загальні відомості
4.2. Імпорт функцій Win32
4.3. Структури
4.3.1. Атрибут StructLayout
4.3.2. Атрибут MarshalAs
4.4. Прямий доступ до даних
4.5. Обробка повідомлень Windows
4.6. Загальні відомості про WMI
4.7. Інтернет-ресурси до цього розділу
Частина ІІ. Класи USB
Розділ 5. Клас CDC
5.1. Методи перетворення інтерфейсів USB/RS-232
5.2. Загальні відомості про інтерфейс RS-232
5.2.1. Лінії обміну
5.2.1.1. Передані дані (BA/TxD/TD)
5.2.1.2. Дані, що приймаються (BB/RxD/RD)
5.2.1.3. Запит передачі (CA/RTS)
5.2.1.4. Готовність до передачі (CB/CTS)
5.2.1.5. Готовність DCE (CC/DSR)
5.2.1.6. Готовність DTE (CD/DTR)
5.2.1.7. Індикатор дзвінка (CE/RI)
5.2.1.8. Виявлення несучої (CF/DCD)
5.2.1.9. Готовність до прийому (CJ)
5.3. Специфікація CDC
5.3.1. Стандартні дескриптори
5.3.2. Функціональні дескриптори
5.3.2.1. Функціональний заголовковий дескриптор
5.3.2.2. Дескриптор режиму команд
5.3.2.3. Дескриптор абстрактного пристрою
5.3.2.4. Дескриптор групування
5.3.3. Спеціальні запити
5.3.3.1. Запит SET_LINE_CODING
5.3.3.2. Запит GET_LINE_CODING
5.3.3.3. Запит SET_CONTROL_LINE_STATE
5.3.3.4. Запит SEND_BREAK
5.3.4. Нотифікації
5.3.4.1. Нотифікація RING^DETECT
5.3.4.2. Нотифікація SERIAL_STATE
5.4. Підтримка CDC у Windows
5.4.1. Огляд функцій Windows для роботи з послідовними портами
5.4.1.1. Основні операції з портом
5.4.1.2. Опції налаштування порту
5.4.1.3. Спеціальне налаштування порту
5.4.1.4. Отримання стану ліній модему
5.4.1.5. Робота із CDC на платформі. NET
5.4.2. Відповідність функцій Windows та USB-запитів
Розділ 6. Клас HID
6.1. Специфікація пристроїв HID
6.2. Порядок обміну даними з HID-пристроєм
6.3. Встановлення драйвера пристрою HID
6.4. Ідентифікація пристрою HID
6.4.1. Ідентифікація завантажувальних пристроїв
6.4.2. Дескриптор конфігурації пристрою HID
6.4.3. HID-дескриптор
6.4.4. Дескриптор репорту
6.5. Структура дескриптора репорту
6.5.1. Елементи репорту
6.5.1.1. Елементи короткого типу
6.5.1.2. Елементи довгого типу
6.5.2. Типи елементів репорту
6.5.2.1. Основні елементи
6.5.2.2. Глобальні елементи
6.5.2.3. Локальні елементи
6.5.3. Приклади дескрипторів
6.6. Запити до НID-пристрою
6.6.1. Запит GET_REPORT
6.6.2. Запит SET_REPORT
6.6.3. Запит GET_IDLE
6.6.4. Запит SET_IDLE
6.6.5. Запит GET_PROTOCOL
6.6.6. Запит SET_PROTOCOL
6.7. Інструменти
6.8. Драйвери для пристроїв HID у Windows
Розділ 7. Інші класи USB
Частина ІІІ. Практика програмування USB
Розділ 8. Створення USB-пристрою на основі АТ89С5131
8.1. Загальна інформація про АТ89С5131
8.2. Структурна схема АТ89С5131
8.3. USB-реєстри AT89C5131
8.3.1. Реєстр USBCON
8.3.2. Реєстр USBADDR
8.3.3. Реєстр USBINT
8.3.4. Реєстр USBIEN
8.3.5. Реєстр UEPNUM
8.3.6. Реєстр UEPCONX
8.3.7. Реєстр UEPSTAX
8.3.8. Реєстр UEPRST
8.3.9. Реєстр UEPINT
8.3.10. Реєстр UEPIEN
8.3.11. Реєстр UEPDATX
8.3.12. Реєстр UBYCTLX
8.3.13. Реєстр UFNUML
8.3.14. Реєстр UFNUMH
8.4. Схемотехніка АТ89С5131
8.5. Базовий проект для АТ89С5131
8.5.1. Перша версія програми для АТ89С5131
8.5.2. Додаємо рядкові дескриптори
8.5.3. Додавання кінцевих точок
8.6. Завантаження програми
Розділ 9. Реалізація класу CDC
9.1. Реалізація CDC
9.2. Дескриптори пристрою
9.2.1. Ініціалізація кінцевих точок
9.2.2. Обробка CDC-запитів
9.2.3. Конфігурування RS-порту та CDC-лінії
9.2.4. Прийом та передача даних
9.3. Встановлення драйвера
9.4. Програмування обміну даними з CDC-пристроєм на мові Delphi
9.5. Програмування обміну з CDC-пристроєм мовою C#
9.5.1. Використання компонента MSCOMM
9.5.2. Використання функцій Win32
9.6. Проблеми CDC
Розділ 10. Реалізація класу HID
10.1. Реалізація HID на АТ89С5131
10.2. Передача кількох байтів
10.3. Feature-репорти
10.4. Передача даних від хоста (SET_REPORT)
10.5. Встановлення HID-пристрою
10.6. Обмін даними з HID-пристроєм
10.6.1. Отримання імені HID-пристрою
10.6.2. Отримання атрибутів пристрою та читання репортів
10.6.3. Передача даних від хоста до пристрою HID
10.7. Приклади HID-пристроїв
10.7.1. Реалізація пристрою "миша"
10.7.2. Реалізація пристрою "Клавіатура"
10.8. Використання протоколу HID
10.8.1. Інтерпретація даних
10.8.2. Колекції
10.8.3. Масиви та кнопки
10.9. HID-пристрій з кількома репортами
Розділ 11. Спеціальні функції Windows
11.1. Опції Setup API
11.1.1. Перелік USB-пристроїв
11.1.2. Отримання стану USB-пристрою
11.2. Перелік USB-пристроїв за допомогою WMI
11.3. Спеціальні функції Windows XP
11.3.1. HidD_GetInputReport - читання HID-репортів
11.3.2. Отримання даних Raw Input
11.4. Функції DirectX
11.5. Діалог додавання нового обладнання
11.6. Робота із символьними іменами пристроїв
11.7. Безпечне вилучення флеш-дисків
11.8. Виявлення додавання та видалення пристроїв
11.9. Інтернет ресурси
Розділ 12. Розробка драйвера
12.1. Основні процедури драйвера WDM
12.1.1. Процедура DriverEntry
12.1.2. Процедура AddDevice
12.1.3. Процедура Unload
12.1.4. Робочі процедури драйвера
12.1.4.1. Заголовок пакета
12.1.4.2. Осередки стека введення/виводу
12.4.1.3. Робочі процедури драйвера
12.1.5. Обслуговування запитів IOCTL
12.2. Завантаження драйвера та звернення до процедур драйвера
12.2.1. Процедура роботи з драйвером
12.2.2. Реєстрація драйвера
12.2.2.1. Реєстрація за допомогою SCM-менеджера
12.2.2.2. Параметри драйвера у реєстрі
12.2.3. Звернення до робочих процедур
12.2.4. Зберігання драйвера всередині файлу.
12.3. Створення драйвера за допомогою Driver Studio
12.3.1. Декілька слів про бібліотеку Driver Studio
12.3.1.1. Клас KDriver
12.3.1.2. Клас KDevice
12.3.1.3. Клас Klrp
12.3.1.4. Клас KRegistryKey
12.3.1.5. Клас KLowerDevice
12.3.1.6. Класи USB
12.3.2. Інші класи Driver Studio
12.3.3. Створення шаблону драйвера за допомогою Driver Studio
12.3.3.1. Крок 1. Завдання імені та шляхи проекту
12.3.3.2. Крок 2. Вибір архітектури драйвера
12.3.3.3. Крок 3. Вибір шини
12.3.3.4. Крок 4. Завдання набору кінцевих точок
12.3.3.5. Крок 5. Завдання імені класу та файлу
12.3.3.6. Крок 6. Вибір функцій драйвера
12.3.3.7. Крок 7. Вибір способу обробки запитів
12.3.3.8. Крок 8. Створення параметрів драйвера, що зберігаються.
12.3.3.9. Крок 9. Властивості драйвера
12.3.3.10. Крок 10. Завдання кодів IOCTL
12.3.3.11. Крок 11. Додаткові налаштування
12.3.4. Дороблення шаблону драйвера
12.3.5. Базові методи класу пристрою
12.3.6. Реалізація читання даних
12.3.7. Встановлення драйвера
12.3.8. Програма читання даних
12.3.9. Читання даних з кінцевих точок інших типів
12.3.10. "Чистий" драйвер USB-пристрою
Частина IV. Довідник
Розділ 13. Формат INF-файлу
13.1. Структура INF-файлу
13.1.1. Секція Version
13.1.2. Секція Manufacturer
13.1.3. Секція DestinationDirs
13.1.3.1. Ключ DefaultDescDir
13.1.3.2. Ключі file-list-section
13.1.3.3. Ключ dirid
13.1.3.4. Ключ subdir
13.1.4. Секція опису моделі
13.1.5. Секція xxx. AddRegw xxx. DelReg
13.1.6. Секція xxx. LogConfig
13.1.7. Секція xxx. CopyFiles
13.1.8. Секція Strings
13.1.9. Зв'язки секцій
13.2. Створення та тестування INF-файлів
13.3. Встановлення пристроїв за допомогою INF-файлу
13.4. Гілки реєстру для USB
Розділ 14. Базові функції Windows
14.1. Функції CreateFile та CloseHandle: відкриття та закриття об'єкта
14.1.1. додаткові відомості
14.1.2. Значення, що повертається
14.1.3. Приклад виклику
14.2. Функція ReadFile: читання даних
14.2.1. додаткові відомості
14.2.2. Значення, що повертається
14.2.3. Приклад виклику
14.3. Функція Write File: передача даних
14.3.1. додаткові відомості
14.3.2. Значення, що повертається
14.3.3. Приклад виклику
14.4. Функція ReadFileEx. АРС-читання даних
14.4.1. Значення, що повертається
14.4.2. додаткові відомості
14.4.3. Приклад виклику
14.5. Функція WriteFiieEx: АРС-передача даних
14.5.1. Значення, що повертається
14.5.2. Приклад виклику
14.6. Функція WaitForSingieObject очікує сигнального стану об'єкта
14.6.1. Значення, що повертається
14.7. Функція WaitForMultipleObjects: очікування сигнального стану об'єктів
14.7.1. Значення, що повертається
14.8. Функція GetOverlapped Result: результат асинхронної операції
14.8.1. Значення, що повертається
14.9. Функція DeviceloControl: пряме керування драйвером
14.9.1. Значення, що повертається
14.10. Функція Cancel/o: переривання операції
14.10.1. Значення, що повертається
14.11. Функція Query Dos Device, отримання імені пристрою за його DOS ім'ям
14.11.1. Значення, що повертається
14.11.2. Приклад виклику
14.12. Функція Define Dos Device: операції з DOS ім'ям пристрою
14.12.1. Значення, що повертається
14.12.2. Приклад виклику
Розділ 15. Структури та функції Windows для послідовних портів
15.1. Структура налаштувань порту COMMCONFIG
15.2. Структура властивостей порту COMMPROP
15.3. Структура тайм-аутів COMMTIMEOUTS
15.4. Структура статусу порту COMSTAT
15.5. Структура DCB
15.6. Функція BuildCommDCB: створення структури DCB з рядка
15.6.1. додаткові відомості
15.6.2. Значення, що повертається
15.6.3. Приклад виклику
15.7. Функція BuildCommDCBAndTimeouts: створення структури DCB та тайм-аутів з рядка
15.8. Функції SetCommBreak та ClearCommBreak: керування виведенням даних
15.8.1. Значення, що повертається
15.9. Функція ClearCommError: отримання та скидання помилок порту
15.9.1. Значення, що повертається
15.10. Функція EscapeCommFunction: керування портом
15.10.1. Значення, що повертається
15.11. Функції GetCommMask та SetCommMask: маска виклику подій
15.11.1. Значення, що повертається
15.12. Функція WaitCommEvent очікує події СОМ-порту
15.12.1. Значення, що повертається
15.12.2. додаткові відомості
15.12.3. Приклад виклику
15.13. Функції GetCommConfig та SetCommConfig: конфігурація параметрів порту
15.13.1. Значення, що повертається
15.13.2. Приклад виклику
15.14. CommConfigDialog: діалог конфігурування порту
15.14.1. Значення, що повертається
15.14.2. додаткові відомості
15.14.3. Приклад виклику
15.15. Функція GetCommProperties: прочитати властивості порту
15.15.1. Значення, що повертається
15.15.2. Приклад виклику
15.16. Функції GetCommState та SetCommState: стан порту
15.16.1. Значення, що повертається
15.16.2. Приклад виклику
15.17. Функції GetCommTimeouts та SetComniTimeouts: тайм-аути порту
15.17.1. Значення, що повертається
15.17.2. Приклад виклику
15.18. Функція PurgeComm: скидання буферів порту
15.18.1. Значення, що повертається
15.18.2. Приклад виклику
15.19. Функція SetupComm: конфігурування розмірів буферів
15.19.1. Значення, що повертається
15.20. Функції GetDefaultCommConfig та SetDefaitltCommConfig: налаштування порту за замовчуванням
15.20.1. Значення, що повертається
15.21. Функція TransmitCommChar. передача спеціальних символів
15.21.1. Значення, що повертається
15.22. Функція GetCommModemStatus: статус модему
15.22.1. Значення, що повертається
15.22.2. Приклад виклику
15.23. Функція EnumPorts: перерахування портів
15.23.1. додаткові відомості
15.23.2. Значення, що повертається
15.23.3. Приклад виклику
Розділ 16. Структури та функції Windows Setup API
16.1. Функція Setup DiGetCiassDevs: перелік пристроїв
16.1.1. Значення, що повертається
16.2. Функція SetupDiDestroyDevicelnfoList звільнення блоку опису пристрою
16.2.1. Значення, що повертається
16.3. Функція SetupDiEnumDevicelnterfaces: інформація про пристрій
16.3.1. Значення, що повертається
16.4. Функція SetupDiGetDevicelnterfaceDetaii: детальна інформація про пристрій
16.5. Функція SetupDiEnumDevicelnfo: інформація про пристрій
16.6. Функція SetupDiGetDeviceRegistryProperty: отримання Plug and Play властивостей пристрою
16.7. Функція CM_Get_DevNode_Status: статус пристрою
16.8. Функція CM_Request_Device_Eject безпечне вилучення пристрою
Розділ 17. Структури та функції Windows HID API
17.1. Функція HidD_Hello: перевірка бібліотеки
17.2. Функція HidD_JetHidGuid: отримання GUID
17.3. Функція HidD_GetPreparsedData: створення описувача пристрою
17.4. Функція HidD_EreePreparsedData: звільнення описувача пристрою
17.5. Функція HidD_Get Feature: отримання Feature-репорту
17.6. Функція HidD_SetFeature: передача Feature-репорта
17.7. Функція HidD_GetNumlnputBuffers: отримання числа буферів
17.8. Функція HidD_SetNumlnputBuffers: встановлення числа буферів
17.9. Функція HidD_GetAttributes: отримання атрибутів пристрою
17.10. Функція HidD_GetManufacturerString. отримання рядка виробника
17.11. Функція HidD_GetProductString отримання рядка продукту
17.12. Функція HidD_GetSerialNumberString. отримання рядка серійного номера
17.13. Функція HidD_GetIndexedString. отримання рядка за індексом
17.14. Функція HidD_Jetlnput Report отримання Input-репорту
17.15. Функція HidD_SetOutputReport. передача Output-репорту
17.16. Функція HidP_GetCaps: отримання властивостей пристрою
17.17. Функція HidP_MaxDataListLength: одержання розмірів репортів
17.18. Функція HidD_FIushQueue: скидання буферів
17.19. Функція HidP_GetLinkColiectionNodes: дерево колекцій
17.20. Функції HidP_GetScaledUsageValue u HidP_SetScaledUsage Value: отримання та завдання перетворених значень
17.21. Функція HidF_MaxUsageListLength: розмір буфера для кодів клавіш
17.22. Функція HidP_UsageListDifference: різницю між масивами
Програми
Додаток 1. Додаткові функції
Додаток 2. Компіляція прикладів в інших версіях Delphi
Додаток 3. Таблиця ідентифікаторів мов (LangID)
Додаток 4. Таблиця кодів виробників (Vendor ID, Device ID)
Додаток 5. Як створити ярлик Device Manager
Додаток 6. Часті питання
Додаток 7. Опис компакт-диска
Література
Предметний покажчик

Почнемо з мінімуму:
include 18f2455 - бібліотека для використовуваного МК
--
enable_digital_io () -- перемикання всіх входів на цифровий режим
--
alias Button is pin_B7 - якщо вже в нас підключена кнопка, оголосимо її
pin_B7_direction = input - кнопка у нас працює на вхід
--
-- один рядок - і ми маємо все необхідне для роботи з USB CDC
include usb_serial - бібілотека для роботи з usb
--
usb_serial_init() -- --ініціалізуємо USB CDC
forever loop- Основний цикл, виконується постійно
usb_serial_flush() - Обновлення usb. Ця процедура виконує всі необхідні
-- дії підтримки з'єднання з ПК
end loop

Скомпілювавши даний код, записавши отриманий HEX файл в МК за допомогою бутлоадера і запустивши пристрій можна буде спостерігати як в системі визначається новий пристрій: Віртуальний сom-порт.

Тепер, коли пристрій працює, навчимо його спілкуватися.

Для читання прийнятого байта існує функція usb_serial_read( byte ) :boolean. За наявності отриманого байта вона заносить його у вказану змінну та повертає true, інакше повертає false.

Для надсилання байта існує процедура usb_serial_data. Вона замаскована під змінну, тому для відправки байта достатньо присвоїти їй значення байта, що відправляється.

Оголосимо змінну розміром в байт до основного циклу, в основному циклі перевірятимемо наявність отриманих байт, і за наявності відправляти їх назад.

include 18f2455
--
enable_digital_io ()
--
alias Button is pin_B7
pin_B7_direction = input
--
--
include usb_serial
--
usb_serial_init()
var byte ch -- оголошуємо змінну
forever loop- Основний цикл
usb_serial_flush()
if(usb_serial_read (ch)) then-- якщо байт отримано, він буде записаний у ch
usb_serial_data = ch -- відправляємо отриманий байт назад
end if
end loop

Компілюємо, затискаємо кнопку, пересмикуємо живлення, запускаючи бутлоадер, міняємо прошивку, запускаємо.
Пристрій знову визначився в системі, тепер нам потрібний софт, щоб протестувати роботу пристрою.

Поки ми не маємо свого, використовуємо готовий термінал: я використовував програму RealTerm.
Відкриваємо порт з потрібним номером та надсилаємо дані.


І нам у відповідь надходить те, що ми відправили. Отже, все працює як слід.

Софт

Отже, наш мікроконтролер вміє приймати байти і відразу відправляти їх назад. Тепер напишемо свій софт для спілкування з ним (я використовуватиму Delphi).

Створюємо новий проект, розкидаємо формою необхідні компоненти:
SpinEdit1 – для вказівки номера порту
Button1 - для встановлення з'єднання
Button2 – для розриву з'єднання
SpinEdit2 - для введення байта у десятковому вигляді
Button3 - для відправки байта
Memo1 – для виведення прийнятої інформації.

Як вже було сказано вище, з com-портом потрібно працювати так само, як і зі звичайним текстовим файлом: використовуючи функції CreateFile, WriteFile та ReadFile.

Щоб не вдаватися до подробиць, візьмемо готову бібліотеку для роботи з com-портом: ComPort.

Вішаємо на кожну кнопку необхідне завдання та отримуємо кінцевий код:

unit Unit1;

interface

Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, ComPort;

Type
TForm1 = class (TForm)
SpinEdit1: TSpinEdit;
Button1: TButton;
Button2: TButton;
SpinEdit2: TSpinEdit;
Button3: TButton;
Memo1: TMemo;
procedure OnRead(Sender: TObject; ReadBytes: array of Byte);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
(Private declarations)
Port: TComPort;
public
(Public declarations)
end;

var
Form1: TForm1;
num: integer;
implementation

Procedure TForm1.Button1Click(Sender: TObject);
begin
Port:= TComPort.Create(SpinEdit1.Value, br115200); //створюємо з'єднання
Port.OnRead:= OnRead; //Створюємо потік читання прийнятих даних
Button2.Enabled:= true; //активуємо кнопку закриття з'єднання
end;

Procedure TForm1.Button2Click(Sender: TObject);
begin
Port.Free; //закриваємо з'єднання
Button2.Enabled:= false ; //відключаємо кнопку
end;

Procedure TForm1.Button3Click(Sender: TObject);
begin
if Button2.Enabled then Port.Write();
end;

Procedure TForm1.FormDestroy(Sender: TObject);
begin
if Button2.Enabled then
Port.Free;
end;

Procedure TForm1.OnRead(Sender: TObject; ReadBytes: array of Byte);
var
i:integer;
begin
for i:= Low(ReadBytes) to High(ReadBytes) do //проходимо масивом прийнятих байт
begin
Memo1.Text:= Memo1.Text + "." +InttoHex(ReadBytes[i],2); //додаємо його HEX значення у вікно
inc(num); //Вважаємо колв-о прийнятих байт
end;
if num > 10 then begin
Memo1.Lines.Add(""); //переносимо рядок
num: = 0;
end;
end;

Запускаємо, встановлюємо з'єднання, відправляємо байти:

Ось і готовий наш найпростіший термінал для роботи з найпростішим USB-пристроєм.

Як видно, читання та запис відбувається динамічними масивами байт.

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

include 18f2455
--
enable_digital_io ()
--
alias Button is pin_B7
pin_B7_direction = input
--
--
include usb_serial
--
usb_serial_init()
var byte ch
var byte i -- оголошуємо другу змінну
forever loop- Основний цикл
usb_serial_flush()
if(usb_serial_read (ch)) then-- якщо байт отримано виконуємо необхідні дії
case ch of - перебираємо номер байта
0 : usb_serial_data = 0xff
1: usb_serial_data = Button -- надсилання стану кнопки
OTHERWISE block- якщо отримано щось інше
for 16 using i loop- відправляємо 10 байт із даними
usb_serial_data = ch +i - від ch до ch +15
end loop
end block
end case
end if
end loop

Додаткові можливості

Якщо на цьому зупинитися, вийде проста стаття з детальним описом прикладу використання бібліотеки, яких на просторах мережі достатньо. Тому додам трохи більш поглибленої інформації.

Спрощення надсилання даних

Відправляти інформацію по одному байту – не завжди зручно. Дуже часто може стати в нагоді бібліотека print. Вона містить процедури з надсилання даних всілякої довжини різними форматами: byte,hex,dec,bin,boolean що може спростити виведення даних у програмі.
>include print
...
var dword data
print_dword_hex (usb_serial_data , data )

Назву всіх команд можна переглянути у файлі бібліотеки.

Очікування підключення до ПК

Якщо перед стартом основного циклу мікроконтролера необхідно попередньо встановити з'єднання з ПК, можна дописати перед ним рядки
while(usb_cdc_line_status () == 0x00 ) loop
end loop

Прив'язуємо до пристрою номер порту

Якщо залишити все як є, система при кожному новому підключенні виділятиме перший вільний номер порту. А це означає, що за ним доведеться завжди стежити.
Для того, щоб цього не відбувалося, необхідно пристрою присвоїти унікальне значення серійного номера до підключення бібліотеки usb:
Номер може бути будь-якої довжини та містити різні символи.
const byte USB_STRING3 =
{
24 , - Довжина масиву
0x03 , -- bDescriptorType
"0" , 0x00 ,
"1" , 0x00 ,
"2" , 0x00 ,
"3" , 0x00 ,
"4" , 0x00 ,
"5" , 0x00 ,
"6" , 0x00 ,
"7" , 0x00 ,
"8" , 0x00 ,
"9" , 0x00 ,
"X", 0x00
}

Змінюємо ім'я пристрою на своє

Змінити ім'я пристрою, видиме в системі до встановлення драйверів, можна оголосивши масив з ім'ям, як і серійний номер, це необхідно зробити до підключення бібліотеки USB.
const byte USB_STRING2 =
{
28 , --
0x03 , -- bDescriptorType
"D", 0x00 ,
"e", 0x00 ,
"m", 0x00 ,
"o", 0x00 ,
" " , 0x00 ,
"B", 0x00 ,
"o", 0x00 ,
"a", 0x00 ,
"r", 0x00 ,
"d", 0x00 ,
" " , 0x00 ,
"=" , 0x00 ,
")" , 0x00
}

Але на жаль, після установки драйверів пристрій змінить ім'я на вказане в.inf файлі, тому змінимо ім'я і там


DESCRIPTION=«Demo CDC»

Організуємо автопідключення пристрою

На жаль, ніяких прямих шляхів виконати це завдання немає, тому доведеться хитрувати.

Насамперед необхідно надати своєму пристрою унікальне значення виробника та продукту, щоб легко визначати його серед сотень інших стандартних CDC-прошивок.
VID і PID видаються за денюжку, тому підемо по шляху китайців: нишком візьмемо собі свідомо вільні значення.

Прошивка:
У прошивці необхідно оголосити дві змінні до підключення бібліотеки USB

const word USB_SERIAL_PRODUCT_ID = 0xFF10
const word USB_SERIAL_VENDOR_ID = 0xFF10

Замість FF10 можна вставити будь-які два слова (2 байти). Кінцевий результат міститься в архіві, що додається.

Драйвера:
Оскільки драйвера не призначені для нашої комбінації VID та PID, допишемо наші значення в.inf файл вручну:


%DESCRIPTION%=DriverInstall, USB\VID_FF10&PID_FF10


%DESCRIPTION%=DriverInstall, USB\VID_FF10&PID_FF10

Софт:
Для вилову подій підключення\відключення пристрою підключимо бібліотеку ComponentUSB. Не вважаю за потрібне пояснювати кожний рядок: всі зміни можна побачити в проекті, що додається.

Результат

На скріншоті складно розглянути, але кнопка відправки активна тільки в момент наявності підключеного пристрою, при цьому кожні 50мс програма подає запит на отримання стану кнопки (що, втім, неправильно, тому що натискання кнопки має оброблятися на МК).

Як видно, організувати обмін даними між МК та ПК через USB – не найскладніше заняття. Отримане з'єднання можна використовувати не тільки для кінцевих цілей: воно так само підходить для налагодження програми. Адже відправити на комп'ютер результати розрахунків, поточні стани регістрів і змінних набагато наочніше, ніж моргати парою світлодіодів азбукою морзе.

І насамкінець: раджу заглянути у вихідний код лампи настрою. Там можна знайти досить хороший варіант обробки даних для організації зручного протоколу обміну.

© 2023 androidas.ru - Все про Android