Programare controler USB. Bazele dezvoltării și programării dispozitivelor USB simple. Programarea dispozitivelor HID la „nivelul superior”

Programare prin portul USB

Programarea dispozitivului pentru configurare antene satelit SF-50 prin USB diferă de programarea prin RS-232 doar prin modul în care datele sunt transferate de la instrument la computer și de la computer la instrument. La programare prin USB, un portabil unitate USB(unitate flash). Acest lucru este convenabil atunci când, de exemplu, computerul dvs. sau, mai des, un laptop (netbook) nu are un port serial RS-232 pe șasiu.
Pentru a programa dispozitivul folosind o unitate USB, veți avea nevoie de:
- Unitate USB (unitate flash) formatată în sistemul de fișiere FAT-32;
- Programul de editare AliEditor, situat în folderul Database_editor_new al secțiunii de software a dispozitivului OPENBOX SF-50.

Înainte de programare, trebuie să transferați baza de date de pe dispozitiv pe computer. Pentru a face acest lucru, porniți dispozitivul, conectați-vă la port unitate flash USB. Executați MENU – Sistem – Salvare pe USB,

Ieșiți din meniu apăsând butonul MENU până când apare canalul curent sau până când imaginea meniului principal dacă nu există încă canale și scoateți unitatea flash. Introduceți unitatea flash în computer.
Rulați programul Editor.exe din folderul Database_editor_new și deschideți imaginea de pe unitatea flash din el.

Când vi se solicită să selectați o bază de date, selectați Baza de date utilizator.

Faceți clic pe OK. Selectați Toate serviciile, se va deschide o listă cu toate canalele TV, radio și servicii scanate și salvate disponibile în baza de date.

Editați canalele după cum doriți, de exemplu, lăsând doar canalele deschise.
Pe tastatura computerului, țineți apăsat butonul Shift, apăsați săgeata în jos și evidențiați canalele pe care doriți să le ștergeți. Faceți clic pe Ștergere pentru a șterge cel selectat.

Pentru a edita setările satelitului, selectați Toate serviciile – Informații satelit – EUTELSAT W4, W7, apăsați butonul ENTER.

Dacă este necesar, editați valorile din Antena 1.
Pentru a șterge un transponder, stați pe cel inutil și apăsați butonul Ștergere de pe tastatura computerului, confirmați acțiunea selectată.

Pentru a adăuga un transponder, accesați numele satelitului, apăsați butonul din dreapta mouse-ul și selectați Adăugare informații (sau evidențiați satelitul și apăsați butonul Inserare de pe tastatură).

Introduceți datele pentru noul transponder, luându-l, de exemplu, de pe site-ul web lyngsat.com.

Faceți clic pe OK și asigurați-vă că transponderul este înregistrat.

Pentru a adăuga un satelit, accesați linia Informații satelit, apăsați tasta Inserare de pe tastatură și introduceți parametrii noului satelit.

închideți programul editor și scoateți unitatea.
Introduceți unitatea în dispozitivul OPENBOX SF-50, urmați MENU – System – Update from USB, selectați modul „SAT&TP List”.

Selectați Start. Confirmați-vă intențiile.

Dispozitivul va actualiza baza de date și va reporni singur. După repornire, va trebui să setați limba meniului la rusă într-un mod nou. Resetați dispozitivul la setările din fabrică.
Ieșiți din meniul de setări apăsând de două ori butonul MENU. Apăsați butonul OK de pe canalul curent și asigurați-vă că lista de canale este editată.

De asemenea, vă puteți asigura că lista de transpondere și sateliți este editată.
Programarea este finalizată.

Să începem cu minimul:
include 18f2455 -- biblioteca pentru MK folosit
--
enable_digital_io() -- comutarea tuturor intrărilor în modul digital
--
alias Buton este pin_B7 -- deoarece avem un buton conectat, să-l declarăm
pin_B7_direction = intrare -- butonul nostru funcționează pentru intrare
--
-- o singură linie - și avem tot ce aveți nevoie pentru a lucra cu USB CDC
include usb_serial -- bibliotecă pentru lucrul cu usb
--
usb_serial_init() -- --inițializați USB CDC
buclă pentru totdeauna-- bucla principală, executată continuu
usb_serial_flush() -- actualizare prin usb. Această procedură realizează toate cele necesare
-- acțiuni pentru menținerea conexiunii cu PC-ul
buclă de capăt

Compilând acest cod, scriind fișierul HEX rezultat în MK folosind un bootloader și lansând dispozitivul, puteți observa cum este definit un nou dispozitiv în sistem: Port com virtual.

Acum că dispozitivul funcționează deja, să-l învățăm să comunice.

Pentru a citi octetul primit există o funcție usb_serial_read( octet ) :boolean. Dacă există un octet primit, acesta îl stochează în variabila specificată și revine adevărat, altfel revine fals.

