AVRUSB技術探討(轉)

作者: 邵子揚、王育強、呂益光

 

本文引用地址:http://lionwq.spaces.eepw.com.cn/articles/trackback/item/16695

 

摘要

本文介紹了一種獨特的AVR單片機和計算機進行USB通信的方法:AVRUSB。介紹了AVRUSB技術的基本原理、特點、應用,同時還詳細的介紹了AVRUSB系統的單片機軟件開發和計算機軟件開發的方法。

 

關鍵字:

AVRUSB,LibUSB,LibUSB-Win32

 

 

正文

 

1         簡介 
1.1   AVRUSB是什麼

AVRUSB技術是利用高性能的8位RISC架構的AVR單片機,使用單片機的IO口來模擬USB的通信端口,由軟件來實現USB通信協議,將普通的AVR單片機模擬成一個USB低速設備,從而實現AVR單片機與計算機之間的通信和控制。

 

AVRUSB 技術的基本原理就是利用AVR單片機的普通IO端口來模擬USB的硬件端口進行通信。因爲低速USB設備的速度是1.5M位/秒,而AVR單片機是單指令 週期的,在單片機使用12MHz的時鐘頻率時,正好是1.5MHz的8倍。也就是說,單片機每8條指令就精確完成一個數據位的採集。採用這種方法時,對單 片機的時序要求非常嚴格,所以軟件的核心部分代碼完全由彙編語言實現。

 

1.2   AVRUSB的歷史

AVRUSB 技術最早的文檔可見於AVR的官方應用筆記《AVR309 Software Universal Serial Bus (USB)》(軟件USB)一文中。在這篇應用筆記裏,詳細的介紹瞭如何使用AVR單片機的普通IO口來實現USB通信,同時介紹了計算機的驅動程序以及 計算機上用戶程序的編程方法,並提供了全部源碼。但是AVR309中介紹的單片機程序完全是使用彙編語言編寫的,不利於將程序移植到其他應用環境中,也不 利於程序的維護(畢竟使用彙編語言的人相對比較少,使用C語言編程是大部分人的選擇),這使得其應用受到了很多限制。

 

後來, OBJECTIVE 公 司推出了AVRUSB。它以彙編語言實現USB通信的底層接口,用C語言實現用戶層的程序接口。用戶接口被簡化爲很簡單的幾個函數(在最簡化的情況下,只 需要三個函數,一個初始化函數、一個輪詢函數和一個數據處理函數)和一個配置文件,用戶可以完全不會使用彙編語言編程。同時它還提供了一個穩定而成熟的用 戶程序框架,用戶可以在此框架的基礎上,通過修改和擴展接口函數的功能來實現各種USB通信功能和控制功能,實現各種帶USB接口的應用系統。並 且,AVRUSB支持目前最流行的AVR GCC編譯器和IAR C編譯器,因此具有很強的實用性。

 

1.3   AVRUSB的特點 
1.3.1  低成本

傳 統的單片機與計算機進行USB通信,需要使用專用的接口芯片進行USB協議轉換,如CP2101、FT232、CH342、PDIUSBD12、 SL811等。象CP2101、FT232這樣的芯片使用起來雖然簡單,但是功能比較單一;而PDIUSBD12、SL811功能較強,但是使用複雜。並 且這些專用芯片的價格都相對較高,增加了系統的成本。而AVRUSB簡單易用,成本低廉,只需要一個普通的低成本AVR單片機以及很少的幾個外部元件,就 可以組成一個USB系統。

 

AVRUSB 的代碼爲AVR GCC編譯器做了高度優化,同時也完全兼容於更專業的IAR C編譯器。程序編譯後在最小情況下還不到2KB,因此絕大部分的AVR單片機都可以使用AVRUSB(只要支持外部中斷INT0,Flash容量不小於 2KB就可以實現AVRUSB的功能)。這樣在很多低成本的小容量AVR單片機上也可以使用AVRUSB,如ATtiny2313、ATmega45、 ATmega48等,因此AVRUSB技術具有很高的實用價值。

 

1.3.2  資源豐富,容易開發

