AVR-USB(V-USB)学习过程(二)

来源:互联网 发布:stm32单片机引脚 编辑:程序博客网 时间:2024/06/13 15:24

    上一篇介绍了如何穿件下位机程序,现在介绍一下上位机程序如何做。上位机程序我是用C#.net做的,现在.net可谓是潮流,编起软件来极其方便,很多人在用,但是如何用.net开发一个usb上位机程序,用来和下位机进行数据通讯?用什么控件?

    也许很多人都知道libusb-win32这个库,它是一个.lib的静态链接库,C#.net却无法调用,供C#嗲用的usb库文件时LibUsbDotNet,这也是一个外国人做的开源的usb上位机驱动库文件,点击这里下载LibUsbDotNet。下载安装之后,你可以再安装目录下找到帮助文件(Docs/LibUsbHelp.chm),示例代码(Examples),可执行示例程序(release),我们要使用的库文件就是安装目录下的LibUsbDotNet.dll。

    之前如果你已经做好了下位机电路,并且烧入了下位机程序,并且windows也能成功检测到你的AVR-USB,并且成功安装驱动,这时你可以打开release目录下的InfWizard.exe程序,它就可以查看到你的Avr-usb。

   它的示例代码其实是很难看懂的(如果你对USB Spec不熟悉的话),我就是没有怎么看懂(这里建议大家只看GettingStart示例和Device.Notification示例)。看到里面的Read/Wirte示例我就直接晕了,一开始里面的EP1,EP0直接看得我云里雾里的,而且如果你运行Read/Write示例程序来读写你的AVR-USB时,系统都会提示找不到EP1,因为示例程序里的读写都是通过EP1来实现的。

    解释一下:EP就是EndPoint,一个Device可以支持多个EndPoint。EP0就是EndPoint0,主要用来传递一些控制信息和有限的数据。其实我们AVR-USB主要就是用EndPoint0来通讯和交换数据的,至少我是这样认为的,我看了USBasp的源程序也是通过EP0来读写的,根本就没有用到EP1和其他EndPoint,不过下位机的vusb Driver似乎支持EP1等其他EndPoint,如果有高手会用的话,我愿意学习哦。

    既然要用EndPoint0来传递数据,那到底是用什么函数呢?通过什么函数来调用EndPoint0传递数据呢?这个问题先留在这里。

   

    先建一个C#工程吧,建好之后 右击 解决方案里面的“引用” -> 添加引用 ,在弹出的框框中选择“浏览”选项卡“,然后找到你的LibUsbDotNet.dll。(你在建好工程后最好把它拷贝到你的工程目录下)

    添加完引用之后,就需要在主程序里面用using来调用LibUsbDotNet里面的命名空间了,如果不知道哪些类包含在什么命名空间里面,不要紧先全部引用就好了,等有时间好好看一下帮助文件细细研究一番。 

    接下来就需要通过libusbdotnet这个控件提供的类来找到我们的vusb device,并显示deviceName和CompanyName.(GetingStart例程就是演示这个的)

    至此,我们已经可以连接上我们的AVR-USB,并且能读取到ProductString河ManufacturerString了。

   (DeviceNotify的使用方法请参看LibUsbDotNet安装目录下的Example里面的Notify实例,这个对于以后你编写健壮的上位机程序很有帮助,我这里就不介绍了,下面主要介绍最关键的上位机和下位机的数据传输问题

   上位机和下位机的数据传输是我们最想知道的,在上位机如何把数据和命令通过usb传给下位机?我这里就只介绍利用EP0来通讯。下位机主要是利用uchar usbFunctionSetup(uchar data[8])函数来接受上位机的命令并返回数据给上位机(当然也可以用usbFunctionRead(uchar *data, uchar len)来返回数据),如果上位机传来的数据比较多的话,就需要用usbFunctionWrite(uchar *data, uchar len)来接受数据。如果数据很少,就可以直接利用uchar usbFunctionSetup(uchar data[8])函数的中间四个字节来传递数据。

   在C#里面我们是用usbDevice.ControlTransfer(ref UsbSetupPacket setupPacket,Object buffer,int bufferLength,out int engthTransferred)来传送命令和数据,这个函数就是利用EP0来把命令和有限的数据传给下位机的uchar usbFunctionSetup(uchar data[8])。下面先看一下代码。

仔细看一下 UsbSetupPacket(UsbRequestType, DeviceRequestType, Int16, Int16, Int16)  构造函数,这个里面的参数是和uchar usbFunctionSetup(uchar data[8]) 里面的参数一一对应的。

第一个字节是UsbReqeustType,第二个字节是DeviceRequestType,最后两个字节是长度Lenth,中间两个字节(程序里的a,b)你可以自己用来传递自定义的数据。程序里演示了从下位机读入4个字节的数据,并把读到的数据保存到buf数组中(buf的前4个字节就是读到的数据),你可以用MessageBox来show出来看一下。

   当然你的下位机程序需要做一些设置。

  至此,你已经了解了如何实现上位机和下位机的通讯已经数据交换了。基本上一般的功能都能够实现了,你已经可以完成你的AVR-USB的项目了。

   剩下的就是另外两个函数:usbFunctionRead(uchar *data, uchar len)和usbFunctionWrite(uchar *data, uchar len)。如果你要使用这两个函数需要设置usbconfig.h的宏定义,并且定义这两个函数。

   如果上位机通过usbDevice.ControlTransfer()函数要求读数据(UsbRequestType.EndpointIn),vusb Driver则自动会调用usbFunctionRead()函数来把数据(rpbuf数组里的数据)返回给上位机,其中len参数就是usbDevice.ControlTransfer()的第三个参数bufferLen。

new UsbSetupPacket(UsbRequestType.EndpointIn | UsbRequestType.TypeVendor | UsbRequestType.RecipDevice, ...

   如果上位机通过usbDevice.ControlTransfer()函数要求向单片机写数据(UsbRequestType.EndpointOut),vusb Driver自动会调用usbFunctionWrite()函数来接收上位机传来的数据,并保存到rcbuf数组中。

new UsbSetupPacket(UsbRequestType.EndpointOut | UsbRequestType.TypeVendor | UsbRequestType.RecipDevice, ...

 

   好了,我知道的已经都将给大家了,希望能给你带来一些帮助。如果你是高手不妨研究一下我没有弄懂的两个问题:

  1.上位机如何通过其他EndPoint(如EP1)来和下位机通讯

  2.也许你已经注意到,这个V-USB系统中一直是上位机占主导地位,下位机是从机。有没有想过如何从下位机主动向上位机发送数据和命令?

 

  最后传上我的上位机(C#)和下位机程序(GCC) ,电路就是通用的电路啦,你可能需要修改usbconfig.h里面的 D+ , D- 等宏定义。

 

 

 

 

 

 

 

 

 

原创粉丝点击