Există o procedură pentru a trimite un octet date_serial_usb. Este deghizat ca o variabilă, așa că pentru a trimite un octet trebuie doar să îi atribuiți valoarea octetului trimis.

Să declarăm o variabilă de dimensiunea unui octet înaintea buclei principale în bucla principală, vom verifica prezența octeților primiți și, dacă există, îi vom trimite înapoi.

include 18f2455
--
enable_digital_io()
--
alias Buton este pin_B7
pin_B7_direction = intrare
--
--
include usb_serial
--
usb_serial_init()
var octet cap -- declara o variabilă
buclă pentru totdeauna-- bucla principală
usb_serial_flush()
dacă(usb_serial_read(ch)) apoi-- dacă se primește un octet, acesta va fi scris în ch
usb_serial_data = ch -- trimite octetul primit înapoi
sfârşitul dacă
buclă de capăt

Compilăm, ținem apăsat butonul, pornim, lansăm bootloader-ul, schimbăm firmware-ul, lansăm.
Dispozitivul a fost detectat din nou în sistem, acum avem nevoie de software pentru a testa funcționarea dispozitivului.

Deși nu avem al nostru, folosim un terminal gata făcut: am folosit programul RealTerm.
Deschide portul cu numărul necesar si trimite datele.


Și primim înapoi ceea ce am trimis. Aceasta înseamnă că totul funcționează așa cum ar trebui.

Software

Deci, microcontrolerul nostru poate primi octeți și îi poate trimite imediat înapoi. Acum să scriem propriul nostru software pentru a comunica cu el (voi folosi Delphi).

Cream un nou proiect, aranjam componentele necesare dupa forma:
SpinEdit1 - pentru a specifica numărul portului
Buton1 - pentru a stabili o conexiune
Buton2 - pentru a deconecta
SpinEdit2 - pentru introducerea octeților în formă zecimală
Button3 - pentru a trimite un octet
Memo1 - pentru afișarea informațiilor primite.

După cum am menționat mai sus, trebuie să lucrați cu portul com în același mod ca și cu unul obișnuit fișier text: Folosind funcțiile CreateFile, WriteFile și ReadFile.

Fără a intra în detalii, să luăm o bibliotecă gata făcută pentru a lucra cu un port com: ComPort.

Atașăm sarcina necesară fiecărui buton și obținem codul final:

unitate Unit1;

interfata

Utilizări
Windows, Mesaje, SysUtils, Variante, Clase, Grafică, Controale, Formulare,
Dialogs, StdCtrls, Spin, ComPort;

Tip
TForm1 = clasa (TForm)
SpinEdit1:TSpinEdit;
Buton1: TBbutton;
Buton2: TBbutton;
SpinEdit2:TSpinEdit;
Buton3: TBbutton;
Memo1: TMemo;
procedura OnRead(Sender: TObject; ReadBytes: array of Byte);
procedură Button1Click(Expeditor: TObject);
procedura Button2Click(Expeditor: TObject);
procedura FormDestroy(Sender: TObject);
procedura Button3Click(Expeditor: TObject);
privat
(Declarații private)
Port: TComPort;
public
(Declarații publice)
Sfârşit;

var
Form1: TForm1;
num:întreg;
implementare

Procedura TForm1.Button1Click(Expeditor: TObject);
ÎNCEPE
Port:= TComPort.Create(SpinEdit1.Value, br115200); //creez o conexiune
Port.OnRead:= OnRead; //creează un flux pentru citirea datelor primite
Button2.Enabled:= true ; //activează butonul pentru a închide conexiunea
Sfârşit;

Procedura TForm1.Button2Click(Expeditor: TObject);
ÎNCEPE
Port.Free; //închide conexiunea
Button2.Enabled:= false ; //dezactivează butonul
Sfârşit;

Procedura TForm1.Button3Click(Expeditor: TObject);
ÎNCEPE
dacă Button2.Enabled atunci Port.Write();
Sfârşit;

Procedura TForm1.FormDestroy(Sender: TObject);
ÎNCEPE
dacă Button2.Enabled atunci
Port.Free;
Sfârşit;

Procedură TForm1.OnRead(Sender: TObject; ReadBytes: array of Byte);
var
i:întreg;
ÎNCEPE
pentru i:= Low(ReadBytes) to High(ReadBytes) nu //treceți prin matricea de octeți primiți
ÎNCEPE
Memo1.Text:= Memo1.Text + "." +InttoHex(ReadBytes[i],2); //adăugați valoarea sa HEX în fereastră
inc(num); //numărați numărul de octeți primiți
Sfârşit;
dacă num > 10 atunci începe
Memo1.Lines.Add("" ); // înfășura linia
num:= 0;
Sfârşit;
Sfârşit;

Lansăm, stabilim o conexiune, trimitem octeți:

Deci, cel mai simplu terminal al nostru este gata să funcționeze cu cel mai simplu dispozitiv USB.

După cum puteți vedea, citirea și scrierea au loc în matrice dinamice de octeți.

