Interface de programmation du fonctionnement du port USB. Utilisation pratique de l'interface USB dans les contrôleurs PIC. Principales propriétés et événements de la classe TJvHidDevice

Dans la dernière leçon, nous avons compilé le firmware du contrôleur afin qu'il fonctionne via USB. Mais pour interagir avec un ordinateur, nous avons également besoin d’un programme spécial qui s’exécutera sur l’ordinateur.

Nous allons maintenant le créer.

Encore une fois, il existe un exemple dans le package de solutions Microchip pour notre contrôleur, mais je l'ai réécrit à ma manière. Premièrement, je l'ai fait sans utiliser d'interface graphique et la taille du code a diminué de 3 à 4 fois. Ce qui est bien mieux à apprendre. Cependant, le principe de fonctionnement est le même. le code de l'exemple standard de Microchip fonctionne exactement comme ceci.

Le programme est écrit en C++. Le projet est construit dans la version étudiante gratuite de Visual C++ express 2010. Je vais donner des idées générales et des commentaires sur le code, mais je suppose que vous avez déjà au moins une certaine expérience en programmation C++.

Alors commençons

Voici l'intégralité du projet, y compris le lien du texte source

Afin de lire et d'écrire des données via le port USB, nous devons obtenir un pointeur vers notre appareil. Puisque, contrairement aux anciens ports, il peut y avoir plus d'une centaine d'appareils connectés, obtenir ce pointeur n'est pas si simple. Pour ce faire, nous nous référerons aux pilotes Windows, à savoir le SetupAPI. D’ailleurs, dès que nous aurons le pointeur, nous communiquerons avec le port USB comme s’il s’agissait d’un fichier.
Le transfert de données ne prendra que quelques commandes. Mais voilà la préparation !
Puisque nous programmons en C++, nous devons être très prudents avec les types de données.
Créez un projet de console win32. Et ajoutez-y le seul fichier main.cpp

Nous devons donc inclure quelques bibliothèques.
#inclure
#inclure
#inclure

Nous incluons également une bibliothèque externe :
Commentaire #pragma (lib, "setupapi.lib")

La première fonction décrite dans le programme est getUSBHandle(). Sa description est dans les commentaires du code. Et de manière générale, les principaux commentaires sont donnés dans le code. Il sert à localiser notre appareil et à préparer des pointeurs afin que nous puissions écrire et lire sur l'appareil.
En un mot, il utilise les fonctions Windows standard pour accéder aux pilotes USB et, grâce à eux, obtient un pointeur vers le périphérique lui-même.
Si vous êtes intéressé par ce que font toutes ces fonctions et comment, reportez-vous au livre MSDN ou Agurov, qui se trouve dans la table des matières. Ce qu’il est important de savoir : chaque appareil a un chemin, et il est important pour nous de l’obtenir. Nous vérifions d'abord si l'identifiant correspond à l'appareil que nous recherchons. Et puis nous trouvons le chemin de l'appareil. Nous recherchons uniquement parmi les appareils de la classe HID. ceci est défini dans la variable Guid. Voir la suite dans les commentaires du programme
La fonction suivante est writeReadUSB. C'est juste une fonction d'assistance qui écrit sur notre appareil. J'attire votre attention sur le fait que l'écriture et la lecture d'un périphérique après avoir créé un pointeur vers celui-ci sont implémentées à l'aide des commandes standard WriteFile et ReadFile.
Et après cela, nous voyons déjà la fonction principale avec laquelle commence l'exécution du programme. Il appelle getUSBHandle jusqu'à ce que nous obtenions un pointeur vers le périphérique, puis lit une commande du clavier et, en fonction de celle-ci, transfère et lit les données du périphérique USB.
Le projet sur le lien ci-dessus contient le code source avec des commentaires et le programme compilé lui-même. Bonne chance.

En train de rechercher un bug, je suis tombé sur la bibliothèque hidapi. C'est multiplateforme. Et uniquement pour travailler avec des appareils cachés. Très facile à utiliser. J'y apporte le projet. lien .
Hidapi téléchargé depuis le site officiel. Afin de démarrer le projet, vous devez ajouter setupapi.lib à l'éditeur de liens. projet-> propriétés-> éditeur de liens-> saisissez et signez-y setupapi.lib ;
Bonne chance.
J'ai trouvé une description décente de la bibliothèque ici : http://microsin.net/programming/PC/multi-platform-hid-api.html.
Merci!

Comme déjà mentionné, les systèmes d'exploitation Windows fournissent un support logiciel pour le fonctionnement des appareils connectés au bus USB. Le traitement des flux de données des périphériques USB au niveau du système d'exploitation est effectué par une pile de pilotes standard qui remplissent les fonctions de base de gestion de tous les périphériques USB et d'échange de données entre eux et le système.

Si vous devez écrire un logiciel pour un périphérique USB qui améliore ses capacités de traitement de données, vous pouvez choisir l'une des trois méthodes possibles :