AVRUSB 提供了一個完整而又簡單易用、成熟穩定的應用程序框架。這個框架包括了底層(單片機部分)和上層(PC部分),單片機可以使用gcc(或者IAR)編 程;PC上則可以使用各種通用編程軟件,如Windows下使用VC、VB、Delphi、C++ Builder、BDS2006、GCC,Linux下使用GCC等等。用戶可以在這個框架基礎上添加和擴展各種功能,快速開發出適合於各種需求的單片機 控制系統,而且AVRUSB支持Windows、Linux、MacOS等多種操作系統,具有很好的跨平臺特性。

 

1.4       AVRUSB的應用

AVR單片機低成本、高性能的特性,使得AVRUSB非常適合於應用到USB加密狗、USB接口的系統控制、低速USB數據採集等,這樣構成的具有USB通信功能的單片機系統比很多使用專用芯片的系統簡單、成本低。

 

目前,AVRUSB已經成功應用到了很多產品上,比較有名的有:USBasp(USB接口的AVR編程器)、AVRCDC(USB轉RS232串口)、USB Bootlader(USB接口的Bootloader軟件)等。在 http://www.obdev.at/products/avrusb/projects.html 中, 還專門列舉了很多使用AVRUSB的開源項目,這些項目提供了完整的單片機程序和計算機程序的代碼和原理圖。我們在開發自己的AVRUSB應用時,可以參 考這些資源,在這些開源項目的基礎上進行修改,快速開發出適合於自己需求的應用來。本文作者也成功的將AVRUSB用到公司的一個項目中,很好的實現了一 個USB接口的開關矩陣控制。

 

1.5       AVRUSB的限制

因爲AVRUSB使用普通IO口模擬來USB通信的過程,由軟件實現了硬件完成的功能。而USB通信的速率是比較高的。因此,在進行USB通信時單片機的CPU佔用率比較高的(大於90%)。

 

另外,因爲受到單片機的處理能力限制,所以通信的數據處理能力不是很強,最大數據處理速度約爲20k/s,因此AVRUSB不適合用於大數據量通信的應用場合。

 

2         硬件結構

構成一個AVRUSB系統的硬件結構非常簡單,只需要一個普通的AVR單片機(大部分型號都可以),再加上少量的外部元件(晶體、幾個電阻以及可選的穩壓二極管等),就組成了一個基本的AVRUSB系統,如圖1。

 

 

圖1. AVRUSB的基本硬件接口

 

圖 中的單片機以ATmega8爲例。數據線D-上的上拉電阻R4用來通知計算機這是一個低速USB設備(這是在USB規範中定義的,更多內容請參考 AVR309以及USB的官方文檔)。12MHz晶體和兩個22p的電容C2和C3組成單片機運行所必須的時鐘。D+ 和D- 數據線可使用單片機的任意IO端口,但是必須使用相同的IO端口。在這裏D+ 連接到PB1,D- 連接到PB0。此外數據線D+還需要連接到INT0上,這是爲了在不同的AVR單片機中使用AVRUSB時有更好的適應性和兼容性,無需修改底層核心部分 程序的代碼。如果D-連接到端口D上(就是和INT0同一端口中),同時D+只連接到INT0,還可以節省出一個端口來。

 

電阻R2、R3起到限流和保護作用,防止在意外情況下損壞計算機的USB端口或單片機的端口。單片機所需的電源Vcc可由USB的5V輸出電源直接提供,或者由USB的5V電源轉換得到(如LDO、穩壓二極管等),或者通過電池等其他外部電源來供電。

 

D+ 和D-上的3.6V穩壓二極管D1和D2起到限制數據線上的電平的作用。因爲在USB規範中規定數據線D+和D-上的電平範圍是3.0V至3.6V,而 AVR單片機的輸出電平是Vcc。如果單片機的Vcc是5V,在沒有D1和D2的情況下將造成電平不匹配,會造成在很多計算機中無法正確識別出USB設 備。如果用戶系統的Vcc在3.0V至3.6V之間,就可以省略這兩個穩壓二極管。從這裏也可以看出用戶系統的Vcc必須高於3V。

 

上 面硬件就組成了一個最小的AVRUSB系統,它能夠和計算機進行USB通信。在上面最小系統的基礎上,如果添加一個紅外傳感器,就可以接收發送紅外信號, 就是一個USB紅外控制器;如果添加一個MAX202,就是一個帶緩衝的USB <-> RS232串口轉換器;如果加入ADC轉換功能,就是USB的數據採集器;如果加入ADC和電源控制,就能夠實現一個簡單實用的USB充電器……各種功能 的AVRUSB系統都是在這個最小系統的基礎上,添加不同功能的外圍模塊或接口來實現的。

 