Prin prelucrarea informațiilor primite, puteți crea protocolul de schimb necesar potrivit pentru sarcina curentă.

include 18f2455
--
enable_digital_io()
--
alias Buton este pin_B7
pin_B7_direction = intrare
--
--
include usb_serial
--
usb_serial_init()
var octet cap
var octet i -- declara a doua variabilă
buclă pentru totdeauna-- bucla principală
usb_serial_flush()
dacă(usb_serial_read(ch)) apoi-- dacă octetul este primit, efectuați acțiunile necesare
caz ch de -- buclă prin numărul de octeți
0: usb_serial_data = 0xff
1: usb_serial_data = Buton -- trimite starea butonului
ALTFEL bloc-- dacă se primește altceva
pentru 16 folosind i buclă-- trimiteți 10 octeți de date
usb_serial_data = ch +i -- de la ch la ch+15
buclă de capăt
bloc final
caz final
sfârşitul dacă
buclă de capăt

Caracteristici suplimentare

Dacă ne oprim aici, obținem un articol obișnuit cu o descriere detaliată a unui exemplu de utilizare a bibliotecii, dintre care există multe pe Internet. Prin urmare, voi adăuga câteva informații mai aprofundate.

Facilitând trimiterea datelor

Trimiterea informațiilor câte un octet nu este întotdeauna convenabilă. Biblioteca poate fi utilă foarte des imprimare. Conține proceduri pentru trimiterea datelor de toate lungimile posibile în toate formatele posibile: byte, hex, dec, bin, boolean, care pot simplifica ieșirea datelor în program.
> include imprimarea
...
var dword date
print_dword_hex(usb_serial_data, data)

Numele tuturor comenzilor pot fi găsite în fișierul bibliotecă.

Se așteaptă conectarea la PC

Dacă înainte de a începe ciclul principal al microcontrolerului este necesar să stabiliți mai întâi o conexiune cu computerul, atunci puteți adăuga liniile în fața acestuia
în timp ce(usb_cdc_line_status() == 0x00) buclă
buclă de capăt

Atribuirea unui număr de port dispozitivului

Dacă lăsați totul așa cum este, sistemul va aloca primul număr de port liber cu fiecare nouă conexiune. Asta înseamnă că va trebui să fii mereu cu ochii pe el.
Pentru a preveni acest lucru, trebuie să atribuiți un număr de serie unic dispozitivului înainte de a conecta biblioteca USB:
Numărul poate fi de orice lungime și poate conține diferite caractere.
const byte USB_STRING3 =
{
24 , -- lungimea matricei
0x03, -- bDescriptorType
"0" , 0x00 ,
"1" , 0x00 ,
"2" , 0x00 ,
"3" , 0x00 ,
"4" , 0x00 ,
"5" , 0x00 ,
"6" , 0x00 ,
"7" , 0x00 ,
"8" , 0x00 ,
"9" , 0x00 ,
"X", 0x00
}

Schimbați numele dispozitivului cu al dvs

Puteți schimba numele dispozitivului vizibil în sistem înainte de a instala driverele, declarând o matrice cu același nume ca și număr de serie, acest lucru trebuie făcut înainte de a conecta biblioteca USB.
const byte USB_STRING2 =
{
28 , --
0x03, -- bDescriptorType
"D", 0x00 ,
"e", 0x00 ,
"m", 0x00 ,
"o", 0x00 ,
" " , 0x00 ,
"B", 0x00 ,
"o", 0x00 ,
"o", 0x00 ,
"r", 0x00 ,
"d", 0x00 ,
" " , 0x00 ,
"=" , 0x00 ,
")" , 0x00
}

Dar, din păcate, după instalarea driverelor, dispozitivul își va schimba numele în cel specificat în fișierul .inf, așa că vom schimba și numele acolo.


DESCRIPTION="Demo CDC"

Organizam conectarea automata a dispozitivului

Din păcate, nu există modalități directe de a finaliza această sarcină, așa că va trebui să fii creativ.

În primul rând, trebuie să atribuiți un producător și o valoare unică a produsului dispozitivului dvs. pentru a-l identifica cu ușurință printre sute de alte firmware-uri CDC standard.
VID și PID sunt date pentru bani, așa că haideți să urmăm calea chinezilor: luați în liniște valorile evident gratuite.

Firmware:
În firmware trebuie să declarați două variabile înainte de a conecta biblioteca USB

const cuvânt USB_SERIAL_PRODUCT_ID = 0xFF10
const cuvânt USB_SERIAL_VENDOR_ID = 0xFF10

În loc de FF10, puteți introduce oricare două cuvinte (2 octeți). Rezultatul final se află în arhiva atașată.

Șoferi:
Deoarece driverele nu sunt proiectate pentru combinația noastră de VID și PID, vom adăuga manual valorile noastre la fișierul .inf:


%DESCRIPTION%=DriverInstall, USB\VID_FF10&PID_FF10