écrivez votre propre pilote de périphérique qui fournirait toutes les fonctions de contrôle et de communication nécessaires, ainsi qu'un programme qui interagirait avec ce pilote en mode utilisateur. Dans ce cas, vous pouvez complètement vous passer des pilotes système standards ;

écrivez un pilote de filtre qui fournit les fonctionnalités requises, mais se trouve dans la pile de pilotes au-dessus des pilotes système. Ainsi, toutes les fonctions de traitement standard seraient exécutées par des pilotes USB installés par le système, et des fonctions supplémentaires seraient fournies par votre pilote de filtre, avec lequel le programme utilisateur interagirait ;

utiliser des bibliothèques de fonctions et de pilotes distribuées gratuitement

pour accéder au périphérique USB.

Dans la plupart des cas, vous devrez peut-être accéder par programmation à un périphérique USB si celui-ci a une fonction très spécifique. Par exemple, des « oscilloscopes électroniques » ou des systèmes d'acquisition de données basés sur USB ont été développés qui nécessitent un accès à l'appareil lui-même. Dans la plupart de ces cas, vous pouvez utiliser des bibliothèques de fonctions distribuées gratuitement qui fonctionneront dans presque tous les environnements de programmation courants. Par exemple, sous les auspices de GNU, un logiciel connu sous le nom de LibUsb a été développé, qui comprend les pilotes et bibliothèques de fonctions nécessaires pour fonctionner sur les systèmes d'exploitation Windows et Linux. Ces bibliothèques de fonctions sont très populaires et vous permettent de développer rapidement des programmes qui interagissent avec votre appareil via un ensemble de fonctions standards. Cela élimine le besoin d'écrire votre propre pilote de périphérique, ce qui permet de gagner beaucoup de temps.

De plus, la plupart des utilisateurs ne sont pas familiers avec les techniques de développement de pilotes,

et il s'agit d'un domaine de programmation très complexe, donc la disponibilité de tels logiciels gratuits sera d'une aide inestimable pour un large éventail d'utilisateurs. Basés sur le projet LibUsb, des wrappers ont été développés pour fonctionner avec Visual Basic .NET et C# .NET, dont le plus populaire est LibUsbDotNet, également développé sous les auspices de logiciels libres. Malgré l'apparente complexité de la programmation des périphériques USB, les logiciels répertoriés simplifient tellement cette tâche que même les débutants peuvent la faire. Examinons des exemples pratiques sur la façon de travailler avec vos périphériques USB et commençons par le progiciel LibUsb. À propos, le logiciel ci-dessus peut être téléchargé gratuitement depuis www.sourceforge.net ou depuis de nombreux sites en double.

Comment travailler avec les bibliothèques de fonctions USB LibUsb ? La bibliothèque est construite comme ça.

zom afin que vous puissiez effectuer les opérations de base liées au périphérique USB :

identification ou, d’une autre manière, dénombrement. Cette opération détecte les appareils connectés au bus USB, ce qui se fait à l'aide des fonctions appropriées de la bibliothèque libusb ;

obtenir les paramètres de l'appareil (identifiants de l'appareil, données sur le fabricant et caractéristiques de l'appareil), pour lesquels la bibliothèque dispose d'un certain nombre de fonctions ;

ouverture, fermeture, lecture et écriture de données, envoi de commandes. Le périphérique USB, ainsi que d'autres objets du système de fichiers, sont accessibles en écriture en lecture, ce qui se fait à l'aide des fonctions de bibliothèque correspondantes.

Toutes les fonctionnalités répertoriées peuvent être implémentées en appelant les fonctions libusb appropriées, mais elles ne seront pas répertoriées ici car cela prendrait trop de place ; nous verrons comment utiliser certaines de ces fonctions

Riz. 6.10

Emplacement du pilote libusb0.sys dans la pile des pilotes de périphérique

recommandations sur des exemples pratiques. Les lecteurs peuvent trouver une description de toutes les fonctions dans la documentation correspondante. Permettez-moi de vous rappeler que nous envisageons d'utiliser les fonctions de la bibliothèque libusb dans les systèmes d'exploitation Windows.

Lors de l'installation d'un kit de distribution avec libusb sur un système d'exploitation Windows, le pilote de filtre libusb0.sys est installé dans le système. Ce pilote se trouvera en haut de la pile de pilotes du système, ce qui est facile à voir, par exemple, en examinant les informations sur le pilote de n'importe quel périphérique USB (Figure 6.10).

De plus, pour accéder au pilote à partir des programmes utilisateur, la bibliothèque libusb0.dll est installée dans le système, à l'aide de laquelle vous pouvez développer des programmes utilisateur.

Riz. 6.17

Vue de la fenêtre de l'application lors de la désinstallation

Périphériques USB du système

