一 上位机的实现
USB上位机使用c#编写,使用到是著名的USB开源库LibUsbDotNet,驱动也是通过LibUsbDotNet自带的InfWizard.exe生成的,实现效果如图1所示,stm32 上电时,软件能够自动检测并显示相关信息,点击亮按钮,上位机通过端点1发一个字节到下位机stm32板上并控制板上的led,stm32收到数据后通过端点2上传2字节的反馈信息。
图1 实现效果图
代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
using LibUsbDotNet.DeviceNotify;
namespace stm32_USB_led控制
{
public partial class Form1 : Form
{
const ushort PID = 0x5712; /*产品ID*/
const ushort VID = 0x0483; /*厂商ID*/
private UsbDevice stm32UsbDevice;
private UsbDeviceFinder stm32UsbFinder = new UsbDeviceFinder(VID, PID);
private IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private UsbEndpointWriter WR;
private UsbEndpointReader RD;
public Form1()
{
InitializeComponent();
}
//窗体载入事件
private void Form1_Load(object sender, EventArgs e)
{
UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent;
FindUsbDevice();
}
//设备通知事件
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
UsbRegDeviceList DeviceList = UsbDevice.AllLibUsbDevices;
UsbRegistry RegInfo = DeviceList.Find(stm32UsbFinder);
if (e.EventType == EventType.DeviceArrival)
{
//匹配插入的设备
if (e.Device.IdProduct == PID && e.Device.IdVendor == VID)
{
try
{
/*打开Usb----------------------------------------------------------------*/
stm32UsbDevice = UsbDevice.OpenUsbDevice(stm32UsbFinder);
/*打开端点2,类型为中断端点--------------------------------------*/
WR = stm32UsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02, EndpointType.Interrupt);
RD = stm32UsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
RD.DataReceived += (OnRxEndPointData);
RD.DataReceivedEnabled = true;
label.Text = "连接信息:设备已连接";
Manufaturer.Text = "生产厂商:" + RegInfo.FullName;
ProductDecrip.Text = "产品描述:" + RegInfo.Name;
SerialNum.Text = "***:" + e.Device.SerialNumber;
}
catch (Exception)
{
MessageBox.Show("USB打开失败!");
}
}
}
else if (e.EventType == EventType.DeviceRemoveComplete)
{
//匹配移除的设备
if (e.Device.IdProduct == PID && e.Device.IdVendor == VID)
{
label.Text = "连接信息:设备已移除";
Manufaturer.Text = "生产厂商:";
ProductDecrip.Text = "产品描述:" ;
SerialNum.Text = "***:" ;
CloseUSB();
}
}
}
/*寻找指定VID的USB设备,只在软件初始化时用到----------------------*/
bool FindUsbDevice()
{
UsbRegDeviceList DeviceList = UsbDevice.AllLibUsbDevices;
UsbRegistry RegInfo = DeviceList.Find(stm32UsbFinder);
if (RegInfo != null)
{
try
{
/*打开Usb---------------------------------------*/
stm32UsbDevice = UsbDevice.OpenUsbDevice(stm32UsbFinder);
/*打开端点2,类型为中断端点----------------------*/
WR = stm32UsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02, EndpointType.Interrupt);
}
catch (Exception)
{
MessageBox.Show("USB打开失败!");
return false;
}
label.Text = "连接信息:设备已连接";
Manufaturer.Text = "生产厂商:" + RegInfo.FullName;
ProductDecrip.Text = "产品描述:"+ RegInfo.Name;
SerialNum.Text = "***:" + RegInfo.SymbolicName;
return true;
}
else
{
label.Text = "连接信息:已断开连接";
Manufaturer.Text = "生产厂商:";
ProductDecrip.Text = "产品描述:";
SerialNum.Text = "***:";
}
return false;
}
//关闭USB设备
private void CloseUSB()
{
if (!ReferenceEquals(WR, null))
WR.Dispose();
if (!ReferenceEquals(stm32UsbDevice, null))
stm32UsbDevice.Close();
}
private void button_Click(object sender, EventArgs e)
{
byte[] txBuf = new byte[2];
int i=0;
if (led.Value)
{
led.Value = false;
txBuf[0] = 0x00;
button.Text = "亮";
}
else
{
led.Value = true;
txBuf[0] = 0x01;
button.Text = "灭";
}
if (stm32UsbDevice.IsOpen)
WR.Write(txBuf, 1000, out i);
}
//USB接收事件
private static void OnRxEndPointData(object sender, EndpointDataEventArgs e)
{
MessageBox.Show("收到数据:"+e.Count.ToString()+"Bytes");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
CloseUSB();
}
}
}
二 下位机的实现
收发回调函数如下
void EP1_IN_Callback(void)
{
GUI_DispStringAt("send complete!",60,200);
}
void EP2_OUT_Callback(void)
{
u8 DataBuf[8];
u8 len;
len = USB_SIL_Read(EP2_OUT,DataBuf);
SetEPRxValid(ENDP2);
if(DataBuf[0] == 1)
{
GPIOE->ODR |= (1<<0);
GUI_DispStringAt("led on! ",60,120);
}
else if (DataBuf[0] == 0)
{
GUI_DispStringAt("led off! ",60,120);
GPIOE->ODR = ~GPIOD->ODR;
}
GUI_DispDecAt(len,60,150,2);
GUI_DispString("Bytes");
/*返回2字节到上位机---------------------------------------------------------------------*/
USB_SIL_Write(EP1_IN,DataBuf,2);
SetEPTxValid(ENDP1);
}
设备描述符定义如下
/* USB标准设备描述符(固定为18个字节)------------------------------------------------*/
const uint8_t USB_DeviceDesc[18] =
{
18, /*设备描述符长度--------------------------------*/
USB_DeviceDescTyp, /*描述符类型-------------------------------------*/
0x00, /*bcdUSB-------------------------------------------*/
0x02,
0xff, /*bDeviceClass:0xff表示自定义*/
0xff, /*bDeviceSubClass:0xff表示自定义*/
0xff, /*bDeviceProtocol:0xff表示自定义*/
0x40, /*bMaxPacketSize 64*/
0x83, /*销售商的ID:先低后高*/
0x04,
0x12, /*产品ID:先低后高*/
0x57,
0x00, /*bcdDevice rel. 2.00*/
0x02,
1, /*manufacturer:厂商描述在字符串描述符中的索引*/
2, /*product:产品描述在字符串描述符中的索引*/
3, /*SerialNum:***在字符串描述符中的索引*/
0x01 /*bNumConfigurations*/
}; /* USBDevice_DeviceDescriptor */
/* 配置描述符(固定为9个字节)------------------------------------------------------------*/
const uint8_t USB_ConfigDesc[] =
{
0x09, /* bLength: Configuation Descriptor size--------------------------------------------*/
USB_ConfigDescTyp, /* bDescriptorType: Configuration-------------------------------*/
32 ,0x00,/* 配置+接口+端点字节数------------------------------------------------------*/
0x01, /*接口数: 1 个接口*/
0x01, /*配置值: 配置的ID为1*/
0x00, /*iConfiguration: Index of string descriptor describing
the configuration*/
0xc0, /*属性: bus powered */
0x64, /*功耗以2mA为单位----------------------------------------------------*/
/* 接口描述符(固定为9个字节)----------------------------------------------------------------*/
0x09, /*bLength: Interface Descriptor size*/
USB_IntefaceDescTyp,/*bDescriptorType: Interface descriptor type*/
0x00, /*接口号*/
0x00, /*bAlternateSetting: Alternate setting*/
0x02, /*接口所使用的端点数(不包括端点0)*/
0xff, /*bInterfaceClass: 通信接口*/
0xff, /*bInterfaceSubClass : 1=BOOT, 0=no boot------------------------------*/
0xff, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse------------------*/
0, /*接口描述符在字符串描述中的索引------------------------------------*/
/* 端点描述符(包含2个端点)----------------------------------------------------------------*/
/*端点1描述符*/
0x07, /*bLength: Endpoint Descriptor size------------------------------------*/
USB_EndPDescTyp, /*bDescriptorType:*/
0x81, /*端点地址bEndpointAddress: Endpoint Address (IN)------------*/
0x03, /*端点属性bmAttributes: Interrupt endpoint*/
0x08, /*最大包长度wMaxPacketSize: 8 Byte max------------------------*/
0x00,
0x20, /*主机轮询周期(1ms为单位): 32 ms--------------------------------*/
/*端点2描述符*/
0x07, /*bLength: Endpoint Descriptor size----------------------------------*/
USB_EndPDescTyp, /*bDescriptorType:*/
0x02, /*端点地址bEndpointAddress: Endpoint Address (OUT)----------*/
0x03, /*端点属性bmAttributes: Interrupt endpoint*/
0x02, /*最大包长度wMaxPacketSize: 8 Byte max */
0x00,
0x20, /*主机轮询周期(1ms为单位): 32 ms----------------------------*/
};
/* USB String Descriptors (optional) */
const uint8_t USBDevice_StringLangID[] =
{
6,
USB_StrDescTyp,
0x09,
0x04,
0x04,
0x08
}; /* LangID = 0x0409: U.S. English ,LangID = 0x0804: chinese*/
const uint8_t USBDevice_StringVendor[] =
{
10,
USB_StrDescTyp, /* bDescriptorType*/
/**-------------------------------
ASCII输入:lw技术
UNICODE输出
size:8Bytes
---------------------------------*/
0x6c,0x0,0x77,0x0,
0x80,0x62,0x2f,0x67
};
const uint8_t USBDevice_StringProduct[] =
{
24, /* bLength -------------------------------------*/
USB_StrDescTyp, /* bDescriptorType ----------------------------*/
/**-------------------------------
ASCII输入:stm32中断传输实验
UNICODE输出
size:22Bytes
---------------------------------*/
0x73,0x0,0x74,0x0,0x6d,0x0,0x33,0x0,
0x32,0x0,0x2d,0x4e,0xad,0x65,0x20,0x4f,
0x93,0x8f,0x9e,0x5b,0x8c,0x9a
};
const uint8_t USBDevice_StringSerial[] =
{
20, /* bLength --------------------------------------------*/
USB_StrDescTyp, /* bDescriptorType -----------------------------------*/
/**-------------------------------
ASCII输入:roger-wen
UNICODE输出
size:18Bytes
---------------------------------*/
0x72,0x0,0x6f,0x0,0x67,0x0,0x65,0x0,
0x72,0x0,0x2d,0x0,0x77,0x0,0x65,0x0,
0x6e,0x0
};
from: http://bbs.elecfans.com/infocenter.php?mod=space&uid=1516870&do=blog&id=363893