2011年6月5日 星期日

Chapter 2

註: 本文為中文翻譯,原文請見底下網址:

http://www.mikroe.com/eng/chapters/view/3/chapter-2-core-sfrs/

TOC Introduction Ch. 1 Ch. 2 Ch. 3 Ch 4. Ch. 5 Ch. 6 Ch. 7 Ch. 8 Ch. 9 App. A App. B App. C

Chapter 2: Core SFRs

特殊暫存器 (Special function registers) 可以分成兩類:

● 核心暫存器 (Core (CPU) registers) – 負責控制與監測中央處理器的運作與程序 (process)。它們的數量雖然很少,但是整個微控制器的運作全仰賴這些暫存器。

● 周邊特殊暫存器 (Peripheral SFRs) – 負責控制周邊單元的運作 (序列通訊模組、A/D converter等)。這些暫存器每一個主要都是為了某個專門的電路而設計的,由於這個原因,這些暫存器跟它們所控制的電路會一併討論。

本章描述 PIC6F877 微控制器的核心 (CPU) 暫存器。由於它們控制著晶片內部許多不同的電路,不太可能它把們分成一些特別的群組,所以這些暫存器的位元和它們控制的程序 (processes) 將合在一起描述。

image

image
Fig. 2-1 STATUS Register

 

STATUS 暫存器包含了:W 暫存器的算術狀態,RESET 狀態和 data memory 的 bank 選擇位元。在寫值到這個暫存器的時候,應該要特別小心,因為如果你不小心弄錯了,結果可能會不如預期。例如,如果你嘗試使用 CLRF STATUS 指令清除所有位元,暫存器的結果將是 000xx1xx 而不是預期的 00000000。之所以會發生這種錯誤,是因為這個暫存器的某些位元是按照硬體而被設定或清除的,而且也因為 bit-3 和 bit-4 是唯讀的位元 (readable only)。基於這些原因,如果需要改變其內容(例如,要改變 active bank),建議只用不會影響任何狀態位元(位元 C,DC 和 Z)的指令。請參考 "Instruction Set Summary"。

image 

OPTION_REG 暫存器

image
Fig.2-2

OPTION_REG 暫存器包含了各種控制位元:Timer0/WDT prescaler, TMR0 計時器, 外部中斷和 PORTB 上的 pull-ups。

image

PS2, PS1, PS0 Prescaler Rate 選擇位元

Prescaler rate 的選擇辦法是透過組合這 3 個位元。先前說過,prescaler rate 取決於它是指派給 (TMR0) 或是 watchdog timer (WDT),如下表所示:

image

當 TMR0 計數脈衝的時候,為了達到 1:1 的 prescaler rate,prescaler 必須指派給 WDT。這麼一來,計時器 TMR0 就不會使用 prescaler,而是直接計數振盪器所產生的脈衝,這就是本來的目的!

中斷系統暫存器 (Interrupt System Registers)

中斷請求到達時,不代表中斷會自動發生,這是因為使用者也必須啟用中斷才行 (從程式內部啟用)。由於這個因素,有幾個特殊的位元用來啟用或停用中斷。要認出這些位元很容易,只要它們名稱裏有 IE 的便是 (代表Interrupt Enable)。此外,每個中斷會與另一個叫做旗號的位元關連,這個中斷旗號表示中斷請求已經到達,不管中斷有沒有啟用。中斷旗號也很容易認出,只要位元名稱最後兩個字母是 IF 的便是 (Interrupt Flag)。

正如所見,一切都是基於一個簡單而有效的想法。當一個中斷請求到達時,旗號首先會豎起來。

image
Fig. 2-8 Interrupt System Registers

如果恰當的 IE 位元沒有設定的話,中斷事件將被完全略過,不然的話,就會產生中斷!如果很多個中斷來源都有啟用,在中斷服務函式開始執行前,有必要偵測作用中的中斷為何。中斷來源的偵測辦法是檢查旗號位元。

中斷旗號不會自動清除,而是在中斷服務函式執行時才由軟體清除,知道這件事是很重要的。如果疏忽這個細節,當回到程式的時候,會立即發生另一個中斷,即使已經沒有中斷請求。簡單地說,之所以會如此,是因為中斷旗號和 IE 位元還豎著的關係。

PIC16F887 微控制器具代表性的中斷來源 (interrupt sources) 顯示在下一頁。注意幾件事情:

● GIE bit – 啟用所有未遮罩的中斷 (unmasked interrupts) 與同時停用所有中斷。

● PEIE bit – 啟用所有未遮罩的周邊中斷 (unmasked peripheral interrupts) 與停用所有周邊中斷(這跟計時器 TMR0 與 port B 中斷來源無關)。

為了啟用 port B 邏輯狀態改變而產生的中斷 (Interrupt on change),有必須單獨為 port B 的每個位元啟用中斷。在這種情況下,IOCB 便是負責控制 port B 的 IE 位元的暫存器。

image
Fig. 2-9 Interrupt SFRs

INTCON 暫存器

INTCON 暫存器包含許多啟用與旗號位元,用於 TMR0 暫存器溢位、Port B 狀態改變和外部腳位產生中斷等事件。

image

image
Fig. 2-10 INTCON Register

image

PIE1 暫存器

PIE1 暫存器包含了周邊中斷的啟用位元。

image

image
Fig. 2-11 PIE1 register

image

PIE2 暫存器

PIE2 暫存器也包含了各種中斷的啟用位元。

image

image
Fig. 2-12 PIE2 Register

image

PIR1 暫存器

PIR1 暫存器裏包含中斷旗號位元。

image

