Windows 下读取 UT395B 激光测距仪返回值

最近有一个需求,需要检测一个物体的运动速度,经过研究我决定使用激光距离传感器来完成这个要求。在模块选择的问题上,我再次遇到了“面粉比面包贵” 的问题-----激光测距模块价格比成品要高。最终选择的是带有USB接口的优利德 UT395B。

最远可以达到150米,我选择的是可以达到70米的

他自带一个软件可以在 Windows 下获得距离,因此可以使用 USBlyzer 来抓取通讯数据数据分析协议。首先抓取Descriptor:

USB 输入设备

Connection Status Device connected
Current Configuration 1
Speed Full (12 Mbit/s)
Device Address 12
Number Of Open Pipes 2

Device Descriptor SDWAY

Offset Field Size Value Description
0 bLength 1 12h
1 bDescriptorType 1 01h Device
2 bcdUSB 2 0200h USB Spec 2.0
4 bDeviceClass 1 00h Class info in Ifc Descriptors
5 bDeviceSubClass 1 00h
6 bDeviceProtocol 1 00h
7 bMaxPacketSize0 1 40h 64 bytes
8 idVendor 2 0483h SGS Thomson Microelectronics
10 idProduct 2 5751h
12 bcdDevice 2 0200h 2.00
14 iManufacturer 1 01h "MyUSB_HID"
15 iProduct 1 02h " SDWAY "
16 iSerialNumber 1 03h
17 bNumConfigurations 1 01h

Configuration Descriptor 1

Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 02h Configuration
2 wTotalLength 2 0029h
4 bNumInterfaces 1 01h
5 bConfigurationValue 1 01h
6 iConfiguration 1 00h
7 bmAttributes 1 C0h Self Powered
4..0: Reserved ...00000
5: Remote Wakeup ..0..... No
6: Self Powered .1...... Yes
7: Reserved (set to one)
(bus-powered for 1.0)
1.......
8 bMaxPower 1 C0h 384 mA

Interface Descriptor 0/0 HID, 2 Endpoints

Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 04h Interface
2 bInterfaceNumber 1 00h
3 bAlternateSetting 1 00h
4 bNumEndpoints 1 02h
5 bInterfaceClass 1 03h HID
6 bInterfaceSubClass 1 00h
7 bInterfaceProtocol 1 00h
8 iInterface 1 00h

HID Descriptor

Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 21h HID
2 bcdHID 2 0110h 1.10
4 bCountryCode 1 00h
5 bNumDescriptors 1 01h
6 bDescriptorType 1 22h Report
7 wDescriptorLength 2 0021h 33 bytes

Endpoint Descriptor 82 2 In, Interrupt, 10 ms

Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 82h 2 In
3 bmAttributes 1 03h Interrupt
1..0: Transfer Type ......11 Interrupt
7..2: Reserved 000000..
4 wMaxPacketSize 2 0040h 64 bytes
6 bInterval 1 0Ah 10 ms

Endpoint Descriptor 01 1 Out, Interrupt, 16 ms

Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 01h 1 Out
3 bmAttributes 1 03h Interrupt
1..0: Transfer Type ......11 Interrupt
7..2: Reserved 000000..
4 wMaxPacketSize 2 0040h 64 bytes
6 bInterval 1 10h 16 ms

Interface 0 HID Report Descriptor

Item Tag (Value) Raw Data
Usage Page (Bar Code Scanner) 05 8C
Usage 09 01
Collection (Application) A1 01
    Usage 09 03
    Logical Minimum (0) 15 00
    Logical Maximum (-256) 26 00 FF
    Report Size (8) 75 08
    Report Count (24) 95 18
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02
    Usage 09 04
    Logical Minimum (0) 15 00
    Logical Maximum (-256) 26 00 FF
    Report Size (8) 75 08
    Report Count (24) 95 18
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02
End Collection C0

 

从上面的结果可以看出这个设备是一个自定义的 HID设备,因此,需要进步一抓取通讯数据。

上面是一次完整的获得测量距离的过程,一共有8笔数据,4 笔是主机发送给设备,4笔是设备的返回值。 OUTPUT Report是主机发送给 UT395B的数据。第一个数据包: 41 54 4B 30 30 31 23 00 00 00 00 41 00 00 00 54 00 00 00  44 00 00 00 00

