"); //-->
完成了驱动程序的开发,我们还需要完成更复杂的用户程序开发。开发用户应用程序同样需要使用到LibUSB,开发使用的编程语言可以使用任何常用的编程语言,在Linux下一般是GCC、Kylix等;在Windows下选择就比较多一些,GCC、VC、VB、Delphi/CBC等都可以。
因为我们平时使用Windows操作系统比较多,所以下面介绍在Windows操作系统下的LibUSB使用方法和编程,LibUSB在Win32平台下对应的版本是LibUSB-Win32。
4.4.1 LibUSB-Win32简介
LibUSB-Win32是一个用于Windows操作系统(Win98SE、WinME、Win2k和WinXP)上的通用USB设备驱动程序。该驱动程序允许使用者在不写任何一行核心驱动程序代码的情况下,可以访问Windows系统上的任意一个USB设备。该驱动程序具有以下特点:
l 能够与任意一个已安装的USB设备进行通信
l 可被用作自己开发的USB设备的驱动程序
l 支持批量和中断传输
l 支持USB规范中定义的所有标准设备请求
l 支持USB设备制造商的自定义请求
LibUsb-Win32是由http://libusb-win32.sourceforge.net发布的,遵守GNU Lesser General Public License(LGPL)和GNU General Public License(GPL)许可协议。这些协议明确规定:允许LibUsb-Win32用于商业软件,而不只是开源软件。
4.4.2 使用LibUSB-Win32
LibUSB-Win32为C/C++程序员提供了用于开发的头文件和Lib文件,其中Lib文件还提供了BCC、GCC和MSVC这三个版本。C/C++程序员在自己的程序中要使用LibUSB-Win32时,只需包含提供的头文件,并链接合适的Lib文件即可。
对于Delphi程序员来说,LibUsb-Win32没有提供现成的Import Unit(导入单元文件),不过Internet上已经有程序员提供了对LibUSB-Win32的Delphi Pascal转换文件。Delphi程序员可以从http://www.xs4all.nl/~ynlmns/ 上下载Delphi版的LibUsb-Win32文件。值得注意的是,该版LibUSB-Win32不仅提供了Import Unit(LibUSB.pas),还提供了一个DLL文件(USBLibExport.dll)。在对LibUSB-Win32编程时,这个DLL必须作为程序的一部分,通过调用这个DLL中的函数来访问LibUSB-Win32,这样的效率比较低。本文的作者在LibUSB.pas文件的基础上进行了分析和研究,对原LibUSB.pas做出了如下一些修改:
1) 在interface部分中,将所有导出函数声明中的调用约定“stdcall”改为了“cdecl”;
2) 在implementation部分中,将所有导出函数中external指示符后面所跟的字符串“USBLibExport.dll”改为了“libusb0.dll”。
3) 进一步封装了LibUSB中的函数,使之和AVRUSB单片机底层函数相对应,简化了LibUSB函数的使用,方便了用户编程调用。
这样可以不再需要使用USBLibExport.dll而直接访问LibUSB-Win32。Delphi程序员只需将修改后的LibUSB.pas包含到自己的程序中,就可让自己的程序直接使用LibUsb-Win32了。这个修改后的LibUSB.pas文件可以在本文作者的博客上下载:
http://shaoziyang.bloger.com.cn/user2/88141/archives/2006/323777.shtml
4.4.3 常用的函数
LibUsb-Win32为开发人员提供了一套丰富的API函数,包括核心函数、设备操作、控制传输、批量传输和中断传输等几类。下面就几个常用的函数进行一下简单介绍:
1) void usb_init(void);
该函数用于初始化LibUSB-Win32,它必须第一个被调用。
2) int usb_find_busses(void);
查找系统上所有的USB总线。
3) int usb_find_devices(void);
查找每一根USB总线上的所有USB设备,该函数应该在usb_find_busses函数之后被调用。
4) struct usb_bus *usb_get_busses(void);
获取已找到的USB总线序列,返回值是一个指向USB总线序列首地址的指针。
5) usb_dev_handle *usb_open(struct *usb_device dev);
打开一个指定的USB设备。在对某个USB设备执行任何操作之前,首先要打开该USB设备,就像打开一个文件、打开一个句柄一样。函数的返回值是一个设备句柄,该句柄在后面与设备进行通信时会被用到。
6) int usb_close(usb_dev_handle *dev);
关闭一个指定的USB设备。在使用完某个USB设备后,应该关闭该USB设备,这和在使用完一个句柄后需要关闭句柄是一样的。
7) int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
向USB设备发送一个请求。函数各参数的含义如下:
dev:USB设备句柄,该参数指定了向哪个USB设备发送请求;
requesttype:请求的类型,说明了是读请求,还是写请求。可以是标准请求、类请求或自定义请求;
request:表示具体请求的值;
value:与请求相关的参数;
index:与请求相关的参数;
bytes:表示在数据阶段时传输的数据;
size:表示在数据阶段时传输的数据量,以字节为单位;
timeout:请求的超时设置,最大值为5000,以毫秒为单位。
通过使用以上七个函数,就可以与USB设备进行简单通信了,通信的主要流程可分为以下四步:
1) 调用usb_init函数,进行初始化。
2) 打开要进行通信的USB设备的句柄。首先依次调用usb_find_busses、usb_find_devices和usb_get_busses这三个函数,获得已找到的USB总线序列;然后通过链表遍历所有的USB设备,根据已知的要打开USB设备的ID(VID/PID),找到相应的USB设备;最后调用usb_open函数打开该USB设备(在这里假设总线上没有相同VID和PID的USB设备。如果总线上存在着相同VID和PID的设备,还需要进行其他条件判断,比如设备名称,以保证是打开的是期望的USB设备)。
3) 与USB设备进行通信。使用usb_control_msg函数,向USB设备读取数据或写入数据。
4) 关闭USB设备。完成所有操作后,调用usb_close函数关闭已经打开的USB设备。
5 其他要注意的问题
在使用AVRUSB时,需要注意以下问题:
1. 晶体一定要使用12MHz的,误差范围在±0.2%之内。如果晶体频率误差太大,对USB通信会有一定的影响,容易造成通信失败。
2. 一个型号的AVR单片机往往分为8M/10M/16M等多个频率等级,不同的电压也有不同的频率限制(参考数据手册上相应的说明)。很多8M/10M频率等级的单片机在12M频率下也可以使用(超频),在一般情况下没有太大的问题。不过在可能情况下应当尽量使用16M频率等级的单片机,以提高系统的稳定性。
3. 使用AVRUSB的CDC类做USB转串口时,因为只能使用12M的晶体,所以有很多波特率的误差比较大,超过了串口通信允许的±2%误差范围。一般最好使用2400、9600、19200等误差较小的波特率。
4. AVRUSB定义的缓冲区最大是254。通信时,一次往缓冲区写入数据不要超过缓冲区的大小,否则很容易在通信时造成数据丢失。
5. AVRUSB中使用了大量的宏定义和条件编译进行系统配置,这样造成了程序的可读性比较差,特别是刚开始时很难弄明白。而且AVRUSB没有专门的说明文档,只有通过研究源代码以及代码中的注释来学习。但是这也是一种编程技巧和编程风格,可以有效的提高程序的代码效率。
参考资料:
1. ATMEL公司的应用笔记《AVR309 Software Universal Serial Bus (USB)》:http://www.atmel.com/
2. AVR309的中文翻译《AVR309 软件USB》:http://shaoziyang.bloger.com.cn/
3. AVRUSB的官方开源项目PowerSwitch:http://www.obdev.at/products/avrusb/
4. 使用AVRUSB的编程器USBasp:http://www.fischl.de/usbasp/
5. LibUSB:http://libusb.sourceforge.net
6. LibUSB-Win32:http://libusb-win32.sourceforge.net
(全文完)
联系方式:
EMAIL:shaoziyang@126.com 或
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。