AVRUSB技術探討

轉載自http://lionwq.spaces.eepw.com.cn/articles/article/item/16695

4.4      用戶程序的開發

完成了驅動程序的開發,我們還需要完成更復雜的用戶程序開發。開發用戶應用程序同樣需要使用到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沒有專門的說明文檔,只有通過研究源代碼以及代碼中的註釋來學習。但是這也是一種編程技巧和編程風格,可以有效的提高程序的代碼效率。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章