%DESCRIPTION%=DriverInstall, USB\VID_FF10&PID_FF10

Software:
Pentru a captura evenimentele de conectare/deconectare a dispozitivului, haideți să conectăm biblioteca ComponentUSB. Nu cred că este necesar să explic fiecare rând: toate modificările pot fi văzute în proiectul atașat.

Rezultat

Este greu de văzut în captură de ecran, dar butonul de trimitere este activ doar atunci când există un dispozitiv conectat, iar la fiecare 50 ms programul trimite o solicitare pentru a primi starea butonului (care, totuși, este incorectă, deoarece apăsarea butonului ar trebui procesată pe MK).

După cum puteți vedea, organizarea schimbului de date între un MK și un computer prin USB nu este cea mai dificilă sarcină. Conexiunea rezultată poate fi folosită nu numai în scopuri finale: este potrivită și pentru depanarea programului. La urma urmei, trimiterea rezultatelor calculelor și a stărilor curente ale registrelor și variabilelor către un computer este mult mai clară decât să clipești o pereche de LED-uri în cod Morse.

Și în sfârșit: te sfătuiesc să te uiți cod sursă lămpi de stare. Puteți găsi destul de multe acolo opțiune bună prelucrarea datelor primite pentru a organiza un protocol convenabil de schimb.

După cum sa menționat deja, sistemele de operare Windows oferă suport software pentru funcționarea dispozitivelor conectate la magistrala USB. Procesarea fluxurilor de date ale dispozitivului USB la nivel de sistem de operare este efectuată de stivă. drivere standard, care îndeplinesc funcțiile de bază de gestionare a tuturor dispozitivelor USB și de schimb de date între acestea și sistem.

Daca trebuie sa scrii software Pentru orice dispozitiv USB care și-ar extinde capacitățile de procesare a datelor, puteți alege una dintre cele trei căi posibile:

scrieți propriul driver de dispozitiv care să ofere toate funcțiile necesare de control și schimb de date și un program care să interacționeze cu acest driver în modul utilizator. În acest caz, puteți renunța complet la driverele de sistem standard;

scrieți un driver de filtru care ar oferi funcționalitatea necesară, dar care ar fi situat în stiva de drivere deasupra driverelor de sistem. Deci totul caracteristici standard procesarea ar fi efectuată de drivere USB, instalat de sistem, A caracteristici suplimentare ar fi furnizat de driverul dvs. de filtru, cu care programul utilizatorului ar interacționa;

profitați de bibliotecile de funcții și drivere distribuite gratuit

mi pentru a accesa dispozitivul USB.

În cele mai multe cazuri acces programatic la un dispozitiv USB poate fi necesar dacă acest dispozitivîndeplinește o funcție foarte specifică. De exemplu, au fost dezvoltate „osciloscoape electronice” sau sisteme de achiziție de date bazate pe USB, care necesită acces la dispozitivul în sine pentru a funcționa. În cele mai multe dintre aceste cazuri, puteți utiliza biblioteci de funcții distribuite gratuit, care vor funcționa în aproape toate mediile de programare populare. De exemplu, sub auspiciile GNU, a fost dezvoltat un software cunoscut sub numele de LibUsb, care include driverele și bibliotecile de funcții necesare pentru a rula pe sistemele de operare Windows și Linux. Aceste biblioteci de funcții sunt foarte populare și vă permit să dezvoltați rapid programe care interacționează cu dispozitivul dvs. folosind un set de funcții standard. Acest lucru elimină necesitatea de a scrie propriul driver de dispozitiv, ceea ce economisește timp semnificativ.

În plus, majoritatea utilizatorilor nu sunt familiarizați cu tehnicile de dezvoltare a driverelor,

Aceasta este o zonă foarte complexă de programare, astfel încât disponibilitatea unui astfel de software distribuit gratuit va oferi asistență neprețuită unei game largi de utilizatori. Pe baza proiectului LibUsb, wrapper-urile au fost dezvoltate pentru a lucra Visual Basic.NET și C# .NET, dintre care cel mai popular este LibUsbDotNet, dezvoltat și el sub auspiciile software-ului liber. În ciuda complexității aparente a programării dispozitivelor USB, software-ul enumerat simplifică atât de mult această sarcină, încât chiar și începătorii o pot face. Să ne uităm la exemple practice cum să lucrezi cu al tău dispozitive USB mi și să începem cu pachetul software LibUsb. Apropo, software-ul de mai sus poate fi descărcat gratuit de pe www.sourceforge.net sau de pe numeroase site-uri duplicat.

Cum să lucrezi cu bibliotecile Funcții USB LibUsb? Biblioteca a fost construită în acest fel

astfel încât să puteți efectua operațiuni de bază legate de dispozitivul USB:

identificare sau, cu alte cuvinte, enumerare. La efectuarea acestei operațiuni sunt detectate dispozitivele conectate la magistrala USB, care se realizează folosind funcțiile corespunzătoare ale bibliotecii libusb;