Commençons par le minimum :
inclure 18f2455 -- bibliothèque pour MK utilisé
--
activer_digital_io() -- passer toutes les entrées en mode numérique
--
alias bouton est pin_B7 -- puisque nous avons un bouton connecté, déclarez-le
pin_B7_direction = entrée -- le bouton fonctionne pour nous à l'entrée
--
-- une ligne - et nous avons tout ce dont vous avez besoin pour travailler avec USB CDC
include usb_serial -- bibliothèque USB
--
usb_serial_init() --- --initialiser le CDC USB
boucle éternelle-- boucle principale, fonctionne en continu
usb_serial_flush() -- mise à jour USB. Cette procédure fait tout le nécessaire
-- actions pour maintenir la connexion avec le PC
boucle de fin

Après avoir compilé ce code, écrit le fichier HEX résultant sur le MK à l'aide d'un chargeur de démarrage et démarré le périphérique, vous pouvez observer comment un nouveau périphérique est défini dans le système : port COM virtuel.

Maintenant que l'appareil fonctionne déjà, apprenons-lui à communiquer.

Pour lire l'octet reçu il y a une fonction usb_serial_read( octet ) :booléen. S'il y a un octet reçu, il le stocke dans la variable spécifiée et renvoie vrai, sinon renvoie FAUX.

Il existe une procédure pour envoyer un octet données_série_usb. Elle est déguisée en variable, donc pour envoyer un octet, il suffit de lui attribuer la valeur de l'octet envoyé.

Déclarons une variable d'une taille d'octets avant la boucle principale, dans la boucle principale nous vérifierons la présence des octets reçus, et s'il y en a, nous les renverrons.

inclure 18f2455
--
activer_digital_io()
--
alias bouton est pin_B7
pin_B7_direction = entrée
--
--
inclure usb_serial
--
usb_serial_init()
var octet ch -- déclarer une variable
boucle éternelle-- boucle principale
usb_serial_flush()
si(usb_serial_read(ch)) alors-- si un octet est reçu, il sera écrit dans ch
usb_serial_data=ch -- renvoyer l'octet reçu
fin si
boucle de fin

Nous compilons, maintenons le bouton enfoncé, déformons l'alimentation, lançons le bootloader, modifions le firmware, le lançons.
L'appareil a été à nouveau détecté dans le système, nous avons maintenant besoin d'un logiciel pour tester le fonctionnement de l'appareil.

Bien que nous n'ayons pas le nôtre, nous utilisons un terminal prêt à l'emploi : j'ai utilisé le programme RealTerm.
Nous ouvrons le port avec le numéro souhaité et envoyons les données.


Et nous récupérons ce que nous avons envoyé. Donc tout fonctionne comme il se doit.

Doux