image
Fig. 2-13 PIR1 Register

image

PIR2 暫存器

PIR2 暫存器包含中斷旗號位元。

image

image
Fig. 2-14 PIR2 register

image

PCON 暫存器

PCON 暫存器僅包含兩個旗號位元,用來區分這些事件:power-on reset, brown-out reset, Watchdog Timer Reset 以 external reset(透過 MCLR 腳位)。

image

image
Fig. 2-15 PCON register

image

PCL and PCLATH 暫存器

PIC16F887 的 program memory 是 8K。因此,它有 8192 個位置供儲存程式。基於這個原因,program counter 必須是 13 位元寬 (2^13 = 8192)。為了讓 program memory 某些位置的內容可以在操作過程中改變,它的位址必須可以透過一些 SFR 來存取。由於所有 SFR 都是 8 位元寬,progrm counter 這個暫存器是 "人為" 創造出來的,方法是將 13 個位元分成兩個獨立的暫存器:PCLATH 和 PCL。

如果程式的執行不影響 program counter,program counter 暫存器會不斷地自動遞增 +1,+1,+1,+1 ... 這樣,程式如同一個指令跟著一個指令執行,沿著固定遞增的地址前進。

image
Fig. 2-16 PCL and PCLATH Registers

如果軟體會改變 program counter,為了避免出問題,有幾件事情應該牢記於心:

● 8 個低位元 (low byte) 來自 PCL 暫存器,可讀可寫,而 5 個高位元來自 PCLATH 暫存器則是唯寫(writable only)。

● 不管發生什麼 Reset,PCLATH 暫存器的內容都會被清除。

● 在組合語言中,program counter 是以 PCL 為標記,顯然它只指的只是 8 位元而已。在使用 "ADDWF PCL" 指令的時候應當小心。這是一個跳躍指令,指定目標位置,並加上一些數字到目前的位址中。這個經常用在跳到 look-up table 或 program branch table 的情況中。一個問題是,如果目前的位址在做加法運算後導致 PCLATH 的位元產生變化,你知道會發生什麼事嗎?在執行 PCL 所指的任何指令後,會同時導致 program counter 高位元的內容被 PCLATH 的內容取代。然而,PCL 暫存器只能存取 8 位元範圍內的指令 (256 bytes),接下來的跳躍指令將完全不正確。問題的解法是把跳躍指令放在以 xx00h 為結尾的位址。這讓程式得以跳到最多 255 個位置。如果要再跳躍更遠的地方,每當對 PCL 進行加法運算導致溢位的時候,PCLATH 就必須遞增1。

● 在呼叫 subroutine 或執行跳躍指令 (CALL 和 GOTO 指令) 時,微控制器只能提供 11 位元的定址能力。基於這個原因,類似 RAM 分成許多 banks,ROM 也分成 4 個 "pages",每個 page 大小 2K。在同一個 page 內,CALL 和 GOTO 這兩個指令的執行不會有問題,簡單的說,由於處理器提供 11 位元的位址,所以可以定址 2KB 內的任何位址。下圖跳到 subroutine PP1 說明了這種情況。但是,從跳躍的地方算起,如果 subroutine 或跳躍的目標位址不在同一個 page 內,就應當預備 program counter 剩下的兩個高位元的內容,方法是寫入到 PCLATH 暫存器。下圖跳到 subroutine PP2 說明了這種情況。

image
Fig. 2-17 PCLATH Registers

在這兩種情況下,當 subroutine 抵達 RETURN, RETLW 或 RETFIE 指令時 (以回到主程式),因為 return address 已經被 push 到 stack 裏,微控制器將從其當初離開的地方繼續執行程式。如前述,stack 由 8 個 13 位元的暫存器組成。

間接定址 (Indirect Addressing)

除了本身很合邏輯又清楚的直接定址外 (direct addressing) (具體指明某個暫存器便足以讀取其內容),這個微控制器也能夠執行間接定址 (indirect addressing),方法是透過 INDF 和 FSR 這兩個暫存器。這有時候大大簡化了程式的撰寫。整個過程是使用 INDF 這個不真實存在的暫存器 (實體上不存在),將目標暫存器的位址放在 FSR 暫存器裏,然後讀寫 INDF 暫存器,實際上就代表讀寫某個暫存器。換言之,方法是在 FSR 暫存器裏指明目標暫存器的位址,而目標暫存器的內容就會存放在 INDF 暫存器裏。直接定址和間接定址的差異如下圖所示:

正如所見,這邊的 "缺少位元" 問題乃透過向另一個暫存器借位元而獲得解決。這一次是使用 STATUS 暫存器第 7 個位元,稱為 IRP。

image
Fig. 2-18 Direct and Indirect addressing

5 意見:

wallace 提到...

有關直接和間接定址還是沒有很懂,有沒有其它的教學特別在說這塊的呢?

coopermaa 提到...

這段翻的不是很好,我剛剛稍微修飾了一下。

直接看範例會比較容易懂,請看 102 ASP(W400)訓練教材 P.37

另外,也可以參考外國網站這個範例,它用 Flash 動畫說明 FSR 和 INDF 的用法。

GCY 提到...

wallace :直接和間接定址在組合語言的概念都一樣,直接定址很好理解,間接定址就跟C語言的指標是類似的概念喔,希望這樣簡單的解釋能幫你到︿︿

wallace 提到...

指標,那我大概懂意思了,但是用間接定址的好處就是跟指標一樣囉

coopermaa 提到...

@wallace
是的,跟 C 的指標一樣。你可以這樣想:
FSR 放的是 address,而 INDF 則是 dereference,作讀寫用的。