obținerea parametrilor dispozitivului (identificatori de dispozitiv, date despre producător și caracteristicile dispozitivului), pentru care biblioteca are o serie intreaga funcții;

deschiderea, închiderea, citirea și scrierea datelor, trimiterea comenzilor. Pe un dispozitiv USB, la fel ca alte obiecte sistem de fișiere, îl puteți accesa prin scriere sau citire, ceea ce se face folosind funcțiile de bibliotecă corespunzătoare.

Toate aceste caracteristici pot fi implementate apelând funcțiile corespunzătoare ale bibliotecii libusb, dar ele nu vor fi listate aici deoarece ar ocupa prea mult spațiu; vom vedea cum să folosim unele dintre aceste funcții

Orez. 6.10

Locația driverului libusb0.sys în stiva de drivere de dispozitiv

mentiuni folosind exemple practice. Cititorii pot găsi o descriere a tuturor funcțiilor în documentația corespunzătoare. Permiteți-mi să vă reamintesc că luăm în considerare utilizarea funcțiilor bibliotecii libusb în sistemele de operare Windows.

Când instalați o distribuție cu libusb in sistem de operare Windows instalează driverul de filtru libusb0.sys pe sistem. Acest driver va fi localizat în partea de sus a stivei de drivere de sistem, ceea ce este ușor de văzut, de exemplu, privind informațiile despre driver pentru orice dispozitiv USB (Fig. 6.10).

În plus, pentru a accesa driverul din programele utilizatorului, în sistem este instalată biblioteca libusb0.dll, cu ajutorul căreia puteți dezvolta programe de utilizator.

Orez. 6.17

Vedere a ferestrei aplicației la dezinstalare

Dispozitive USB din sistem

Dar nu este suficient doar să conectați fizic dispozitivul la computer, trebuie să stabiliți și un schimb de date între ei. Cum să alegi un port și să organizezi o conexiune? În urmă cu câțiva ani, soluția standard era utilizarea unui port COM. Apropo, diverși specialiști încă instalează 8, 16 sau chiar 32 de porturi COM pe computere industriale (există o întreagă categorie de diferite plăci de expansiune PCI pentru porturi seriale, controlere etc.). Astfel, dacă aveți nevoie să conectați mai multe dispozitive externe cu o interfață RS-232, este posibil să aveți nevoie de adaptoare scumpe și plăci de expansiune exotice, care, conform vechii tradiții, călătoresc în Rusia cu vaporul săptămâni întregi. Apropo, numele unui adaptor obișnuit „Adaptor DB9m/DB25f” poate provoca doar iritare pentru un manager de magazin de calculatoare.

Ce este un dispozitiv HID

În zilele noastre, aproape toate dispozitivele sunt conectate la un computer printr-o interfață USB. Prin urmare, multe PC-uri noi nu au deloc un port COM.

Interfață USB - o soluție tipică pentru conectarea unui nou dispozitiv extern cu un computer, mai exact, este o interfață HID bazată pe protocol USB 1.1.

Deși mulți oameni cred că interfața HID (Human Interface Device) este destinată exclusiv tastaturii, mouse-ului și joystick-ului, este potrivită pentru multe soluții legate de asocierea dispozitivelor externe cu un computer.

Dacă utilizatorul trebuie să efectueze schimburi de date la viteză redusă (până la 64 kbit/s) și, în același timp, dorește să reducă timpul petrecut pentru dezvoltarea obositoare a propriilor drivere, atunci HID este destul de potrivit pentru el. Rezultatul final va fi o soluție simplă și complet modernă bazată pe o interfață software standard USB cu suport garantat pe toate platformele software comune.

Proprietăți dispozitiv HID

Din punctul de vedere al organizării suportului software pentru un dispozitiv HID, totul pare destul de atractiv: să lucrezi sub Control Windows puteți crea rapid cod ușor de înțeles, compact, bazat pe algoritmi gata făcuti și dovediți. În același timp, dezvoltatorul va avea la dispoziție mult timp pentru a-și implementa propriul protocol de schimb de date de nivel superior, deoarece nivelul de abstracție necesar este deja organizat prin protocolul HID (vezi tabel). În plus, este ușor pentru un programator să depaneze un protocol de schimb scris (desigur, dacă există un dispozitiv HID care funcționează) - datorită rigidității relative a protocolului în sine, este suficient să dezvolte pur și simplu un program de suport pentru computer pentru dispozitiv. Desigur! Creatorul dispozitivului HID a luat deja multă muncă.

Organizarea schimbului de date între dispozitivul HID și computer

Pentru a descrie interacțiunea unui dispozitiv HID cu un computer, vom folosi termenul „gazdă”. În acest caz, este înțeles ca un dispozitiv de control în arhitectura fizică generală a interacțiunii prin protocolul USB. Deci, toate porturile de pe un computer sunt gazde. Puteți conecta diverse dispozitive USB (unități flash, șoareci, camere web, camere etc.) care nu au o gazdă pentru ele. Gazda oferă descoperirea dispozitivului, conexiunea, deconectarea, configurarea, precum și colectarea de statistici și gestionarea energiei.

