windows下USB通讯

前言

Windows下USB通讯,利用设备VID与PID查询设备,利用了windows的setupapi.libhid.lib库,开发时需要包含
#include <hidsdi.h> 
#include <setupapi.h>  头文件

USB通讯类

CommUsb.h

#pragma once

#include <windows.h> //一定要加入该头文件
#include <iostream>
#include <vector>

extern "C" {
#include <hidsdi.h> 
#include <setupapi.h>  
}
#pragma comment (lib, "setupapi.lib")
#pragma comment (lib, "hid.lib")
using namespace std;


class CommUsb
{
public:
	CommUsb();
	~CommUsb();

	//根据usb的VID与PID打开设备
	BOOL DeviceOpen(HANDLE&handle, WORD wVID, WORD wPID);

	//关闭设备,释放句柄类资源
	void DeviceClose();

	//向usb写入数据
	BOOL DeviceWrite(LPCVOID lpBuffer, DWORD dwSize);

	//从usb读取响应数据
	void DeviceRead();
	
	//读取数据线程
	static void ReadThread(CommUsb *usb);
private:
	HANDLE m_handle;
	int m_size;
	DWORD m_dwResult;
public:
	BYTE m_rBuffer[64];
	
};

CommUsb.cpp

#include "CommUsb.h"
#include <thread>

CommUsb::CommUsb()
{
	m_rBuffer[64] = { 0 };
	m_handle = NULL;
	m_size = 0;
	m_dwResult = 0;
}

CommUsb::~CommUsb()
{
	
}

void CommUsb::ReadThread(CommUsb *usb)
{
	ReadFile(usb->m_handle, usb->m_rBuffer, usb->m_size, &usb->m_dwResult, NULL);
}

BOOL CommUsb::DeviceOpen(HANDLE&handle, WORD wVID, WORD wPID)
{
	
	BOOL bRet = FALSE;
	GUID hidGuid;
	HDEVINFO hardwareDeviceInfo;
	SP_INTERFACE_DEVICE_DATA deviceInfoData;
	PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData = NULL;
	ULONG predictedLength = 0;
	ULONG requiredLength = 0;
	CloseHandle(handle);
	handle = INVALID_HANDLE_VALUE;
	deviceInfoData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
	HidD_GetHidGuid(&hidGuid);
	hardwareDeviceInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
	for (int i = 0; i < 128; i++)
	{
		if (!SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, 0, &hidGuid, i, &deviceInfoData)) continue;
		SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo, &deviceInfoData, NULL, 0, &requiredLength, NULL);
		predictedLength = requiredLength;
		functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(predictedLength);
		if (!functionClassDeviceData) continue;
		functionClassDeviceData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
		if (!SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo, &deviceInfoData, functionClassDeviceData, predictedLength, &requiredLength, NULL)) break;
		handle = CreateFile(functionClassDeviceData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);//   倒数第二个参数可以指定为异步FILE_FLAG_OVERLAPPED   0为同步
																																// cout <<"devicePath"<<functionClassDeviceData->DevicePath<<endl;
		if (handle != INVALID_HANDLE_VALUE)
		{
			HIDD_ATTRIBUTES attri;
			HidD_GetAttributes(handle, &attri);
			if ((attri.VendorID == wVID) && (attri.ProductID == wPID))
			{
				
				m_handle = handle;   //将USB设备句柄存入类成员变量
				bRet = TRUE;
				break;
			}
			CloseHandle(handle);
			handle = INVALID_HANDLE_VALUE;
		}
		
		
	}
	SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
	return bRet;
}

void CommUsb::DeviceClose()
{

	CloseHandle(m_handle);

	m_handle = INVALID_HANDLE_VALUE;
}