发送到设备之后,设备会打开激光(手册上说这是打开瞄准的功能)。第5笔数据和第1笔数据相同,设备会关闭激光。

经过研发总结: 41 54 4B 30 30 31 23 …….这个命令是打开/关闭激光。   41 54 44 30 30 31 23 …….是主机要求返回距离信息的命令。

上面8个数据的含义如下:

  1. 主机要求打开激光
  2. 设备 ECHO
  3. 主机要求获得上一笔数据
  4. 设备返回上一笔数据
  5. 主机要求关闭激光
  6. 设备 ECHO
  7. 主机要求获得距离数据
  8. 设备返回数据,就是我们需要的距离信息

一个典型的返回值:

41 54 44 00 00 3A E8 00 …… 其中的  3A E8 就是距离信息。0x3AE8=15080 对应显示在屏幕上的距离是1.508米。经过多次实验,显示小数点后3位的数值,但是实际上的数据是小数点后4位,最后一位会进行四舍五入。

最终编写 Windows 下 Console 代码如下:

//http://blog.csdn.net/xuxinhua/article/details/6329182

#include "stdafx.h"

#include <stdio.h>

#include <tchar.h>

#include <windows.h>

#include <setupapi.h>



extern "C" {

void __stdcall

HidD_GetHidGuid (

   OUT   LPGUID   HidGuid

   );

typedef struct _HIDD_ATTRIBUTES {

    ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)



    //

    // Vendor ids of this hid device

    //

    USHORT  VendorID;

    USHORT  ProductID;

    USHORT  VersionNumber;



    //

    // Additional fields will be added to the end of this structure.

    //

} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;



BOOLEAN __stdcall

HidD_GetAttributes (

    IN  HANDLE              HidDeviceObject,

    OUT PHIDD_ATTRIBUTES    Attributes

    );



BOOLEAN __stdcall

HidD_SetFeature(

       _In_    HANDLE   HidDeviceObject,

       _In_reads_bytes_(ReportBufferLength) PVOID ReportBuffer,

       _In_    ULONG    ReportBufferLength

);

}



#pragma comment( lib, "hid.lib" )

#pragma comment( lib, "setupapi.lib" )



void Switch(HANDLE hUsb)

{

       BOOL Result;

       //Output DataµÄ»º³åÇø£¬ÒòΪÏÂÃæ·¢ËÍ HID ±¨ÎÄÐèÒª9×Ö½Ú£¬ËùÒÔÕâÀïÖ±½Ó°´ÕÕ×î´óµÄ¶¨Òå

       UCHAR WriteReportBuffer[25];



       WriteReportBuffer[00] = 0x00;



       WriteReportBuffer[1] = 0x41;

       WriteReportBuffer[2] = 0x54;

       WriteReportBuffer[3] = 0x4b;

       WriteReportBuffer[4] = 0x30;



       WriteReportBuffer[5] = 0x30;

       WriteReportBuffer[6] = 0x31;

       WriteReportBuffer[7] = 0x23;

       WriteReportBuffer[8] = 0x00;



       WriteReportBuffer[9] = 0x00;

       WriteReportBuffer[10] = 0x00;

       WriteReportBuffer[11] = 0x00;

       WriteReportBuffer[12] = 0x41;



       WriteReportBuffer[13] = 0x00;

       WriteReportBuffer[14] = 0x00;

       WriteReportBuffer[15] = 0x00;

       WriteReportBuffer[16] = 0x54;



       WriteReportBuffer[17] = 0x00;

       WriteReportBuffer[18] = 0x00;

       WriteReportBuffer[19] = 0x00;

       WriteReportBuffer[20] = 0x44;



       WriteReportBuffer[21] = 0x00;

       WriteReportBuffer[22] = 0x00;

       WriteReportBuffer[23] = 0x00;

       WriteReportBuffer[24] = 0x00;

       DWORD lpNumberOfBytesWritten;



       //µ÷ÓÃWriteFileº¯Êý·¢ËÍÊý¾Ý

       //±¨Îij¤¶ÈÊÇ9×Ö½Ú

       Result = WriteFile(hUsb,

             WriteReportBuffer,

             25,

             &lpNumberOfBytesWritten,

             NULL);



       printf("Written %d bytes Result [%d]\n", lpNumberOfBytesWritten, Result);



}