Dispozitivul HID își poate seta propria frecvență de interogare pentru a determina dacă conține date noi. Aceasta înseamnă că, chiar și la un nivel atât de scăzut, programatorul poate avea încredere în sistem, deoarece frecvența de interogare și alți parametri de comunicare trebuie să fie prestabiliți în programul controlerului dispozitivului HID. Acest lucru distinge protocolul HID de descrierea generală a USB 1.1 sau USB 2.0, care nu are cerințe stricte pentru organizarea protocolului. Cu toate acestea, pentru sarcini specifice care necesită un nivel crescut de securitate, poate fi destul de dificil să scapi de sondajele ciclice, când aproape aceleași blocuri de date sunt transmise în mod constant.

Caracteristici de programare a dispozitivului HID

Dispozitivele HID au descriptori speciali. Când gazda stabilește că dispozitivul aparține clasei HID, acesta transferă controlul acestuia către driverul corespunzător. Se presupune că ulterior schimbul de date se realizează sub conducerea sa.

În Windows, serviciul de sistem HidServ este responsabil pentru accesarea dispozitivelor HID. Mai multe detalii despre funcțiile solicitărilor către dispozitivele HID și alte caracteristici ale lucrului cu driverul HID sunt descrise în lucrarea lui P. V. Agurov „Interfața USB. Practică de utilizare și programare” (Sankt. Petersburg: BHV-Petersburg, 2005).

Programarea dispozitivelor HID la „ nivel superior»

Viața grea a programatorilor de „aplicații” care lucrează în Pascal este simplificată de modulul HID dovedit. PAS, software shell pentru hid. dll (Hid User Library - așa cum este specificat în proprietățile fișierului). Comentariile la fișier indică faptul că acesta se bazează pe modulele hidsdi.h și hidpi.h de la Microsoft. Și fișierul HID în sine. PAS face parte din pachetul JEDI().

Pentru a lucra cu un dispozitiv HID în Mediul Delphi pentru win32, se folosește componenta TJvHidDeviceController, care este un manager global convenabil pentru accesarea dispozitivelor HID. Și deja pe baza sa puteți obține o instanță de obiect pentru a lucra cu un anumit dispozitiv.

Proprietățile și evenimentele de bază ale componentei TJvHidDeviceController

Să ne uităm la componenta TJvHidDeviceController mai detaliat. Evenimentul OnArrival este declanșat atunci când un dispozitiv HID intră (se conectează) la sistem, accesul la dispozitiv este oferit în handlerul acestui eveniment printr-o instanță a clasei TJvHidDevice. Evenimentul simplu OnDeviceChange reacționează la schimbările în starea dispozitivului, semnalează doar schimbări în sistem. Evenimentul OnDeviceData este declanșat atunci când datele sosesc de la unul dintre dispozitivele HID și transmite următoarele operatori: HidDev: TJvHidDevice; - dispozitivul de la care au fost primite datele;

Evenimentul OnDeviceDataError notifică o eroare de transfer de date prin transmiterea parametrilor HidDev la procedura de procesare: TJvHidDevice; - Dispozitiv HID și Eroare: DWORD; - cod de eroare. Evenimentul OnDeviceUnplug notifică faptul că un dispozitiv este eliminat din lista celor instalate pe sistem. Tipurile de gestionare a evenimentelor de pe Plug and Unplug sunt aceleași (în textul sursă: TJvHidUnplugEvent = TJvHidPlugEvent). Un obiect din clasa TJvHidDevice care corespunde dispozitivului HID este transmis handler-ului.

Pentru a enumera secvențial dispozitivele HID disponibile în sistem prin apelarea metodei Enumerate, este intenționat evenimentul OnEnumerate, adică în handlerul de evenimente, dispozitivele găsite sunt transferate secvenţial ca obiecte. Acest eveniment este forțat de metoda Enumerate, care este folosită pentru a „trece” dispozitivele HID existente printr-un handler, de exemplu, la revizuirea stării dispozitivelor HID la inițiativa gazdei (calculatorului).

Evenimentul OnRemoval este declanșat atunci când un dispozitiv este eliminat fizic din sistem și are același tip de handler TJvHidUnplugEvent ca și pentru OnDeviceUnplug. Funcția CountByProductName returnează numărul de dispozitive care se potrivesc cu numele produsului specificat în argument, iar CountByVendorName returnează numele producătorului specificat în argument.

Principalele proprietăți și evenimente ale clasei TJvHidDevice

