摘要:消費類娛樂設備的紅外線(IR)遙控器所造成的混亂狀況似乎已經成為全球每個家庭所關注的問題。利用MAXQ2000微控制器和一些便宜的元器件,可以構建一個能夠“學習”其它遙控器代碼,并根據需要回放這些代碼的遙控器。
但是隨處可見的IR遙控器也導致了一個問題,絕大多數家庭的桌子可能都堆放著三個、四個甚至更多的遙控器。一個用于電視機、一個用于DVR、另一個用于VCR,此外還有用于音響及其它設備的,而且,這里還沒有列出機頂盒或衛星接收機、分配開關、DVD刻錄機及其它受我們支配的設備。
解決這種由遙控器引發的混亂現象的一個方法是:使用可以學習其它遙控器代碼的學習型遙控器。將學習型遙控器設置到“學習”模式,由第二個遙控器“教導”學習型遙控器如何發送命令,比如如何提高音量。然后,每當按下正確的按鍵,學習型遙控器就會發送學到的命令。
本應用筆記介紹如何圍繞MAXQ2000微控制器構建這樣一個學習型遙控器,MAXQ2000屬于Maxim公司的MAXQ RISC微控制器產品。但在開始設計之前,需要了解一些背景知識。
查看大圖(PDF, 388kB)
隨著半導體器件價格越來越便宜,應用范圍的普及,IR紅外光取代超聲成為遙控設備的選擇。最簡單的IR遙控系統由發射紅外光調制信號的終端和接收IR調制信號的基座部分組成,基座電路進行解調,通常是執行某個操作命令。但是,考慮到工程實施的便利性、體積要求以及市場需求等因素,具體實現時并不簡單。
一個很現實的問題是:我們的周圍充滿了IR輻射,要在充滿輻射干擾源的環境中接收一個普通調制信號顯然不現實。任何發熱的物體也會產生IR輻射,比如白熾燈發出的IR光就高于可見光。人體本身也會產生IR輻射。考慮到這些原因,大部分IR遙控器在發射數據之前會以低頻載波(通常在28kHz到60kHz)調制紅外光信號。
在一個典型的家居環境中,用固定頻率調制光信號可以使其在所有IR輻射干擾中更容易檢測到。通過一個簡單的帶通濾波器,可以提取出IR信號并對其解碼。有很多廉價的集成電路都包含實現這一功能的IR光電二極管和帶通濾波器。
產生這樣一個調制光很容易。紅外發射LED器件比較普遍,也很便宜,簡單地利用一個振蕩器驅動IR LED即可產生調制光。調制、接收IR調制數據的電路如圖1所示。
圖1. 電信號被轉換成IR調制光信號,然后又被恢復為電信號。為了擴展發射范圍,采用PNP驅動器。根據所選IR LED可以調整元器件值
當具備LED光源調制和工作在同一頻率的接收IC后,就構成了一個遙控系統的雛形。當LED電路工作在接收范圍內時,接收器輸出有效。如果這就是所有控制的要求(對外圍電路的簡單開關控制),任務就算完成了。
但是,簡單的開關控制還不能滿足實際應用的需求,即使很簡單的遙控器也需要發送不同的命令,比如音量的增、減,頻道選擇,輸入源選擇以及可能的數字輸入。考慮到這個原因,還需要添加其他它電路:可以進一步“調制”光信號。這使整個設計變得有趣。
當IR遙控器的使用不斷普及后,生產商都采用自己的方式調制光信號。雖然都是數字控制(也就是說,調制光信號代表數字位“1”或“0”),不同設計之間卻有很大差異。有些設計采用簡單的非歸零(NRZ)調制,有些則采用脈寬調制(PWM)形式,用長脈沖代表一種狀態,短脈沖代表另一種狀態。還有一些設計采用兩相調制,從開到關的跳變代表一種狀態,從關到開的跳變代表另一種狀態。這種混亂狀況一直持續到現在,構建一個能夠配合任何廠家設備工作的通用型遙控器面臨巨大的挑戰。
另一種比特格式采用固定“光”脈沖,但脈沖之間的間隔是變化的。有些Matsushita (Panasonic?)設備發射800μs的固定脈沖,但脈沖間隔為2,400μs時代表“1”,脈沖間隔為800μs時代表“0”。
Philips的RC-5碼是一種最常用的編碼系統。這種編碼中,每一比特由889μs的調制光脈沖和889μs的間隔組成。如果一個比特表現為“光”脈沖加上一個“無光”周期,則被認為是比特“1”;如果由一個“無光”周期加上一個“光”脈沖組成,則認為是比特“0”。在RC-5系統中,通過強制每幀的兩位起始位為“1”來保證位同步。圖2所示為不同的比特格式。
圖2. 可以用于IR遙控系統的幾種比特格式,所有格式都用載波調制光信號,然后用某種方式調制載波
有些編碼在一幀中發送兩次信息:一次為常規格式,另一次為比特反轉。通過這種方式可以在某種程度上實現初級的誤碼檢查。如果兩次信息不一致,這個命令就被視為無效。
一幀數據發送完畢后,該命令通常會不斷地重復發送。一般幀重復速率在每秒10到20幀。有一些協議只發送一次代碼,然后不斷重復“按鍵按下”的代碼。由于假定每個重復幀都包含數據和定制代碼,所以本文介紹的系統不處理這些協議。
最后,有些協議,包括RC-5,會在每次按鍵操作時反轉比特。這有助于識別是否由于信號丟失造成接收間斷,比如,有人正好位于遙控器和基座之間,或者是否真的出現第二次按鍵操作。本項目中沒有包含這一功能。
因此對于本項目,我們實際上不用關心比特格式或幀格式。因為系統只是簡單記錄并回放它檢測到的一切。保持系統工作的未知性就可以實現真正的通用性。
光電晶體管工作在飽和狀態會產生一個問題。光電晶體管工作速度不高,從完全導通到完全關閉的恢復時間遠遠超過大部分系統的比特周期。因此,如果光信號太強,光電晶體管就會飽和,造成載頻丟失,只能跟隨調制波形的包絡。但是,如果信號太弱,將無法識別波形。圖3顯示了這些條件。
圖3. 在接收IR信號時,信號強度必須合適。如果信號強度太大,光電晶體管就會飽和,此時只能檢測到信號的低頻部分。如果信號強度太弱,載波頻率將無法達到檢測門限
因此,很重要的一點是將主遙控器和學習遙控器放置在適當的距離內。但是距離多少合適呢?為了確定距離,學習遙控器的內置軟件會進行預采樣,以此確定距離是否合適。進行記錄之前,學習遙控器(比如,MAXQ2000微控制器)在輸入通道上對采樣信號進行轉換。如果沒有信號,遙控器假定信號電平太低,并點亮相應的LED。但是,如果微控制器檢測到輸入通道的轉換信號,只是沒有100μs或更小的脈沖(載頻可以假定為大于10kHz),則假定信號電平太高并點亮另一個LED。最后,如果微控制器檢測到以“關斷”周期為間隔的高速脈沖串,則假定信號電平合適,即位于所謂的“最佳點”。學習遙控器的代碼由此轉換到記錄狀態。
記錄狀態期間必須完成幾個操作。遙控器的微控制器必須確定載波的輸入頻率。由于微控制器工作在16MHz,載波頻率(最大)為60kHz,可以精確測量到載頻。從后沿到后沿累計進行四次采樣,然后將結果除以8,以此確定高低電平的周期時間。
然后,接收器開始搜尋大于10ms的傳輸間隔。每個協議都會在重復發送同一編碼之間加入一個間隔,而且任何協議都不容許一個編碼內部存在大于1ms的間隔。找到發送間隔后,接收器可以找到一個編碼序列的開始。由此可以開始記錄。
為了記錄代碼,遙控器的微控制器會累計載波存在的時間。當檢測到載波丟失時,遙控器會累計載波消失的時間。由此可以得到一個通斷時間向量,在需要的時候它可以用來重建信號。
由于這是一個演示設計,并非最終產品,這些通斷時間向量存儲在易失RAM中。在實際產品中,通過軟件例程可以將這些向量復制到非易失存儲器(比如EEPROM)。
按下按鍵后,CPU被喚醒并且開始掃描其輸入引腳,以此確定哪一個鍵被按下。然后它會指向RAM中的向量,RAM中存放有如何執行與此按鍵相關的指令。
RAM向量由以下部分組成:包含通斷周期計數的報頭,代表載頻的數值以及代表每個通斷周期導通和關斷時間的數值序列。第一個報頭數值即通斷周期值存儲在循環計數寄存器(LC1)中。將此值保存在計數寄存器中可以方便地循環任何周期。
報頭中的第二個值即載波周期,換算后進行存儲。發射IR光時,這個數值被載入另一個循環計數寄存器(LC0)。因為MAXQ2000是單周期核,程序的循環定時非常可靠。通過執行四個循環指令就可以產生載波的高電平,然后執行四個循環指令產生低電平。繼續重復這個過程即執行一個導通周期和隨后的關斷周期。
如果沒有定時器,程序會一直照此進行,在一個周期內導通IR LED,然后再另一個周期關斷,以此產生載波。實際上每半個位周期,向量中包含的一個值就會寫入MAXQ2000的一個定時通道。定時器工作在除32模式,所以定時器的精度大概為2μs。
在每個半比特周期的開始,定時器載入該周期的持續時間。然后,當程序代碼使IR LED導通或關斷(在導通周期內)或簡單地使IR LED關斷(在關斷周期內)時,連續檢測定時器就可以確定位周期是否結束。
在超出半個位周期后,循環計數寄存器(LC1)遞減并檢測是否為零。如果不是零,那么就仍有比特要發送,分支程序會回到循環的頂部,否則就要檢測是否按鍵仍然被按下。如果按鍵還是有效,那么整個周期(從向量中讀取初始值并重新初始化計數器)再次開始。否則,CPU會回到睡眠模式直到按下另一個按鍵。
圖4. 增加額外的按鍵功能,按鍵操作必須中斷處理器。在睡眠模式,所有列通過軟下拉電阻保持低電平,所有行驅動至高電平。按下按鍵時,列被拉至高電平,喚醒處理器并且開始行掃描過程
另一項改進是利用MAXQ2000的定時時鐘外設,在特定時刻喚醒CPU并執行IR命令的編程序列。定時時鐘為低功耗外設,可以在電池供電情況下長期工作。當MAXQ2000處于關閉高頻時鐘的休眠模式時,定時時鐘可繼續工作。這個時鐘可以按照某個時刻要求或時間間隔產生中斷,喚醒CPU。例如,定時時鐘可以喚醒CPU,然后遙控器可以將指令發送到電纜或衛星機頂盒,接著發送指令到VCR或PVR,開始錄制節目。節目結束后,CPU可以再次喚醒,以結束錄制。
第三種可能性是將MAXQ2000與個人計算機連接。在這種情況下,PC可以當作節目站,從網絡上下載節目信息,并自動將其載入通用型遙控器。
由此可見,僅僅利用幾個外圍元器件和少量軟件,功能強大的MAXQ2000微控制器就變成了一個通用的學習型遙控器核。
類似文章發表于2007年12月刊的Circuit Cellar。
概述
在眾多家庭中,一個簡單的紅外(IR)遙控器可能占據非常關鍵的地位,這一點也很容易理解。有了遙控器,人們就可以命令現代家庭必備的各種娛樂設備。可以在舒適的房間里,隨心所欲地收看來自全球各地的不同節目,聽到不同渠道傳播的音樂,可以播放音視頻媒體播放器,甚至可以保存節目以便在晚些時候觀看。但是隨處可見的IR遙控器也導致了一個問題,絕大多數家庭的桌子可能都堆放著三個、四個甚至更多的遙控器。一個用于電視機、一個用于DVR、另一個用于VCR,此外還有用于音響及其它設備的,而且,這里還沒有列出機頂盒或衛星接收機、分配開關、DVD刻錄機及其它受我們支配的設備。
解決這種由遙控器引發的混亂現象的一個方法是:使用可以學習其它遙控器代碼的學習型遙控器。將學習型遙控器設置到“學習”模式,由第二個遙控器“教導”學習型遙控器如何發送命令,比如如何提高音量。然后,每當按下正確的按鍵,學習型遙控器就會發送學到的命令。
本應用筆記介紹如何圍繞MAXQ2000微控制器構建這樣一個學習型遙控器,MAXQ2000屬于Maxim公司的MAXQ RISC微控制器產品。但在開始設計之前,需要了解一些背景知識。
查看大圖(PDF, 388kB)
光控
第一個電視遙控器是Zenith? Space Commander。它在工作時通過一個機械結構產生某個特定頻率的超聲波。類似于音叉,通過擊打可以在一個固定可預測的頻率上振動。從理論上講,音叉發出的聲波可以被接收下來,然后轉換成一個執行命令。因為這個最早的遙控裝置完全是機械式裝置,它不需要電池供電。但它只有三個命令,電視開關,頻道號的增、減。隨著半導體器件價格越來越便宜,應用范圍的普及,IR紅外光取代超聲成為遙控設備的選擇。最簡單的IR遙控系統由發射紅外光調制信號的終端和接收IR調制信號的基座部分組成,基座電路進行解調,通常是執行某個操作命令。但是,考慮到工程實施的便利性、體積要求以及市場需求等因素,具體實現時并不簡單。
一個很現實的問題是:我們的周圍充滿了IR輻射,要在充滿輻射干擾源的環境中接收一個普通調制信號顯然不現實。任何發熱的物體也會產生IR輻射,比如白熾燈發出的IR光就高于可見光。人體本身也會產生IR輻射。考慮到這些原因,大部分IR遙控器在發射數據之前會以低頻載波(通常在28kHz到60kHz)調制紅外光信號。
在一個典型的家居環境中,用固定頻率調制光信號可以使其在所有IR輻射干擾中更容易檢測到。通過一個簡單的帶通濾波器,可以提取出IR信號并對其解碼。有很多廉價的集成電路都包含實現這一功能的IR光電二極管和帶通濾波器。
產生這樣一個調制光很容易。紅外發射LED器件比較普遍,也很便宜,簡單地利用一個振蕩器驅動IR LED即可產生調制光。調制、接收IR調制數據的電路如圖1所示。
圖1. 電信號被轉換成IR調制光信號,然后又被恢復為電信號。為了擴展發射范圍,采用PNP驅動器。根據所選IR LED可以調整元器件值
當具備LED光源調制和工作在同一頻率的接收IC后,就構成了一個遙控系統的雛形。當LED電路工作在接收范圍內時,接收器輸出有效。如果這就是所有控制的要求(對外圍電路的簡單開關控制),任務就算完成了。
但是,簡單的開關控制還不能滿足實際應用的需求,即使很簡單的遙控器也需要發送不同的命令,比如音量的增、減,頻道選擇,輸入源選擇以及可能的數字輸入。考慮到這個原因,還需要添加其他它電路:可以進一步“調制”光信號。這使整個設計變得有趣。
當IR遙控器的使用不斷普及后,生產商都采用自己的方式調制光信號。雖然都是數字控制(也就是說,調制光信號代表數字位“1”或“0”),不同設計之間卻有很大差異。有些設計采用簡單的非歸零(NRZ)調制,有些則采用脈寬調制(PWM)形式,用長脈沖代表一種狀態,短脈沖代表另一種狀態。還有一些設計采用兩相調制,從開到關的跳變代表一種狀態,從關到開的跳變代表另一種狀態。這種混亂狀況一直持續到現在,構建一個能夠配合任何廠家設備工作的通用型遙控器面臨巨大的挑戰。
設計參數
在設計一個通用學習型遙控器時,必須要考慮三個參數:載波頻率、比特格式和幀格式。載波頻率
載波頻率就是用來調制光信號的頻率。它與實際比特率沒有任何關系。對于給定系統它是一個固定頻率,頻率范圍在28kHz到60kHz之間,大部分工作在36kHz到38kHz之間。比特格式
比特格式是系統辨別比特“1”和比特“0”的方法,不同廠家會采用完全不同的方法。有時“光”脈沖的寬度是決定因素。有些Sony?設備中利用1,100μs的“光”脈沖代表“1”,用550μs的“光”脈沖代表“0”。脈沖之間的間隔始終是550μs。另一種比特格式采用固定“光”脈沖,但脈沖之間的間隔是變化的。有些Matsushita (Panasonic?)設備發射800μs的固定脈沖,但脈沖間隔為2,400μs時代表“1”,脈沖間隔為800μs時代表“0”。
Philips的RC-5碼是一種最常用的編碼系統。這種編碼中,每一比特由889μs的調制光脈沖和889μs的間隔組成。如果一個比特表現為“光”脈沖加上一個“無光”周期,則被認為是比特“1”;如果由一個“無光”周期加上一個“光”脈沖組成,則認為是比特“0”。在RC-5系統中,通過強制每幀的兩位起始位為“1”來保證位同步。圖2所示為不同的比特格式。
圖2. 可以用于IR遙控系統的幾種比特格式,所有格式都用載波調制光信號,然后用某種方式調制載波
幀格式
一旦確定了比特格式,設計者必須確定幀格式。很多情況下,由同步脈沖(通常比普通脈沖更寬的脈沖)以及具有特定格式的數據位組成。通常數據由兩部分組成:用來傳達所要實現的功能的“數據”和用來與受控設備通信的“定制”數據。因此,用于某個設備的數據內容可能對于另一設備而言代表完全不同的含義。有些編碼在一幀中發送兩次信息:一次為常規格式,另一次為比特反轉。通過這種方式可以在某種程度上實現初級的誤碼檢查。如果兩次信息不一致,這個命令就被視為無效。
一幀數據發送完畢后,該命令通常會不斷地重復發送。一般幀重復速率在每秒10到20幀。有一些協議只發送一次代碼,然后不斷重復“按鍵按下”的代碼。由于假定每個重復幀都包含數據和定制代碼,所以本文介紹的系統不處理這些協議。
最后,有些協議,包括RC-5,會在每次按鍵操作時反轉比特。這有助于識別是否由于信號丟失造成接收間斷,比如,有人正好位于遙控器和基座之間,或者是否真的出現第二次按鍵操作。本項目中沒有包含這一功能。
通用性研究
從上述討論可以看出,通用學習型遙控器為了完成操作需要知道所有的比特格式。如果需要考慮最終的數據組的尺寸,可以注意這個事實:典型的IR遙控器信息只有幾十位。而且目前存儲器價格相對比較便宜,可以僅采樣輸入比特流并記錄這些采樣值。因此對于本項目,我們實際上不用關心比特格式或幀格式。因為系統只是簡單記錄并回放它檢測到的一切。保持系統工作的未知性就可以實現真正的通用性。
接收與記錄
接收電路本身很簡單。一個上拉至VDD的光電晶體管即可構成輸入電路,而且可以直接與MAXQ2000微控制器的輸入引腳相連。實際上,并不需要特殊的接收IC。雖然不需要考慮接收范圍,但卻需要記錄任何載頻的調制包絡。光電晶體管工作在飽和狀態會產生一個問題。光電晶體管工作速度不高,從完全導通到完全關閉的恢復時間遠遠超過大部分系統的比特周期。因此,如果光信號太強,光電晶體管就會飽和,造成載頻丟失,只能跟隨調制波形的包絡。但是,如果信號太弱,將無法識別波形。圖3顯示了這些條件。
圖3. 在接收IR信號時,信號強度必須合適。如果信號強度太大,光電晶體管就會飽和,此時只能檢測到信號的低頻部分。如果信號強度太弱,載波頻率將無法達到檢測門限
因此,很重要的一點是將主遙控器和學習遙控器放置在適當的距離內。但是距離多少合適呢?為了確定距離,學習遙控器的內置軟件會進行預采樣,以此確定距離是否合適。進行記錄之前,學習遙控器(比如,MAXQ2000微控制器)在輸入通道上對采樣信號進行轉換。如果沒有信號,遙控器假定信號電平太低,并點亮相應的LED。但是,如果微控制器檢測到輸入通道的轉換信號,只是沒有100μs或更小的脈沖(載頻可以假定為大于10kHz),則假定信號電平太高并點亮另一個LED。最后,如果微控制器檢測到以“關斷”周期為間隔的高速脈沖串,則假定信號電平合適,即位于所謂的“最佳點”。學習遙控器的代碼由此轉換到記錄狀態。
記錄狀態期間必須完成幾個操作。遙控器的微控制器必須確定載波的輸入頻率。由于微控制器工作在16MHz,載波頻率(最大)為60kHz,可以精確測量到載頻。從后沿到后沿累計進行四次采樣,然后將結果除以8,以此確定高低電平的周期時間。
然后,接收器開始搜尋大于10ms的傳輸間隔。每個協議都會在重復發送同一編碼之間加入一個間隔,而且任何協議都不容許一個編碼內部存在大于1ms的間隔。找到發送間隔后,接收器可以找到一個編碼序列的開始。由此可以開始記錄。
為了記錄代碼,遙控器的微控制器會累計載波存在的時間。當檢測到載波丟失時,遙控器會累計載波消失的時間。由此可以得到一個通斷時間向量,在需要的時候它可以用來重建信號。
由于這是一個演示設計,并非最終產品,這些通斷時間向量存儲在易失RAM中。在實際產品中,通過軟件例程可以將這些向量復制到非易失存儲器(比如EEPROM)。
回放
當完成按鍵編程后,CPU進入休眠模式。在這個模式下,依然保持寄存器和RAM值,但會停止CPU時鐘。只有中斷(或復位)可以喚醒CPU。按下按鍵后,CPU被喚醒并且開始掃描其輸入引腳,以此確定哪一個鍵被按下。然后它會指向RAM中的向量,RAM中存放有如何執行與此按鍵相關的指令。
RAM向量由以下部分組成:包含通斷周期計數的報頭,代表載頻的數值以及代表每個通斷周期導通和關斷時間的數值序列。第一個報頭數值即通斷周期值存儲在循環計數寄存器(LC1)中。將此值保存在計數寄存器中可以方便地循環任何周期。
報頭中的第二個值即載波周期,換算后進行存儲。發射IR光時,這個數值被載入另一個循環計數寄存器(LC0)。因為MAXQ2000是單周期核,程序的循環定時非常可靠。通過執行四個循環指令就可以產生載波的高電平,然后執行四個循環指令產生低電平。繼續重復這個過程即執行一個導通周期和隨后的關斷周期。
如果沒有定時器,程序會一直照此進行,在一個周期內導通IR LED,然后再另一個周期關斷,以此產生載波。實際上每半個位周期,向量中包含的一個值就會寫入MAXQ2000的一個定時通道。定時器工作在除32模式,所以定時器的精度大概為2μs。
在每個半比特周期的開始,定時器載入該周期的持續時間。然后,當程序代碼使IR LED導通或關斷(在導通周期內)或簡單地使IR LED關斷(在關斷周期內)時,連續檢測定時器就可以確定位周期是否結束。
在超出半個位周期后,循環計數寄存器(LC1)遞減并檢測是否為零。如果不是零,那么就仍有比特要發送,分支程序會回到循環的頂部,否則就要檢測是否按鍵仍然被按下。如果按鍵還是有效,那么整個周期(從向量中讀取初始值并重新初始化計數器)再次開始。否則,CPU會回到睡眠模式直到按下另一個按鍵。
增強遙控功能
到目前為止我們已經得到了一個基本的學習型遙控器,但它只有兩個按鍵。改善這個設計的顯著需求是增加更多的按鍵功能。增加按鍵很簡單,僅需增加少量的硬件電路。當CPU空閑時,所有的行驅動器將輸出置為邏輯“1”,每一列的軟下拉(即高阻)使得這些輸入在空閑狀態時為低電平。當用戶按下任意按鍵時,相應列被驅動至高電平,喚醒CPU (圖4)。CPU可以將每一行置為高電平,每次一行,由此判斷按鍵所在的行和列。圖4. 增加額外的按鍵功能,按鍵操作必須中斷處理器。在睡眠模式,所有列通過軟下拉電阻保持低電平,所有行驅動至高電平。按下按鍵時,列被拉至高電平,喚醒處理器并且開始行掃描過程
另一項改進是利用MAXQ2000的定時時鐘外設,在特定時刻喚醒CPU并執行IR命令的編程序列。定時時鐘為低功耗外設,可以在電池供電情況下長期工作。當MAXQ2000處于關閉高頻時鐘的休眠模式時,定時時鐘可繼續工作。這個時鐘可以按照某個時刻要求或時間間隔產生中斷,喚醒CPU。例如,定時時鐘可以喚醒CPU,然后遙控器可以將指令發送到電纜或衛星機頂盒,接著發送指令到VCR或PVR,開始錄制節目。節目結束后,CPU可以再次喚醒,以結束錄制。
第三種可能性是將MAXQ2000與個人計算機連接。在這種情況下,PC可以當作節目站,從網絡上下載節目信息,并自動將其載入通用型遙控器。
由此可見,僅僅利用幾個外圍元器件和少量軟件,功能強大的MAXQ2000微控制器就變成了一個通用的學習型遙控器核。
類似文章發表于2007年12月刊的Circuit Cellar。
評論
查看更多