之所以把題目訂為 USB HID 與 UART 的關係,是想以大家比較普遍容易遇到的
應用問題拿出來討論,但實際上跟所謂的USB 轉I2C 或是USB 轉SPI 等等問題是
一樣的啦!所以呢?!我也實在不想在UART 這個基本問題上討論太多為什麼會
掉資料的問題。因為...您的UART(RS232 )會掉資料,那難道人家USB 轉I2C
或USB 轉SPI 就不會嗎?!您USB 轉RS232 還有一大堆超級終端機或是VB 程式
可以參考寫程式,那人家那個USB 轉I2C 或USB 轉SPI 怎麼辦?!人家又沒有
那個VCP Class 的東西可以參考啊?!您該不會今天碰到UART 時,就搞那個
USB 轉RS232 ,那下回遇到USB 轉I2C 時,怎麼辦?!...算了吧!
還是直接想個根本解決之道,不要再讓這一種問題困擾您了吧!
所以啦....在系列一的文章我們所討論的那個什麼Null Modem Protocol 的問題,
就不要理他了吧~反正,您在用USB 轉RS232時,您還不是只用到 RD/TD 兩根I/O
而已嗎?!其他硬體的Protocol 您也都是視而不見...有差嗎?這樣子的搞法,
跟USB 轉I2C 或是USB 轉SPI 有差嗎?!.........
-----
所以啦~我們就乾脆直接看根本的資料傳輸問題吧...我們就直接借用USB 的基本精髓
來解決我們的這一類問題吧!
之前文章中,有讀者回應提到網路通訊OSI 七層的基本概念,沒錯....如果我們以這一個
觀點來看USB 其實他已經幫您定義到至少 Physical/Data/Network 以上了...
這三層比較是偏硬體!另外四層是比較偏軟體層的...當然啊,如果您是採用USB
某些Class 來說:那他的層次定義就越高了~當然他的使用彈性就越少了!
---- 這是個取類似的比較(比喻)方式。
因為USB 基本上都其基本的Frame 、CRC Check 及基本的Protocol ...所以我們先前
在討論那個Null Modem 中那些軟體定義Protocol 對USB 來說:那不是問題!
所以我才說:還真的有點懶得討論這些什麼DTR/CTS 或什麼 DCD、DSR 的!
人家USB有自己的定義,而您在用TD/RD 時也沒在鳥?!用SPI 或I2C 更沒有!
您既然要用最簡單的TD/RD 兩根I/O ,我們就用最簡單的兩根I/O 來搞吧!
(很巧,USB 也剛好就是兩根I/O :D+ 及D- !哈~哈~.........)
--------------------
我們就直接切實際應用問題吧!
若以HOST (PC)端來看:TD 的問題比較少!這對UART 、I2C 及SPI 都一樣!
因為USB 是屬於主從架構的通訊方式,所以只要Host 要往下傳資料,那Device 端
就不得不接收...以USB 的基本精髓來說,很基本。這一點大家在使用上應該也沒啥問題!
在AP 應用軟體的程式撰寫上,也沒多大爭議,您只要往作業系統的底層一丟資料,
那怕是一個Byte 一個Byte 丟...我相信以現在這麼Powerful 的電腦硬體幾搭配作業系統
應該都不難!
但比較大的問題應該就在 RD 這一個方向的接收問題吧!
因為USB 是主從架構,所以當USB 轉XXX 這一棵USB Controller MCU 收到資料時,
該如何"主動"的通知 PC Host ?! 所以~以USB 的架構來看:那就非得要靠Intertupt pipe
不可。當然之所以會這麼考量也是因為也要考慮 PC 端AP 該如何配合!
因為寫PC 端AP 軟體又不能像寫MCU 韌體一樣,靠硬體中斷來寫啊!
您說:那用Multi-thread 來寫?!我沒意見,只是我自己寫這一種程式的功力不足,
會把自己在AP 端的程式搞得很辛苦,很複雜...只要稍微沒搞懂Multi-Thread 的作法,
就連Debug 都會搞死自己!
對於PC 端來說,您根本很難定義說:您該多久要檢查一次那個Receive 端的FIFO ?!
或是多少的Byte 時,該要抓一次RD 資料?!在抓的時候,會不會剛好又有資料進來?
當然這些問題很難一次得到正確的答案!
但如果我們真正的回到:資料傳輸的真正的基本精髓,因為我們在做資料傳輸時,
都應該都會定義一定的軟體通訊協定:譬如會有資料檔頭(header),或是宣告一次
傳輸的長度,甚至說多久會傳一次資料等等!...尤其是我們在玩UART 這一種傳輸介面時,
我們也常要求傳輸雙方要定義一定的傳輸命令集或傳輸資料格式。
譬如:若以DMX512 的規格來看,他每一次就是會傳個 512 bytes 資料...
中間至少也會停留幾個uSec 或甚至mSec 等。或是工控上用的MODBUS 等等。
所以...我們在USB 的Interrupt pipe 中,就可以很明確的定義這一個傳輸長度。
又因為在USB HID class 的宣告中也是要宣告Interrupt pipe 會多久傳一次...
(沒有人規定您一定多久就要傳"正確"的資料,您當然可以在所傳輸的資料中,
擺入Data Ready 的識別碼...讓AP 軟體判斷。)但以微軟底層的USB 驅動程式
是一定會依照您所宣告的Interrupt pipe 中的Interval time 來抓一次資料...
(當然啊...如果您USB Controller 沒有準時送出資料,微軟的驅動程式也不會怪您!)
這一部份我在USB DIY-- 自學計畫(十)中有作實驗給大家看!
那這樣子,您就可以很容易的把資料準確的送到PC HOST端了!
----
所以當我們直接利用一棵帶有UART 功能的USB Controller IC 來對您的UART 應用的
系統來說:我們可以在USB Controller MCU 那邊,把您所需的UART 傳輸功能處理掉,
然後,很輕鬆利用本身USB HID 介面,把資料準確的往上傳給 PC Host 端,也可以讓AP
準確的讀到正確資料,我所說的意思是如下圖所示:
之所以這麼說的原因是:很簡單,現在隨便要找一棵USB Controller MCU 都應該很容易了,
而且現在這一種MCU 若以32 bits ARM 來說:搞不好都比以前我剛搞USB時的PC 的
CPU 都還強大,讓他來處理您應用上的UART 應該都是綽綽有餘了!
您幹嘛還要都要依賴PC 端呢?!這樣子您的產品應用也比較單純也比較有彈性。
當然,您會說:這樣子不是有點要客製化?!我有點無法像一般通用型USB 轉RS232
那樣簡單嗎?!---但我們之前不是討論了嗎?...簡單好用的代價是什麼?!
您付出了什麼代價?!...
--------
所以我們再來看PC 端的程式該如何寫?!
以下是一段我利用 USB HID 的Interrupt pipe 來抓資料的範例程式:
BOOL CUSB_RFIDTool::GetUSBHID_MCUDetector_Interrupt(unsigned char *nReportID, unsigned char *SnapshotBuf)
{
BOOL success = FALSE;
WORD inputReportSize = HidDevice_GetInputReportBufferLength(m_hid); // Size of the biggest input interrupt report
DWORD numReports = HidDevice_GetMaxReportRequest(m_hid); // The maximum number of reports that can be read in a single read
DWORD bufferSize = inputReportSize * numReports;
BYTE* buffer = new BYTE[bufferSize];
DWORD bytesReturned = 0;
BYTE status;
memset(buffer, 0x00, bufferSize);
// Get the max number of input reports via the interupt endpoint
status = HidDevice_GetInputReport_Interrupt(m_hid, buffer, bufferSize, numReports, &bytesReturned);
// If the function times out, we still have to check for returned data
if (status == HID_DEVICE_SUCCESS || status == HID_DEVICE_TRANSFER_TIMEOUT)
{
// Go through each input report one at a time
for (DWORD i = 0; i < bytesReturned; i += inputReportSize)
{
// If the current input report is a Get MCU Detector report
if (buffer[i] == IN_ReportID02) {
*nReportID = IN_ReportID02;
SnapshotBuf[0] = buffer[i + 1];
SnapshotBuf[1] = buffer[i + 2];
//*Detector = buffer[i + 1];
//*nValue = buffer[i + 2];
success = TRUE;
}
//--- Snapshot Report
if (buffer[i] == IN_ReportID10) {
*nReportID = IN_ReportID10;
for(int j=0;j<0x10;j++){
SnapshotBuf[j] = buffer[i + j];
}
success = TRUE;
}
//--- Report
if (buffer[i] == IN_ReportID08) {
*nReportID = IN_ReportID08;
for(int j=0;j<0x08;j++){
SnapshotBuf[j] = buffer[i + j];
}
success = TRUE;
}
if (buffer[i] == IN_ReportID0C) {
*nReportID = IN_ReportID0C;
for(int j=0;j<0x0C;j++){
SnapshotBuf[j] = buffer[i + j];
}
success = TRUE;
}
// Note: Ignore any other type of input report
}
}
delete [] buffer;
return success;
}
您可以看到我利用了四組 HID 中的Report ID 來處理UART 的回傳資料...
不同的Report ID 可以拿來處理不同的Data Length 資料,反正對於微軟作業系統
來說:他才不管您USB Controller MCU 傳什麼資料?他只要發現USB Interrupt pipe
一有資料,他就用固定長度的FIFO ,把您的資料儲存起來...
這一點看起來至少比那個RS232 那一種Comm port 作法嚴謹及有規律多了!
也難怪人家微軟的作業系統的底層驅動程式喜歡這樣子的東西。
所以~只要您的USB Controller MCU 在處理 UART 那邊不會掉資料,那在USB 這邊,
您就不用擔心那個什麼Null Modem 裡那個什麼DTR/CTS ?!或是會不會需要
Checksum 或是Error Correction 問題?!因為USB 硬體本身就已經幫您處理了!
這樣子的處理與設計方式,您也可以同時套用在I2C 或是SPI 等其他奇奇怪怪的MCU 介面裡!
連USB HID 這一端來說:根本不用動到什麼?!因為全由USB Controller MCU 來處理!
您說:這樣子簡不簡單?!
------------------------------------------
您或許會覺得這樣子作,會不會很花功夫?!很簡單~您不花功夫,錢就讓別人賺!
當然,如果您又老是碰到我們一直在強調的~出問題搞不清楚問題在哪?!
也不之該如何下手?!那又是另當別論了!您的代價還不少耶!
如果關於這一點您不是很認同的話,那我就Show 兩張圖給您看:
以下是Silabs 這一家USB Controller MCU 廠在賣您所謂的 USB 轉UART (RS232) IC
的資料與IC 接腳圖:
CP2103 :
------
CP2104 :
---------------------------
我這兩張比較圖,您看到了什麼?!看得懂的人就不用我說什麼了吧!
如果您搞USB 韌體程式行的話,您也可以!
-----
那您就更不用說:現在市面上一缸子 32 bits ARM 都帶有USB 介面的MCU 。
------------------------------------------
關於本篇文章我們就簡單的下個註腳:
1:如果您與其要用USB 轉RS232 來讓PC 端來處理UART 傳輸問題,您倒不如
直接套用一棵帶有UART介面的USB Controller MCU 來幫您處理系統之間的UART
問題,讓USB Controller MCU 跟PC 端只要處理單純的USB HID 問題!
以現在帶有USB介面的 Controller MCU 很多,甚至都有32 bits ARM 可供選擇,
其UART 的處理能力是比早期PC 的CPU 效能好很多!
2:PC 端的應用程式只剩下HID 單純的程式設計,既簡單又容易與作業系統底層驅動程式
配合,那怕下回修改成為USB 轉I2C 或USB 轉SPI 等介面,都一樣適用的啦!
而且還可以提供其他USB Command Interface ,讓您的PC 與USB Controller MCU
之間有更好彈性與應用介面。
(待續)...
雖然我沒真的寫過USB,只有在MCHP上個課沾過醬油,不過看了您這篇文章還是恍然大悟!之前真是浪費了不少時間鑽研PC收UART掉資料的問題啊,最後都還是沒有完美解,早知道拿那個時間來學USB HID !
回覆刪除MCHP ? Microchip ?! ....他們家的USB Microcontroller 產品太弱了啦。
刪除我文章中也講了~如果還要在8 bits MCU 學USB 就不如直接跳ARM 了。
但很奇怪,可能以前大家都習慣用他的低階MCU...用久了,好像習慣不好改?
但Microchip 的MCU 自從被台廠這些低階MCU 廠搞的血流成河之後,
我對他們家的東西就沒啥好感...好像那一種PIC like 的MCU,除了他們家的以外,
就只剩下台廠(甚至現在還一大堆陸廠)這些MCU 可以選似的?
有時還覺得人家Arduino 把AVR 拱得還比較有聲有色!
Arduino的流行看在我眼裡,其實很令人難過
回覆刪除今年11月我去宜蘭大學參加民生電子研討會,看到一大堆用Arduino的學生作東西,但是只會抓function套來用,所有用Arduino的學生原理一問三不知,還有一組做電壓警示偵測的,問他們ADC在哪裡? 竟然說沒有用ADC,其實我看他們的paper知道他們用AVR內建的ADC,但是Arduino的高度模組化,卻讓他們連自己都看不出來,真是可悲。倒是用其他MCU的學生就會比較清楚自己在做什麼
以前的我~也會對於您所說的事情會一樣的感到難過。
刪除學生本來就應該好好的把基礎底子給打好。....
但現在呢?!如果我們換個角度想:既然學生是用Arduino 來做研討會的作品,
那背後一定也有指導老師啊,那這些指導老師是怎麼想的?!
難道這些老師也是如我們這般的想說要好好的要求學生把一些原理搞清楚再來參加研討會。
那我想:可能搞了好幾年,也有可能這些學校也派不出學生參加了吧。
---
我在十一月寫了一篇:人才培育教育問題與社會國家競爭力。
裡面就有提到我們家賈老師的一些教學經驗,當您面對學習態度不佳,您又要
拿出您自己的教學成績時,您又該如何是好?難道還要逼著學生要像
一流學校的學生一樣:坐下來好好的研修這些基礎理論與學科嗎?
...
有時當我們在怪罪這些學生時,我們自己有沒有想過:
是我們大人把我們的教育制度搞成怎樣了?...
怎樣程度的學生,本來就應該定位在怎樣的教學條件與一定教學成效要求。
但我們現在卻是想扮演好上帝,要讓一樣大學畢業文憑是有一樣的教學成效?
您覺得有可能嗎?...最後不只是在折磨學生而已,也同樣的折磨這些指導老師。
所以當您換個角度的想到這些背後的指導老師時,您心裡就會舒坦一點。
得天下英才而教之,是每一個老師的夢想與理想。
但很不幸的是,那是不可能的!! ....看開一點吧。
「如果還要在8 bits MCU 學USB 就不如直接跳ARM 了」看了又看,可能是我只用過8bit MCU,在文章中還是看不出來您為什麼要這樣說?不是都要照著USB Protocol 來嗎? ARM會比帶USB的8051或PIC好寫許多嗎? 是否會搞得像高度模組化的Arduino,用了結果不知其所以然呢?
回覆刪除其實這是一個很無奈的結果。
刪除當初人家為什麼會想推 Arduino ?!想法很簡單,因為現代人都過渡依賴電子產品。
所以提供一個簡單入門的平台給大家有機會不用學太艱深的電子理論就可以做出自己想做的東西。
從全球市場觀點來看...沒錯! ...Arduino 提供了一個簡單易入門的電子平台。
就是您看到的學生所做的東西。---- 但是偏偏我們台灣過於強調我們自己的高科技產業。
所以,我們就一直認為我們的下一代或是對於電子有興趣的有志之士就應該嚴謹的
面對電子科技技術...我們應該有責任或有義務...責無旁貸的教育下一代。
但然後呢?!學會這些基礎之後呢?!出了社會再繼續賣肝幫國外代工?!
----
我說過:我老了,我搞電子一方面是興趣,一方面真的也是為了三餐。
但是現在如果有人找我搞個簡單的東西,我是肯定想用Arduino 的。道理很簡單:
因為十個客人有九個奧客...講了老半天,也沒量,也沒多少利潤可以發揮,
一塊Arduino 版子加模組比Layout 外加PCB 版簡單多了。
至於說真的~現在跟別人講說:ADC...USB... I2C...就很有學問嗎?
或甚至搞MCU...ARM ...滿街都是,講難的手機晶片不是每個人或每家公司可玩得起的。
回到基礎來說:就不外乎就這些標準界面或平台嗎?
我倒寧願讓年輕一代的從創意出發,等他們真的有興趣可以從這些創意應用領域裡
悟出一些創意商機之後,再來決定要不要再深入研究,探討...沒必要把這個東西看得太嚴肅。
就像我寫的那一篇鮭魚故事一樣:我鮭魚同學根本不懂得ADC的基本東西...更不懂得
什麼單晶片或ARM 等等...但他一樣買工控卡把機台玩得很快樂,又可賺錢啊!
---
您看現在Arduino 的一塊網路卡,就可以寫出簡單的網路監控的東西...
您想N 年前,有多少人花多少心思在8051 ,PIC 等等上面搞了老半天...
我以前還真的花了兩、三千元買過這一種8051 網路版,結果怎麼玩也玩不起來。多氣人啊!
人家Arduino 就可以讓這樣子的東西平易近人...如果未來真的有市場或真的有商機
再來進一步整合或Cost Down 就好了,但我們還要下一代幹這一種事嗎?
------
至於ARM 的確是高度取代 8 bit 產品,尤其是在這一種需要模組化的平台來看。
真的搞電子的人沒那多體力可以天天寫程式...Debug 搞系統的啦。
就連我自己也清楚ARM 的優勢,但我也真的沒那個體力與精力花在ARM 上面了。
但年輕人不同,如果他們從這些模組化得到一些靈感與創意時,我相信資源充沛的
ARM 可以提供更多更好的選擇。我當然就會鼓勵年輕人去學,去接觸。
----
科技總是來自於人性。
搞電子科技,無非也是想促進我們生活品質的改善,但如果搞一個電子產品
或學個系統平台,還要像我們以前那樣子要每一個工程師都要從組合語言,邏輯電路...
慢慢的磨耗出來...我想這樣子的系統平台也不是這些做電子科技界的大老們所樂見的。
現在趨勢之所以推所謂的Total Solution 或系統平台...無非就是想一開始就是以創意
先拉攏市場與客人....然後可以讓很多人可以快速上手去創造系統產品價值。
要不然,您說:現在哪一家MCU 廠在展示他們的產品規格時,您又真的可以看出他們的差異?
無非就是ADC 啦USB 、IIC、SPI、UART、Touch .....等等。
價值不會只會在這些MCU 身上的啦...現在有太多客人都很精了,他們根本不懂
電子科技技術,但他們都知道用電子科技技術可以做到很多事,所以客人都習慣只出一張嘴,
把他的想法講得天花亂墜,然後就無俚頭叫您搞一個出來,又不想出開發費?也沒Promise
什麼市場量...難道您還真的要幫他洗一塊PCB ,寫個程式嗎?...當然最好的方法:
就是用模組化的東西,趕快弄一塊來戳一戳他的市場謊言!
難道像我們寫程式寫這麼久了,難道也沒有累積自己的一些模組程式或模組化的東西嗎?
我們能快速的搞出樣品給這些無俚頭客人時,不也是東湊西湊的拼出來的嗎?
---- 我們都懂...我們當然也會用這些模組化的東西。差別的是我們的模組化的東西,
不像Arduino 這麼容易可以讓大家接受或銷售...要不然我的也想拿出來賣啊!
----
最後結論是:有時或許我們真的把自己的電子技術價值看得太高了,也有點自戀了。
這也或許是我們台灣這幾十年來電子科技產業帶我們的思維模式了。
或許,大家可以用別的方式或換個角度來思考,或許我們還可以為我們下一代
鋪出另一條不同的道路與價值吧!
照著USB的Protocol?天啊,真的沒有摸過才會如此說。USB書和枕頭是一樣高的。
回覆刪除若是照這樣的思維,照著Ethernet的Protocol寫也是可以寫得出來。那不就一堆公司會被您給幹掉了。
早期的RS232是可以這樣玩,但通信比較複雜的就不行了。所以才會有整合成簡單的玩具出現,不然一般人要如何入門?
學生玩玩就可以了,叫去寫Windows Driver只會把人逼退。
話說我有一位工程師朋友,叫他兒子考電機系,然後去修資工系Compiler課程,說是為了能完全了解電腦運作,從軟硬體都要最精。國立研究所畢業系,他兒子再也不想摸電腦了。
要人家學不是給就行了,要考量吸收率啊!
現在是技術過剩的時代, 硬體在未來只會更便宜,甚至 free !
回覆刪除年輕人再走過去的老路, 不會做得更好, 也做不贏 現在這批40歲左右的資深從業人員.
現在是 "用" IC 的時代, 不是 "開" IC 的年代.
只有善用 IC, 實現創意. 台灣的電子業才能繼續存活,
拼量,拼價, 早晚搞不過對岸.
嗯...非常同意您的看法。
刪除尤其您所說的:現在是 "用" IC 的時代, 不是 "開" IC 的年代.。
更何況現在已經有很多IC 對我們系統應用來說:早就綽綽有餘了。
只是還有一大堆人還在幻想說:我還要開一大堆已經有了,只是想拼命Cost down 去擠出
毛利的IC...何苦呢?!有必要嗎?!更不用說:您還要二三十歲的小伙子來做同樣的事。
那萬一您老了,不幹了~這些二三十歲的小伙子們到了40 幾歲時,他們還要再來一次嗎?
其實,只要我們自己多想遠一點...道理就很明顯了,
只是有時反而是我們自己沒辦法說服自己罷了!--- 不敢去承認自己老了嘛!
怕失去舞台,怕被後生晚輩笑嘛...不是嗎?
嗯...所以我也在想說:我們台灣高科技產業已經開始漸漸的影響我們的下一代了。
回覆刪除那到底是我們自己太過於嚴肅的對待這一件事?!還是真的有那個必要嗎?
因為我們台灣在這一二十年來,有太多優秀的人才在這個行業裡,
搞的東西千奇百怪...隨便您想做的,大概隨便翻一翻都有一缸子的人做的是您曾經想過的。
但是呢?!我們一般工程師們的心態就是會有點見不得別人好,但心裡呢?
卻又想賭一口氣...結果就是我們的一般心態。
但回頭又想一想:我相信賈伯斯應該也不懂得 ADC 的原理或是硬體上與軟體上的細節...
或許就是他不懂,他可以不受這些枝微末節所影響,可以天馬行空的發揮創意。
那到底我們要怎樣的去面對下一代的教育問題?...基礎的東西,我同意~真的要嚴謹以對。
但如果到了工程應用的東西,真的就不要太過流於形式了。甚至用逼的是沒有用的啦!
像我本身是念航空機械的,但後來我有興趣電子,也需要用到電子技術...我當然就會花時間
鑽研這些...當然也因為我不是賈伯斯,我不能用創意去指使別人幫我搞這個,做那個....
有些技術的問題就不得不自己想辦法克服。要不然誰要這麼辛苦,搞了老半天,才發現
網路上面有一缸子的人都有的東西嘛!---- 這也就是我整理寫了這麼多USB 的東西。
就是不希望有太多人花太多時間耗在一些根本沒必要的學習過程。而應該去想更多
創意與發揮更高的系統整合與產品開發工作上。
就像我鮭魚同學搞那台自動錫膏機,人家也沒什麼都得要搞得清清楚楚,
他整台機台的電控硬體與軟體就多花個幾萬元的跟日本買啊...也不需要養EE的人...
東西開發就一年多就搞定了...該給別人賺得,就讓別人去賺...有本事的人就去賺。
但他的經驗就是日本的螺桿,Yaskawa的控制器....您行~您先打敗這些人再說。
----
我們自己都會有一段職場黃金十年,這在十幾年中,您可以好好的鑽研某一項技術,
也可以取得一定的成果與績效。老闆懂,您後來也會懂。
但我們不可能一輩子都會有這一種黃金十年,可以讓您一直學,一直鑽研技術,
在台灣的職場上,老闆更不可能讓您有這一種機會...所以,當您跨越這個黃金十年之後,
您是要如何發揮您黃金十年所累積的,用另一種超越黃金十年的想法與作法,才有辦法創造
自己的人生價值,就像我鮭魚同學,他就可以選擇他自己想做的事,也不用礙著別人(家人),
別人也礙不了他(沒有老闆或奧客!)...那不是很好嗎!?
或許我也真的老了,有太多技術的東西對來說:真的沒那個體力與精力去搞得很清楚了。
但我已經懂得如何去運用資源,換個角度想,如果我的下一代能比我在人生的道路上
更早懂得這一種道理,那不是很好嗎?那又何必逼他去搞清楚這些原理與枝微末節呢?
他只要有興趣,他當然自己就會懂得花時間去鑽嘛!...真的不要太嚴肅的去看待這件事。
否則,只是讓自己更"切心"(台語)的啦!您說:對不對啊?!