Clasa TJvHidDevice este o reprezentare virtuală a unui singur dispozitiv HID. Un nou obiect al acestei clase poate fi obținut, după cum sa menționat deja, din evenimentul OnArrival sau OnEnumerate. Funcționalitatea claselor TJvHidDeviceController și TJvHidDevice este parțial duplicată, deoarece prima dintre ele integrează instrumente comune pentru lucrul cu un set de dispozitive HID disponibile în sistem și un mecanism de accesare a unuia dintre ele. Un dispozitiv poate fi identificat în mod unic prin proprietățile sale SerialNumber, ProductName și VendorName. Pentru a obține informații despre sosirea datelor folosind un astfel de obiect, puteți utiliza evenimentul OnData. Datele sunt trimise prin metoda WriteFile (în sens strict - printr-o funcție). WriteFile este un wrapper functia sistemului WriteFile(kernel32).

Pentru a controla dacă dispozitivul a fost eliminat, ar trebui să atribuiți propriul dvs. handler evenimentului OnUnplug. Înainte de a începe să faceți schimb de date cu un dispozitiv HID, trebuie să vă asigurați că acest schimb este posibil utilizând HasReadWriteAccess. Această clasă are chiar și un eveniment OnDataError separat atunci când apare o eroare de schimb de date.

Acum să ne uităm la fragmentele de cod dintr-un proiect „în direct” care implementează o aplicație client de testare pentru organizarea schimbului de date cu un dispozitiv nestandard - carduri cu cip din plastic bazate pe HID. În lupta pentru realism, autorul și-a luat libertatea de a nu arunca conexiunile de cod tehnologic „extra” din listări.

Metoda ScanDevices (Listarea 1) are scopul de a iniția procesul de căutare în sistem a dispozitivului HID necesar. Majoritatea codului, cu excepția apelului la metoda Enumerate, este opțional și oferă flexibilitate aplicației, de exemplu, pentru a program de testare a fost posibil să adăugați capacitatea de a lucra printr-o altă interfață decât HID. Metoda AddError afișează informații de depanare în fereastră în timp ce programul rulează.

Lista 2 arată un handler de evenimente OnEnumerate pentru a găsi dispozitivul extern necesar. Pentru simplitate, vom presupune că programul poate funcționa doar cu un singur dispozitiv de tipul de care are nevoie.

Înainte de a lua în considerare implementarea ulterioară a proiectului, ar trebui să vorbim puțin despre formatul de schimb de date de nivel superior adoptat, adică despre structura menită să fie un intermediar între metodele de primire și transmitere a datelor și problema specifică a aplicației care se rezolvă. Faptul este că aici dezvoltatorului i se oferă posibilitatea de a-și realiza abilitățile creative. Sau, mai degrabă, dezvoltatorii, pentru că procesul de creare a unui nou protocol este de multe ori bidirecțional, iar prima lăutară este jucată de cel căruia îi este mai greu să implementeze algoritmul de schimb. În general, indiferent de protocolul de schimb, este întotdeauna plăcut să facem fiecare entitate software cât mai vizuală și autosuficientă posibil, chiar și în detrimentul unor tradiții general acceptate. Pentru că cea mai bună soluție este cea care va fi implementată în scurt timp cu conexiune minimă la mediu software si cu mari oportunități dezvoltare ulterioară. Pe baza acestor principii, a fost creat un protocol de schimb de nivel superior, unde conceptul principal este „comandă”. Lista 3 arată cât de mult îi plac autorului datele șir, ceea ce l-a salvat de mai multe ori în timpul depanării. module software. Ce minunat este că avem chiar și un tip String! Toate comenzile de protocol sunt împărțite în categorii (clase), în cadrul cărora există un cod de comandă care îi caracterizează în mod unic scopul. Parametrul edParam este utilizat pentru a trimite date către dispozitiv, iar parametrul edAnswerData conține date primite de la dispozitiv. Tipul de șir al membrilor de înregistrare descriși vă permite să manipulați liber și clar datele în format șir HEX. Și ceea ce este cel mai bun este că formatul înregistrării descrise se situează ideologic undeva la mijloc între scopul său direct și diferitele forme de prezentare (INI, HEX, XML etc.)

Executarea comenzii, adică trimiterea datelor către dispozitiv, este implementată utilizând trimiterea de pachete de date cu lungimea de 8 octeți (Listing 4). Această lungime nu este singura soluție; această alegere este dictată de cerințele protocolului de nivel superior și poate fi diferită în fiecare caz specific. Aceasta, după cum se spune, este o chestiune de gust. Steagul ciudat IsUSBMode din metoda ExecuteCommand (Listing 5 în PC World) este lăsat ca un memento că este posibil să fie nevoie să folosim un port COM sau o altă interfață în loc să lucrăm cu USB. La începutul grupului de date trimis, o serie de sincronizare a unui format selectat aleatoriu (de exemplu, 3E3E3E2B) este transmisă dispozitivului, informând dispozitivul că are date complet legale la intrare. Permiteți-mi să vă reamintesc că în acest caz despre care vorbim nu atât despre HID, cât despre un protocol specific de nivel superior, divorțat ideologic de hardware și conceput pentru a rezolva probleme specifice aplicației.

