分享

【转】使用Delphi与Usb设备进行通讯

 Gavin-book 2013-09-25
下面是访问 USB 设备的类单元文件:
{
     Usb通讯操作助手
     Date:     2008-7-10
     Version: 1.0
     Author:   zlz (47953@163.com)
   }
unit TUsbUtil_U;
interface
uses Windows, Messages, SysUtils, Variants, Classes,
   StdCtrls,Dialogs,SetupApi;
const
     MAX_PATH         = 260;     //文件名最大长度
   MAX_DATA_BUFFER   = 1024;     //缓冲区大小
Type
   //数据缓存
   TDataBuffer = record
       DataBuffer:array[0..MAX_DATA_BUFFER] of byte;   //缓存数据
     DataSize :Integer;                               //缓存数据长度
   end;
   //串口操作助手
   TUsbUtil   = class(TObject)
   public
     function Open(usbguid:String) :boolean;       //打开USB设备
     procedure Close();                             //关闭USB设备
     procedure WriteBytes(bs:TDataBuffer);         //向USB设备发送字节数组
     function ReadBytes():TDataBuffer;             //从USB设备读取数据
   private
     hUsbHandle :   THandle;
     //打开一个设备
   function OpenOneDevice(hDvcInfo:HDEVINFO; DvcInfoData:PSPDeviceInterfaceData ; sDevNameBuf:pchar) :THandle;
     //打开指定的USB设备
     function OpenUsbDevice(pGuid :TGUID; sDevNameBuf :pchar):THandle;
   end;
implementation
{ TUsbUtil }
procedure TUsbUtil.Close;
begin
     CloseHandle(hUsbHandle);
end;
function TUsbUtil.Open(usbguid: String): boolean;
var
   DeviceName: array[0..MAX_PATH] of char;
   USB_GUID   : TGUID;
begin
       Result := false;
       USB_GUID := StringToGuid('{' + usbguid + '}');
       hUsbHandle := OpenUsbDevice(USB_GUID, DeviceName);
       if (hUsbHandle = INVALID_HANDLE_VALUE) then
       begin
         raise Exception.Create('无法打开指定的USB设备');
       end;
       Result := True;
end;
function TUsbUtil.OpenOneDevice(hDvcInfo: HDEVINFO;
   DvcInfoData: PSPDeviceInterfaceData; sDevNameBuf: pchar): THandle;
var
iReqLen : dword;
iDevDataLen : DWord;
pDevData : PSPDeviceInterfaceDetailDataA ;
hOut: THandle;
begin
   hOut := INVALID_HANDLE_VALUE;
   iReqLen := 0;
   SetupDiGetDeviceInterfaceDetail(hDvcInfo,DvcInfoData, nil, 0, iReqLen, nil);
   iDevDataLen := DWORD(integer(iReqLen));
   GetMem(pDevData, iDevDataLen);
   pDevData.cbSize := sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
   if (SetupDiGetInterfaceDeviceDetail(hDvcInfo, DvcInfoData, pDevData, iDevDataLen, @iReqLen, nil)) then
   begin
     strcopy(sDevNameBuf, pDevData.DevicePath);
     hOut := CreateFile(pDevData.DevicePath,GENERIC_WRITE or GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil,OPEN_EXISTING,0,0);
   end;
   FreeMem(pDevData);
   Result := hOut;
end;
function TUsbUtil.OpenUsbDevice(pGuid: TGUID; sDevNameBuf: pchar): THandle;
var
   hDevInfo1 : HDEVINFO;
   deviceInfoData : TSPDeviceInterfaceData ;
   nGuessCount : Dword;
   iDevIndex :DWord;
   hOut: THandle;