BOOL CommUsb::DeviceWrite(LPCVOID lpBuffer, DWORD dwSize)
{
	if (m_handle == INVALID_HANDLE_VALUE)
	{
		//MessageBox(NULL,"数据写入失败","失败!",MB_OK);
		return 0;
	}
	
	DWORD dwRet;
	BOOL bRet;

	PHIDP_PREPARSED_DATA PreparsedData;
	HIDP_CAPS Capabilities;

	HidD_GetPreparsedData(m_handle, &PreparsedData);
	HidP_GetCaps(PreparsedData, &Capabilities);

	m_rBuffer[0] = 0x00;  //第一个字节为report Id,不能省略

	memcpy(m_rBuffer + 1, lpBuffer, min(20, dwSize));

	//这里写的长度要大于Capabilities.OutputReportByteLength
	
	bRet = WriteFile(m_handle, m_rBuffer, Capabilities.OutputReportByteLength, &dwRet, NULL);
	if (bRet)
	{
		//MessageBox(NULL,"写入数据成功","成功!",MB_OK);
	}
	return bRet;
}

void CommUsb::DeviceRead()
{
	if (m_handle == INVALID_HANDLE_VALUE)
	{
		//MessageBox(NULL, "数据读取失败", "失败!", MB_OK);
		//return 0;
	}

	PHIDP_PREPARSED_DATA PreparsedData;
	HIDP_CAPS Capabilities;
	HidD_GetPreparsedData(m_handle, &PreparsedData);
	HidP_GetCaps(PreparsedData, &Capabilities);
	//memcpy(&wBuffer[2], lpBuffer, min(6, dwSize));
	COMMTIMEOUTS timeout;
	timeout.ReadIntervalTimeout = 1000;
	timeout.ReadTotalTimeoutConstant = 1000;
	timeout.ReadTotalTimeoutMultiplier = 1000;
	SetCommTimeouts(m_handle, &timeout);

	//读的长度也一定要是Capabilities.OutputReportByteLength

	//线程函数参数初始化
	m_size = Capabilities.OutputReportByteLength;
	
	thread Rthread(ReadThread, this);
	Rthread.join();
	

	//return bRet;
}


测试示例

Win32测试

#include "../common/CommUsb.h"

int main()
{
	CommUsb Myusb;

	HANDLE handle = NULL;
	
	if (Myusb.DeviceOpen(handle, 0x0483, 0x5750) == FALSE)
	{
		MessageBox(NULL, "打开设备失败", "错误", MB_OK);
	}

	BYTE str[20] = { 0 };
	/*str[0] = 0x00;
	str[1] = 0x80;
	str[2] = 0xAA;
	str[3] = 0xFD;
	str[4] = 0x02;
	str[5] = 0x60;
	str[6] = 0x06;
	str[7] = 0x66;*/

	str[0] = 0x00;
	str[1] = 0x80;
	str[2] = 0xAA;
	str[3] = 0xFD;
	str[4] = 0x02;
	str[5] = 0x60;
	str[6] = 0x07;
	str[7] = 0x67;
	
	Myusb.DeviceWrite(str, 20);
	Myusb.DeviceRead();

	for (int i = 0; i < sizeof(Myusb.m_rBuffer); i++)
	{
		printf("%02hhx ", Myusb.m_rBuffer[i]);
	}
	cout << endl;
	Myusb.DeviceClose();
	system("pause");
	return 0;

}

MFC测试


// USBMfcTestDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "USBMfcTest.h"
#include "USBMfcTestDlg.h"
#include "afxdialogex.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CUSBMfcTestDlg 对话框



CUSBMfcTestDlg::CUSBMfcTestDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_USBMFCTEST_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_handle = NULL;
}

void CUSBMfcTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_VID, m_Edit_VID);
	DDX_Control(pDX, IDC_EDIT_PID, m_Edit_PID);
	DDX_Control(pDX, IDC_EDIT_SEND, m_Edit_Send);
	DDX_Control(pDX, IDC_EDIT_RECIEVE, m_Edit_Recieve);
}

BEGIN_MESSAGE_MAP(CUSBMfcTestDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_oPEN, &CUSBMfcTestDlg::OnBnClickedopen)
	ON_BN_CLICKED(IDC_BUTTON1, &CUSBMfcTestDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CUSBMfcTestDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_CLOSE, &CUSBMfcTestDlg::OnBnClickedClose)
	ON_BN_CLICKED(IDC_SEND, &CUSBMfcTestDlg::OnBnClickedSend)
	ON_WM_TIMER()
END_MESSAGE_MAP()


// CUSBMfcTestDlg 消息处理程序

