石保敬,王长荀,怯肇乾
WinUSB驱动实现及其通信传输应用
石保敬,王长荀,怯肇乾
(河南驰诚电气,河南 郑州 450001)
微软近年来推出的规范简便的WinUSB设备通信模型,编程对接的关键是“底层USB设备如何添加描述使Windows OS识别其为WinUSB设备”和“可视化测试/应用程序怎样通过WinUSB.dll调用与之进行管道数据传输的实现”,恰到好处的运用定时器或线程是异步快速实时数据接收软件设计的核心,USB测试/应用程序发布针对低级操作系统版本需要编写引导安装程序,USB设备插拔处置和多USB设备通信的操控也需要特定处置,如此编程设计,Windows下USB设备传输通信就如同传统的RS-232C通信一样方便自如而且还直截了当和迅速高效了。
USB描述符;WinUSB设备;异步数据传输;定时数据接收;线程数据接收
Windows操作系统OS(Operation System)下,通过USB(Universal Serial Bus)接口,读写访问USB设备,是嵌入式应用系统和可视化测试/应用软件开发必不可少的常用环节。微软从Winxp-SP2版本开始,在Windows中集成了通用的WinUSB Device驱动及其连接OS底层和应用层的WinUSB.dll,极大简化了USB数据的通信传输。恰到好处的运用WinUSB进行开发,同样可以到达类似使用傻瓜托管式的WinDriver软件的效果。编程设计的关键是如何让Windows快速的把USB设备识别为通用WinUSB设备和应用软件怎样合理调用WinUSB.dll对应的WinUSB.lib库。本文就此展开详细阐述。
开发WinUSB驱动实现及其通信传输应用,可以采用C++、C#或JavaScript等语言,最好的集成开发环境IDE(Integrated Development Environment)是Visial Studio,也可以是Rad Studio XE等,无论哪个IDE都需要首先安装Windows驱动程序开发工具包WDK(Windows Driver Kit)。这里以Rad Studio XE和STM32F103系列微控制器的可视化USB设备通信开发为例加以说明。
嵌入式应用系统实现USB设备通信,主要是在高优先级的中断服务程序中实现的,包括常规的USB标准请求应答和管道读写收发实现,管道操作主要是中断和批量传输,USB标准请求包括设备、配置、接口及其端点描述与速度限定变换。必须设法让Windows识别为通用WinUSB设备,可视化测试/应用程序才可以使用通用的WinUSB设备驱动进行沟通交互,如图1所示。
图1 通用WinUSB设备的操作系统识别
为此,需要特别构造1个标准USB类描述符--OS描述符和2个供应商类描述符--OS特征ID(Identifier)描述符和注册设备接口GUID描述符。全球唯一标识符GUID(Globally Unique Identifier)。
OS描述符,定义存储在字符串索引0xEE 处,对应的USB标准请求为:
80 06 ee 03 00 00 12 00
典型的OS描述符定义如下:
#define bMS_VendorCode 0x01
//Vendor 请求的请求代码
const unsigned char OsDscrptStr[] =
// "MSFT100" : index : 0xEE : langId : 0
{ 0x12, 0x03, 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, bMS_VendorCode, 0 };
供应商类OS特征ID描述符,用作设置扩展兼容,对应的供应商类请求为:
初步请求--c0 01 00 00 04 00 10 00,再次请求--c0 01 00 00 04 00 28 00
典型的OS特征ID描述符包定义如下:
const unsigned char cptbIdDscrpt [] =
{ 0x28, 0x00, 0x00, 0x00, //包长
0x00, 0x01, //BCD版本
0x04, 0x00, //索引
0x01, //数量
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, //保留[7]
0x00, //第一接口编号
0x01, //保留(0x01)
'W', 'I', 'N', 'U', 'S', 'B',
0x00, 0x00, //兼容ID[8]
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, //子兼容ID[8]
0x00, 0x00, 0x00,
0x00, 0x00, 0x00 //保留[6]
};
供应商类注册设备接口GUID,将体现在注册表中,如图2所示,GUID可用相应工具软件产生。
图2 Windows注册表中的特定通用USB设备接口GUID示意图
该描述符,供应用程序调用该GUID做读写访问的USB设备识别,对应的供应商类请求为:
初次请求--c1 01 00 00 05 00 0a 00,再次请求--c1 01 00 00 05 00 8e 00
典型的注册设备接口 GUID描述符定义如下:
const unsigned char itfcGuidDscrpt[] =
{ 0x8E, 0x00, 0x00, 0x00, //包长(头+各部分)
0x00, 0x01, //头: BCD版本
0x05, 0x00, //索引
0x01, 0x00, //数量
0x84, 0x00, 0x00, 0x00 //部分: 大小
0x01, 0x00, 0x00, 0x00, //属性数据类型
0x28, 0x00, //属性名字长度
{ 'D', 0, 'e', 0, 'v', 0, 'i', //属性名称[40]:
0, 'c', 0, 'e', 0, 'I', 0, "DeviceInterfaceGUID"
'n',0, 't', 0, 'e', 0, 'r',
0, 'f',0, 'a', 0, 'c', 0,
'e', 0, 'G',0, 'U', 0,
'I', 0, 'D', 0, 0, 0
},
0x4E, 0x00, //属性数据长度:
0x00, 0x00, 78[0x4E]
{ '{', 0, '1', 0, '2', 0, '3', 0, //属性数据: {12345678-
'4', 0, '5', 0, '6', 0, '7', 1234-1234-1234-
0, 8', 0, '-', 0, '1', 0, '2', 123456789ABC}
0, '3', 0, '4', 0, '-', 0, '1',
0, '2', 0, '3', 0, 4', 0, ' '-',
0, '1', 0, '2', 0, '3', 0, '4',
0, '-', 0, '1', 0,'2', 0, '3', 0,
'4', 0, '5', 0, '6', 0, '7', 0,
8', 0, '9', 0, 'A', 0, 'B', 0,
'C', 0, '}', 0, 0, 0
}
};
可用作者的“ARM系列微处理控制器的软件体系架构工具”得到完整的STM32103系列USB驱动程序,包括上述3个特殊描述符在内的标准USB请求类和供应商请求及其应答配置与控制、中断、批量或同步管道传输代码,限于篇幅,不再赘述。
可视化测试/应用程序中使用Windows OS通用的WinUSB设备驱动,必须引入对WDK头文件的引用,需要在可视化窗口.cpp文件头部加入的典型.h文件引用如下:
#include "Windows Kits10Include10.0.15063. 0sharedusb.h"
#include "Windows Kits10Include10.0.15063. 0sharedstrsafe.h"
#include "Windows Kits10Include10.0.15063. 0umSetupAPI.h"
#include "Windows Kits10Include10.0.15063. 0umwinusb.h"
可视化测试/应用程序,通过连接OS底层和应用层的WinUSB.dll操作特定的通用WinUSB Device,必须在项目工程中引用WinUSB.dll对应的WinUSB.lib库文件。WDK提供有相应的WinUSB. lib,在Visival Studio中引用没有问题,但不能直接在Rad Studio XE中引用,编译连接时会报错:
BCB contains invalid OMF record, type 0x21 (possibly COFF)
这是IDE要求的原始设备制造商OEM(Original Equipment Manufacturer)的通用对象文件格式COFF(Common Object File Format)不同引起的lib文件兼容不足导致的。可以使用Rad Studio XE的coff2omf. exe工具进行转换再加以引用,命令行操作如下,其中前者是微软DDK提供的,后者就是得到的Rad Studio XE开发所需的库:
coff2omf -lib:ms WinUSB.lib bcb WinUSB.lib
与其它OS一样,Winsows把设备当做文件操作,但USB设备又有特定的集成端点在内的管道传输的接口,所以打开USB设备文件后还要打开相应的USB接口,得到特定的USB接口操作句柄,之后就可以运用该句柄,调用管道读写进行数据传输了。可视化测试/应用程序退出时必须依次关闭USB接口操作句柄和设备文件操作句柄。
获取USB设备及其接口操作句柄的典型函数代码如下:
HANDLE hDeviceHandle = INVALID_HANDLE_VALUE; // 设备文件句柄
WINUSB_INTERFACE_HANDLE hWinUSBHandle // WinUSB操作句柄
= INVALID_HANDLE_VALUE;
// USB设备文件句柄创建[接口GUID,设备句柄]-------------------------------------------------------------------
BOOL GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle )
{ if ( guidDeviceInterface == GUID_NULL ) return FALSE;
BOOL bResult = TRUE; HDEVINFO hDeviceInfo;
SP_DEVINFO_DATA DeviceInfoData; DWORD index = 0;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
ULONG requiredLength = 0; LPTSTR lpDevicePath = NULL;
// 为特定设备的接口类而获取安装设备的所有信息
hDeviceInfo = SetupDiGetClassDevs(&guidDeviceInterface, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
if ( hDeviceInfo == INVALID_HANDLE_VALUE ) goto done; // 无效退出
// 在设备信息集中枚举所有设备接口
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(index=0; SetupDiEnumDeviceInfo(hDeviceInfo, index, & DeviceInfoData); index++)
{ if(lpDevicePath) LocalFree(lpDevicePath); // 复位相应项
if(pInterfaceDetailData) LocalFree(pInterfaceDetailData);
deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
bResult = SetupDiEnumDeviceInterfaces( hDeviceInfo, // 获取设备接口信息
&DeviceInfoData, &guidDeviceInterface, 0, &deviceInterfaceData );
if(GetLastError()== ERROR_NO_MORE_ITEMS) break; // 最后项?
if(!bResult) goto done; // 错误退出
// 动态调用2次,首次分配空间,再次得到接口数据
bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
&deviceInterfaceData, NULL, 0, &requiredLength, NULL );
if(!bResult) // 错误检查
{ if((ERROR_INSUFFICIENT_BUFFER == GetLastError())
&& ( requiredLength > 0 ) )
{ pInterfaceDetailData = // 动态分配缓冲区大小
(PSP_DEVICE_INTERFACE_DETAIL_DATA)
LocalAlloc(LPTR, requiredLength );
if (!pInterfaceDetailData ) goto done; // 错误退出
}
else goto done; // 错误退出
}
pInterfaceDetailData->cbSize // 获取接口详细数据
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
&deviceInterfaceData, pInterfaceDetailData,
requiredLength, NULL, &DeviceInfoData );
if (!bResult) goto done; // 错误退出
size_t nLength = wcslen(pInterfaceDetailData->DevicePath ) + 1; // 设备文件路径
lpDevicePath = (TCHAR *) LocalAlloc( LPTR, nLength * sizeof(TCHAR));
StringCchCopy(lpDevicePath, nLength, pInterfaceDetailData->DevicePath);
lpDevicePath[(nLength - 1)] = 0;
}
if (!lpDevicePath) goto done; // 错误退出
}
*hDeviceHandle = CreateFile( lpDevicePath, // 打开设备文件, 得到设备文件句柄
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ
| FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (*hDeviceHandle != INVALID_HANDLE_VALUE ) return true;
done: LocalFree( lpDevicePath );
LocalFree( pInterfaceDetailData );
bResult = SetupDiDestroyDeviceInfoList( hDeviceInfo );
return bResult;
}
// 获取设备的 WinUSB 接口句柄------------------------------------------------------------------------------------
BOOL GetWinUSBHandle(HANDLE hDeviceHandle,
PWINUSB_INTERFACE_HANDLE phWinUSBHandle)
{ if(hDeviceHandle == INVALID_HANDLE_VALUE) return FALSE;
BOOL bResult = WinUsb_Initialize(hDeviceHandle, phWinUSBHandle);
if (!bResult) return FALSE;
return bResult;
}
可视化窗口,创建时运用特定USB接口GUID,调用这两个函数创建设备文件句柄和USB接口操作句柄;窗口关闭时依次关闭这两个句柄;若USB设备没有挂接,应用禁止窗口上所有USB数据收发按钮操作,相关核心代码如下:
void__fastcall TfrmShow::FormCreate(TObject *Sender)
{static const GUID stm32F1xxDvcItfc = { 0x12345678, 0x1234, 0x1344,
{0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC } };
GUID guidDeviceInterface = stm32F1xxDvcItfc;
BOOL bResult = TRUE; ULONG cbSize = 0;
bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
if (!bResult) return;
bResult = GetWinUSBHandle(hDeviceHandle, & hWinUSBHandle);
if(!bResult) return;
flgWinUSB = true;
}
//---------------------------------------------------------
void __fastcall TfrmShow::FormClose(TObject *Sender, TCloseAction &Action)
{ if(!flgWinUSB) return;
CloseHandle(hDeviceHandle);
WinUsb_Free(hWinUSBHandle);
}
运用WinUSB应用程序编程接口API (Application Programming Interface)函数WinUsb_ReadPipe和WinUsb_WritePipe进行数据管道收发传输时,若没有收到或发出数据,程序会一直等待,造成可视化窗口失控,可以通过调用WinUsb_SetPipePolicy函数,使用WinUSB的超时管道传输策略来避免这种阻塞式的尴尬局面,取消请求之前等待超时时间,超过超时时间退出等待。通常在USB设备文件句柄和WinUSB接口句柄创建成功后进行超时传输设置,时间据实际传输量而定,典型代码如下,这里超时时间取100ms,0x81对应输入IN管道1,0x02对应输出OUT管道2:
UINT timeout = 100;
bResult = WinUsb_SetPipePolicy(hWinUSBHandle, 0x81, // 输入IN管道1
PIPE_TRANSFER_TIMEOUT, sizeof (timeout), & timeout);
if(!bResult) return;
bResult = WinUsb_SetPipePolicy(hWinUSBHandle, 0x02, // 输出OUT管道2
PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout);
if(!bResult) return;
数据发送,同异步操作差别不大,只要准备好数据,很容易知道其数据大小,主动同步发出,以最简方式实现,典型代码如下:
if(hWinUSBHandle==INVALID_HANDLE_VALUE) return;
UCHAR szBffr[50]; ULONG cbSent = 0;
AnsiString str = edtSdDt->Text; // 窗口文本输入控件
strcpy(szBffr, str.c_str());
ULONG cbSize = str.Length();
WinUsb_WritePipe(hWinUSBHandle, 0x02, szBffr, cbSize, &cbSent, 0 );
异步数据收发传输,对于不知数据量大小的操作非常有效,特别是USB管道的读操作。
首先需要定义全局的OVERLAPPED结构变量,并在USB设备文件及其WinUSB接口句柄创建成功后初始化这个结构变量,主要是其相关“事件Event”的初始化,典型代码如下:
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
典型的异步USB管道读事件代码如下,首先以小固定数量15进行盲读,在限定的超时时间内,只要收到数据,都可以接收,并成行显示在窗口的文本指示框内:
void WinUSB_Read(void)
{ if(hWinUSBHandle==INVALID_HANDLE_VALUE) return;
ULONG cbRead = 0; UCHAR szBffr[20] = {'0'}; AnsiString str;
BOOL bResult = WinUsb_ReadPipe(hWinUSBHandle, 0x81,
szBffr, 15, &cbRead, &overlapped);
if(bResult)
{ const char* t = szBffr; str = t;
mRcvDt->Lines->Add(str); // 可视窗口文本显示控件
}
else if(ERROR_IO_PENDING == GetLastError ())
{bResult = WinUsb_GetOverlappedResult(hWinUSBHandle, & overlapped, &cbRead, true);
if(NULL != cbRead)
{ int m = cbRead; cbRead = 0;
if(bResult)
{ const char* d = szBffr; str = d;
mmRcvDt->Lines->Add(str);
}
}
}
}
随时监听USB输入管道并接收可能传入的数据,在可视化测试/应用程序设计中,简洁高效的方法就是采用定时器控制,以一定的时间间隔,在定时器的OnTimer事件处理中,去异步的读取USB输入管道,典型代码如下,其中设置的时间间隔是100 ms:
void __fastcall TfrmShow::rcvTmrTimer(TObject *Sender)
{ rcvTmr->Enabled = false; // 关闭定时器
WinUSB_Read(); // 异步数据谋取并进行可视化窗口显示
rcvTmr->Enabled = true; // 重开定时器
}
以线程方式在后台进行USB输入管道的监听并接收可能传入的数据,是另外一种及时高效的USB数据接收形式。在项目工程中新建线程对象rcvThrd,进而在生成的rcvThrd.h文件中声明引用的窗口显示控件和数据接收函数RcvDt(),典型代码如下:
class thrdRcvDt : public TThread
{ private: TMemo *memo;
protected: void __fastcall Execute();
public: void __fastcall thrdRcvDt::RcvDt();
__fastcall thrdRcvDt(bool CreateSuspended, TMemo *Amemo);
};
在rcvThrd.cpp文件中,声明所需的包含文件、外部变量,并定义操作函数,典型代码如下:
#include "frmStm32Tst.h" // 可视化窗口文件
#include "Windows Kits10Include10.0.15063. 0sharedusb.h" // DDK文件
#include "Windows Kits10Include10.0.15063. 0sharedstrsafe.h"
#include "Windows Kits10Include10.0.15063. 0umSetupAPI.h"
#include "Windows Kits10Include10.0.15063. 0umwinusb.h"
extern WINUSB_INTERFACE_HANDLE hWinUSBHandle;
extern OVERLAPPED overlapped;
extern void WinUSB_Read(void);
__fastcall thrdRcvDt::thrdRcvDt(bool CreateSuspended, TMemo *Amemo) : TThread(CreateSuspended)
{ memo = Amemo; }
void __fastcall thrdRcvDt::Execute() // 线程执行[休眠100ms]
{ while(!Terminated)
{ Synchronize(RcvDt); Sleep(100); }
}
void __fastcall thrdRcvDt::RcvDt() // 数据异步接收窗口指示
{ WinUSB_Read(); }
在可视化窗口的frmStm32Tst.h中加入线程对象包含和线程实例化声明,典型代码如下:
#include "rcvThrd.h"
class TfrmShow : public TForm
{ …
private: thrdRcvDt *rcvThrd;
…
}
在可视化窗口的frmStm32Tst.cpp中,打开设备文件和WinUSB接口句柄后,启动线程,定义线程终止时自动销毁,然后运行线程,典型代码如下:
rcvThrd = new thrdRcvDt(true, mmRcvDt);
rcvThrd->FreeOnTerminate = true;
rcvThrd->Resume();
对比定时数据接收,异曲同工。定时器控件,本质就是休眠时间可调整的线程操作封装。
以上阐述基于先插上USB设备,再打开可视化测试/应用程序,进行通信传输,用后关闭应用程序,拨下设备。而USB设备即插即用,在USB设备突然被拔下后,还进行读写传输,程序就阻塞了。为避免这种现象发生,可创建一个线程,定时(如每2s)枚举检查相关的USB设备,若被拔下,停止定时数据接收或休眠接收线程;若重新插入,则重新创建操作句柄,恢复定时数据接收或线程数据接收。
应用软件发布,除Rad Studio产生的.exe文件外,还需要包含WinUSB.lib。若编译时不能包含动态库,还需要包含IDE相关的cc32240mt.dll和borlndmm.dll。上述各种方法综合在一起,得到的针对STM32F103系列微控制USB设备的WinUSB数据收发测试的可视化应用程序窗口界面如图3所示:
图3 WinUSB数据收发测试的可视化应用程序窗口界面
编写驱动安装文件.inf,引导OS调用内置的winusb.sys驱动文件的安装应用,主要指明USB设备的厂商号、产品号、USB接口GUID等,通知安装程序类已设置为 "USBDevice"。需要使用WinUSB协助安装库文件WinUsbCoInstaller,区分32位和64位版本,常用版本是V1.9,Win7之后也可以是V1.11。Win7之后系统,还需要准备cat文件,可运用WDK的Inf2Cat.exe工具得到,命令行操作如下:
Inf2Cat.exe /driver:[inf文件目录] /os: XP_X86, XP_X64,7_X86,7_X64,8_X32,8_X64
典型inf驱动安装文件如下:
[Version]
Signature="$Windows NT$"
Class=USBDevice
ClassGUID={88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider=%ManufacturerName%
CatalogFile=instlWinUSB.cat
DriverVer=01/13/2018,12.4.23.896
[Manufacturer]
%ManufacturerName%=Standard,NTx86,NTx64
[Standard.NTx86]
%DeviceName%=USB_Install,USBVID_0483& PID_5720
[Standard.NTx64]
%DeviceName%=USB_Install,USBVID_0483& PID_5720
[ClassInstall32]
AddReg=ClassInstall_AddReg
[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"C:WindowsSystem32setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2
[USB_Install]
Include=winusb.inf
Needs=WINUSB.NT
[USB_Install.Services]
Include=winusb.inf
AddService=WinUsb,0x00000002,WinUsb_ServiceInstall
[WinUsb_ServiceInstall]
DisplayName=%WinUsb_SvcDesc%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=C:WindowsSystem32driversWinUSB.sys
[USB_Install.HW]
AddReg=Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{12345678-1234-1344-1234-123456789ABC}"
[USB_Install.Wdf]
KmdfService=WINUSB, WinUsb_Install
[WinUSB_Install]
KmdfLibraryVersion=1.9
[USB_Install.CoInstallers]
AddReg=CoInstallers_AddReg
CopyFiles=CoInstallers_CopyFiles
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller"
[CoInstallers_CopyFiles]
WdfCoInstaller01009.dll
[DestinationDirs]
CoInstallers_CopyFiles=11
[SourceDisksNames]
1=%DiskName%
[SourceDisksFiles]
WdfCoInstaller01009.dll=1
[Strings]
ManufacturerName="STMicroelectronics"
ClassName="USB通用串行总线设备"
DiskName="kzq"
WinUsb_SvcDesc="WinUSB Driver"
DeviceName="STM3210"
REG_MULTI_SZ = 0x00010000
多个同类WinUSB设备插入同一台电脑,系统都可以识别,通信时连接传输快的USB设备占主动权后,其它USB设备就不通信了。可以修改USB设备的接口GUID,使连入USB设备差异化,以实现各个对应的传输通信,找到一个设备通信一个,从而实现类似设备参数配置的批量操作实现。
表1 几种驱动及其开发对比表
Tab.1 Some kind of device drivers and it’s design comparison
底层嵌入式应用软件中添加特定描述支持,Windows OS就可以自动识其为WinUSB设备,上层可视化测试/应用程序就可以通过WinUSB.dll与其进行USB数据传输通信了。这样,Windows下USB设备的数据采集、监视控制、配置参数、软件刷新等软件编程操控,就同传统的“RS-232C通信”一样了,无需USB转串口硬软件转接,而且速度快、实时性强,直截了当。同样,定时接收、线程接收、多设备通信等软件手段也可以搬来使用,进一步提升效率和实用性。
[1] CSDN博客. USB设备描述符举例说明[EB/OL]. http://blog. csdn.net/u013256018/article/details/60805770?locationNum=10&fps=1, 2017.3.
[2] CSDN博客﹒WinUSB--微软为所有USB设备提供的常规驱动程序[EB/OL]. http://blog.csdn.net/whw8007/article/details/ 9569989, 2013.8.
[3] 微软开发网. 如何通过WinUSB功能访问USB设备[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff540174(v=vs.85).aspx, 2017.12.
[4] 马开东博客. 如何使用WinUSB与USB设备USBDevice通信[EB/OL]. http://www.makaidong.com/%E5%8D%9A%E5% AE%A2%E5%9B%AD7/20151013/306670_4.html, 2015.10.
[5] 微软开发网. 适用于USB设备的Windows桌面应用[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/ hardware/dn376885(v=vs.85).aspx, 2017.12.
[6] 微软开发网. 编写基于WinUSB模板的Windows桌面应用[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/ hardware/dn376872(v=vs.85).aspx, 2017.12.
[7] 微软开发网. 用于管道策略修改的WinUSB功能[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff728833(v=vs.85).aspx, 2017.12.
[8] 怯肇乾等. Windows异步串行通信编程纵横[J]. 电脑与开发应用, 2009, 6(445): 21-25.
[9] CSDN博客. winusb--不再为你的usb设备编写驱动[EB/OL]. https://blog.csdn.net/phenixyf/article/details/46744419, 2015.7.
[10] 彭伟. 基于WinUSB与SHT75的温湿度数据采集与控制系统设计仿真[J]. 制造业自动化, 2013, 7(15): 129-133.
Implementation of WinUSB Driver and Its Application in Communication Transmission
SHI Bao-jing, WANG Chang-xun, KAI Zhao-qian
(HNCC Electronic Co., LTD, Zhengzhou 450001, China)
Software design key about WinUSB-Device-Model-Application is how to add descriptor to WinUSB-Device in Windows OS and how to communicate in Windows Application. It’s kernel is how to use timer and thread with asynchronous-data-transmission. Note WinUSB-Application-Publishing in low operating system version, account USB-Plug-in-Plug-out handling and multi-USB-devices-communication. So, Windows USB device data transmission are easy to use such as RS-232C.
USB descriptor; WinUSB device; Asynchronous data transmission; Data reception with timer; Data reception with thread.
TP36
B
10.3969/j.issn.1003-6970.2018.08.013
怯肇乾(1969-),男,电子与信息技术高级工程师,嵌入式系统设计师/培训师,web网络测控软件系统架构师,研究方向为软硬件体系及其网络系统软件设计;石保敬(1977-),男,经济师,风险评估师,环保健康探测警报专家,研究方向为危害和易燃易爆气体探测产品系统及其开发设计;王长荀(1988-),男,嵌入式硬软件开发工程师,研究方向为软硬件体系及其网络系统软件设计。
本文著录格式:石保敬,王长荀,怯肇乾. WinUSB驱动实现及其通信传输应用[J]. 软件,2018,39(8):57-64