引言
有關(guān)通用串行總線(USB)的文章通常從USB是個(gè)人電腦的一個(gè)新連接標(biāo)準(zhǔn)開(kāi)始講起。謝天謝地現(xiàn)在不再需要如此做,因此本引言可以簡(jiǎn)短地寫為:如果你有一個(gè)嵌入式系統(tǒng)并且想連到PC,主流的連接通道是USB。本文介紹了一款Maxim最新推出的芯片,MAX3420E,它可以很容易地把USB加入到任何系統(tǒng)中。本文主要著重于SPI接口,提供了實(shí)現(xiàn)通用SPI的C例程。最后給出了一個(gè)簡(jiǎn)單的USB HID (人機(jī)接口設(shè)備) ― 基于Windows的應(yīng)急按鈕程序。
為任何系統(tǒng)增加USB
微控制器(μC)的選擇通?;谒傻耐庠O(shè)。許多處理器集成了USB功能,但是大多數(shù)處理器,特別是一些低價(jià)位的處理器不含USB。有時(shí),您可能選用了一個(gè)I/O和外設(shè)都很完美的微控制器,但它卻缺少USB。您是否希望只是添加USB功能而繼續(xù)使用當(dāng)前的微控制器呢?利用Maxim的芯片MAX3420E,可以為任何處理器添加USB功能。MAX3420E集成了USB全速收發(fā)器、智能USB串行接口引擎(SIE)和一個(gè)可工作到26MHz時(shí)鐘的從SPI接口。MAX3420E的使用如同一個(gè)具有單個(gè)控制端點(diǎn)、兩個(gè)雙重緩沖的64字節(jié)數(shù)據(jù)端點(diǎn)和一個(gè)64字節(jié)的中斷端點(diǎn)的全速USB外設(shè)。
總線供電
圖1. USB供電
圖1是一個(gè)普通的USB外設(shè)結(jié)構(gòu)。USB的VBUS電源線為3.3V穩(wěn)壓器提供5V輸入,該穩(wěn)壓器給微控制器和MAX3420E供電(無(wú)需墻上適配器)。SPI接口可以是3、4或5線。表1列出了5線接口。
表1. 使用3到5線的SPI接口
Signal | MAX3420E Direction | Description |
MOSI | In | SPI master out, slave in |
MISO | Out | SPI master in, slave out |
SCLK | In | Serial clock |
SS# | In | Slave select |
INT | Out | Interrupt (level or pulse) |
如果應(yīng)用中不需要中斷(MAX3420E的中斷條件可以通過(guò)讀取寄存器直接檢測(cè)到)s,可以去掉INT引腳,得到一個(gè)4線接口。如果SPI主機(jī)具有雙向數(shù)據(jù)接口(MOSI/MISO),則可以省掉另外一條接口線,這樣,沒(méi)有中斷、支持雙向通信的SPI接口只需要3個(gè)引腳。
如果微控制器沒(méi)有SPI接口怎么辦呢?沒(méi)問(wèn)題,可以很容易地設(shè)計(jì)一個(gè)直接觸發(fā)GPIO的、固件形式的SPI主控器。USB的一個(gè)非常強(qiáng)的特性是自控流量能力,它自動(dòng)配合SPI側(cè)的任何速度(它利用在USB側(cè)插入NAK握手來(lái)提示“忙,重試”)。很多USB外設(shè),特別是與人接口的,即使與最低速的SPI接口都能應(yīng)答自如。
如果圖1中的微控制器非常小,只有10腳以下怎么辦呢?難道就不能把這些珍貴的I/O口用來(lái)連USB芯片了?不,這就是為什么MAX3420E提供了四個(gè)通用輸出口和四個(gè)通用輸入口的原因,它們可以替代被用掉的處理器上的I/O口,事實(shí)上你的系統(tǒng)在接上MAX3420E后還得到了更多的口線。
大規(guī)模集成芯片
圖2. 只連接大規(guī)模集成芯片的少許引腳
MAX3420E不僅僅只限用于小系統(tǒng)。圖2說(shuō)明了如何給一個(gè)ASIC,FPGA,DSP和其他大芯片增加USB功能。這樣做的一個(gè)明顯原因是大芯片沒(méi)有內(nèi)建的USB或內(nèi)部的USB不是正好符合你的所需。另一個(gè)原因是隨著工藝尺寸的縮小,這些大片子不能兼容USB所需的3.3V “高”壓,此時(shí)使用外部帶低壓SPI接口的USB芯片就是一個(gè)很好的方案。MAX3420E內(nèi)帶電平轉(zhuǎn)換器,VL腳設(shè)定接口電平的范圍,從1.7V到3.6V。
隔離USB
圖3. 隔離USB
如圖3所示,由于SPI接口信號(hào)是單向的,還很容易進(jìn)行光隔。同時(shí)還可以設(shè)定較低的速率來(lái)支持廉價(jià)的光耦。
SPI接口
SPI (串行外設(shè)接口)是一個(gè)簡(jiǎn)單的串行接口,它使用兩根數(shù)據(jù)線,一根串行時(shí)鐘和一個(gè)片選信號(hào)。SPI主控把SS#拉低來(lái)開(kāi)始傳輸,然后驅(qū)動(dòng)串行時(shí)鐘SCLK來(lái)把數(shù)據(jù)同步輸入和輸出從設(shè)備。SPI主控通過(guò)把SS#拉回到高電平,以終止傳輸。SPI接口有四種時(shí)鐘模式,反映了兩個(gè)信號(hào)CPOL (時(shí)鐘極性)和CPHA (時(shí)鐘相位)的兩個(gè)狀態(tài)。這兩信號(hào)以(CPOL, CPHA)的形式來(lái)表示??梢宰C明一個(gè)接口利用正沿SCLK且在第一個(gè)正沿時(shí)鐘到來(lái)以前MOSI數(shù)據(jù)已經(jīng)準(zhǔn)備就緒可以工作在(0,0)和(1,1)模式而無(wú)需任何改變。這一屬性使MAX3420E無(wú)需額外的模式引腳設(shè)置,就可以工作在(0,0)或(1,1)模式。
圖4和圖5顯示了利用SPI模式在微控制器(MAXQ2000,隨后介紹)和MAX3420E之間的數(shù)據(jù)傳輸。圖4所示為(0,0)模式,圖5所示為(1,1)模式。兩者的區(qū)別是SCLK信號(hào)的無(wú)效電平不同,(0,0)是低無(wú)效,(1,1)是高無(wú)效。
圖4. 工作在(0,0)模式的SPI接口
圖5. 工作在(1,1)模式的SPI接口
MAX3420E每次傳輸接收的第一個(gè)字節(jié)是命令字節(jié)。命令字節(jié)包含寄存器號(hào)和方向位,第二個(gè)字節(jié)和后續(xù)字節(jié)包含數(shù)據(jù)。在圖4和圖5中,移入命令字時(shí),來(lái)自MAX3420E (MISO引腳)的8位數(shù)據(jù)是USB狀態(tài)位。此特性只在使用分離MISO和MOSI腳的接口中有效。
SPI代碼
編寫MAX3420E通用C代碼的竅門是把原始的最基本的SPI操作封裝到獨(dú)立的模塊中,然后針對(duì)不同的SPI接口的只需客戶化這一模塊。最基本的模塊只須做三件事:- 初始化SPI口
- 讀一個(gè)字節(jié)
- 寫一個(gè)字節(jié)
位仿真SPI
Init SPI
初始化SPI口的函數(shù)會(huì)隨處理器的不同而有很多變化。比較好的做法是先指定接口使用的I/O腳,設(shè)置它們的方向,然后設(shè)定SS=1和SCLK=0的初始條件(我們假定用SPI主控器的(00)模式)。
讀寄存器,寫寄存器
rreg是讀取MAX3420E寄存器的C函數(shù),這個(gè)宏把功能從不同微控制器的不同I/O結(jié)構(gòu)中獨(dú)立出來(lái),使用宏使代碼易讀且與處理器無(wú)關(guān)。wreg是寫MAX3420E寄存器的例程。
更換處理器時(shí),只需對(duì)宏進(jìn)行修改即可使用這些例程。例如:下面是用于不帶硬件SPI單元的微控制器的宏。
#define SCLK_HI OUTA = PINSA | 0x02; #define SCLK_LO OUTA = PINSA & 0xFD; #define SS_HI OUTA = PINSA | 0x04; #define SS_LO OUTA = PINSA & 0xFB; #define MOSI(v) OUTA = (PINSA & 0x7F) | (v & 0x80); #define MISO inval |= PINSA & 0x01; BYTE rreg(BYTE r) // Read a register, return its value. { int j; BYTE bv,inval; inval = 0; SS_LO bv = r<<3; // Left-shift the reg number, WRITE=0 for (j=0; j<8; j++) // send the register number and direction bit { MOSI(bv) // put out a bit bv <<= 1; // shift one bit left SCLK_HI SCLK_LO } for (j=0; j<7; j++) // get 7 bits and shift left into 'inval' { SCLK_HI MISO inval <<= 1; // shift in one bit SCLK_LO } SCLK_HI // one more bit, but don't shift 'inval' this time MISO SCLK_LO SS_HI return inval; // return the byte we read in } void wreg(BYTE r,BYTE v) // register, value { int j; BYTE bv; SS_LO bv = (r<<3)+2; // Left-shift the reg number, set the WRITE direction bit for (j=0; j<8; j++) // send the register number and direction bit { MOSI(bv) // put out a bit bv <<= 1; // shift one bit left SCLK_HI SCLK_LO } for (j=0; j<8; j++) // send the register data { MOSI(v) // put out a bit v <<= 1; // shift one bit left SCLK_HI SCLK_LO } SS_HI }硬件SPI
這一部分討論上面提到的MAXQ2000微控制器,簡(jiǎn)單地說(shuō),MAXQ2000是低功耗、16位、高性能RISC處理器家族中的第一個(gè)?!癚”代表安靜,表示這一結(jié)構(gòu)能夠與敏感的模擬電路很好地協(xié)調(diào)工作。MAXQ2000內(nèi)建了一個(gè)SPI口,它與MAX3420E配合特別合適,下面的例子使用MAXQ2000開(kāi)發(fā)板和MAX3420E搭建了一個(gè)簡(jiǎn)單、有趣的Windows小產(chǎn)品。
MAXQ2000硬件SPI單元提供了SCK、MOSI和MISO,但是沒(méi)有SS#。由于SS#的操作方式會(huì)變化(比如尋址一個(gè)字節(jié)與突發(fā)的字節(jié)串),最好用通用I/O腳做SS#。
MAXQ I/O單元
圖6. MAXQ I/O單元
圖6所示是一個(gè)基本的MAXQ I/O單元。I/O口以格式'port.bit'表示,'p'代表端口,'b'代表位。作為例子,我們主要討論I/O口5,第3位(用P53)表示。
每一個(gè)I/O單元有一個(gè)觸發(fā)器,本例中用一個(gè)稱為PO5.3的位來(lái)寫。'O'代表輸出。你一直可以寫這個(gè)觸發(fā)器,它的輸出有沒(méi)有與引腳相連由方向位決定。配置輸出腳時(shí),實(shí)際應(yīng)用時(shí)先寫觸發(fā)器再連到引腳比較好,這樣它可以避免引腳上出現(xiàn)毛刺。
P53腳的方向由稱作PD5.3的位來(lái)設(shè)定。'D'代表方向,D信號(hào)充當(dāng)引腳驅(qū)動(dòng)的輸出使能:1 = 驅(qū)動(dòng),0 = 浮空。引腳的狀態(tài)一直可以通過(guò)稱作PI5.3的位讀取,'I'代表輸入,無(wú)論引腳是如何驅(qū)動(dòng)的,被內(nèi)部觸發(fā)器(PD5.3 = 1)還是被外部的信號(hào)(PD5.3 = 0),PI位表示引腳狀態(tài)。
這種結(jié)構(gòu)的一個(gè)好處是如果引腳被配制成輸入(PD5.3 = 0),觸發(fā)器的輸出沒(méi)有被用作輸出,那么它可以作為上拉電阻的開(kāi)關(guān)重新利用。如果D = 0,0信號(hào)被重新定義,表示“連接一個(gè)上拉電阻”,如圖6中的點(diǎn)狀線所示。
許多I/O腳有中斷功能,如圖6下面的框圖所示,中斷模塊有三個(gè)信號(hào):
- 一個(gè)中斷標(biāo)志位,中斷請(qǐng)求有效時(shí)被置位,由CPU來(lái)復(fù)位。
- 一個(gè)邊沿選擇位,決定是正信號(hào)跳變還是負(fù)信號(hào)跳變引起中斷請(qǐng)求。
- 對(duì)每一個(gè)能引起中斷的引腳有一個(gè)中斷使能位。
初始化SPI
MAXQ2000的I/O引腳由通用I/O和像SPI單元這樣的特殊功能硬件共享。使用特殊功能硬件時(shí),先配置硬件塊,然后把它連到I/O腳上。程序清單中的SPI_Init()過(guò)程設(shè)置了引腳方向,配置了SPI接口,最后使能它。
void SPI_Init(void) { // MAXQ2000 SPI port CKCN = 0x00; // system clock divisor is 1 SS_HI // SS# high PD5 |= 0x070; // Set SPI output pins (SS, SCLK, DOUT) as output. PD5 &= ~0x080; // Set SPI input pin (DIN) as input. SPICK = 0x00; // fastest SPI clock--div by 2 SPICF = 0x00; // mode(0,0), 8 bit data SPICN_bit.MSTM = 1; // Set Q2000 as the master. SPICN_bit.SPIEN = 1; // Enable SPI // MAX3420E INT pin is tied to MAXQ2000 P60; make it an input PD6 &= ~0x01; // PD6.0=0 (turn off output) }讀寄存器,寫寄存器
以下函數(shù)利用了MAXQ2000硬件SPI單元的優(yōu)點(diǎn),因此比起那些位仿真代碼尺寸小而且快。
// Read a MAX3420E register, return its value. BYTE rreg(BYTE reg) { BYTE dum; SS_LO SPIB = reg<<3; // reg number w. dir=0 (IN) while(SPICN_bit.STBY); // loop if data still being sent dum = SPIB; // read and toss the input byte SPIB=0x00; // data is don't care, we're clocking in MISO bits while(SPICN_bit.STBY); // loop if data still being sent SS_HI return(SPIB); } // Write a MAX3420E register. void wreg(BYTE reg, BYTE dat) { SS_LO // Set SS# low SPIB = (reg<<3)+2; // send reg. number w. DIR bit (b1) set to WRITE while(SPICN_bit.STBY); // loop if data still being sent SPIB = dat; // send the data while(SPICN_bit.STBY); // loop if data still being sent SS_HI // set SS# high }
例子:基于Windows的應(yīng)急按鈕
這個(gè)USB小產(chǎn)品是一個(gè)USB HID,或人體學(xué)輸入設(shè)備-單個(gè)按鍵。當(dāng)你按下按鍵,所有的活動(dòng)窗口被最小化,你看到的僅剩桌面,再按一下它,所有的應(yīng)用窗口又重新彈回來(lái)。USB鍵盤很有意思,如果插入幾個(gè)鍵盤,它們將同時(shí)有效。所以我們的小應(yīng)急按鈕可以和你的正常鍵盤一起工作。
如果PC在待機(jī),這個(gè)應(yīng)急按鈕擔(dān)當(dāng)了一個(gè)新角色-它可以充當(dāng)PC的遠(yuǎn)程喚醒按鍵。不過(guò)這取決于你的PC支持不支持USB喚醒,有些可以,有些不可以。這個(gè)按鈕可以幫你判斷你的PC可不可以。
此例程在帶有一個(gè)USB子卡(包含MAX3420E)的MAXQ2000開(kāi)發(fā)板上運(yùn)行。
USB詳細(xì)說(shuō)明
這個(gè)應(yīng)用代碼包含了USB做枚舉類型瑣碎工作的樣板代碼,此設(shè)備的屬性已經(jīng)用Panic_Button_Enum_Data.h中的特性陣列完全描述。
這個(gè)應(yīng)用使用了兩個(gè)端點(diǎn),強(qiáng)制的CONTROL端點(diǎn)0,和EP3-IN,單緩沖64字節(jié)端點(diǎn)。雖然MAX3420E內(nèi)含兩個(gè)雙重緩沖的64字節(jié)端點(diǎn)(EP1-OUT和EP2-OUT),在這個(gè)應(yīng)用中并不需要雙重緩沖的吞吐優(yōu)勢(shì)。
一個(gè)普遍存在HID錯(cuò)誤概念是HID設(shè)備僅僅工作在低速下,本例展示了即使是像鍵盤這樣的東西也可以從全速運(yùn)行中得到好處,通過(guò)發(fā)送12MHz的包來(lái)而不是1.5MHz包,它可以使用更低的總線帶寬。
圖7. 應(yīng)急按鈕的流程圖
中斷端點(diǎn)有查詢間隔,它決定了USB主設(shè)備隔多久向IN端點(diǎn)要數(shù)據(jù)。每隔一段時(shí)間我們可以預(yù)計(jì)到主控制器發(fā)了一個(gè)IN請(qǐng)求給我們的設(shè)備端點(diǎn)3。圖7顯示了處理這些請(qǐng)求的一個(gè)簡(jiǎn)單的狀態(tài)機(jī)。只要設(shè)備被例舉了,處理器重復(fù)地執(zhí)行這一過(guò)程。為了簡(jiǎn)單起見(jiàn),該應(yīng)用程序查詢中斷腳是否有效,當(dāng)然,如果你還有其他事要微控制器處理,你會(huì)用中斷來(lái)激活Do_IN3函數(shù)。
狀態(tài)機(jī)使用了兩個(gè)全局變量:state和button。C宏定義了三個(gè)狀態(tài):IDLE, RELEASE和 WAIT 。狀態(tài)變量初始化為IDLE。如果連在MAX3420E的GPIN0上的按鍵按下,變量button是高,否則為低。Main()中的無(wú)窮循環(huán)增加一個(gè)按鍵檢查定時(shí)器,當(dāng)定時(shí)器到時(shí)它會(huì)讀一下MAX3420E中的GPIO寄存器來(lái)決定按鍵狀態(tài)。此方法省掉了不必要的SPI流量。
當(dāng)按鍵處于彈起狀態(tài)時(shí),狀態(tài)圖轉(zhuǎn)到左邊的兩個(gè)分支,不做任何事。如果按鍵在IDLE狀態(tài)被按下,就發(fā)一個(gè)清除桌面上活動(dòng)窗口的鍵碼。鍵碼次序是08 (windows鍵) 00 (保留)和07 (字母d)。下一個(gè)狀態(tài)轉(zhuǎn)到RELEASE,這樣就完成了。
只要MAX3420E把數(shù)據(jù)包送到USB,它就產(chǎn)生另一個(gè)EP3-IN中斷請(qǐng)求來(lái)表示EP3-IN FIFO可以再一次裝載數(shù)據(jù)。然后再次進(jìn)入圖7函數(shù),此時(shí)狀態(tài)state = RELEASE ,因此函數(shù)發(fā)送序列00 00 00來(lái)表示“按鍵彈起”,下一個(gè)狀態(tài)進(jìn)入WAIT,意思是“等待按鍵被釋放”。
現(xiàn)在函數(shù)要做的所有工作是利用WAIT狀態(tài)分支程序來(lái)檢測(cè)按鍵釋放。如果按鍵一直按著,程序不做任何事,當(dāng)按鍵一被釋放,狀態(tài)圖就進(jìn)到右邊的兩個(gè)分支,重新初始化state 變量為IDLE,使函數(shù)等候下一個(gè)按鍵按下。
占大部分運(yùn)行時(shí)間的代碼只有少數(shù)幾行,圖7給出了流程圖:
void Do_IN3(void) { switch(state) { case IDLE: if (button) { wreg(rEP3INFIFO,0x08); // "Windows" prefix key wreg(rEP3INFIFO,0); wreg(rEP3INFIFO,0x07); // "D" key wreg(rEP3INBC,3); // arm it state = RELEASE; // next state sends the "keys up" code } break; // else do nothing (and the SIE will NAK) // case RELEASE: { wreg(rEP3INFIFO,0x00); // key up wreg(rEP3INFIFO,0x00); wreg(rEP3INFIFO,0x00); // key up wreg(rEP3INBC,3); // arm it state = WAIT; // next state waits for the PB to be unpressed } break; case WAIT: if (!button) state = IDLE; break; default: state = IDLE; } // end switch }
代碼關(guān)鍵
需要對(duì)代碼中的一些細(xì)節(jié)加以說(shuō)明。時(shí)間敏感的USB事件
MAX3420E 通過(guò)在USB總線上送'K'狀態(tài)10ms時(shí)間發(fā)了一個(gè)遠(yuǎn)程喚醒信號(hào),為了避免用SPI主控器來(lái)做設(shè)定時(shí)間這種雜活,MAX3420E用自己內(nèi)部來(lái)定時(shí)這個(gè)信號(hào)(事實(shí)上,所有的USB時(shí)間敏感事件),然后在時(shí)間到時(shí)給SPI主控器發(fā)一個(gè)中斷。SPI主控器對(duì)這些事件不必用上它自己的定時(shí)器-它只需啟動(dòng)操作,然后等待完成中斷。
ACKSTAT位
函數(shù)rregAS和wregAS的功能與rreg和wreg只有一點(diǎn)不同,它們?cè)赟PI命令字中設(shè)了ACK STATUS位。SPI主控器(我們的例子中是MAXQ2000)用這一位表示MAX3420E已經(jīng)完成了當(dāng)前的CONTROL請(qǐng)求服務(wù),因此用應(yīng)答它的狀態(tài)情況的方式來(lái)終止CONTROL傳輸。ACKSTAT還扮演了一個(gè)內(nèi)部寄存器位的角色,而且由于它含在SPI的命令字中,對(duì)它的操作能快速執(zhí)行且只需少量代碼。
readbytes(), writebytes()函數(shù) 這些函數(shù)使用了MAX3420E的數(shù)據(jù)突發(fā)能力。與每次字節(jié)尋址發(fā)兩個(gè)字節(jié)(一個(gè)命令字節(jié)和一個(gè)數(shù)據(jù)字節(jié))不同,這些函數(shù)先拉低SS#,送命令字,然后送入/送出一串字節(jié),最后把SS#來(lái)拉高結(jié)束SPI傳輸。
哪里找到產(chǎn)品ID
圖8. 產(chǎn)品ID在這里顯示
產(chǎn)品ID碼(在Panic_Button_Enum_Data.h中)是第一次插入應(yīng)急按鈕時(shí)出現(xiàn)的一小段信息。在確定應(yīng)急按鈕為HID的枚舉過(guò)程中彈出來(lái),并把它和Windows的內(nèi)部驅(qū)動(dòng)聯(lián)系起來(lái)。
除了插入任何USB設(shè)備時(shí)都會(huì)聽(tīng)到一小聲“叭噠”外,后續(xù)的每個(gè)附件都不發(fā)聲。任何時(shí)候如果你想檢查設(shè)備狀態(tài),請(qǐng)打開(kāi)圖8所示屏幕。你可以右擊“我的電腦”,選擇“屬性”,“硬件”頁(yè),“設(shè)備管理器”按鈕,展開(kāi)“人機(jī)接口設(shè)備”項(xiàng),右擊“USB人機(jī)接口設(shè)備”,選擇“屬性”。
USB兼容性
查看代碼后,你可能認(rèn)為這對(duì)一個(gè)單鍵的USB設(shè)備來(lái)說(shuō)要做很多工作,因?yàn)閷?duì)任何USB設(shè)備都需要寫一段固定代碼。幸運(yùn)的是我們對(duì)USB進(jìn)行了仔細(xì)的歸納,枚舉代碼可作為任何USB設(shè)備的一個(gè)模板(拷貝-粘貼即可)。像所有認(rèn)真的開(kāi)發(fā)者一樣,我們希望自己的設(shè)計(jì)能夠通過(guò)USB-IF認(rèn)證,以避免任何知識(shí)產(chǎn)權(quán)問(wèn)題。這個(gè)應(yīng)用已經(jīng)通過(guò)了USB命令驗(yàn)證(USBCV版本1.2.1.0)和USB-IF網(wǎng)站為開(kāi)發(fā)者提供的HID測(cè)試。
圖9. USB和HID測(cè)試記錄和狀況報(bào)告
結(jié)論
如果需要設(shè)計(jì)一個(gè)USB外設(shè),可選擇MAX3420E。該器件提供小尺寸封裝,并可提供許多免費(fèi)程序。MAX3420E能夠?yàn)樵O(shè)計(jì)增加I/O口線,在支持SPI的系統(tǒng)中能很好地工作。由于SPI很容易通過(guò)位仿真實(shí)現(xiàn),因此可以使用任何微控制器。如果需要更高性能,可以使用高達(dá)26MHz的SPI時(shí)鐘。類似文章發(fā)表于Circuit Cellar 2005年7月刊。
附錄. 代碼列表
下載代碼列表
評(píng)論
查看更多