BOOL CUSBMfcTestDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	//初始化各个输入框的初始值
	m_Edit_VID.SetWindowText("0483");
	m_Edit_PID.SetWindowText("5750");
	m_Edit_Send.SetWindowText("0080AAFD02600666");

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CUSBMfcTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CUSBMfcTestDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CUSBMfcTestDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CUSBMfcTestDlg::OnBnClickedopen()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData();
	
	CString StrVid,StrPid,StrRecv;
	WORD Hvid = 0,Hpid = 0;

	m_Edit_VID.GetWindowTextA(StrVid);
	m_Edit_PID.GetWindowTextA(StrPid);
	Hvid = _tcstoul(StrVid, 0, 16);
	Hpid = _tcstoul(StrPid, 0, 16);
	
	if (StrVid.IsEmpty() || StrPid.IsEmpty())
	{
		Hvid = 0x0483;
		Hpid = 0x5750;
	}

	if (MyUsb.DeviceOpen(m_handle, Hvid, Hpid) == FALSE)
	{
		m_Edit_Recieve.GetWindowTextA(StrRecv);
		m_Edit_Recieve.SetWindowTextA(StrRecv + "USB设备打开失败\r\n");
	}
	else
	{
		m_Edit_Recieve.GetWindowTextA(StrRecv);
		m_Edit_Recieve.SetWindowTextA(StrRecv + "USB设备打开成功\r\n");
	}
}


void CUSBMfcTestDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Edit_Send.SetWindowTextA("");
}


void CUSBMfcTestDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Edit_Recieve.SetWindowTextA("");;
}


void CUSBMfcTestDlg::OnBnClickedClose()
{
	// TODO: 在此添加控件通知处理程序代码
	MyUsb.DeviceClose();
}

//send
void CUSBMfcTestDlg::OnBnClickedSend()
{
	// TODO: 在此添加控件通知处理程序代码
	CString StrSend = "";
	char SendHex[20] = { 0 };
	m_Edit_Send.GetWindowTextA(StrSend);
	Str2Hex(StrSend, SendHex);

	MyUsb.DeviceWrite(SendHex, 8);
	SetTimer(1, 1000, NULL);
}


void CUSBMfcTestDlg::OnTimer(UINT_PTR nIDEvent)
{
	CString StrRec=" ",StrTemp=" ",StrPost=" ";
	
	if (nIDEvent==1)
	{
		
		MyUsb.DeviceRead();
		
		for (int i=0;i<sizeof(MyUsb.m_rBuffer);i++)
		{
			StrTemp.Format("%02x ", MyUsb.m_rBuffer[i]);
			if ((i+1)%25==0)
			{
				StrRec += "\r\n";
			}
			StrRec += StrTemp;
		}
		m_Edit_Recieve.GetWindowTextA(StrPost);
		m_Edit_Recieve.SetWindowTextA(StrRec + "\r\n" + StrPost);

		KillTimer(1);
	}
}

int CUSBMfcTestDlg::Str2Hex(CString str, char* data)
 {
	int t, t1;
	    int rlen = 0, len = str.GetLength();
	    //data.SetSize(len/2);
		     for (int i = 0; i < len;)
		     {
		         char l, h = str[i];
		         if (h == ' ')
			         {
			             i++;
			             continue;
			         }
		         i++;
		         if (i >= len)
			             break;
		         l = str[i];
		         t = HexChar(h);
		         t1 = HexChar(l);
		         if ((t == 16) || (t1 == 16))
			             break;
		         else
			             t = t * 16 + t1;
		         i++;
		         data[rlen] = (char)t;
		         rlen++;
		     }
	     return rlen;
	 }

 char CUSBMfcTestDlg::HexChar(char c)
 {
	     if ((c >= '0') && (c <= '9'))
		         return c - 0x30;
	     else if ((c >= 'A') && (c <= 'F'))
		         return c - 'A' + 10;
	     else if ((c >= 'a') && (c <= 'f'))
		         return c - 'a' + 10;
	     else
		        return 0x10;
	 }

运行效果:

源代码下载

https://download.csdn.net/download/qq_22642239/12736524

文章参考:网络资源

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值