3         單片機程序的開發

要使用AVRUSB,就需要在單片機中開發合適的軟件,實現特定的功能。下面將具體介紹開發需要使用的工具軟件和開發的步驟。

3.1   開發環境

AVRUSB可使用AVR GCC編譯器或IAR C編譯器。因爲AVRUSB特別爲AVR GCC編譯器做了優化,並且AVR GCC還是免費軟件,使用非常廣泛,是目前AVR單片機主要的開發工具軟件之一,所以我們下面以AVR GCC爲例來介紹。

 

在 Windows操作系統下開發時,使用WinAVR中帶有的AVR GCC編譯器;代碼編輯、仿真和調試使用了Atmel公司的AVR Studio,這個IDE的好處是不需要用手工修改makefile配置文件,減少了初學者的使用難度。如果希望使用其他IDE或編輯軟件作爲開發工具也 可以,下面的使用步驟也是類似的。如果是在Linux操作系統下開發,可以使用Linux版本的AVR GCC,以及其他工具軟件進行編輯和調試。

 

3.2   建立項目文件

要 將AVRUSB加入到自己的程序中,首先需要在AVR Studio中建立一個新的項目(Project),然後將AVRUSB所需要的文件複製到項目文件的文件夾中(當然也可以不用複製文件,只添加已經存在 的AVRUSB的文件路徑到項目中也可以,但是將項目的所有文件放在一個文件夾下更容易對整個項目進行維護)。一般來說,凡是使用AVRUSB的項目,在 項目文件夾下都會單獨存放一個USBDRV的文件夾,裏面存放着所有與AVRUSB相關的文件。AVRUSB包含了多個文件,但是我們只需要添加以下幾個 文件到項目中:

 

usbconfig.h           用戶配置文件
iarcompat.h           爲兼容IAR編譯器而定義的宏
usbdrv.h              usb驅動接口文件的頭文件
usbdrv.c              usb驅動接口文件
usbdrvasm.asm         爲兼容IAR編譯器而使用的底層接口函數文件的別名
usbdrvasm.S           彙編語言編寫的底層接口函數
oddebug.h             調試用函數的頭文件(不使用調試功能時可以不添加)
oddebug.c             包含調試用的函數(不使用調試功能時可以不添加)

注 意到上面的文件除了usbconfig.h外,都在USBDRV文件夾中。在USBDRV文件夾中一般都有一個usbconfig- prototype.h文件,這個文件是用戶配置文件usbconfig.h的原始模板,我們需要將這個文件複製到項目文件夾中並將它改名爲 usbconfig.h。複製後,還需要再添加USBDRV文件夾的路徑到項目的包含路徑中,這樣在編譯時纔可以正確找到上面的文件,如圖二(因爲 USBDRV文件夾在項目文件夾下,所以顯示出的是相對路徑)。如果不使用AVR Studio,也可以使用其他的IDE軟件或編輯軟件,但是可能會需要用戶自行手工修改項目配置文件makefile,具體做法這裏就不做介紹了。
點擊看大圖  

 

圖2. 添加USBDRV路徑到項目中

 

3.3   參數配置

在 編譯項目之前,除了需要對項目本身的參數進行配置外(如AVR單片機的型號、系統時鐘頻率、代碼優化等級等),還需要對AVRUSB的參數進行配置,這樣 才能產生出正確的代碼。AVRUSB中包含的參數雖然看起來很多,其實配置起來很容易。在用戶配置文件usbconfig.h中存放了所有與USB相關的 配置參數,配置參數都是以宏定義的方式給出,配置參數的過程就是修改相關的宏定義。只要修改這個文件中的參數就可以實現不同的功能,其它的文件不用修改。

爲 了獲得儘可能高的效率,AVRUSB中使用了大量的宏定義和條件編譯,用以獲得最小的代碼大小和最快的運行速度。配置文件usbconfig.h中的參數 非常多,表1列出了主要需要修改的參數。一般的情況下只要修改這幾個參數就可以了,其它的參數可以根據用戶的實際需求做適當的修改。

1 usbconfig.h 中的主要參數

USB_CFG_IOPORTNAME

定義USB數據線使用的端口。只要是通用的IO都可以,沒有特殊的要求。

USB_CFG_DMINUS_BIT

USB數據線D-使用的引腳。

USB_CFG_DPLUS_BIT

USB數據線D+使用的引腳。因爲D+要求同時連接到INT0上,所以一般情況下需要使用3個IO口。如果D+使用的引腳就是INT0,那麼可以少使用一個IO端口。

USB_CFG_VENDOR_ID

設備生產商的ID號

USB_CFG_DEVICE_ID

設備的產品ID號。這兩個參數就是Windows識別USB設備的主要參數。需要注意的是,這兩個參數都是低字節在前,高字節在後。

USB_CFG_DEVICE_VERSION

設備的版本號次版本號在前,主版本號在後。在Windows的設備管理中可以看到這個版本號

USB_CFG_VENDOR_NAME

設備生產商的名稱,它在Windows的設備管理中可以看到。這裏一般寫入的是網址。

USB_CFG_VENDOR_NAME_LEN

設備生產商名稱的長度。

USB_CFG_DEVICE_NAME

設備的名稱,它在Windows的設備管理中可以看到。設備名稱和生產商的名稱都是以字符的方式定義的,它們目前不支持中文。

USB_CFG_DEVICE_NAME_LEN

設備名稱的長度。

 

3.4   主要接口函數

配置好參數,就可以開始編寫用戶程序了。用戶程序和計算機之間的USB通信是通過AVRUSB提供的接口函數完成的,接口函數有6個,下面將分別介紹。

 

3.4.1  初始化函數

在使用AVRUSB前,需要進行必要的初始化,這通過調用初始化函數usbInit()完成。一般是在程序其他部分初始化完成後再調用函數usbInit(),最後再調用sei()函數允許中斷。

void main()

{

  …
      usbInit();
      sei();
      …
      while(1)        //主循環
      {
        …
      }

}

 

3.4.2  USB事件處理函數

在用戶程序的主循環中需要定期調用USB事件處理函數usbPoll()。USB事件處理函數usbPoll()在沒有USB事件需要處理時將直接返回,否則將調用內部函數進行相應的事件處理,最後再將數據通過傳遞到後面介紹的用戶接口函數中。通常的用法是:

while(1)        //主循環
{
    usbPoll();  //USB事件處理
    ……        //其他用戶事件
}

一次USB通信的超時時間是50ms。所以在編程時注意其他事件不要佔用太長的時間,使得usbPoll()函數不能及時執行。

 

3.4.3  用戶事件接口函數

在用戶程序中需要編寫USB用戶事件接口函數,完成USB通信。AVRUSB將用戶接口簡化爲以下3個函數,這三個函數需要用戶進行編程處理,它們將完成USB通信的數據處理。

usbFunctionWrite    主機向單片機寫入數據
usbFnctionRead      主機從單片機中讀取數據
usbFunctionSetup    一般功能設置

函數usbFunctionSetup負責傳遞USB請求,參數存放在一個8字節的數組中(uchar data[8]),其的含義是:

uchar requestType;  //[0]        請求類型
uchar request;      //[1]        請求的內容
unsigned value;     //[2], [3]   參數
unsigned index;     //[4], [5]   序號
unsigned length;    //[6], [7]   長度

在一般 情況下,除了data[0]和data[1]用於存放USB事件的請求參數外,data[2]至data[7]都可以傳遞用戶參數。這樣在數據量非常小的 時候,通過usbFunctionSetup就可以完成全部參數傳遞了,不需要使用函數usbFnctionRead和 usbFunctionWrite。這時可以在usbconfig.h中將宏USB_CFG_IMPLEMENT_FN_READ和 USB_CFG_IMPLEMENT_FN_WRITE設置爲0,禁止使用函數usbFnctionRead和usbFunctionWrite,這樣可 以節省出不少代碼空間。

在傳遞 的數據比較多時,就需要使用usbFunctionWrite和usbFnctionRead函數了。這兩個函數具有相同的參數(uchar *data, uchar len),len表示參數的數量,*data指向數據緩衝區。在編程時,一般是先在usbFunctionSetup函數中根據計算機發送過來的請求類型 和參數來設置一個全局標誌,然後在usbFunctionWrite和usbFnctionRead函數中根據相應全局標誌進行不同的功能處理。

 

3.4.4  數據校驗