Ainsi, notre microcontrôleur peut recevoir des octets et les renvoyer immédiatement. Écrivons maintenant notre propre logiciel pour communiquer avec lui (j'utiliserai Delphi).

Nous créons un nouveau projet, disséminons les composants nécessaires sous la forme :
SpinEdit1 - pour spécifier le numéro de port
Button1 - pour établir une connexion
Button2 - pour rompre la connexion
SpinEdit2 - pour saisir un octet sous forme décimale
Button3 - pour envoyer un octet
Memo1 - pour afficher les informations reçues.

Comme mentionné ci-dessus, vous devez travailler avec le port com de la même manière qu'avec un fichier texte ordinaire : en utilisant les fonctions CreateFile, WriteFile et ReadFile.

Afin de ne pas entrer dans les détails, prenons une bibliothèque toute faite pour travailler avec un port COM : ComPort.

Nous accrochons la tâche nécessaire sur chaque bouton et obtenons le code final :

unité Unité1 ;

interface

les usages
Windows, messages, SysUtils, variantes, classes, graphiques, contrôles, formulaires,
Boîtes de dialogue, StdCtrls, Spin, ComPort ;

taper
TForm1 = classe(TForm)
SpinEdit1 : TSpinEdit ;
Bouton1 : TButton ;
Bouton2 : TButton ;
SpinEdit2 : TSpinEdit ;
Bouton3 : TButton ;
Mémo1 :TMémo ;
procédure OnRead (Expéditeur : TObject ; ReadBytes : tableau d'octets);
procédure Button1Click (Expéditeur : TObject);
procédure Button2Click (Expéditeur : TObject);
procédure FormDestroy(Expéditeur : TObject);
procédure Button3Click (Expéditeur : TObject);
privé
(Déclarations privées)
Port : TComPort ;
publique
(Déclarations publiques)
fin;

var
Formulaire1 : TForm1 ;
num : entier ;
mise en œuvre

Procédure TForm1.Button1Click(Expéditeur : TObject);
commencer
Port := TComPort.Create(SpinEdit1.Value, br115200); // crée une connexion
Port.OnRead := OnRead ; //crée un flux pour lire les données reçues
Button2.Enabled:= vrai ; //active le bouton de fermeture de connexion
fin;

Procédure TForm1.Button2Click(Expéditeur : TObject);
commencer
Port gratuit ; //ferme la connexion
Button2.Enabled:= faux ; //désactive le bouton
fin;

Procédure TForm1.Button3Click(Expéditeur : TObject);
commencer
si Button2.Enabled alors Port.Write();
fin;

Procédure TForm1.FormDestroy(Expéditeur : TObject);
commencer
si Button2.Enabled alors
Port gratuit ;
fin;

Procédure TForm1.OnRead(Sender : TObject ; ReadBytes : tableau d'octets );
var
je:entier;
commencer
pour i:= Low(ReadBytes) à High(ReadBytes) faire //passe par le tableau des octets reçus
commencer
Mémo1.Texte := Mémo1.Texte + "." +InttoHex(ReadBytes[i],2); //ajoute sa valeur HEX à la fenêtre
inc(nombre); //compte le nombre d'octets reçus
fin;
si num > 10 alors commencez
Mémo1.Lines.Add("" ); //ligne de transfert
num:=0;
fin;
fin;

Nous démarrons, établissons une connexion, envoyons des octets :

Notre terminal le plus simple est donc prêt à fonctionner avec le périphérique USB le plus simple.

Comme vous pouvez le constater, la lecture et l'écriture sont des tableaux dynamiques d'octets.

En traitant les informations reçues, il est possible d'élaborer le protocole d'échange nécessaire et adapté à la tâche en cours.

inclure 18f2455
--
activer_digital_io()
--
alias bouton est pin_B7
pin_B7_direction = entrée
--
--
inclure usb_serial
--
usb_serial_init()
var octet ch
var octet je -- déclarer la deuxième variable
boucle éternelle-- boucle principale
usb_serial_flush()
si(usb_serial_read(ch)) alors-- si l'octet est reçu, effectuez les actions nécessaires
cas ch de -- parcourir le numéro d'octet
0 : usb_serial_data = 0xff
1 : usb_serial_data = Bouton -- envoyer l'état du bouton
SINON bloc-- si quelque chose d'autre est reçu
pour 16 en utilisant je boucle-- envoyer 10 octets de données
usb_serial_data = ch +i -- ch à ch+15
boucle de fin
bloc de fin
cas final
fin si
boucle de fin

Caractéristiques supplémentaires

Si vous vous arrêtez là, vous obtenez un article régulier avec une description détaillée d'un exemple d'utilisation de la bibliothèque, dont il existe suffisamment sur le Web. Par conséquent, j'ajouterai des informations un peu plus approfondies.

Simplifiez l'envoi de données

Envoyer des informations un octet à la fois n'est pas toujours pratique. La bibliothèque peut être très utile imprimer. Il contient des procédures pour envoyer des données de toutes les longueurs possibles dans tous les formats possibles : octet, hexadécimal, déc, bin, booléen, ce qui peut simplifier la sortie des données dans le programme.
>inclure l'impression
...
mot de passe données
print_dword_hex (usb_serial_data , données )

Le nom de toutes les commandes peut être trouvé dans le fichier de bibliothèque.

En attente de connexion au PC

Si avant de démarrer le cycle principal du microcontrôleur, il est nécessaire d'établir d'abord une connexion avec le PC, vous pouvez alors ajouter les lignes qui le précèdent.
alors que(usb_cdc_line_status() == 0x00) boucle
boucle de fin

Lier le numéro de port à l'appareil

Si vous laissez tout tel quel, le système attribuera le premier numéro de port libre à chaque nouvelle connexion. Et cela signifie qu’il faut y prêter attention.
Pour éviter que cela ne se produise, vous devez attribuer une valeur de numéro de série unique à l'appareil avant de connecter la bibliothèque USB :
Le numéro peut être de n’importe quelle longueur et contenir différents caractères.
octet const USB_STRING3=
{
24 , -- longueur du tableau
0x03 , --bTypeDescripteur
"0" , 0x00 ,
"1" , 0x00 ,
"2" , 0x00 ,
"3" , 0x00 ,
"4" , 0x00 ,
"5" , 0x00 ,
"6" , 0x00 ,
"7" , 0x00 ,
"8" , 0x00 ,
"9" , 0x00 ,
"X" 0x00
}

Remplacez le nom de l'appareil par le vôtre

Vous pouvez changer le nom du périphérique visible dans le système avant d'installer les pilotes en déclarant un tableau avec le nom, comme le numéro de série, cela doit être fait avant de connecter la bibliothèque USB.
octet const USB_STRING2=
{
28 , --
0x03 , --bTypeDescripteur
"D", 0x00 ,
"e", 0x00 ,
"m", 0x00 ,
"o", 0x00 ,
" " , 0x00 ,
"B", 0x00 ,
"o", 0x00 ,
"un", 0x00 ,
"r", 0x00 ,
"d", 0x00 ,
" " , 0x00 ,
"=" , 0x00 ,
")" 0x00
}

Mais hélas, après avoir installé les pilotes, l'appareil changera son nom pour celui spécifié dans le fichier .inf, nous y changerons donc également le nom


DESCRIPTION="Démo CDC"

Nous organisons la connexion automatique de l'appareil

Hélas, il n'existe aucun moyen direct d'accomplir cette tâche, vous devez donc vous y prendre.

Tout d'abord, vous devez attribuer un fabricant et une valeur de produit uniques à votre appareil afin de l'identifier facilement parmi des centaines d'autres micrologiciels CDC standard.
Le VID et le PID sont distribués contre de l'argent, alors suivons le chemin des Chinois : prenons tranquillement des valeurs évidemment gratuites.

Micrologiciel :
Deux variables doivent être déclarées dans le firmware avant de connecter la librairie USB

mot const USB_SERIAL_PRODUCT_ID = 0xFF10
mot const USB_SERIAL_VENDOR_ID = 0xFF10

Au lieu de FF10, vous pouvez insérer deux mots quelconques (2 octets). Le résultat final est contenu dans les archives ci-jointes.

Conducteurs:
Étant donné que les pilotes ne sont pas conçus pour notre combinaison de VID et PID, nous ajouterons manuellement nos valeurs au fichier .inf :


%DESCRIPTION%=Installation du pilote, USB\VID_FF10&PID_FF10


%DESCRIPTION%=Installation du pilote, USB\VID_FF10&PID_FF10

Doux:
Pour capturer les événements de connexion/déconnexion de l'appareil, nous connecterons la bibliothèque ComponentUSB. Je ne considère pas qu'il soit nécessaire d'expliquer chaque ligne : tous les changements sont visibles dans le projet ci-joint.

Résultat

C'est difficile à voir sur la capture d'écran, mais le bouton d'envoi n'est actif que lorsqu'il y a un appareil connecté, et toutes les 50 ms, le programme envoie une demande pour obtenir l'état du bouton (ce qui est cependant faux, car l'appui sur le bouton doit être traité sur le MK).

Comme vous pouvez le constater, organiser l'échange de données entre MK et PC via USB n'est pas la tâche la plus difficile. La connexion résultante peut être utilisée non seulement à des fins finales : elle convient également au débogage d'un programme. Après tout, envoyer les résultats des calculs, les états actuels des registres et des variables à un ordinateur est beaucoup plus clair que de faire clignoter une paire de LED en code Morse.

Et enfin : je vous conseille de vous pencher sur le code source de la lampe d'ambiance. Vous y trouverez une très bonne option pour traiter les données reçues afin d'organiser un protocole d'échange pratique.

Programmation USB

La programmation du tuner satellite SF-50 via le port USB diffère de la programmation via le port RS-232 uniquement par la manière dont les données sont transférées de l'instrument à un ordinateur et d'un ordinateur à l'instrument. Lors de la programmation via USB, une clé USB portable (lecteur flash) est utilisée. Ceci est utile lorsque, par exemple, votre ordinateur ou, plus souvent, un ordinateur portable (netbook) ne possède pas de port série RS-232 sur son châssis.
Pour programmer l'appareil à l'aide d'une clé USB, vous aurez besoin de :
- Clé USB (lecteur flash) formatée dans le système de fichiers FAT-32 ;
- Programme éditeur AliEditor, situé dans le dossier Database_editor_new de la section logiciel OPENBOX SF-50.

Avant de commencer la programmation, il est nécessaire de transférer la base de données de l'appareil vers un ordinateur. Pour ce faire, allumez l'appareil, connectez une clé USB au port USB. Exécutez MENU - Système - Enregistrer sur USB,

Quittez le menu en appuyant sur le bouton MENU jusqu'à ce que la chaîne actuelle apparaisse, ou sur l'image du menu principal s'il n'y a pas encore de chaînes et retirez la clé USB. Insérez la clé USB dans l'ordinateur.
Exécutez le programme Editor.exe à partir du dossier Database_editor_new et ouvrez-y l'image sur le lecteur flash.

Lorsque vous êtes invité à sélectionner une base de données, sélectionnez Base de données utilisateur.

Appuyer sur OK. Sélectionnez Tous les services, une liste de toutes les chaînes de télévision, de radio et de service analysées et enregistrées dans la base de données s'ouvrira.

Modifiez les chaînes à votre guise, par exemple, ne laissez que les chaînes ouvertes.
Sur le clavier de l'ordinateur, maintenez la touche Shift enfoncée, appuyez sur la "Flèche vers le bas" et sélectionnez les chaînes que vous souhaitez supprimer. Appuyez sur Supprimer pour supprimer la sélection.

Pour modifier les paramètres satellite, sélectionnez Tous les services - Informations satellite - EUTELSAT W4, W7, appuyez sur la touche ENTER.

Si nécessaire, modifiez les valeurs dans Antenne 1.
Pour supprimer un transpondeur, sélectionnez-en un inutile et appuyez sur le bouton Supprimer du clavier de l'ordinateur, confirmez l'action sélectionnée.

Pour ajouter un transpondeur, placez-vous sur le nom du satellite, appuyez sur le bouton droit de la souris et sélectionnez Ajouter des informations (ou sélectionnez le satellite et appuyez sur le bouton Insérer du clavier).

Saisissez les données du nouveau transpondeur, en les reprenant, par exemple, sur le site lyngsat.com.

Appuyez sur OK, assurez-vous que le transpondeur est enregistré.

Pour ajouter un satellite, rendez-vous sur la ligne Informations satellite, appuyez sur la touche Inser du clavier et saisissez les paramètres du nouveau satellite.

fermez le programme éditeur, retirez le lecteur.
Insérez le lecteur dans l'appareil OPENBOX SF-50, exécutez MENU - Système - Mise à jour depuis USB dans l'ordre, sélectionnez le mode "Liste SAT&TP".

Sélectionnez Démarrer. Confirmez vos intentions.

L'appareil mettra à jour la base de données et se redémarrera. Après le redémarrage, dans les paramètres, vous devrez définir la langue du menu russe d'une nouvelle manière. Réinitialisez l'appareil aux paramètres d'usine.
Quittez le menu des paramètres en appuyant deux fois sur le bouton MENU. Appuyez sur le bouton OK de la chaîne actuelle et assurez-vous que la liste des chaînes est modifiée.

Vous pouvez également vous assurer que la liste des transpondeurs et des satellites a été éditée.
Programmation terminée.

Mais il ne suffit pas de connecter physiquement l'appareil à l'ordinateur, il faut également établir un échange de données entre eux. Comment choisir un port et organiser une connexion ? Il y a quelques années, la solution standard consistait à utiliser un port COM. D'ailleurs, divers spécialistes installent encore 8, 16, voire 32 ports COM sur les ordinateurs industriels (il existe toute une catégorie de cartes d'extension PCI différentes pour les ports série, les contrôleurs, etc.). Ainsi, si vous devez connecter plusieurs appareils externes avec une interface RS-232, vous aurez peut-être besoin d'adaptateurs coûteux et de cartes d'extension exotiques qui, selon la vieille tradition, naviguent vers la Russie pendant des semaines sur des bateaux à vapeur. D'ailleurs, le nom d'un adaptateur ordinaire « adaptateur DB9m / DB25f » ne peut qu'irriter le gérant d'un magasin d'informatique.

Qu'est-ce qu'un appareil HID

Désormais, presque tous les appareils sont connectés à un ordinateur via une interface USB. Par conséquent, de nombreux nouveaux PC ne disposent pas du tout de port COM.

Interface USB - une solution typique pour coupler un nouveau périphérique externe avec un ordinateur, plus précisément, il s'agit d'une interface HID basée sur le protocole USB 1.1.

Bien que beaucoup de gens pensent que l'interface HID (Human Interface Device) est exclusivement destinée au clavier, à la souris et au joystick, elle convient à de nombreuses solutions liées à l'interfaçage de périphériques externes et d'un ordinateur.

Si l'utilisateur a besoin d'effectuer un échange de données à faible vitesse (jusqu'à 64 kbps) et qu'il est en même temps souhaitable de réduire le temps de développement fastidieux de ses propres pilotes, alors HID lui convient parfaitement. Le résultat sera une solution simple et entièrement moderne basée sur une interface logicielle USB standard avec une prise en charge garantie sur toutes les plates-formes logicielles courantes.

Propriétés du périphérique HID

Du point de vue de l'organisation du support logiciel pour un périphérique HID, tout semble assez attractif : pour travailler sous Windows, vous pouvez rapidement créer un code compact compréhensible basé sur des algorithmes prêts à l'emploi éprouvés. Dans ce cas, le développeur aura tout le temps d'implémenter son propre protocole d'échange de données de haut niveau, puisque le niveau d'abstraction nécessaire est déjà organisé par le protocole HID (voir tableau). De plus, il est facile pour un programmeur de déboguer un protocole d'échange écrit (bien sûr, s'il existe un périphérique HID fonctionnel) - en raison de la relative rigidité du protocole lui-même, il suffit simplement de développer un programme pour prendre en charge le périphérique par un ordinateur. Je le ferais toujours ! Beaucoup de travail a déjà été réalisé par le créateur du dispositif HID.

Établir un échange de données entre un appareil HID et un ordinateur

Pour décrire l'interaction d'un périphérique HID avec un ordinateur, nous utiliserons le terme « hôte ». Dans ce cas, il s'agit d'un dispositif de contrôle dans l'architecture physique générale de communication sur le protocole USB. Ainsi, tous les ports d’un ordinateur sont des hôtes. Vous pouvez y connecter divers périphériques USB (lecteurs flash, souris, webcams, caméras, etc.) qui ne disposent pas d'hôte. L'hôte assure la découverte, la connexion, la déconnexion, la configuration des appareils, ainsi que la collecte de statistiques et la gestion de l'alimentation.

Le périphérique HID lui-même peut définir la fréquence d'interrogation au cours de laquelle la présence de nouvelles données est détectée. Cela signifie que même à un niveau aussi bas, le programmeur peut faire confiance au système, puisque le taux d'interrogation et d'autres paramètres de communication doivent être prédéfinis dans le programme du contrôleur de périphérique HID. En cela, le protocole HID diffère de la description générale de l'USB 1.1 ou de l'USB 2.0, qui n'a pas d'exigences strictes pour l'organisation du protocole. Cependant, pour des tâches spécifiques nécessitant un haut niveau de sécurité, il peut être assez difficile de se débarrasser des interrogations cycliques, lorsque presque les mêmes blocs de données sont constamment transmis.

Caractéristiques de programmation des appareils HID

Les appareils HID ont des descripteurs spéciaux. Lorsque l'hôte détermine que le périphérique appartient à la classe HID, il en transfère le contrôle au pilote approprié. On suppose que d'autres échanges de données seront effectués sous sa direction.

Sous Windows, le service système HidServ est responsable de l'accès aux appareils HID. Plus de détails sur les fonctions de requêtes vers les appareils HID et d'autres fonctionnalités de travail avec le pilote HID sont décrits dans l'ouvrage de P. V. Agurov « Interface USB. La pratique de l'utilisation et de la programmation » (Saint-Pétersbourg : BHV-Petersburg, 2005).

Programmation des appareils HID au "niveau supérieur"

La dure vie des programmeurs « appliqués » travaillant sur Pascal est facilitée par le module HID éprouvé. PAS, la coquille pour caché. dll (Bibliothèque utilisateur masquée - comme spécifié dans les propriétés du fichier). Les commentaires sur le fichier indiquent qu'il est basé sur les modules hidsdi.h et hidpi.h de Microsoft Corporation. Et le fichier HID lui-même. PAS fait partie du package JEDI().

Pour travailler avec un périphérique HID dans l'environnement Delphi pour win32, le composant TJvHidDeviceController est utilisé, qui est un gestionnaire global pratique pour accéder aux périphériques HID. Et déjà sur cette base, vous pouvez obtenir une instance d'objet pour travailler avec un appareil spécifique.

Principales propriétés et événements du composant TJvHidDeviceController

Examinons plus en détail le composant TJvHidDeviceController. L'événement OnArrival se déclenche lorsqu'un périphérique HID arrive (se connecte) au système, l'accès au périphérique est fourni dans le gestionnaire de cet événement via une instance de la classe TJvHidDevice. Le simple événement OnDeviceChange réagit à un changement d'état de l'appareil, il signale uniquement les changements dans le système. L'événement OnDeviceData se déclenche lorsque les données arrivent de l'un des périphériques HID et transmet les éléments suivants au gestionnaire : HidDev : TJvHidDevice ; - l'appareil à partir duquel les données ont été reçues ;

L'événement OnDeviceDataError notifie une erreur de transfert de données en passant les paramètres HidDev à la procédure de traitement : TJvHidDevice ; - Périphérique HID et erreur : DWORD ; - code d'erreur. L'événement OnDeviceUnplug vous informe qu'un périphérique a été supprimé de la liste des périphériques installés sur le système. Les types de gestionnaires d'événements sur Plug et Unplug sont les mêmes (dans le texte source : TJvHidUnplugEvent = TJvHidPlugEvent). Un objet de la classe TJvHidDevice correspondant au périphérique HID est transmis au gestionnaire.

Pour énumérer séquentiellement les périphériques HID disponibles dans le système en appelant la méthode Enumerate, l'événement OnEnumerate est prévu, c'est-à-dire que dans le gestionnaire d'événements, les périphériques trouvés sont transmis séquentiellement en tant qu'objets. Cet événement est déclenché de force par la méthode Enumerate, qui est utilisée pour « transmettre » les périphériques HID existants via le gestionnaire, par exemple lors de l'audit de l'état des périphériques HID initié par l'hôte (ordinateur).

L'événement OnRemoval se déclenche lorsque le périphérique est physiquement supprimé du système et possède le même type de gestionnaire TJvHidUnplugEvent que pour OnDeviceUnplug. La fonction CountByProductName renvoie le nombre d'appareils correspondant au nom de produit spécifié dans l'argument et CountByVendorName renvoie le nombre de noms de fournisseurs spécifiés dans l'argument.

Principales propriétés et événements de la classe TJvHidDevice

La classe TJvHidDevice est une représentation virtuelle d'un seul périphérique HID. Un nouvel objet de cette classe peut être obtenu, comme déjà mentionné, à partir de l'événement OnArrival ou OnEnumerate. La fonctionnalité des classes TJvHidDeviceController et TJvHidDevice est partiellement dupliquée, puisque la première d'entre elles intègre une boîte à outils commune pour travailler avec un ensemble de périphériques HID disponibles dans le système et un mécanisme pour accéder à l'un d'entre eux. Un appareil peut être identifié de manière unique par ses propriétés SerialNumber, ProductName et VendorName. Vous pouvez utiliser l'événement OnData pour obtenir des informations sur l'arrivée de données à l'aide d'un tel objet. Les données sont envoyées via la méthode WriteFile (au sens strict, via une fonction). WriteFile est un wrapper autour de la fonction système WriteFile (kernel32).

Pour contrôler le fait que le périphérique est supprimé, attribuez un gestionnaire personnalisé à l'événement OnUnplug. Avant de démarrer l'échange de données avec un périphérique HID, vous devez vous assurer qu'un tel échange est possible à l'aide de HasReadWriteAccess. Cette classe possède même un événement OnDataError distinct pour l'apparition d'une erreur d'échange de données.

Et maintenant, regardons des fragments de code d'un projet "en direct" qui implémente une application client de test pour organiser l'échange de données avec un appareil non standard - des cartes à puce en plastique basées sur HID. Dans la lutte pour le réalisme, l'auteur a pris la liberté de ne pas supprimer les liaisons de codes technologiques « supplémentaires » des listes.

La méthode ScanDevices (liste 1) est conçue pour lancer le processus de recherche dans le système du périphérique HID requis. La plupart du code, à l'exception de l'appel à la méthode Enumerate, est facultatif et offre une flexibilité d'application, par exemple, afin que vous puissiez ajouter la possibilité de travailler sur une interface non HID au même programme de test. La méthode AddError imprime les informations de débogage dans la fenêtre pendant l'exécution du programme.

Le listing 2 montre le gestionnaire d'événements OnEnumerate pour trouver le périphérique externe requis. Pour plus de simplicité, nous supposerons que le programme peut fonctionner avec un seul appareil du type dont il a besoin.

Avant d'envisager la poursuite de la mise en œuvre du projet, nous devrions parler un peu du format d'échange de données de haut niveau accepté, c'est-à-dire de la structure conçue pour être un intermédiaire entre les méthodes de réception et de transmission de données et la tâche appliquée spécifique à résoudre. . Le fait est qu'ici, le développeur a la possibilité de réaliser ses capacités créatives. Ou plutôt, les développeurs, car le processus de création d'un nouveau protocole est très souvent bidirectionnel, et le premier violon est joué par celui qui a le plus de mal à mettre en œuvre l'algorithme d'échange. De manière générale, quel que soit le protocole d'échange, il est toujours agréable de rendre chaque entité logicielle la plus visuelle et autonome possible, même au détriment de certaines traditions généralement admises. Car la meilleure solution est celle qui sera mise en œuvre dans un court laps de temps avec une liaison minimale avec l'environnement logiciel et avec de grandes opportunités de développement ultérieur. Sur la base de ces principes, un protocole d'échange de haut niveau a été créé, dont le concept principal est « commande ». Le listing 3 montre à quel point l'auteur aime les données de chaîne, ce qui l'a sauvé plus d'une fois lors du débogage des modules du programme. Comme c'est merveilleux que nous ayons même un type String ! Toutes les commandes de protocole sont divisées en catégories (classes), au sein desquelles se trouve un code de commande qui caractérise de manière unique son objectif. Le paramètre edParam est utilisé pour envoyer des données à l'appareil et le paramètre edAnswerData contient les données reçues de l'appareil. Le type de chaîne des membres d'enregistrement décrits vous permet de manipuler librement et visuellement les données au format de chaîne HEX. Et ce qui est le plus agréable, c'est que le format de l'enregistrement décrit se situe idéologiquement quelque part entre son objectif direct et les diverses formes de sa présentation (INI, HEX, XML, etc.)

L'exécution de la commande, c'est-à-dire l'envoi de données à l'appareil, est mise en œuvre à l'aide de l'envoi de paquets de données d'une longueur de 8 octets (liste 4). Cette longueur n'est pas la seule décision, ce choix est dicté par les exigences du protocole de couche supérieure et peut être différent dans chaque cas spécifique. C'est ce qu'on appelle une question de goût. L'étrange indicateur IsUSBMode dans la méthode ExecuteCommand (liste 5 dans PC Disk World) est laissé pour rappeler qu'au lieu de travailler avec USB, nous devrons peut-être utiliser un port COM ou une autre interface. Au début du groupe de données envoyé, une séquence de synchronisation d'un format arbitrairement choisi (par exemple, 3E3E3E2B) est transmise à l'appareil, informant l'appareil qu'il dispose de données tout à fait légales en entrée. Permettez-moi de vous rappeler que dans ce cas, nous ne parlons pas tant de HID, mais d'un protocole spécifique de haut niveau, idéologiquement séparé du matériel et conçu pour résoudre des problèmes appliqués particuliers.

Dans le gestionnaire GetDataExecutor des données reçues de l'appareil (paquet de 8 octets), un événement OnNewInputData spécialement créé a été utilisé pour transférer les données initialement traitées pour un traitement ultérieur, en indiquant leurs anciennes et nouvelles valeurs (Listing 6 sur le "World du disque PC »). Ainsi, les événements d'arrivée de données brutes et une indication de traitement ultérieur sont découplés, ce qui permet d'ajouter un algorithme d'avertissement spécifique à un stade précoce pour les informations d'entrée erronées, répétées ou inutiles.

Les exemples de travail avec un périphérique HID présentés ici illustrent l'idée générale de l'article - la relative simplicité de programmation de périphériques HID non standard à l'aide des outils Delphi.

Vous avez aimé l'article ? Partager avec des amis: