至少有兩個因素表明轉向功能更強大的處理器并不一定意味著需要占用更多比特。隨著應用程序的成熟,功能強大,功能特定的處理器或引擎可用于承擔大部分繁重的工作。例如,使用MP3播放器,您可以購買完整的數字音頻解碼引擎。您只需要一個用戶
接口和PC的I/O接口,可以充實您的數字播放器。 8位處理器可以有效地處理這些功能。而且,對于需要更多功能的任務,您可能會驚訝于那些小型8位處理器已經成為40-MHz時鐘,可擴展程序存儲器,向量中斷表,浮點庫,C編譯器的強大工具,和外圍設備的范圍。您可能會發現選擇使用較少位的處理器可以更好地幫助您滿足成本和性能限制,同時節省空間。
我花了10多年的時間在工業控制應用程序中使用16位和32位x86組裝。對于這個動手實踐的項目,我想看看我所有的16/32位偏差會讓我們后退并使用8位處理器進行設計。畢竟,因為處理器不那么復雜,設計過程應該更簡單,不應該嗎?
一個人的愚蠢錯誤往往會產生最好的學習材料。因此,一些設計經驗可能有點令人尷尬。幸運的是,總是存在這樣的安慰:在完成這個項目之后,我不再是那些犯了這些錯誤的程序員。如果你正在考慮轉向8位處理器,那么閱讀這個項目可能會讓你免于我所遇到的一些痛苦和痛苦。
項目
對于我的項目,我決定制作一個音序器。我的一些工程師和我最近發現了“Cool-Neon”,也稱為電致發光線(參考文獻1)。您可以使用逆變器將9V電源轉換為300V交流電,從而驅動電線以創建多色光雕塑。我們首先建造了一條二維魚,我們可以騎在自行車上,創造一個游泳魚群的幻覺。對于我們的下一代項目,我們需要一個可以循環通過光線模式的音序器,為移動的雕塑或電子萬花筒創造一種運動的幻覺,其中不同時間點亮的不同光束代表短幀和循環動畫中的幀序列
8位處理器似乎非常適合這個項目。我需要一個輸出引腳來驅動每根導線;對于10股容量,我需要10個引腳。一個按鈕(使用另一個引腳)將允許某人循環通過模式選項。在功能列表中,我快速添加了傳感器的輸入。例如,放置在自行車車輪周圍的傳感器可以基于外部事件而不是內部計時器來觸發模式。決定使用Microchip的PIC系列產品,我發現18引腳封裝處理器有13個I/O引腳,所以我有一個引腳備用,但不會長時間保留備用。
資源有限:記憶
您通??梢酝ㄟ^在更強大的處理器上投入資源(如內存,處理和I/O)來解決問題。然而,由于配置的多樣性,8位世界中的家庭成員之間的差異可以直接節省成本。例如,具有2千字節板載內存的處理器成本低于4千字節的處理器。我記得有64千克的銀行可用;你可以通過使用一個大表來加速一個關鍵的計算 - 一個可行的,有時是至關重要的選項來燃燒記憶。
早期,我做了什么才能成為我的音序器的關鍵設計決策。我沒有用1位(10個燈等于10位)表示活動燈,而是創建了一個10字節長的表,其中包含適當邏輯光的物理端口代碼;也就是說,I/O端口A上的指示燈1 =位3)。我制作這張桌子是因為,當我測試是否填充了燈光時,我必須計算物理端口。當時,存儲這個預先計算的值似乎更容易。鑒于我的心態,這個選擇是明智的:在開始時(主處理循環之外)執行一次計算,并在每次稍后使用計算時保存那么多循環。
不幸的是,這個選擇很糟糕。首先,定序器將大部分時間花在輪詢循環中,等待按鍵是否被按下或是否已觸發定時器。因此,在輪詢循環中,我節省了幾個周期(最多10個燈,10個指令= 100個周期)。其次,更重要的是,我使用了比我需要多8個字節的RAM。我習慣丟掉數百字節的填充緩沖區來覆蓋可能出現的最壞情況。但是,當8個字節幾乎占總數據存儲器的八分之一時,這是一個糟糕的決定。
在我用完數據存儲器之前,我沒有意識到這種選擇的重要性。我添加了一個變量,程序無法運行,因為另一個變量被推入未定義的0xFF區域。我的項目似乎沒有足夠的復雜性來使用這么多的內存,但是當我添加更多功能時,我忘了留意內存。當我努力恢復字節時,擊中數據存儲器的頂部使我的開發暫時停止。然后我犯了一個愚蠢的錯誤,即偶然試圖加倍臨時變量。例如,某些函數需要循環計數器。但是,您可以使用這些循環計數器來計算除這些函數之外的其他內容。為了完成這項工作,我需要嚴格控制變量的范圍,以確保一個函數不使用相同的變量調用另一個函數。
我的第一個直覺指示我只給一個雙重任務變量一個名字。我可以想象調試的噩夢是沒有記住兩個不同的變量實際上是相同的變量并相互改變。至少如果他們有相同的名字,如果我不小心違反變量的范圍,我就有更好的機會抓住自己。
當我嘗試按范圍對變量進行分組時,我了解到在整個程序中使用變量之前我可以更輕松地執行此任務。例如,變量Temp具有直接范圍,這意味著如果函數調用另一個函數,則第一個函數應該假定Temp被銷毀。另一個極端是系統或全局變量,例如Flags,所有函數都可以使用。然后是灰色區域。例如,循環計算當前正在處理燈光模式中的哪個步驟。因為一次只能執行一個模式,所以每個模式函數都可以使用Cycle。此外,當用戶編輯用戶可編程模式時,沒有預定義模式正在運行,因此您也可以在此處使用Cycle。但是,當我想在編輯時顯示用戶可編程模式時,我確實存在潛在的范圍違規。我必須在顯示之前存儲Cycle并在編輯后恢復它,或者我可以讓用戶通過在他或她想要編輯的周期停止顯示來重置Cycle,這是我實現的選擇。
在這種情況下存儲Cycle會需要一個全局變量,因為顯示一個模式使用了主程序循環,但是為此目的專用變量會使變量首先加倍。我也可以選擇實現數據堆棧。在16位和32位的世界中,堆棧是一個方便的朋友。但是,我使用的微處理器只有一個內部堆棧用于程序地址。 (我確信有一些方法可以欺騙處理器來存儲數據,但只有8個級別,如果我想保存多于一個或兩個值,我會冒著堆棧的風險。)堆棧至少需要一個額外的字節用于尾部管理,你必須緩沖他們最壞情況下使用。我避免實現堆棧,因為我認為我的值太少而無法保存。
變量的范圍對于通過加倍使用變量來跟蹤和創建變量的依賴性至關重要。這項任務應該是一個謹慎的決定。我試圖將變量劃分為功能塊,但是,即使仔細規劃,似乎總是可以同時使用兩個塊,因此也就是所有變量。然后我會發現自己正在追逐自己造成的錯誤。
一旦您決定將處理器放在電路板上,您就有可能顯著降低處理器的成本。當你發展時,給自己一些重新編程的空間是有意義的;但是,您可能會發現自己只需幾個字節就可以將設計融入更便宜的處理器中。較便宜的選項并不總是等價的,并且會影響開發,因為它們定義了內存和性能閾值。通過在開始開發時而不是在完成開發時了解這些閾值,您可以確定限制可用資源的緊密程度。無論如何,你可能永遠不會雇用一個字節作為一個角色。
資源有限:處理
由于“功能蠕變”-extra功能使設計復雜化并拋棄計劃 - 繼續為順控程序添加選項和增強功能,我意識到我可能也會在程序內存中占據優勢。在16位和32位的世界中,我經常為一個問題投入內存以減少總計算時間。我發現自己正在使用我的音序器進行反向權衡。
當我設計用戶可編程模式(存儲在EEPROM中)時,我使用位來表示每個光。但是,10位是1字節,剩下2位,您可以打包成四個組以完全使用另一個字節。這個決定產生了一個問題,因為模式將以與我用來打開燈光的格式不同的格式存儲。 (EEPROM格式使用邏輯格式來跟蹤被點亮的燈:點亮零到九。燈格式使用物理格式:每個端口一個字節,A和B,每個位代表相應的I/O引腳,由于板布局考慮而無序。)存在兩種格式,因為物理格式是用于驅動輸出端口的實際掩碼。但是,物理格式使用16位而不是像邏輯格式那樣僅使用10位。因此,我需要一個轉換函數。
我通常會同時寫兩個轉換函數的方向。為了最大限度地減少總處理周期,我將EEPROM邏輯格式轉換為光/物理格式。當用戶編輯模式的這個循環時,我將制作并顯示光/物理格式的變化。當用戶完成編輯此循環后,我會將光/物理格式轉換回EEPROM/邏輯格式并保存循環。
我決定轉而支持內存而不是處理性能。通過直接更改EEPROM/邏輯格式,我可以調用轉換函數來創建光/物理格式并顯示修改后的周期。每次運行此轉換需要更多的處理周期,但同樣,這些周期僅來自輪詢循環。我獲得了廢除逆轉換函數的選項,因為它從未被調用過。因此,我節省了程序內存和一些開發時間。我還獲得了將所有更改立即保存在EEPROM中的好處,使我無需在用戶移動到新周期時管理保存更改,想要顯示模式,左編輯模式等等。
計時器
在我的問題上投擲處理能力而不是記憶力幾乎適用于我。 PIC16F84有一個內部定時器TMR0,粒度為256個周期,預分頻器大小為2 8 (256×256 = 65,536個周期)。在沒有預分頻器的情況下運行,每256個周期發生一次TMR0中斷。因為我將每個模式的循環連接到TMR0,所以每個循環必須在256個循環內完成執行,或者在完成處理最后一個循環之前我會遇到TMR0事件,偶爾在模式期間丟失一個循環。增加預分頻器可以選擇將TMR0間隙增加2倍,以防止超出。通過盡可能多地處理中斷以避免中斷處理期間的中斷延遲,保持中斷處理程序的清潔和簡單也很重要。
我使用電位計讓用戶調整音序器的速度。鑒于你需要在模式的周期之間進行一點處理,我選擇使用RC時鐘而不是晶體。這個決定節省了晶體成本,系統復雜性和I/O引腳;電位計驅動RC時鐘,而不是告訴PIC應該運行多快,并在內部管理這個速度。如果我想讓兩個序列發生器相互通信,我將不得不創建一個連接兩個節點的協議,這些節點具有獨立且可能變化的時鐘速度。
我想要幾種速度選項 - 從幾分之一到幾秒 - 用于循環模式。電位器給了我一個范圍,所以我創建了兩個用戶可選擇的速度區域,為TMR0使用了不同的預分頻器。我的設計最初支持三個區域,但有兩個簡化的用戶選擇,將速度參數切換為1位,并簡化了TMR0事件的內部管理。
預分頻器3(2 4 = 16)和4(2 5 <之間的差異/sup> = 32)可以變寬,特別是RC時鐘被調到5和50 kHz。當我的設計支持三種模式時,我發現添加(TMR0_COUNT預分頻器讓我可以更好地控制中斷。如果你用一個10-MHz時鐘運行PIC,你可能會發現這個額外的預分頻器讓你測量有用的時間長度。
調試
鑒于要重復這個項目,我會獲得一個用于軟件開發的模擬器。嘗試解決困難編程所節省的時間很快就會彌補費用。相反,我非常依賴MPLAB模擬器。
模擬器的運行速度比我預期的要慢得多。有時,我認為系統已經凍結,因為它努力到達我的斷點。有時候,我引起了一個延遲,例如當我在輪詢循環后將斷點放在代碼中的某個點時,模擬器卡在輪詢循環中等待我響應。我的設計有一個短于256個時鐘的主循環,所以我可以快速測試迭代和情況。以10 MHz運行的設計可能有更長的主循環或更多的輪詢。
我發現使用Define創建模擬器標簽很有用。在真正的董事會上,我想要真正的延遲。但是,通常沒有理由在模擬器中的輪詢或延遲循環中永遠等待。例如,我有一個Flash功能,可以閃爍特定的線W次。在模擬器中,我沒有必要“看到”這種閃爍。因此,我添加了以下代碼以跳過無用的函數和速度模擬:
TMR0也觸發了事件。我將所有延遲量命名為常量,以便我可以將所有模擬器常量設置為零。我還添加了一些代碼來模擬按鈕按下或其他事件。有時,等待TMR0中斷變得令人難以忍受。在我的輪詢循環中,然后,我添加了僅模擬器代碼,它將設置我的TMR0事件標志(然后將TMR0重置為零,以便最終不會觸發我)。
模擬器代碼的另一個有用位置是中斷處理程序的開頭。我的中斷處理程序足夠短,可以將它留在代碼的前面,而不是調用放在內存中其他地方的函數,這會增加中斷的延遲。但是,當我模擬輸入時,會調用一個中斷,我不得不單步執行所有中斷代碼。我添加了代碼:
此代碼創建了一個調用,我可以用鍵擊來代替。
我通常發現MPLAB環境包含很多很好的功能,但是我很痛苦地追逐一個接口問題。例如,我想測試需要按兩次按鈕才能到達的代碼。 MPLAB有一個“激勵模擬器”窗口,通過它我可以激活輸入端口。不幸的是,當刺激窗口打開時,模擬器的運行速度明顯變慢,所以我通常不得不關閉窗口并在幾秒鐘后重新打開它。選擇刺激時鐘似乎比它值得更麻煩,因為我必須弄清楚我希望輸入觸發的時鐘周期。通過查看合適的輸出引腳,我也可以看到燈是否亮起。但是,對于任何復雜的輸出序列,驗證準確的反饋可能很困難。
與MPLAB環境一樣有用,我建議您訪問一個快速而骯臟的開發環境,例如Basic,來測試算法。例如,微芯片應用筆記庫中的隨機數生成器功能似乎在0到255的值中具有不均勻分布的數字。由于存儲器限制,在Microchip環境中測試此功能似乎很困難。例如,如果我有256字節的RAM,我可以很容易地計算很長一段時間內的分布。然而,如果不到40H字節,我將不得不想出一個聰明的計數方案,并且可能會多次運行我的模擬以確定傳播是均勻的。在Basic中,我可以在幾分鐘內彈出這段代碼并幾乎立即看到結果。
我遇到了其他令人沮喪的錯誤;如果我使用了模擬器,我會節省數小時的調試時間。
因為我使用了可重新編程的設備,所以我不得不將設備插入板中以及從板中取出設備以將其放入設備編程器中。我在電路板上有一個插座,但是將設備插入插座意味著我必須將插座插入插座中,從而產生松動且因此不良的電氣配合。我最終在一臺設備上打破了領先優勢,使其無用。我還需要偶爾向外彎曲引線,因為向內彎曲的引腳連接不良,I/O引腳會神秘地停止工作。使用模擬器可以消除我的大部分套接字問題。
我安裝了一個新的逆變器,可以驅動比我當前的逆變器更多的電線,從而使我能夠同時點亮幾根電線。雖然設計是在程序模式下,但我會閃現一條線來代表一個參數。參數One工作正常,但參數二不會閃爍。因為我專注于用戶可編程模式并禁用了其他參數,所以我認為我的一些更改可能會改變代碼的閃存能力 - 通過使用變量。經過大約一個小時的追逐幻象代碼錯誤后,我終于將問題縮小到了實際的電線,除非我點亮另一根電線,否則我無法關閉。突然間,我意識到新的逆變器可能是問題所在。當我連接舊逆變器時,電線正確閃爍。
出現問題是因為逆變器傾向于保持電線點亮;一些導線 - 但不是其他導線 - 超過驅動導線的三端雙向可控硅開關中的相位間隙。我通過代碼搜索,因為一根電線工作,而另一根沒電。我懷疑是一個邏輯問題,并且忽視了導線出錯的可能性,因為它之前一直有效。使用模擬器,我會看到端口已經變低,我正面臨硬件,而不是邏輯問題。我還了解到,當我使用新設備進行測試時,我應該檢查一下,在更改硬件之前是否存在先前設置中存在的錯誤。
值得一提的是,我保持了“健全性” - 使用舊版本代碼刻錄的幾個芯片。每當原型開始變得怪異時,我就會放入其中一個完整的燒傷。如果原型工作,那么我的最新版本的代碼已經破壞了一些關鍵的東西。如果健全性刻錄無法正常工作,則硬件會出現諸如斷線之類的問題。
電源問題引發了一系列令人討厭的錯誤。我最初使用壁式電源為我的原型供電。但是,我得到了一些奇怪的閃爍,我很快就將其評估為電源問題。由于電路板應使用9V電池供電,因此我切換到電池供電。然而,點亮的電線消耗大量電力。我還做了一個不幸的假設,即當電池電量太低時我的電線就會死掉。 PIC實際上首先變得缺電,然后行動不穩定。我在追逐想象中的錯誤一天之后才發現了這個事實。使用新電池可以處理所有事情。我希望在嘗試查找錯誤并注釋掉部分,設置不必要的調試掛鉤等之前保存了特殊版本的代碼。
為了避免電池問題,我回到墻上供應。然后我發現閃爍不是由電源引起的,正如我所假設的那樣。 (墻上插座給了我足夠的力量來看到我的弱電池上的閃爍。)相反,這是我在設置下一個周期之前短暫關閉燈并顯示它們的問題。我將代碼更改為只是從一個循環移動到另一個循環而不顯示其間的所有燈。奇怪的閃爍消失了。
我創建的另一個原型錯誤涉及使用重置按鈕。我在面包板原型上添加了一個復位按鈕,這樣我就可以輕松地重置電路板而無需進行物理斷開,然后重新連接9V電池。模擬器可以提供相同的功能。但是,最終產品沒有重置按鈕。使用原型,當我想離開程序模式時,我會按下重置按鈕重新啟動電路板。然而,這種復位不是全功率復位,這意味著標志和存儲器沒有被清除;在這種情況下唯一重大的變化是程序計數器重置為0x00。當我最終轉移到真正的用戶所擁有的制造原型時,我通過關閉然后再打開電路板離開編程模式,但是電路板沒有注冊我的更改。出現此問題的原因是斷電復位也會清除內存。
我列舉了這些例子,因為它們說明了使用原型的一些危險。一方面,你需要一個干凈的環境來開發,所以你不會追逐幻影。您還希望訪問所有硬件,并且應該能夠隨意進行探測。另一方面,您需要使用與客戶相同的硬件來查看實際發生的情況。
時滯
當我炸掉我唯一的控制器時,我遇到了開發周期中最大的延遲之一。我首先訪問Microchip的網站以獲得更多芯片。最快的送貨服務是三天,這意味著我只能使用模擬器進行開發。我找到了多個銷售PIC芯片的互聯網網站,并且可選擇更快的交付。雖然其他站點提供了有限的PIC選擇,但我確實找到了PIC16F84,這是很好的開發,然后計劃換成更便宜的芯片。鑒于PIC微處理器的普遍可用性,我購買了一些零件而無需與經銷商建立關系。我還學到了庫存的第一條規則:有一些。當出現問題時,您的時間和產品的上市時間應該得到一些額外部件的保險。
延遲的一個更具破壞性的因素是特征蠕變。在我完成基本功能之前,我已經決定了一系列新功能,例如用戶可編程模式,這些功能已經進入規范。我為需要非標準模式的專家用戶構思了用戶可編程模式。這些模式還需要與項目其余部分一樣多的編碼開發時間。突然之間,由于我努力解決專家代碼中的錯誤,上市時間受到了沖擊。具有諷刺意味的是,beta測試人員對用戶可編程模式不感興趣。換句話說,如果我關閉了規范并將專家功能推遲到第二版(參見附文“經典混音和錯誤”),我本可以更快地將測試板交付給beta測試人員并測試音序器的基本穩健性。
殺手NOP
每當我得到一個新工具時,我總會感到興奮。安裝后,我要做的最后一件事是特別注意說明。我已經閱讀了足夠的內容以便開始,然后向我保證我會返回并稍后完成。
早期,當我嘗試實現演示模式時,我發現了一個奇怪的問題:電路板只能點亮六盞燈。當我刪除代碼時,電路板工作正常。此時,我開始重新編寫代碼片段,每次測試電路板時都會進行測試。最后,除了一段代碼之外的所有代碼都重新進入。當我注釋掉代碼時,電路板運行了。奇怪的是,只有按下按鈕才會執行此代碼。不知何故,我想,事件是錯誤地觸發的。當我刪除除了Goto和Return之外的所有代碼時,代碼工作正常。添加CLRF標志會導致失敗。但是怎么樣?然后,我決定添加非操作(NOP)指令而不是CLRF標志。隨著NOP,董事會失敗了。如果沒有NOP,代碼就會運行。
當NOP指令導致嚴重錯誤時,通常意味著存在內存誤解。果然,我的一張桌子越過100H邊界,因為我慢慢地在它前面添加了程序代碼。在這種情況下,出現問題是因為表地址變為9位長; 14位PIC指令可以容納Goto地址的額外位,但它們會丟棄算術指令的第9位和第10位,例如Add。因為我測試的代碼長5個字節,所以表超過了4個字節。 (因此,在光7之前只有六個燈顯示PIC設置為00H(復位)而不是100H。)
我通過將所有表移動到代碼部分的前面然后仔細閱讀指令集來解決問題,以查看是否有任何更多的命令具有匯編程序無法捕獲的偷偷摸摸的細微差別。后來,當我閱讀John Peatman的使用PIC微控制器進行設計時,我發現將表放在存儲器前面是PIC的標準做法,因為這個原因(參考文獻) 2)。我快速閱讀,看看是否還有其他標準做法我應該遵循。在中斷區域,這本書給我帶來了很大的悲傷。例如,在16位和32位的世界中,標志會自動保存,并且有一個堆棧來保存寄存器。使用PIC系列,您必須自己保存標志,但首先必須以一種棘手的方式保存累加器(使用Swap)而不影響標志(清單1)。我發現disable-interrupt命令特別具有欺騙性。由于PIC具有兩級流水線,因此如果中斷因此與請求禁用中斷同時發生,則會出現問題。 PIC根據您的指令清除中斷標志,然后執行掛起中斷。當您從中斷返回,從而啟用中斷標志時,即使您認為剛剛禁用了它們,也會在主代碼中啟用中斷(清單2)。
最后,我發現PIC規格表雖然技術上已經完整,但需要一些澄清。至少買一本像皮特曼這樣的書。他建議一個強大的編程結構,可以幫助您避免許多問題。然而,他的問題部分讓我煩惱,因為你必須提前閱讀一兩章才能最終發現答案。在任何情況下,在您發現之前閱讀本書,與大多數錯誤一樣,您無法理解架構的細微差別。
你可能會問35條指令有多復雜。不幸的是,減少的指令集實際上導致更復雜的程序。對于一個簡單的類比,想象一下,我試著寫這篇文章而不使用字母T.較少的單詞構成一個不太復雜的詞匯,但可用的單詞較少意味著說某些事情需要更長的時間。例如,高階語言具有復雜的詞匯表,可以讓您在一條指令中描述復雜的匯編任務,例如打印或乘法。使用精簡的指令集,例如PIC系列的指令集,即使是簡單的函數,例如位移,也會變得更加復雜。例如,x86的程序集提供了諸如旋轉而不進位和旋轉CL次等命令(清單3)。當我需要將比特封裝的位移實現到這個項目時,我不得不考慮這個過程。沒有旋轉 - 不進位指令,所以在右旋轉的情況下,我必須在每次旋轉之前將進位標志設置到最右邊的位置。
創建比特移位等功能并不困難;但是,你仍然需要創建它們。如果您從未在此級別工作 - 例如,如果您始終有可用的打印指令 - 創建基本功能庫可能需要一段時間。您還會發現,第一次嘗試時,您可能無法確定實現功能的最有效或最靈活的方式。因此,我的項目花費的時間比我想象的要長,因為我編寫了“基本”函數,我習慣于在不太復雜的16位和32位架構中實現這些函數。
我還發現,盡早構建我的基本功能庫可以提高我布置音序器架構的能力。例如,一旦我編寫了用于讀寫EEPROM的基本功能,我開始將EEPROM視為一種資源,而不僅僅是我后來需要編寫代碼的東西。這種觀點的改變促使我考慮創建在斷電后保持設置的靜態用戶參數的想法。 EEPROM還打開了一組可用的數據存儲器,訪問速度要慢得多,但可以想象我會忘記內存堵塞。
硬件/軟件斷開連接
在我編程16位和32位架構的過程中,我一直使用完整的硬件系統;也就是說,我在PC或已經設計,打印,填充和測試的電路板上工作。在這些條件下,我的首要任務之一是確定新功能的可行性。通常,您可以在軟件中實現任何功能,因為該功能滿足處理速度,內存和接口的限制。如果不是這三個限制,8位μP可以執行視頻會議,雖然速度很慢。一旦我確定我有足夠的處理能力,并且我可以在必要時實時執行任務,足夠的內存和正確的接口,我會編寫該函數。
然而,在這個項目中,我是構建電路板的設計團隊的一員。雖然我的硬件技能有限,但我提供了一個在代碼中可以合理實現的視角。也就是說,包含PIC無法有效處理的硬件接口將是荒謬的。該團隊開發的一項功能是自動檢測電路,確定端口是否實際連接到電線。如果沒有這樣的電路,PIC就無法知道用戶想要點亮和循環多少根導線,除非他每次給電路板加電時輸入該值。相比之下,由于帶有電位計的RC電路為PIC提供時鐘,因此PIC永遠不會知道它的運行速度。 (PIC的設計人員認為此功能不是必需或有用的。)
請注意,在我們支付第一批電路板之前,我們沒有鎖定硬件規格??紤]到產品上市時間的壓力,即使我們仍然需要編寫代碼,我們也會將電路板放到屏幕上進行篩選。我們完成了足夠的代碼來滿足團隊需求,硬件按照我們的預期運行,但是我們還沒有把所有的花里胡哨都用到了。
一旦我們鎖定硬件規格,整個設計氛圍就會改變:硬件和軟件之間發生斷開連接。到目前為止,硬件設計是瓶頸。軟件隨時準備好等待測試電路板。一旦我們完成硬件,軟件突然成為瓶頸。此外,我們不再討論我們在硬件或軟件方面可以做些什么;現在,這是所有的軟件。硬件團隊離開了項目,因為沒有人能做到。任何硬件“問題”,例如I/O引腳反轉或引腳布局,現在都是軟件問題。令人沮喪的一天,當硬件團隊努力解決地面問題時,他們宣稱董事會已經完成并走開了,留下了一個未能運行與會話開始時相同代碼的原型。我發現,有人將輸入按鈕反轉為驅動低而不是高,但沒有給我這個信息。
此外,每個人都對如何改善董事會的職能有很好的想法,這也帶來了另一個挑戰。我們擁有簡單的硬件基礎,為軟件提供了極大的靈活性現在我在槍口下,規格變化和特征蠕變成了流行病。存在兩類規范更改:功能更改以及如何向用戶(接口)提供這些功能的更改。在這兩者中,設計師通常認為界面變化更簡單,但實際上它們更難。例如,音序器沒有顯示,只有兩個按鈕。經過一些反思,我們意識到我們可以使用線本身來向用戶傳達信息,所以我現在有一個原始的10位顯示器。但是,我還必須創建一個用于“打印”到此顯示的函數庫。只有兩個按鈕創造了在用戶可編程序列模式下嘗試為多達10個命令提供用戶訪問的挑戰。我們提出了一個擴展移位鍵的想法;也就是說,按住一個按鈕,同時反復按下另一個按鈕。盡管該計劃允許我們訪問許多功能,但它在按鈕事件的評估中產生了復雜性。最初,當按下按鈕時,我標記了按鈕1或按鈕2事件?,F在,我仍然不得不支持這個機制來編寫我編寫的代碼,同時創建一個計數按鈕2按下的移位狀態并觸發按鈕1的釋放。鑒于我必須在模擬環境中調試此問題,擴展移位起到中斷的作用,并且我必須支持觸發事件的舊方法,這個函數是我設計中最復雜的部分。
PIC匯編語言最令人煩惱的一個方面是你必須記住位組合。例如,PIC16F84的文檔說您可以在累加器W(0)或正在使用的文件寄存器(1)中存儲計算?;蛘呤侵車钠渌绞?直到我讀到Peatman的書時,我才意識到,在F84包含文件中,PIC的設計者已經為你設置了W = 0和F = 1的常數。
使用常量和宏來簡化代碼的誘惑誘惑了我。對于W/F區別,使用常量是有意義的。但是,我猶豫是否盡可能使用宏。例如,我發現自己總是被SUBLW和SUBWF拋棄。首先,助記符是不一致的:SUBLW從文字(LW)中減去W,SUBWF從F中減去W(應該是SUBWF?)。我一直不得不回到手冊來說明問題。此外,在比較期間使用減法設置標志始終需要仔細檢查。在x86匯編中,標志JA(如果在上面跳轉),JB(如果在下面跳轉)和JZ(如果在零時跳轉)清楚地定義比較后的動作。這些命令在一條指令中測試零和進位標志。您還可以使用PIC(清單4)在一條指令中測試高于,低于和零。但是,您必須在從A減去A或從A減去A以僅檢查進位標志而不是零標志。 (交換順序會改變進位標志是否占零情況。)
我考慮編寫一個宏來進行比較,但是認為這個任務可能變得復雜,因為值可能是數據或常量,因此需要MOVLW或SUBLW。另外,我考慮了宏的一個有害的副作用:它們創建“專有”命令。專有命令的問題在于,有人閱讀代碼最初會發現它們令人困惑并且必須學習它們。此外,您在其他應用程序中編寫代碼時會遇到問題,因為某些原因您無法使用宏,或者必須使用其他人的代碼。
Microchip可以通過管理標準宏庫來簡化該領域的開發。例如,幾乎每個程序都使用比較宏(參考文獻3)。如果您使用標準宏庫,宏將成為整個行業的命令,而不是程序員之間的絆腳石。在其辯護中,Microchip確實提供了一個令人印象深刻的應用筆記庫(參考文獻4),展示了程序員如何在PIC??上實現各種功能。但是,需要花時間對這些筆記進行分類,讓我自己通過自己開發代碼來節省時間。
在盒子外面思考
我們在將音序器投入生產時學到的最重要的一課是設計不是一個線性過程。團隊通常分為功能組:硬件;軟件;包裝,制造和測試;等等。不幸的是,設計依賴性不那么整齊。例如,包裝被證明是一種粗魯的覺醒。塑料盒似乎比電路板成本更高,我們必須將大部分元件安裝在電路板的背面,以使電路板適合我們選擇的現成的??盒子。設計的每個階段,無論其看似簡單,都對其他階段具有依賴性和影響。如果我們在急于制造電路板之前已經看過盒子,我們可以用不同的外形設計電路板并擴大我們可能的盒子選項。
總而言之,這種經歷啟發了我們。我天真地認為編碼只需要幾天時間,所以我對我們超出預計時間表的時間感到震驚。當然,我們每個人都有其他全職工作和個人生活。但是,我嚴重低估了我加快PIC速度所需的時間。我忘記了我有多年的x86匯編經驗,并且已經花費了大量的時間來理解該架構的復雜性和細微差別,以及常見的邏輯結構,例如表格。這些知識讓我在PIC開發方面處于領先地位,但我仍然不得不重新構建我可編碼的許多函數,而不用考慮x86,以及克服我的偏見和假設。關于假設的令人討厭的事情是很容易忘記你曾經做過它們。
現實情況是,8位μP仍然存在,并且正在尋找越來越復雜的應用程序(參考文獻5)。在某些方面,它們專門用于某些任務,例如接口管理,傳感器監控和串行通信,因為音頻解碼器適用于MP3播放器。而且,在設備不斷變得更加智能化的世界中,它們以低成本提供了相當大的智能。
經典混淆和錯誤
臭蟲是討厭的小家伙,特別是如果他們是你自己的錯。以下是我制作的一些經典混淆和錯誤,希望您能避免:
十六進制/十進制混音:示例:當您使用10代替10而不是0'0a時。我發現最好在整個程序中使用一個基數和編號約定來避免歧義。
文字/地址混淆:我有很多關于文字和地址的混淆,因為兩者都被定義為常量。在16位和32位的世界中,匯編程序通常會標記對常量的誤用。例如,我沒有使用ADDLW posxw_table,而是使用ADDWF posxw_table,W。很明顯,這個錯誤是我的,因為我試圖在該地址而不是偏移處添加字節。然而,對于不熟悉的助記符,更容易犯這個錯誤,因為我習慣于使用Offset命令而不是明確地聲明我在add指令中使用了文字。
拐杖功能:早期,我的設計需要延遲功能。我第一次寫了一個計算周期。制作這種快速和骯臟功能的問題在于我繼續使用它的時間比我應該的時間長得多。更有用的功能,我知道我最終還是要編寫,是TMR0延遲。因為我依賴于拐杖功能,所以我避免編寫TMR0延遲,它定義了我的中斷結構和事件標記機制。當我寫TMR0延遲時,我不得不調整并重新調整它影響的部分。您應該更早而不是更晚地編寫基礎和結構函數。
始終清除內存或假設它未定義:一度,我遇到了一個看起來像參數的問題,讓我想知道存儲在EEPROM中的參數是如何設置的。當我檢查EEPROM時,參數是正確的,但程序無法根據參數執行。問題是由物理參數轉換為邏輯參數造成的。 EEPROM存儲上電參數,但您可以在運行模式下在RAM中更改它們。例如,您可以將速度從慢速切換到快速。我一直在為演示模式開發代碼,其中邏輯參數工作(以慢速模式啟動),但是當我以正常模式運行(以快速模式啟動)時它們失敗了。我造成了這個問題,因為我在用比特掩碼之前從未清除過邏輯參數;我錯誤地認為內存從0開始(當芯片通過0xff啟動時尤其愚蠢)!
確認所有模式在主要代碼更改:我經常在演示模式或編程模式下進行更改,然后在返回運行模式時發現錯誤。模式對整個系統狀態做出了不同的假設,并且在您花費時間對代碼的其他部分進行重大更改后,確認您的代碼不會違反這些假設。
強大的id =“id1138604-119-strong”>了解設備的架構:沒有什么比認識到芯片不能按照你想象的那樣工作的尷尬或沮喪。我已經說明了PIC家族對我的一些驚喜。雖然我可能會認為我使用了不充分的文檔,但我不理解芯片,并且我失去了寶貴的開發時間。我在16位和32位世界中學到的許多經驗都沒有延續到8位領域。僅當我無法弄清楚某些內容時才參考規格表,這不利于學習PIC架構。
了解您自己的硬件:一兩次,硬件人員的任務與他們說的不同。早期,我希望我創建了一個簡單測試硬件特性的虛擬程序,例如它是否驅動輸出高或低,所以我可以確認沒有人在我的原型上“修復”或“改進”電路板。此程序也類似于“健全性刻錄”,以確認測試運行失敗是您的代碼的結果,而不是因為硬件故障或更改。
-
PCB打樣
+關注
關注
17文章
2968瀏覽量
21791 -
華強PCB
+關注
關注
8文章
1831瀏覽量
27883 -
華強pcb線路板打樣
+關注
關注
5文章
14629瀏覽量
43138
發布評論請先 登錄
相關推薦
評論