爲了保證USB數據通信的可靠,避免傳輸中出現誤碼,還應當對數據進行校驗。USB通信使用了CRC校驗來保證通信的可靠性,數據校驗的方法是調用usbCrc16()函數,函數的使用方法是:

crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);

USB數據緩衝區中存放的校驗結果在

  ((uchar *)(unsigned)(usbAppBuf + 1))[usbRxLen - 3] 和
((uchar *)(unsigned)(usbAppBuf + 1))[usbRxLen - 2] 兩個字節中。

將計算 結果和緩衝區的數據進行比較就可以知道通信緩衝區中的數據是否正確了。需要注意的是usbCrc16函數並不是在用戶程序中調用的,而是在 usbdrv.c文件中的usbPoll函數中。在usbPoll函數的開始部分有一段註釋,解釋了可以在此調用usbCrc16函數。

在很多 AVRUSB項目中(如USBasp)並沒有處理CRC校驗,這是因爲在USB通信中對時間要求比較嚴格,AVRUSB在底層處理時來不及進行數據校驗, 所以底層函數在接收到數據後就直接將ACK信號發送回去了。這樣即使在數據校驗中發現了錯誤,也不能由底層函數報告給計算機,只能在用戶程序中向計算機發 出錯誤報告。在一般要求不高的應用中可以不進行數據校驗,以簡化程序結構。但是在要求比較高的控制系統中應當進行CRC校驗,使得整個系統具有更高的可靠 性。當然,用戶也可以不使用比較耗時的CRC校驗而用其他方法建立起自己的數據錯誤處理機制。

 

4         計算機程序編程

計算機程序的編程主要包括了驅動程序的設計和用戶程序的開發,每個部分又包含了很多內容。

4.1   PID和VID

每 種USB設備都有一個PID和VID。VID是生產商的代號,PID是產品的代號,每個代號都是一個雙字節的整數。PID和VID不能隨意設置,它是由 USB標準協會進行分配的,就像IP地址的分配一樣。一個USB的PID/VID許可需要花費1500美元,在很多情況下,特別對小公司是一個很大的費 用。針對這種情況,AVRUSB提供了3個免費的PID/VID對,分別適用於HID類、CDC類和通用類設備,使用AVRUSB的用戶可以免費使用它 們,這樣對於大多數應用來說就不用再自己去申請PID/VID了。

 

表二: 免費的PID/VID對

 

VID

PID

控制類

0x16C0

0x05DC

CDC類

0x16C0

0x05DF

HID類

0x16C0

0x05E1

 

PID和VID在驅動程序和用戶程序中都將用到,它是windows識別USB設備的關鍵參數,用戶程序也需要通過PID和VID來查找相應的USB設備。

 

4.2       USB設備類型

AVRUSB 有多個版本,早期的版本只支持控制類的USB設備和最多兩個節點,而最新的版本還可以支持CDC類(串口類)和HID類(人體工學設備)以及最多4個節 點。CDC類和HID類都無需自己編寫Windows的驅動程序(Windows自帶)。AVRUSB的作者不推薦使用CDC類的方式(據說是因爲在有些 計算機上兼容性不好),而推薦使用HID類,但是使用HID類的應用目前還不是很多,支持的程序也比較少。本文將只介紹應用最廣泛的控制類設備的編程方 法。

 

4.3       驅動程序

對於每種USB設備,都需要有相應的驅動程序。只有安裝了驅動程序後,USB設備才能被操作系統所識別,設備才能正常工作。每個驅動程序都包含了底層驅動程序、設備描述文件等幾部分。

 

雖 然現在已經有很多優秀的開發底層驅動程序的工具,但是對於一般用戶來說開發驅動程序還是一件比較複雜的事情。AVRUSB的底層驅動程序使用了 LibUSB,這是一個很有名的開源USB驅動程序,支持多種操作系統平臺,在Windows操作系統下對應的版本是LibUSB-Win32。也就是 說,計算機上的USB底層驅動程序不需要用戶自己再編寫了,直接使用LibUSB就行了,用戶只需要編寫設備描述文件。設備描述文件是一個文本文件,用於 說明設備的參數,主要就是設備的PID、VID、設備名稱、使用的底層驅動程序名稱等。

 

4.3.1  定製自己的USB設備驅動程序