Managerul GetDataExecutor pentru datele primite de la dispozitiv (un pachet de 8 octeți) utilizează un eveniment OnNewInputData special creat pentru a transfera datele procesate inițial pentru procesare ulterioară, indicând valorile lor vechi și noi (Lista 6 pe „World of PC Disk ”). În acest fel, evenimentele de sosire a datelor brute și indicația pentru procesarea ulterioară sunt decuplate, permițând adăugarea unui algoritm specific într-un stadiu incipient pentru a avertiza împotriva informațiilor de intrare eronate, duplicate sau inutile.

Exemplele de lucru cu un dispozitiv HID prezentate aici ilustrează ideea generală a articolului - ușurința relativă de a programa dispozitive HID non-standard folosind Delphi.

În ultima lecție, am asamblat firmware-ul pentru controler, astfel încât să funcționeze prin USB. Dar și pentru a interacționa cu un computer avem nevoie program special, care va rula pe computer.

Acum o vom crea.

Din nou, există un exemplu în pachetul de soluții Microchip pentru controlerul nostru, dar l-am rescris în felul meu. In primul rand am facut fara sa folosesc GUI, iar dimensiunea codului a scăzut de 3-4 ori. Ceea ce este mult mai bine pentru studiu. Cu toate acestea, principiul de funcționare este același. Codul din exemplul standard de la microcip funcționează la fel ca acesta.

Programul este scris în C++. Proiectul este compilat în versiunea gratuită pentru studenți a Visual C++ express 2010. Voi oferi idei generale și comentarii cu privire la cod, dar presupun că aveți deja cel puțin ceva experiență de programare în C++.

Deci să începem

Iată întregul proiect, inclusiv linkul textului sursă

Pentru a citi și scrie date prin portul USB, trebuie să obținem un pointer către dispozitivul nostru. Deoarece, spre deosebire de porturile vechi, pot exista peste o sută de dispozitive conectate, nu este atât de ușor să obțineți acest index. Pentru a face acest lucru ne vom adresa drivere pentru Windows, și anume SetupAPI. Apropo, de îndată ce primim indicatorul, vom comunica cu Port USB, de parcă ar fi fost un dosar.
Transferul datelor va dura doar câteva comenzi. Dar iată pregătirea!
Deoarece programăm în C++, trebuie să fim foarte atenți la tipurile de date.
Creați un proiect de consolă win32. Și adăugați singurul fișier main.cpp acolo

Deci, trebuie să includem câteva biblioteci.
#include
#include
#include

De asemenea, conectăm o bibliotecă externă:
#pragma comentariu (lib, "Setupapi.lib")

Prima funcție descrisă în program este getUSBHandle(). Descrierea sa este în comentariile codului. Și, în general, principalele comentarii sunt date în cod. Servește pentru a găsi dispozitivul nostru și pentru a pregăti indicatorii astfel încât să putem scrie și citi de pe dispozitiv.
Pe scurt, ea folosește ferestre standard funcții de accesat drivere USB iar prin ele primește un pointer către dispozitivul în sine.
Dacă sunteți interesat de ce fac și cum toate aceste funcții, atunci consultați MSDN sau cartea lui Agurov, care se află în cuprinsul. Ce este important de știut: fiecare dispozitiv are o cale și este important pentru noi să o obținem. Mai întâi verificăm dacă ID-ul se potrivește cu dispozitivul pe care îl căutăm. Și apoi găsim calea dispozitivului Căutăm doar printre dispozitivele din clasa HID. aceasta este definită în variabila Guid. Pentru restul, vezi comentariile programului.
Următoarea funcție este writeReadUSB. Aceasta este doar o funcție de ajutor care scrie pe dispozitivul nostru. Vă rugăm să rețineți că scrierea și citirea unui dispozitiv după ce am creat un pointer către acesta este implementată folosind comenzile standard WriteFile și ReadFile
Și după aceasta vedem funcția principală cu care începe execuția programului. Apelează getUSBHandle până când obținem un pointer către dispozitiv, apoi citește comanda de pe tastatură și, în funcție de aceasta, transferă și citește date de pe dispozitivul USB.
Proiectul de la linkul de mai sus conține codul sursă cu comentarii și programul compilat în sine. Noroc.

În timp ce căutam o eroare, am dat peste biblioteca hidapi. Este multiplatformă. Și numai pentru lucrul cu dispozitive ascunse. Foarte usor de folosit. Aduc un proiect pentru el. link .
Hidapi descărcat de pe site-ul oficial. Pentru a începe un proiect, trebuie să adăugați setupapi.lib la linker. proiect->proprietăți->linker->input și semnează setupapi.lib acolo;
Noroc.
Am găsit o descriere decentă a bibliotecii aici: http://microsin.net/programming/PC/multi-platform-hid-api.html.
Multumesc!