void SendData(HANDLE hUsb)

{

       BOOL Result;

       //Output DataµÄ»º³åÇø£¬ÒòΪÏÂÃæ·¢ËÍ HID ±¨ÎÄÐèÒª9×Ö½Ú£¬ËùÒÔÕâÀïÖ±½Ó°´ÕÕ×î´óµÄ¶¨Òå

       UCHAR WriteReportBuffer[25];



       WriteReportBuffer[00] = 0x00;



       WriteReportBuffer[1] = 0x41;

       WriteReportBuffer[2] = 0x54;

       WriteReportBuffer[3] = 0x44;

       WriteReportBuffer[4] = 0x30;



       WriteReportBuffer[5] = 0x30;

       WriteReportBuffer[6] = 0x31;

       WriteReportBuffer[7] = 0x23;

       WriteReportBuffer[8] = 0x00;



       WriteReportBuffer[9] = 0x00;

       WriteReportBuffer[10] = 0x00;

       WriteReportBuffer[11] = 0x00;

       WriteReportBuffer[12] = 0x41;



       WriteReportBuffer[13] = 0x00;

       WriteReportBuffer[14] = 0x00;

       WriteReportBuffer[15] = 0x00;

       WriteReportBuffer[16] = 0x54;



       WriteReportBuffer[17] = 0x00;

       WriteReportBuffer[18] = 0x00;

       WriteReportBuffer[19] = 0x00;

       WriteReportBuffer[20] = 0x44;



       WriteReportBuffer[21] = 0x00;

       WriteReportBuffer[22] = 0x00;

       WriteReportBuffer[23] = 0x00;

       WriteReportBuffer[24] = 0x00;

       DWORD lpNumberOfBytesWritten;



       //µ÷ÓÃWriteFileº¯Êý·¢ËÍÊý¾Ý

       //±¨Îij¤¶ÈÊÇ9×Ö½Ú

       Result = WriteFile(hUsb,

             WriteReportBuffer,

             25,

             &lpNumberOfBytesWritten,

             NULL);



       printf("Written %d bytes Result [%d]\n", lpNumberOfBytesWritten, Result);



}

void GetData(HANDLE hUsb)

{

       //½ÓÊÕ±¨¸æµÄ»º³åÇø£¬1×Ö½Ú±¨¸æID+8×Ö½Ú±¨¸æÊý¾Ý¡£                          

       UCHAR ReadReportBuffer[25];

       DWORD lpNumberOfBytesRead;

       UINT LastError;

       BOOL Result;

       DWORD tmp;



       //µ÷ÓÃReadFile ½ÓÊÕÊý¾Ý

       Result = ReadFile(

             hUsb,

             ReadReportBuffer,

              25,

             &lpNumberOfBytesRead,

             NULL);

       //printf("Read %d bytes\n", lpNumberOfBytesRead);

       //Èç¹ûº¯Êý·µ»Øʧ°Ü£¬Ôò¿ÉÄÜÊÇÕæµÄʧ°Ü£¬Ò²¿ÉÄÜÊÇIO¹ÒÆð

       if (Result == FALSE)

       {

             //»ñÈ¡×îºó´íÎó´úÂë

             LastError = GetLastError();

             //¿´ÊÇ·ñÊÇÕæµÄIO¹Ò        

             if ((LastError == ERROR_IO_PENDING) || (LastError == ERROR_SUCCESS))

             {

                    exit;

             }

             //·ñÔò£¬ÊǺ¯Êýµ÷ÓÃʱ·¢Éú´íÎó£¬ÏÔʾ´íÎó´úÂë

             else

             {

                    printf("Sending error£º%d \n", LastError);

                    //Èç¹û×îºó´íÎóΪ1£¬ËµÃ÷¸ÃÉ豸²»Ö§³Ö¸Ãº¯Êý¡£

                    if (LastError == 1)

                    {

                           printf("This device doesn't support WriteFile function \n");

                    }

             }

       }

       else //Õý³£¶ÁÈ¡

       {

             for (DWORD Index = 0; Index < lpNumberOfBytesRead; Index++) {

                    printf("%02X ", ReadReportBuffer[Index]);

             }

             printf("\n");

             if (0x44 == ReadReportBuffer[0x03]) {

                    tmp = (ReadReportBuffer[0x06] << 8) + ReadReportBuffer[0x07];

                    printf("%d.%d\n", tmp / 10000, (tmp - tmp /10000 * 10000 +5)/10);

             }

       }



       printf("\n");

}