要 想讓LibUsb-Win32成爲自己開發的USB設備的驅動程序,只需對LibUsb-Win32提供的libusb.inf設備信息文件(INF)的 內容按照其中的註釋給出的說明進行適當的修改即可。其中最重要的修改是對VID/PID的修改,將文件中的VID/PID值替換爲自己開發的USB設備的 VID/PID值(也就是上面表二給出的值)。其它可以修改的內容還有設備製造商名稱,設備描述字符串等等。

 

以 LibUSB-Win32的0.1.10.1版本爲例,一個使用LibUSB的USB設備驅動程序包至少要包含以下的3個文件:libusb0.sys、 libusb0.dll和libusb.inf。在LibUsb-Win32的0.1.10.1版本中,還提供了一個用於自動生成INF文件的嚮導工具。 該工具位於libusb-win32-device-bin-0.1.10.1/bin目錄下,文件名爲inf-wizard.exe。通過使用該向導工 具,可以方便地生成與自己開發的USB設備相關的INF文件。需要注意的是,該向導工具不僅生成了一個INF文件,同時也生成了一個安全目錄文件 (*.cat),該文件包含的由Microsoft提供的對將要安裝到Windows系統上的驅動程序文件的數字簽名。如果沒有這樣的安全目錄文件,需要 從生成的INF文件中刪除掉“Version“部分中的“CatalogFile“內容。

 

4.3.2  預安裝USB設備的驅動程序

通 過“找到新硬件嚮導“的方式來安裝設備的驅動程序作爲Windows系統的一種標準方式已經使用很多年了,每當我們加入一個新的設備到計算機上 時,Windows會提示我們發現一個新的設備,然後進一步提示我們去查找並安裝相應的驅動程序。這個步驟對於終端用戶來說還是不太方便,對他們而言,希 望只要將新的硬件裝(插)到Windows系統上就可以使用了,而無需再做其它額外的工作。

 

Microsoft 已經認識到了這個問題,並已製作了一套能夠在Win2000及更高版本的操作系統上使用的驅動程序安裝工具——Driver Install Frameworks (DIFx)。這些工具能夠進行驅動程序的預安裝,即新硬件在系統上可用之前安裝驅動程序。這允許當一個匹配的設備首次被連接到電腦上時,相應的驅動程序 能夠被自動裝載。

 

Driver Package Installer(DPInst)是DIFx工具集中的工具之一,該工具提供了進行驅動程序預安裝的最簡單也是最常用的方法。DPInst由 DPInst.exe和DPInst.xml這兩個文件組成,其中DPInst.xml是一個可以對安裝過程進行配置的文件。將驅動程序包放在與 DPInst.exe和DPInst.xml一樣的目錄下(或者將驅動程序包放在DPInst.exe所在目錄的子目錄下),然後運行 DPInst.exe,就可以將驅動程序包進行安裝。以下是DPInst.xml的一個例子:

 

 

<?xml version="1.0"?>

<dpInst>

    <search>

      <subDirectory>DriverPackage</subDirectory>

    </search>

    <language code="0x804">

        <dpinstTitle>XXX控制器USB設備驅動程序安裝嚮導</dpinstTitle>

        <welcomeTitle>

歡迎使用XXX控制器USB設備驅動程序安裝嚮導!

</welcomeTitle>

        <welcomeIntro>

此嚮導將幫助您安裝XXX控制器USB設備驅動程序。沒有該驅動程序,XXX控制器USB設備將無法運行。

</welcomeIntro>

        <eulaHeaderTitle>最終用戶許可協議</eulaHeaderTitle>

        <eulaYesButton>我同意此協議(&amp;A)</eulaYesButton>

        <eulaNoButton>我不同意此協議(&amp;D)</eulaNoButton>

        <installHeaderTitle>

正在爲您的設備安裝該驅動程序,請稍候...

</installHeaderTitle>

        <finishTitle>祝賀您!該驅動程序已成功安裝到了您的電腦上。</finishTitle>

        <finishText>您現在可以使用XXX控制器USB設備了。</finishText>

        <eula type="txt" path="CustomData/eula.txt" />

    </language>

    <legacyMode/>

 

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沒有專門的說明文檔,只有通過研究源代碼以及代碼中的註釋來學習。但是這也是一種編程技巧和編程風格,可以有效的提高程序的代碼效率。

 

 

 

參考資料

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

 

 

(全文完)

 

 

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