(教學簡報內容保留所有版權~欲轉載請註明出處~謝謝)
本章有點長,內容也很多,建議分成2-3小節來教學…
P1.
這一章開始正式進入FPPA程式設計的世界,我會從一個簡單的程式開始解說,一邊介紹專案開發時最常應用的技巧還有程式控制的手段,一邊把系統規畫的概念導入給大家,讓大家對專案的規畫能有一個初步的概念。
P2.
要學習 FPPA 程式設計可以從幾個地方開始著手…
一、原廠 Datasheet。
二、FPPA指令集.doc 以及原廠光碟 Instructions Example code 目錄,有每個指令的簡單範例。
三、原廠光碟 Training Course 目錄,有 Assembler 的基本介紹跟一些程式流程的控制方法,譬如判斷等於大於小於、迴圈的用法…。
四、原廠光碟 Application Note 目錄,有提供一些專案常常會用到的周邊界面的程式範例,很有參考價值。
這些內容很詳細很豊富但是也很多,需要很多時間來學習,建議是先大略看過一遍,等有需要再去回頭去參考就好了。
這邊只介紹幾個「必學」的指令,這些指令算是最基本也最常用到的。
注意 iobit 跟一般 bit 的差別。
IDE簡介。
P3.
重點解說:
打開新專案樣板,開始寫第一個程式。
IO腳位的設定。
TODO 包含了執行按鍵的動作跟等待按鍵放開。
ICE實作,執行,詢問大家是否沒問題,有自己在家測試過?
P4.
作為一個按鍵從沒有按下到按下以及放開是一個完整的過程,也就是說,當我們按下一個按鍵時,希望某個命令只執行一次,而在按鍵按下的過程中,不要有干擾進來,因為,在按下的過程中,一旦有干擾過來,可能造成誤觸發過程,這並不是我們所想要的。因此在按鍵按下的時候,要把我們手上的干擾信號以及按鍵的機械接觸等干擾信號給濾除掉,一般情況下,我們可以採用電容來濾除掉這些干擾信號,但實際上,會增加硬體成本及硬體電路的體積,因此我們可以採用軟體濾波的方法去除這些干擾信號,一般情況下,一個按鍵按下的時候,總是在按下的時刻存在著一定的干擾信號,按下之後就基本上進入了穩定的狀態。具體的一個按鍵從按下到釋放的全過程的信號圖如上圖所示
從圖中可以看出,我們在程序設計時,從按鍵被識別按下之後,延時3-5ms以上,從而避開了干擾信號區域,我們再來檢測一次,看按鍵是否真得已經按下,若真得已經按下,這時肯定輸出為低電位,若這時檢測到的是高電位,證明剛才是由於干擾信號引起的誤觸發,CPU就認為是誤觸發信號而捨棄這次的按鍵識別過程。從而提高了系統的可靠性。
由於要求每按下一次,命令被執行一次,直到下一次再按下的時候,再執行一次命令,因此從按鍵被識別出來之後,我們就可以執行這次的命令,所以要有一個等待按鍵釋放的過程,顯然釋放的過程,就是使其恢復成高電位狀態。
P5.
介紹 Compare and Merge 基本用法。
副程式呼叫方式,Delay 副程式介紹,delay 時序的計算後面會提到。
接下來的程式,一直延續原來的程式。
P7.
重點講解:delay副程式,時間的計算。
程式的目的只有產生一段時間的延遲,並不在要求精確,所以這邊只用一個大略的值,當然你也可以仔細的去調整成準確的4ms,調整的技巧我們後續會提到,不過在這個例子,意義並不大,因此以程式的可讀性跟程式撰寫的方便性來作考量,也是最直覺的寫法。
P8.
輪詢-意即不斷的去檢查輸入的狀態,執行相對應的動作,動作與動作間會有處理優先順序的問題,而且是相依的,也就是若同時有很多按鍵被按下,程式也是按照一定的順序去執行。通常,由於 UI ( User Interface ) 是透過使用者透過按鍵之類輸入的觸動才會作用,一般而言都會有足夠的時間來反應,因此沒有必要特別的把不同的按鍵用多核多工的方式來處理。
P10.
問題討論:一個按鍵按住的時候另一個按鍵無法動作。
這時候會需要把按鍵再細分成按下跟放開兩種不同的狀況來處理,寫在同一段程序的優點是比較好寫、程序走向比較好掌握,缺點則是按鍵會相依,一個按鍵沒放開,另一個按鍵就無效。(demo),回頭看程式碼。
P11.
細分成兩個不同的狀態來寫的話,就不會有這個缺點,但是程式設計時對於事件處理的概念要更清楚。這是一個抽象化的過程,把 IO 的狀態,當成不同的事件來處理,把事件集中起來當成一個物件來處理,這其實也是物件導向程式設計的一個重要方法,有興趣的人可以找相關的書籍來參考。
P12.
程式的架構看起來像這樣,其實只是原來的延伸,只不過在輪詢時多處理二種狀況
P13.
問題討論:在一個系統中,常常會有很多像按鍵這樣子的狀況需要去處理,譬如按鍵輸入(IO觸發)、紅外線輸入、計時器、外部SENSOR的狀況… ,我們都可以用輪詢的方式去檢查系統的狀態來決定要不要做某些事情,
所以事實上,我們可以把這些都整合起來一起處理,寫在一起。
P14.
剛剛提到的的一個事件、狀態的概念,事件改變狀態,狀態造成動作,動作可能又引發不同的狀態。
用事件觸發的方式來處理底層 IO 不同的狀態要去執行的不同工作,程式碼寫起來就像這個樣子。程式碼其實是完全一樣,差別只在於,我們在實體 IO 跟程序之間多了一層「狀態」,而程序則是根據不同的狀態來跑程式。
P15.
至於狀態的檢查的程式碼也集中寫在一起,主要是檢查IO的狀態,設定相對應的事件。
這樣的好處有二個,一事件集中處理,不同輸入方式可以觸發相同的事件,相同輸入也可以觸發不同的事件。
二、對於按鈕的 low 或 high active 能統一在這裡作修改維護,而不會因為程式有好幾個地方需要作按鍵處理,分散開來,光維護就是個問題了。
P16.
左邊 FPPA1 負責檢查 IO 狀態並且 設定相對應發生的事件,中間 FPP0 則不斷檢查是不是有事件發生,有的話就去執行一段程式。
整個系統把它分成這樣的抽象概念後,就能夠很容易的進行系統分析的工作,並且系統變的能很容易的去增加新功能或刪除某個特定的功能。
P17.
舉個例來說,輸入的部份可以增加IR、觸控面板…甚至是透過PC連線控制、Chip 對 Chip…等等各種不同的操作方式,只要單獨去開發它的界面模組,然後把它對應成系統的事件就可以把界面掛到這個系統。
同樣的概念其實也可以應用在輸出的部份,不同的輸出等於不同的驅動模組。
P18.
重點講解:
這邊我們第一次用到了多核的方式來處理,一個CPU處理外部IO狀態造成的事件,一個CPU依據事件的發生來產生動作。大家也可以試試不用多核來寫會變成怎樣的寫法。
P19.
比較一下傳統的 MCU 程式設計方式。
P20.
以FPPA的觀點,程式可以讓妳自由的去分割到不同的CPU來執行,但是8個CPU仍舊是有限的,總不能讓無限制的來把程式分段放在不同的CPU來執行,系統一大起來,要處理的事情會變的非常的多,這個時候軟體的策略就很重要,怎樣去把不同的功能、不同的輸入、不同的輸出、重要性、優先程度、即時性…等等不同的系統需求來作整合、分配給不同的CPU使用,善用多核的優勢,才是FPPA程式設計的重要課題。
P21.
SOC 系統的規畫對一個專案的執行非常重要,整個系統其實就是一個狀態機,系統要求的功能抽象化出來,各個子系統可以獨立去設計、撰寫、維護程式,這對大型專案的開發非常有幫助,甚至可以讓多人協同開發一個大型專案變的相對容易。在軟體工程的定義上,便是資料層、邏輯層、表現層的分層規畫、設計,應用在韌體系統的開發上,其實是一樣的道理。
P22.
寫程式的目的不光只是在把功能寫出來,還要考慮到可讀性(萬一需要由不同的人來作維護)、維護的方便性(bug維護)、功能增刪的便利性(軟硬體功能變更),習慣上,我把專案分成幾個不同的控制物件來撰寫程式,也就是模組化、物件化的概念,一個專案裡面事實上大致區分成這幾種控制,控制與控制之間是依據整個系統的狀態來達成協調。
不管是用FPPA、PIC、8051、ARM或甚至用PC來開發程式,這個概念是不變的。
大家可以參考軟體工程、多核多工或物件導向相關的書籍可以有更深入的了解。
底下再回到實作。
P24.
延伸上節的概念,同樣的,我們也可以把動作的程式碼分配給不同的核心來做,使用的技巧是透過一個FLAG旗標來作設定動作是不是被觸發,觸發時設成1,觸發後設成0,負責處理動作的CPU則是一直在等待觸發絛件成立,然後執行觸發的動作。
P25.
程式的架講看起來像這樣,當然,你可以依系統需求來調整哪些動作需要用這樣的方式來觸發。
哪些?
一些不希望被干擾的動作、或反過來不希影響主程序的工作、需要長時間去執行的動作…都適合拿來用這樣子的模式觸發。
底下舉蜂鳴器來作範例。
P26.
重點講解,buzzer 發聲原理。
多核的應用蜂鳴器demo。
沒有用多核的話會如何?
程式不如預期~發生幾種狀況
一、按住的情況
二、放開的情況
三、連按的情怳
什麼原因? 怎麼解決?
P27.
如同按鍵防彈跳的處理方式一樣,我們也可以設立旗標來限定某些事件在某些狀況下允不允許執行。同樣的也是用FALG來作設置,在事件被鎖住時設成1,解除時設成0。
Demo 2個蜂嗚器,解決按住的問題。
P28.
隨時可以停止,控制一段程序的運行開始、停止的方法。
Demo 蜂嗚器 CPU 控制,解決放開的問題。
CPU停止的時機,主動或被動的方式?
P30.
讓一段程序的重新運行的方法。
注意:要小心 STACK 的回復。
Demo 蜂嗚器 PC 控制,解決連按時的問題。
P31.
IO 有支援 wait0 wait1 指令 RAM 沒有
P32.
重點講解,透過Lst 檔解析了解,FPPA在實際編譯成指令碼時的狀況,其實只是 ROM address 的 mov
同樣的用法可以用在取表指令 ldtabl 、 ldtabh
P33.
再回過頭來看之前的程式規劃,可以細分成這些個步驟。
P35.
一個按鍵的重作可以有很多不同操作的方法,按一下、按住、連按二下,按住3秒…
P37.
TIMER 計時器,主要的功用在系統定時,讓系統在固定時間會去執行某些程式,而在實際應用上可以分成兩大類,一、短時間的計時,二、長時間的計時。一般而言短時間的計時要求都是非常的精確到us,例如高速 PWM 輸出,這個我們可以用簡單的 delay 指令來達成,在往後的實習單元我們會用實例來介紹。而長時間的計時又分成二種,一種是要求不精準的,主要目的只是拿來分時執行不同的工作,另一種則正要求精確的長時間計時,譬如鬧鐘。其實基本的概念是相同的。
在實作上反而是長時間的計時比較麻煩也比較需要技巧,也就是這一章節主要要談的內容。
Todo的執行時間會影響到整個loop的總計時間,誤差會累積,並且難以控制。
如果有二件事要計時,要怎麼處理?
P38.
這是最直觀的作法,但是實際應用上會出問題,如果同時有好幾件工作要計時或有新的工作要加進來,時間就會變的難以估算。
P39.
解決的方法是使用 time_base counter 的辦法,計算出系統所需 timer 的最小公因數,作為固定延時的基數,透過計數才達到不同時間計時的目的。
P40.
同樣的Todo的執行時間會影響到整個loop的總計時間,誤差會累積,並且難以控制。
一般的專案這樣子的計時方式其實就己經足夠了,如果不是很CARE誤差,冬是要抓個大約的時間,間隔著去作,例如閃爍燈的功能。
但如果要更精確的計時?
P41.
解答:在傳統的 MCU 解決的方式是使用 TIMER 中斷,FPPA一樣也有 TIMER 中斷,我們後面再來介紹,先來看看,不用中斷,用FPPA多核的特性如何來解決?
使用上一章提到的事件觸發的技巧,由一個 cpu 負責計時,在時間到了的時候發起一個事件,或直接 trigger 另一個 cpu 工作。
如此,todo的執行時間並不會會影響到整個loop的總計時間,誤差較容易控制,甚至可以修正到0誤差。
P42.
Check Counter 0 跟 Check Counter 0 的時間相較於長時間的計時的話是非常的短的。
P44.
todo的執行時間並不會會影響到整個loop的總計時間,誤差較容易控制。
P46.
先討論為何會產生誤差,主要有二,一是因為程式運行本身需要時間,這個比較好修正,只要更改固定delay的時間即可,二是程式遇到的分岐造成延時不固定,在這裡 A 跟 B 就會有 1us 的誤差產生。
消除誤差的技巧不止在這裡用的到,其它很需要精確計算時序的應用也常常會用到。
P47.
方法很簡單,就是讓不同的分岐都跑相同的時間,也就是透過加空指令 nop 來調整時序,把變數都變成常數,如此一來要調整整個工作的時序就變的非常簡單了,只要改變常數就可以了,這個技巧在要求短時間且精確的時序控制上是非常有用的。
這樣程式看起來比較多,但卻比較具可讀性,而且確實的指定程式的走向,是比較方便維護的,不會因為程式碼增加淢少造成潛藏的bug。
P48.
另解決方式是使用系統提供的 16bit timer,接下來介紹它的基本使用方法。
FPPA 的中斷暫存器介紹
FPPA 負責處理中斷的CPU FPP0
FPPA 中斷運作的方式
P50.
FPPA TIMER 使用的暫存器介紹
使用 pa0 可以當作計數器
P52.
todo的執行時間並不會會影響到整個loop的總計時間,誤差不會累積,並且可以控制,甚至修正到零誤差。
(前提是todo的時間少於所給予的時間片段。
如果是透過事件驅動的方式,更是能夠準確的控時計時。
P53.
T16M 設定好後,不論有無啟用中斷均會開始累加,並且在進位時觸發 intrq,也就是說可以透過觀察intrq來看看是否有中斷請求發生(timer進位、pa0、pa1改變準位…),因此可以由別的CPU來處理中斷~而不打擾到FPP0的運行。
P54.
總結使用 TIMER 跟不使用 TIMER 的差別…
使用 TIMER 就像透過一個獨立計時裝置來計時,
如果TIIMER HANDLE 的處理時間小於 timer 的計時時間,則誤差是可以自動修正回來的,因此可以保證誤零誤差。
而使用自己計時的話,則要自己去計算,修正誤差,同樣的,也是能調整到零誤差,以結果而言,其實是一樣的,只是技巧不同。
P55.
傳統的 MCU 程式設計。
P56.
傳統的 MCU 的系統規畫只是概念上的抽象,到了真正實作還是得乖乖的循序去作,細節的處理跟實現都需要程式設計師去完成,多核的系統不止是概念上,連實作上都可以達到硬體層、邏輯層、表現層不同的縱向規畫。