int main(array<System::String ^> ^args)

{  

        GUID HidGuid;

        BOOL Result;

        int  counter=-1;



       //»ñÈ¡HIDÉ豸µÄ½Ó¿ÚÀàGUDI

             HidD_GetHidGuid(&HidGuid);

       //Êä³öһϿ´¿´GUID

             printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"

                , HidGuid.Data1, HidGuid.Data2, HidGuid.Data3

                , HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]

                , HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7] );

      

       //¸ù¾Ý»ñµÃµÄGUIDö¾ÙHIDÉ豸

       HDEVINFO hDevInfo = SetupDiGetClassDevs( &HidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );

    if( INVALID_HANDLE_VALUE != hDevInfo )

    {

        SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };

        for( DWORD index=0; SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,&strtInterfaceData); ++index )

        {

            char buf[1000];

            SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];

            strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

            if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )

            {

                printf("[%d] path: %ls\n", index, strtDetailData.DevicePath);

                          

                           //ÕâÀï´ò¿ªµÄÓпÉÄÜÊÇUSB¼üÅÌÊó±êÕâÑù±È½ÏÌرðµÄÉ豸£¨Ö»Äܲéѯ£©

                HANDLE hUsb = CreateFile( strtDetailData.DevicePath,

                                               NULL, FILE_SHARE_WRITE,

                                               NULL, OPEN_EXISTING,

                                               FILE_ATTRIBUTE_NORMAL,

                                               NULL );

                            

                // ²éѯÉ豸±êʶ

                HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };

                           Result=HidD_GetAttributes(hUsb,&strtAttrib);

               

                           //ËùÒÔÕâÀïÒª¹Ø±Õһϣ¬ºóÃæÕÒµ½ÎÒÃÇ×Ô¼ºµÄÉ豸ȷ¶¨¿ÉÒÔдÈëÔÙ´ò¿ªÒ»´Î

                        CloseHandle( hUsb );

               

                           if(TRUE==Result)

                    {

                                 if ((0x0483 == strtAttrib.VendorID) &&

                                        (0x5751 == strtAttrib.ProductID))       //ÕÒµ½ÎÒÃÇ×Ô¼ºµÄÉ豸

                                 {

                                        printf("VendorID : %hX\n", strtAttrib.VendorID);

                                        printf("ProductID: %hX\n", strtAttrib.ProductID);

                                        printf("VerNumber: %hX\n", strtAttrib.VersionNumber);



                                        //È·¶¨ÊÇÎÒÃÇ×Ô¼ºµÄÉ豸£¬ÔÙ´ò¿ªÒ»´Î,×¢ÒâÎÒÃÇÕâÀïʹÓõÄÊÇͬ²½·¢ËÍ

                                        hUsb = CreateFile(strtDetailData.DevicePath,

                                               GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE,

                                               NULL, OPEN_EXISTING,

                                               FILE_ATTRIBUTE_NORMAL, NULL);



                                        Switch(hUsb); GetData(hUsb);

                                        //Sleep(100);

                                        SendData(hUsb); GetData(hUsb);

                                        Switch(hUsb); GetData(hUsb);

                                        SendData(hUsb); GetData(hUsb);

                                       

                                       



                                                      CloseHandle( hUsb );

                                                     }//if ((0x8888==strtAttrib.VendorID) &&

                                 }            //if(TRUE==Result)

            } // if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )



        }    //for( DWORD index=0;

       

             if( GetLastError() != ERROR_NO_MORE_ITEMS )

                    {printf("No more items!\n"); }



        SetupDiDestroyDeviceInfoList( hDevInfo );

    }  //if( INVALID_HANDLE_VALUE != hDevInfo )



       system("PAUSE");

    return 0;

}

 

运行结果:

发表评论

电子邮件地址不会被公开。 必填项已用*标注