begin
   hDevInfo1 := SetupDiGetClassDevs(@pGuid, nil,0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
   deviceInfoData.cbSize := sizeof(TSPDeviceInterfaceData);
   nGuessCount := MAXLONG;
   for iDevIndex :=0 to nGuessCount do
   begin
     if(SetupDiEnumDeviceInterfaces(hDevInfo1,nil,pGuid,iDevIndex,deviceInfoData)) then
     begin
         hOut := OpenOneDevice(hDevInfo1, @deviceInfoData, sDevNameBuf);
         if (hOut <> INVALID_HANDLE_VALUE) then
         begin
           break;
         end
         else if (GetLastError() = ERROR_NO_MORE_ITEMS) then
         begin
           break;
         end;
     end;
   end;
   SetupDiDestroyDeviceInfoList(hDevInfo1);
   Result := hOut;
end;
function TUsbUtil.ReadBytes: TDataBuffer;
var
   nBytesReaded:LongWord;
   bs: TDataBuffer;
begin
     ReadFile(self.hUsbHandle,bs.DataBuffer,MAX_DATA_BUFFER, nBytesReaded, nil);
     bs.DataSize :=   nBytesReaded;
     Result := bs;
end;
procedure TUsbUtil.WriteBytes(bs: TDataBuffer);
var
   nBytesWritten:LongWord;
begin
   WriteFile(self.hUsbHandle, bs.DataBuffer, bs.DataSize, nBytesWritten, nil);
end;
end.
有了上面的类就可以与USB设备进行通讯了
procedure TUsbUtil.Test;
var
     bs:TDataBuffer;
     objUsb:TUsbUtil;
begin
   objUsb :=   TUsbUtil.Create();
//打开USB设备,参数是驱动程序的GUID值, 这里我乱写的数
objUsb.Open('A5DCBF10-6530-11D2-901F-00C04FB951ED');
//写入数据
bs.DataBuffer[0] := $1B;
bs.DataBuffer[1] := $10;
bs.DataBuffer[2] := $00;
bs.DataBuffer[3] := $00;
bs.DataBuffer[4] := $05;
bs.DataBuffer[5] := $44;
bs.DataBuffer[6] := $D0;
bs.DataSize := 7;
objUsb.WriteBytes(bs);
//读取数据
bs := objUsb.ReadBytes();
//关闭设备
objUsb.Close();
end;
USB 设备、USB 驱动、USB 应用程序
1.USB 设备硬件部分
   a.这个硬件的标识是用的 Vender ID 和 Product ID, 即“厂家标识”和“产品标识”
   b.这个硬件规定了各个 End Point (端点) 的性质, 读/写 及 类型 (Control/Interrupt/Bulk/Isochronous)
   c.这个硬件的固件里面有 DeviceIoControl 的实现部分, 规定了这个函数的具体参数和动作
2.USB 设备驱动
①硬件接口
   a.需要识别 Vender ID 和 Product ID
   b.对每个 EndPoint 的每个 I/O 分配一个 Pipe, 并且起一个名字作为软件接口
   c.做 DeviceIoControl 的接口
②软件接口
   a.GUID, 驱动程序的标识, 每个驱动程序使用不同的 GUID, GUID 是识别驱动的, 与硬件无关 (驱动程序升级版本 GUID 不能修改)
   b.硬件接口里面的 b: Pipe 名字是软件接口, 这个 Pipe 名字纯粹由驱动定义的, 和硬件无关, 升级驱动不能改 Pipe 的名字
   c.硬件接口里面的 c 的各个参数也是软件的接口, 这些参数是由硬件带来的, 不是驱动规定的, 当然也可以在驱动里面转义, 隐藏设备的真实情况
③这个驱动程序是用 WinDDK 编译的, 可以用文本编辑器或其他开发工具的编辑器编程序代码, 然后调用 WinDDK 编译
3.读写 USB 口的程序
①与驱动的接口
   a.利用驱动程序里面的 GUID 找出设备的文件名, 用 CreateFile 函数打开设备。我前面的程序里面的 OpenUsbDevice 就是这个作用
   b.通过 a.得到的设备文件名和驱动程序里面的 Pipe 名打开 Pipe, 访问这个 Pipe 对应的 USB 端点 (读写数据)
   c.使用 a.的 CreateFile 得到的句柄, 通过 DeviceIoControl 实现设备规定的动作
②有关需要的资料
   a.Vender ID, Product ID 和 GUID 一般在驱动程序的 .inf 文件里面能看到, 如果找不到就需要和厂家联系
   b.Pipe 的名字是驱动程序规定的, 需要有驱动程序的资料才能知道
   c.DeviceIoControl 的参数需要有驱动程序的资料或者硬件资料才能知道
③这个程序一般用 C/C++ 直接编写, 如果使用其他语言(VB/PB等)需要调用 C/C++ 编的 DLL
其他相关内容:
USB 驱动程序可以到注册表里面找到:
"HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Enum\\USB\\Vid_厂家标识&Pid_产品标识\\驱动程序"
里面的 ClassGUID 就是驱动程序的 GUID 标识, 例如 {36FC9E60-C465-11CF-8056-444553540000}
相当于程序的: DEFINE_GUID(USB_DRIVER_GUID, 0x36FC9E60,0xC465,0x11CF,0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00);
另外在这个注册表键里面还可找到有关设备的其他描述, 例如 DeviceDesc = "USB Mass Storage Device" 等

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多